refaktorálás javításai

This commit is contained in:
Roo
2026-03-13 10:22:41 +00:00
parent 2d8d23f469
commit f53e0b53df
140 changed files with 7316 additions and 4579 deletions

View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""
Central Model Registry for Service Finder
Automatically discovers and imports all SQLAlchemy models from the models directory,
ensuring Base.metadata is fully populated with tables, constraints, and indexes.
Usage:
from app.models.registry import Base, get_all_models, ensure_models_loaded
"""
import importlib
import os
import sys
from pathlib import Path
from typing import Dict, List, Type
from sqlalchemy.ext.declarative import DeclarativeMeta
from sqlalchemy.orm import DeclarativeBase
# Import the Base from database (circular dependency will be resolved later)
# We'll define our own Base if needed, but better to reuse existing one.
# We'll import after path setup.
# Add backend to path if not already
backend_dir = Path(__file__).parent.parent.parent
if str(backend_dir) not in sys.path:
sys.path.insert(0, str(backend_dir))
# Import Base from database (this will be the same Base used everywhere)
from app.database import Base
def discover_model_files() -> List[Path]:
"""
Walk through models directory and collect all .py files except __init__.py and registry.py.
"""
models_dir = Path(__file__).parent
model_files = []
for root, _, files in os.walk(models_dir):
for file in files:
if file.endswith('.py') and file not in ('__init__.py', 'registry.py'):
full_path = Path(root) / file
model_files.append(full_path)
return model_files
def import_module_from_file(file_path: Path) -> str:
"""
Import a Python module from its file path.
Returns the module name.
"""
# Compute module name relative to backend/app
rel_path = file_path.relative_to(backend_dir)
module_name = str(rel_path).replace(os.sep, '.').replace('.py', '')
try:
spec = importlib.util.spec_from_file_location(module_name, file_path)
if spec is None:
raise ImportError(f"Could not load spec for {module_name}")
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module_name
except Exception as e:
# Silently skip import errors (maybe due to missing dependencies)
# but log for debugging
print(f"⚠️ Could not import {module_name}: {e}", file=sys.stderr)
return None
def load_all_models() -> List[str]:
"""
Dynamically import all model files to populate Base.metadata.
Returns list of successfully imported module names.
"""
model_files = discover_model_files()
imported = []
for file in model_files:
module_name = import_module_from_file(file)
if module_name:
imported.append(module_name)
# Also ensure the __init__.py is loaded (it imports many models manually)
try:
import app.models
imported.append('app.models')
except ImportError:
pass
print(f"✅ Registry loaded {len(imported)} model modules. Total tables in metadata: {len(Base.metadata.tables)}")
return imported
def get_all_models() -> Dict[str, Type[DeclarativeMeta]]:
"""
Return a mapping of class name to model class for all registered SQLAlchemy models.
This works only after models have been imported.
"""
# This is a heuristic: find all subclasses of Base in loaded modules
from sqlalchemy.orm import DeclarativeBase
models = {}
for cls in Base.__subclasses__():
models[cls.__name__] = cls
# Also check deeper inheritance (if models inherit from other models that inherit from Base)
for module_name, module in sys.modules.items():
if module_name.startswith('app.models.'):
for attr_name in dir(module):
attr = getattr(module, attr_name)
if isinstance(attr, type) and issubclass(attr, Base) and attr is not Base:
models[attr.__name__] = attr
return models
def ensure_models_loaded():
"""
Ensure that all models are loaded into Base.metadata.
This is idempotent and can be called multiple times.
"""
if len(Base.metadata.tables) == 0:
load_all_models()
else:
# Already loaded
pass
# Auto-load models when this module is imported (optional, but useful)
# We'll make it explicit via a function call to avoid side effects.
# Instead, we'll provide a function to trigger loading.
# Export
__all__ = ['Base', 'discover_model_files', 'load_all_models', 'get_all_models', 'ensure_models_loaded']