Alembic configuration
This commit is contained in:
@@ -1,175 +0,0 @@
|
||||
# scripts/setup_dev.py
|
||||
# !/usr/bin/env python3
|
||||
"""Development environment setup script."""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def run_command(command, description):
|
||||
"""Run a shell command and handle errors."""
|
||||
print(f"Running: {description}")
|
||||
try:
|
||||
subprocess.run(command, shell=True, check=True)
|
||||
print(f"✅ {description} completed successfully")
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ {description} failed: {e}")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def setup_alembic():
|
||||
"""Set up Alembic for database migrations."""
|
||||
alembic_dir = Path("alembic")
|
||||
|
||||
# Check if alembic directory exists and has necessary files
|
||||
if not alembic_dir.exists() or not (alembic_dir / "script.py.mako").exists():
|
||||
print("📝 Initializing Alembic...")
|
||||
if alembic_dir.exists():
|
||||
# Remove incomplete alembic directory
|
||||
import shutil
|
||||
|
||||
shutil.rmtree(alembic_dir)
|
||||
|
||||
if not run_command("alembic init alembic", "Initializing Alembic"):
|
||||
return False
|
||||
|
||||
# Update alembic/env.py with proper configuration
|
||||
env_py_content = '''from logging.config import fileConfig
|
||||
from sqlalchemy import engine_from_config, pool
|
||||
from alembic import context
|
||||
import os
|
||||
import sys
|
||||
|
||||
# Add your project directory to the Python path
|
||||
sys.path.append(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
from models.database import Base
|
||||
from config.settings import settings
|
||||
|
||||
# Alembic Config object
|
||||
config = context.config
|
||||
|
||||
# Override sqlalchemy.url with our settings
|
||||
config.set_main_option("sqlalchemy.url", settings.database_url)
|
||||
|
||||
if config.config_file_name is not None:
|
||||
fileConfig(config.config_file_name)
|
||||
|
||||
target_metadata = Base.metadata
|
||||
|
||||
def run_migrations_offline() -> None:
|
||||
"""Run migrations in 'offline' mode."""
|
||||
url = config.get_main_option("sqlalchemy.url")
|
||||
context.configure(
|
||||
url=url,
|
||||
target_metadata=target_metadata,
|
||||
literal_binds=True,
|
||||
dialect_opts={"paramstyle": "named"},
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
def run_migrations_online() -> None:
|
||||
"""Run migrations in 'online' mode."""
|
||||
connectable = engine_from_config(
|
||||
config.get_section(config.config_ini_section, {}),
|
||||
prefix="sqlalchemy.",
|
||||
poolclass=pool.NullPool,
|
||||
)
|
||||
|
||||
with connectable.connect() as connection:
|
||||
context.configure(
|
||||
connection=connection, target_metadata=target_metadata
|
||||
)
|
||||
|
||||
with context.begin_transaction():
|
||||
context.run_migrations()
|
||||
|
||||
if context.is_offline_mode():
|
||||
run_migrations_offline()
|
||||
else:
|
||||
run_migrations_online()
|
||||
'''
|
||||
|
||||
env_py_path = alembic_dir / "env.py"
|
||||
env_py_path.write_text(env_py_content)
|
||||
print("✅ Updated alembic/env.py with project configuration")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def setup_environment():
|
||||
"""Set up the development environment."""
|
||||
print("🚀 Setting up ecommerce API development environment...")
|
||||
|
||||
# Check Python version
|
||||
if sys.version_info < (3, 8):
|
||||
print("❌ Python 3.8+ is required")
|
||||
return False
|
||||
|
||||
# Create .env file if it doesn't exist
|
||||
env_file = Path(".env")
|
||||
env_example = Path(".env.example")
|
||||
|
||||
if not env_file.exists() and env_example.exists():
|
||||
print("📝 Creating .env file from .env.example...")
|
||||
env_file.write_text(env_example.read_text())
|
||||
elif not env_file.exists():
|
||||
print("📝 Creating default .env file...")
|
||||
default_env = """DATABASE_URL=sqlite:///./ecommerce.db
|
||||
JWT_SECRET_KEY=development-secret-key-change-in-production
|
||||
JWT_EXPIRE_HOURS=24
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
DEBUG=True
|
||||
RATE_LIMIT_ENABLED=True
|
||||
DEFAULT_RATE_LIMIT=100
|
||||
DEFAULT_WINDOW_SECONDS=3600
|
||||
LOG_LEVEL=INFO
|
||||
"""
|
||||
env_file.write_text(default_env)
|
||||
|
||||
# Install dependencies
|
||||
if not run_command("pip install -r requirements.txt", "Installing dependencies"):
|
||||
return False
|
||||
|
||||
# Set up Alembic
|
||||
if not setup_alembic():
|
||||
print(
|
||||
"⚠️ Alembic setup failed. You'll need to set up database migrations manually."
|
||||
)
|
||||
return False
|
||||
|
||||
# Create initial migration
|
||||
if not run_command(
|
||||
'alembic revision --autogenerate -m "Initial migration"',
|
||||
"Creating initial migration",
|
||||
):
|
||||
print("⚠️ Initial migration creation failed. Check your database models.")
|
||||
|
||||
# Apply migrations
|
||||
if not run_command("alembic upgrade head", "Setting up database"):
|
||||
print(
|
||||
"⚠️ Database setup failed. Make sure your DATABASE_URL is correct in .env"
|
||||
)
|
||||
|
||||
# Run tests
|
||||
if not run_command("pytest", "Running tests"):
|
||||
print("⚠️ Some tests failed. Check the output above.")
|
||||
|
||||
print("\n🎉 Development environment setup complete!")
|
||||
print("To start the development server, run:")
|
||||
print(" uvicorn main:app --reload")
|
||||
print("\nDatabase commands:")
|
||||
print(' alembic revision --autogenerate -m "Description" # Create migration')
|
||||
print(" alembic upgrade head # Apply migrations")
|
||||
print(" alembic current # Check status")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup_environment()
|
||||
200
scripts/verify_setup.py
Normal file
200
scripts/verify_setup.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# scripts/verify_setup.py
|
||||
"""Verify database setup and migration status for complete project structure."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from sqlalchemy import create_engine, text
|
||||
from alembic import command
|
||||
from alembic.config import Config
|
||||
|
||||
# Add project root to Python path (same as alembic does)
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
|
||||
def verify_database_setup():
|
||||
"""Verify database and migration setup."""
|
||||
|
||||
print("[VERIFY] Verifying database setup...")
|
||||
print()
|
||||
|
||||
# Check if database file exists
|
||||
db_path = "ecommerce.db"
|
||||
if not os.path.exists(db_path):
|
||||
print("[ERROR] Database file not found!")
|
||||
return False
|
||||
|
||||
print(f"[OK] Database file exists: {db_path}")
|
||||
|
||||
try:
|
||||
# Create engine and connect
|
||||
engine = create_engine('sqlite:///./ecommerce.db')
|
||||
|
||||
with engine.connect() as conn:
|
||||
# Get table list
|
||||
result = conn.execute(text("SELECT name FROM sqlite_master WHERE type='table'"))
|
||||
tables = [row[0] for row in result.fetchall()]
|
||||
|
||||
print(f"[OK] Found {len(tables)} tables:")
|
||||
|
||||
# Expected tables from your models
|
||||
expected_tables = [
|
||||
'users', 'products', 'stock', 'shops', 'shop_products',
|
||||
'marketplace_import_jobs', 'alembic_version'
|
||||
]
|
||||
|
||||
for table in sorted(tables):
|
||||
if table == 'alembic_version':
|
||||
print(f" ✓ {table} (migration tracking)")
|
||||
elif table in expected_tables:
|
||||
print(f" ✓ {table}")
|
||||
else:
|
||||
print(f" ? {table} (unexpected)")
|
||||
|
||||
# Check for missing expected tables
|
||||
missing_tables = set(expected_tables) - set(tables) - {'alembic_version'}
|
||||
if missing_tables:
|
||||
print(f"[WARNING] Missing expected tables: {missing_tables}")
|
||||
|
||||
# Check if alembic_version table exists
|
||||
if 'alembic_version' in tables:
|
||||
result = conn.execute(text("SELECT version_num FROM alembic_version"))
|
||||
version = result.fetchone()
|
||||
if version:
|
||||
print(f"[OK] Migration version: {version[0]}")
|
||||
else:
|
||||
print("[WARNING] No migration version recorded")
|
||||
else:
|
||||
print("[ERROR] No alembic_version table - migrations not initialized")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Database connection failed: {e}")
|
||||
return False
|
||||
|
||||
# Check Alembic configuration
|
||||
try:
|
||||
alembic_cfg = Config("alembic.ini")
|
||||
print("[OK] Alembic configuration found")
|
||||
|
||||
# Try to get current migration
|
||||
print()
|
||||
print("[MIGRATE] Current migration status:")
|
||||
command.current(alembic_cfg, verbose=True)
|
||||
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Alembic configuration issue: {e}")
|
||||
return False
|
||||
|
||||
print()
|
||||
print("[SUCCESS] Database setup verification completed!")
|
||||
return True
|
||||
|
||||
|
||||
def verify_model_structure():
|
||||
"""Verify both database and API model structure."""
|
||||
|
||||
print("[MODELS] Verifying model structure...")
|
||||
|
||||
# Test database models
|
||||
try:
|
||||
from models.database.base import Base
|
||||
print(f"[OK] Database Base imported")
|
||||
print(f"[INFO] Found {len(Base.metadata.tables)} database tables: {list(Base.metadata.tables.keys())}")
|
||||
|
||||
# Import specific models
|
||||
from models.database.user import User
|
||||
from models.database.product import Product
|
||||
from models.database.stock import Stock
|
||||
from models.database.shop import Shop, ShopProduct
|
||||
from models.database.marketplace import MarketplaceImportJob
|
||||
|
||||
print("[OK] All database models imported successfully")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"[ERROR] Database model import failed: {e}")
|
||||
return False
|
||||
|
||||
# Test API models
|
||||
try:
|
||||
import models.api
|
||||
print("[OK] API models package imported")
|
||||
|
||||
# Test specific API model imports
|
||||
api_modules = ['base', 'auth', 'product', 'stock', 'shop', 'marketplace', 'admin', 'stats']
|
||||
for module in api_modules:
|
||||
try:
|
||||
__import__(f'models.api.{module}')
|
||||
print(f" ✓ models.api.{module}")
|
||||
except ImportError:
|
||||
print(f" ? models.api.{module} (not found, optional)")
|
||||
|
||||
except ImportError as e:
|
||||
print(f"[WARNING] API models import issue: {e}")
|
||||
# This is not critical for database operations
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def check_project_structure():
|
||||
"""Check overall project structure."""
|
||||
|
||||
print(f"\n[STRUCTURE] Checking project structure...")
|
||||
|
||||
critical_paths = [
|
||||
"models/database/base.py",
|
||||
"models/database/user.py",
|
||||
"models/database/product.py",
|
||||
"models/database/stock.py",
|
||||
"app/core/config.py",
|
||||
"alembic/env.py",
|
||||
"alembic.ini"
|
||||
]
|
||||
|
||||
for path in critical_paths:
|
||||
if os.path.exists(path):
|
||||
print(f" ✓ {path}")
|
||||
else:
|
||||
print(f" ✗ {path} (missing)")
|
||||
|
||||
# Check __init__.py files
|
||||
init_files = [
|
||||
"models/__init__.py",
|
||||
"models/database/__init__.py",
|
||||
"models/api/__init__.py"
|
||||
]
|
||||
|
||||
print(f"\n[INIT] Checking __init__.py files...")
|
||||
for init_file in init_files:
|
||||
if os.path.exists(init_file):
|
||||
print(f" ✓ {init_file}")
|
||||
else:
|
||||
print(f" ✗ {init_file} (missing - will cause import issues)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = True
|
||||
|
||||
check_project_structure()
|
||||
|
||||
if verify_model_structure():
|
||||
success = verify_database_setup()
|
||||
else:
|
||||
success = False
|
||||
|
||||
if success:
|
||||
print()
|
||||
print("[READY] 🎉 Your complete project structure is ready!")
|
||||
print()
|
||||
print("Database models: ✓ SQLAlchemy models for data storage")
|
||||
print("API models: ✓ Pydantic models for request/response validation")
|
||||
print("Migrations: ✓ Alembic managing database schema")
|
||||
print()
|
||||
print("Next steps:")
|
||||
print(" 1. Run 'make dev' to start your FastAPI server")
|
||||
print(" 2. Visit http://localhost:8000/docs for interactive API docs")
|
||||
print(" 3. Use your API endpoints for authentication, products, stock, etc.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print()
|
||||
print("[FAILED] Project setup has issues that need to be resolved!")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user