diff --git a/app/api/v1/endpoints/audit.py b/app/api/v1/endpoints/audit.py index 01183f5..15d24a5 100644 --- a/app/api/v1/endpoints/audit.py +++ b/app/api/v1/endpoints/audit.py @@ -13,7 +13,7 @@ from app.auth.metadata_dependencies import ( get_current_metadata_admin, get_current_metadata_user, ) -from app.infra.db.metadata.database import get_metadata_session +from app.infra.db.metadb.database import get_metadata_session from sqlalchemy.ext.asyncio import AsyncSession router = APIRouter() diff --git a/app/auth/metadata_dependencies.py b/app/auth/metadata_dependencies.py index 7846396..50e22fa 100644 --- a/app/auth/metadata_dependencies.py +++ b/app/auth/metadata_dependencies.py @@ -8,7 +8,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.auth.keycloak_dependencies import get_current_keycloak_sub from app.core.config import settings -from app.infra.db.metadata.database import get_metadata_session +from app.infra.db.metadb.database import get_metadata_session from app.infra.repositories.metadata_repository import MetadataRepository logger = logging.getLogger(__name__) diff --git a/app/auth/project_dependencies.py b/app/auth/project_dependencies.py index a1d68df..fd65703 100644 --- a/app/auth/project_dependencies.py +++ b/app/auth/project_dependencies.py @@ -11,7 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.auth.keycloak_dependencies import get_current_keycloak_sub from app.core.config import settings from app.infra.db.dynamic_manager import project_connection_manager -from app.infra.db.metadata.database import get_metadata_session +from app.infra.db.metadb.database import get_metadata_session from app.infra.repositories.metadata_repository import MetadataRepository DB_ROLE_BIZ_DATA = "biz_data" diff --git a/app/core/audit.py b/app/core/audit.py index b3f96eb..90d57ff 100644 --- a/app/core/audit.py +++ b/app/core/audit.py @@ -66,7 +66,7 @@ async def log_audit_event( response_status: 响应状态码 session: 元数据库会话(可选) """ - from app.infra.db.metadata.database import SessionLocal + from app.infra.db.metadb.database import SessionLocal from app.infra.repositories.audit_repository import AuditRepository if request_data: diff --git a/app/infra/audit/middleware.py b/app/infra/audit/middleware.py index 556f5e0..b04b2b2 100644 --- a/app/infra/audit/middleware.py +++ b/app/infra/audit/middleware.py @@ -15,7 +15,7 @@ import logging from jose import JWTError, jwt from app.core.config import settings -from app.infra.db.metadata.database import SessionLocal +from app.infra.db.metadb.database import SessionLocal from app.infra.repositories.metadata_repository import MetadataRepository logger = logging.getLogger(__name__) diff --git a/app/infra/db/metadata/__init__.py b/app/infra/db/metadb/__init__.py similarity index 100% rename from app/infra/db/metadata/__init__.py rename to app/infra/db/metadb/__init__.py diff --git a/app/infra/db/metadata/database.py b/app/infra/db/metadb/database.py similarity index 100% rename from app/infra/db/metadata/database.py rename to app/infra/db/metadb/database.py diff --git a/app/infra/db/metadata/models.py b/app/infra/db/metadb/models.py similarity index 100% rename from app/infra/db/metadata/models.py rename to app/infra/db/metadb/models.py diff --git a/app/infra/repositories/__init__.py b/app/infra/db/metadb/repositories/__init__.py similarity index 100% rename from app/infra/repositories/__init__.py rename to app/infra/db/metadb/repositories/__init__.py diff --git a/app/infra/repositories/audit_repository.py b/app/infra/db/metadb/repositories/audit_repository.py similarity index 98% rename from app/infra/repositories/audit_repository.py rename to app/infra/db/metadb/repositories/audit_repository.py index 91af4fb..cd24d85 100644 --- a/app/infra/repositories/audit_repository.py +++ b/app/infra/db/metadb/repositories/audit_repository.py @@ -6,7 +6,7 @@ from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from app.domain.schemas.audit import AuditLogResponse -from app.infra.db.metadata import models +from app.infra.db.metadb import models class AuditRepository: diff --git a/app/infra/repositories/metadata_repository.py b/app/infra/db/metadb/repositories/metadata_repository.py similarity index 99% rename from app/infra/repositories/metadata_repository.py rename to app/infra/db/metadb/repositories/metadata_repository.py index b9c47b7..943097f 100644 --- a/app/infra/repositories/metadata_repository.py +++ b/app/infra/db/metadb/repositories/metadata_repository.py @@ -12,7 +12,7 @@ from app.core.encryption import ( is_database_encryption_configured, is_encryption_configured, ) -from app.infra.db.metadata import models +from app.infra.db.metadb import models def _normalize_postgres_dsn(dsn: str) -> str: diff --git a/app/infra/repositories/user_repository.py b/app/infra/db/metadb/repositories/user_repository.py similarity index 100% rename from app/infra/repositories/user_repository.py rename to app/infra/db/metadb/repositories/user_repository.py diff --git a/app/main.py b/app/main.py index 947647c..fe00e06 100644 --- a/app/main.py +++ b/app/main.py @@ -10,7 +10,7 @@ from app.api.v1.router import api_router from app.infra.db.timescaledb.database import db as tsdb from app.infra.db.postgresql.database import db as pgdb from app.infra.db.dynamic_manager import project_connection_manager -from app.infra.db.metadata.database import close_metadata_engine +from app.infra.db.metadb.database import close_metadata_engine from app.services.tjnetwork import open_project from app.core.config import settings diff --git a/scripts/build_extensions.py b/scripts/build_extensions.py new file mode 100755 index 0000000..4877d07 --- /dev/null +++ b/scripts/build_extensions.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +import os +import sys +import shutil +from setuptools import setup, Extension +from Cython.Build import cythonize + + +def build_extensions(target_dirs): + """ + Compiles all .py files in the target directories (recursively) into .so/.pyd extensions. + Args: + target_dirs (list or str): List of directories or single directory path to scan. + """ + # Ensure input is a list + if isinstance(target_dirs, str): + target_dirs = [target_dirs] + + extensions = [] + project_root = os.getcwd() + + print(f"Scanning directories: {target_dirs}") + + for target_dir in target_dirs: + # Ensure target directory exists + if not os.path.exists(target_dir): + print(f"Warning: Directory '{target_dir}' not found. Skipping.") + continue + + # Get the absolute path of the target directory + abs_target_dir = os.path.abspath(target_dir) + + print(f"Scanning {abs_target_dir} for Python files...") + + # Walk through the directory + for root, dirs, files in os.walk(abs_target_dir): + for file in files: + if file.endswith(".py"): + file_path = os.path.join(root, file) + + # Skip this script if it happens to be in the target dir + if os.path.abspath(file_path) == os.path.abspath(__file__): + continue + + # Skip setup.py if it exists + if file == "setup.py": + continue + + # Determine the module name based on path relative to project root + # This ensures imports like 'from app.services import ...' work + try: + rel_path = os.path.relpath(file_path, project_root) + except ValueError: + # If file is not under project root, we can't easily determine module name + # relative to project root. Skip or warn. + print( + f"Skipping {file_path}: cannot determine relative path to {project_root}" + ) + continue + + # Convert file path to module name (e.g. app/services/foo.py -> app.services.foo) + module_name = os.path.splitext(rel_path)[0].replace(os.sep, ".") + + print(f"Found: {rel_path} -> {module_name}") + + extensions.append(Extension(module_name, [file_path])) + + if not extensions: + print("No Python files found to compile.") + return + + print(f"\nCompiling {len(extensions)} modules...") + + # Build options + # compiler_directives: language_level=3 for Python 3 + # force=True: force recompilation even if timestamps are up to date + try: + setup( + ext_modules=cythonize( + extensions, + compiler_directives={"language_level": "3"}, + build_dir="build", # Put intermediate files in build/ directory + force=True, + ), + script_args=["build_ext", "--inplace"], + ) + print("\nCompilation successful!") + except Exception as e: + print(f"\nCompilation failed: {e}") + sys.exit(1) + finally: + # Cleanup build directory (intermediate C files) + if os.path.exists("build"): + print("Cleaning up build artifacts...") + try: + shutil.rmtree("build") + except OSError as e: + print(f"Warning: Failed to clean up build directory: {e}") + + +if __name__ == "__main__": + # Default directories to compile if none provided + DEFAULT_TARGETS = ["app/services", "app/native", "app/services"] + + # Check for help flag + if len(sys.argv) > 1 and sys.argv[1] in ["--help", "-h"]: + print("Usage: python scripts/build_extensions.py [directory1] [directory2] ...") + print( + "Compiles all Python files in the given directories into C extensions (.so/.pyd)." + ) + print(f"Default directories if none provided: {DEFAULT_TARGETS}") + sys.exit(0) + + if len(sys.argv) > 1: + target_directories = sys.argv[1:] + else: + print(f"No directories specified. Using defaults: {DEFAULT_TARGETS}") + target_directories = DEFAULT_TARGETS + + build_extensions(target_directories)