Fix Alembic migration import error in containerized environment
This commit is contained in:
parent
da0fe5a40e
commit
a1c3bee298
@ -1,11 +1,19 @@
|
|||||||
"""
|
"""
|
||||||
Alembic environment script for database migrations
|
Alembic environment script for database migrations
|
||||||
"""
|
"""
|
||||||
|
import sys
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
|
# Custom module to help with finding modules in containerized environments
|
||||||
|
from alembic.find_modules import setup_python_path
|
||||||
from sqlalchemy import engine_from_config, pool
|
from sqlalchemy import engine_from_config, pool
|
||||||
|
|
||||||
|
# Setup Python path to find app modules in various environments
|
||||||
|
setup_python_path()
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
config = context.config
|
config = context.config
|
||||||
@ -15,10 +23,43 @@ config = context.config
|
|||||||
if config.config_file_name is not None:
|
if config.config_file_name is not None:
|
||||||
fileConfig(config.config_file_name)
|
fileConfig(config.config_file_name)
|
||||||
|
|
||||||
# add your model's MetaData object here
|
# Try different import strategies to handle various deployment environments
|
||||||
# for 'autogenerate' support
|
try:
|
||||||
from app.models import Todo # noqa
|
# Standard import approach
|
||||||
from app.core.database import Base # noqa
|
from app.models import Todo # noqa
|
||||||
|
from app.core.database import Base # noqa
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
# Path-based import for some container setups
|
||||||
|
import importlib.util
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Try to find the module file
|
||||||
|
for base_path in sys.path:
|
||||||
|
model_path = Path(base_path) / "app" / "models" / "todo.py"
|
||||||
|
db_path = Path(base_path) / "app" / "core" / "database.py"
|
||||||
|
|
||||||
|
if model_path.exists() and db_path.exists():
|
||||||
|
# Load the todo module
|
||||||
|
spec = importlib.util.spec_from_file_location("todo", model_path)
|
||||||
|
todo_module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(todo_module)
|
||||||
|
|
||||||
|
# Load the database module
|
||||||
|
spec = importlib.util.spec_from_file_location("database", db_path)
|
||||||
|
db_module = importlib.util.module_from_spec(spec)
|
||||||
|
spec.loader.exec_module(db_module)
|
||||||
|
|
||||||
|
# Get the required objects
|
||||||
|
Todo = getattr(todo_module, "Todo")
|
||||||
|
Base = getattr(db_module, "Base")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ImportError("Could not find app modules in any path")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error importing models: {e}")
|
||||||
|
print(f"Current sys.path: {sys.path}")
|
||||||
|
raise
|
||||||
|
|
||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
|
29
alembic/find_modules.py
Normal file
29
alembic/find_modules.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
Module finder helper for Alembic migrations in containerized environments.
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def setup_python_path():
|
||||||
|
"""
|
||||||
|
Add necessary paths to Python's sys.path to make imports work
|
||||||
|
in various environments including Docker containers
|
||||||
|
"""
|
||||||
|
# Get the directory where this script is located
|
||||||
|
current_dir = Path(__file__).resolve().parent
|
||||||
|
|
||||||
|
# The project root is one level up from the 'alembic' directory
|
||||||
|
project_root = current_dir.parent
|
||||||
|
|
||||||
|
# Add the project root to the Python path if it's not already there
|
||||||
|
if str(project_root) not in sys.path:
|
||||||
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
# Check if we're in a Docker container with code mounted at /app/repo
|
||||||
|
repo_path = Path('/app/repo')
|
||||||
|
if repo_path.exists() and str(repo_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(repo_path))
|
||||||
|
|
||||||
|
# Return the actual Python paths used, for debugging
|
||||||
|
return sys.path
|
50
test_imports.py
Normal file
50
test_imports.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
Test script to verify imports work correctly.
|
||||||
|
This can be run both locally and in the container to verify the setup.
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Print current working directory
|
||||||
|
print(f"Current working directory: {os.getcwd()}")
|
||||||
|
|
||||||
|
# Print Python path
|
||||||
|
print(f"Python path: {sys.path}")
|
||||||
|
|
||||||
|
# Try to import the app modules
|
||||||
|
try:
|
||||||
|
# Add current directory to path
|
||||||
|
sys.path.insert(0, os.getcwd())
|
||||||
|
|
||||||
|
# Try importing the models
|
||||||
|
from app.models import Todo
|
||||||
|
print(f"Successfully imported Todo from app.models: {Todo}")
|
||||||
|
|
||||||
|
from app.core.database import Base
|
||||||
|
print(f"Successfully imported Base from app.core.database: {Base}")
|
||||||
|
|
||||||
|
print("All imports succeeded!")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error importing modules: {e}")
|
||||||
|
|
||||||
|
# Try a different approach for containerized environments
|
||||||
|
try:
|
||||||
|
# Try to execute the find_modules code
|
||||||
|
sys.path.insert(0, os.path.join(os.getcwd(), 'alembic'))
|
||||||
|
from find_modules import setup_python_path
|
||||||
|
|
||||||
|
# Setup paths
|
||||||
|
paths = setup_python_path()
|
||||||
|
print(f"Updated paths: {paths}")
|
||||||
|
|
||||||
|
# Try importing again
|
||||||
|
from app.models import Todo
|
||||||
|
print(f"Successfully imported Todo after path setup: {Todo}")
|
||||||
|
|
||||||
|
from app.core.database import Base
|
||||||
|
print(f"Successfully imported Base after path setup: {Base}")
|
||||||
|
|
||||||
|
print("Imports succeeded after path setup!")
|
||||||
|
except Exception as inner_e:
|
||||||
|
print(f"Still failed after path setup: {inner_e}")
|
||||||
|
print("This might indicate a deeper issue with the module structure.")
|
Loading…
x
Reference in New Issue
Block a user