fix: resolve cross-module import violations with lazy import pattern

- Convert core→optional imports to lazy imports with try/except fallbacks
- cms/media_service: use TYPE_CHECKING for ProductMedia type hints
- customers/customer_service: wrap Order imports in try/except
- tenancy/admin_platform_users: wrap stats_service import in try/except
- Enhance validate_architecture.py to recognize lazy import patterns
- Add module_dependency_graph.py script for dependency visualization

The lazy import pattern allows optional modules to be truly optional while
maintaining type safety through TYPE_CHECKING blocks.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-04 19:22:11 +01:00
parent 5afc0fdfae
commit 37942ae02b
5 changed files with 574 additions and 40 deletions

View File

@@ -16,10 +16,14 @@ import shutil
import uuid
from datetime import UTC, datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any
from sqlalchemy import or_
from sqlalchemy.orm import Session
if TYPE_CHECKING:
from app.modules.catalog.models import ProductMedia
from app.modules.cms.exceptions import (
MediaNotFoundException,
MediaUploadException,
@@ -28,7 +32,6 @@ from app.modules.cms.exceptions import (
MediaFileTooLargeException,
)
from app.modules.cms.models import MediaFile
from app.modules.catalog.models import ProductMedia
logger = logging.getLogger(__name__)
@@ -454,7 +457,7 @@ class MediaService:
product_id: int,
usage_type: str = "gallery",
display_order: int = 0,
) -> ProductMedia:
) -> "ProductMedia | None":
"""
Attach a media file to a product.
@@ -467,8 +470,14 @@ class MediaService:
display_order: Order for galleries
Returns:
Created ProductMedia association
Created ProductMedia association, or None if catalog module unavailable
"""
try:
from app.modules.catalog.models import ProductMedia
except ImportError:
logger.warning("Catalog module not available for media-product attachment")
return None
# Verify media belongs to vendor
media = self.get_media(db, vendor_id, media_id)
@@ -524,8 +533,14 @@ class MediaService:
usage_type: Specific usage type to remove (None = all)
Returns:
True if detached
True if detached, False if catalog module unavailable
"""
try:
from app.modules.catalog.models import ProductMedia
except ImportError:
logger.warning("Catalog module not available for media-product detachment")
return False
# Verify media belongs to vendor
media = self.get_media(db, vendor_id, media_id)