SCGR's picture
fix HF register & dynamic fallback
3cf9fa0
# ---- ensure .env is loaded for alembic too ----
from pathlib import Path
try:
from dotenv import load_dotenv
# Use utf-8-sig to strip BOM just in case
load_dotenv(dotenv_path=Path(__file__).resolve().parents[1] / ".env",
override=True, encoding="utf-8-sig")
except Exception:
pass
# -----------------------------------------------
import os
import sys
from dotenv import load_dotenv
# Set environment encoding to handle Windows encoding issues
if sys.platform == "win32":
import locale
try:
# Try to set UTF-8 encoding for environment variables
os.environ['PYTHONIOENCODING'] = 'utf-8'
except:
pass
env_path = os.path.join(os.path.dirname(__file__), '..', '.env')
print(f"Looking for .env file at: {env_path}")
print(f".env file exists: {os.path.exists(env_path)}")
if os.path.exists(env_path):
load_dotenv(env_path, encoding="utf-8-sig")
print("SUCCESS: Loaded .env file from py_backend directory")
else:
print("ERROR: .env file not found in py_backend directory")
# Try current directory
load_dotenv(encoding="utf-8-sig")
print("INFO: Attempted to load .env from current directory")
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from alembic import context
from sqlalchemy import create_engine, pool
try:
from app.models import Base
target_metadata = Base.metadata
print("Successfully imported models from app.models")
except ImportError as e:
print(f"Could not import app.models: {e}")
print(f"Current working directory: {os.getcwd()}")
print(f"Python path: {sys.path}")
from sqlalchemy import MetaData
target_metadata = MetaData()
print("Using fallback metadata - migrations may not work properly")
config = context.config
target_metadata = Base.metadata
def _get_db_url() -> str:
"""
Prefer a dedicated migration URL; otherwise use the app URL.
Only adds sslmode=require for remote connections (not localhost).
"""
# Debug: Environment variables loaded
print("Environment variables loaded")
url = os.getenv("ALEMBIC_DATABASE_URL") or os.getenv("DATABASE_URL")
if not url:
print("No DATABASE_URL found in environment")
raise RuntimeError("Set ALEMBIC_DATABASE_URL or DATABASE_URL for Alembic migrations.")
# Clean the URL to remove any problematic characters (fallback for edge cases)
try:
# Test if the URL can be used for connection
url.encode('utf-8').decode('utf-8')
except UnicodeError:
print("WARNING: Encoding issue detected in database URL, attempting to clean...")
# Replace common problematic characters
url = url.replace('"', '"').replace('"', '"') # Smart quotes
url = url.replace(''', "'").replace(''', "'") # Smart apostrophes
url = url.replace('–', '-').replace('β€”', '-') # En/em dashes
# Remove any non-ASCII characters
url = ''.join(char for char in url if ord(char) < 128)
print("Cleaned URL: [HIDDEN]")
print("Alembic database URL: [HIDDEN]")
if url.startswith("psql '") and url.endswith("'"):
url = url[6:-1]
print("Cleaned URL: [HIDDEN]")
if "sslmode=" not in url and "localhost" not in url and "127.0.0.1" not in url:
url = f"{url}{'&' if '?' in url else '?'}sslmode=require"
print(f"Added sslmode: {url}")
return url
def run_migrations_offline() -> None:
"""Run migrations in 'offline' mode."""
url = _get_db_url()
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
compare_type=True,
compare_server_default=True,
)
with context.begin_transaction():
context.run_migrations()
def run_migrations_online() -> None:
"""Run migrations in 'online' mode."""
try:
url = _get_db_url()
print(f"Creating engine with URL: {url}")
# Add encoding parameters to handle Windows encoding issues
engine_kwargs = {
'poolclass': pool.NullPool,
'future': True,
}
# For PostgreSQL connections, add encoding parameters
if url.startswith('postgresql://'):
engine_kwargs['connect_args'] = {
'client_encoding': 'utf8',
'options': '-c client_encoding=utf8'
}
connectable = create_engine(url, **engine_kwargs)
print("Engine created successfully")
with connectable.connect() as connection:
print("Database connection established")
context.configure(
connection=connection,
target_metadata=target_metadata,
compare_type=True,
compare_server_default=True,
)
with context.begin_transaction():
print("Running migrations...")
context.run_migrations()
print("Migrations completed successfully")
except Exception as e:
print(f"Migration failed: {e}")
print(f"Error type: {type(e).__name__}")
import traceback
print(f"Full traceback: {traceback.format_exc()}")
raise
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()