22
33from __future__ import annotations
44
5+ import sys
6+ from pathlib import Path
57from types import ModuleType , SimpleNamespace
68from typing import Any
79from unittest .mock import AsyncMock , MagicMock , patch
1820configure_import_environment ()
1921ensure_import_paths ()
2022
23+ _API_ROOT = str (Path (__file__ ).resolve ().parents [2 ])
2124
22- def _load_api_modules () -> tuple [ModuleType , ModuleType , ModuleType , ModuleType ]:
25+
26+ def _prioritize_api_import_root () -> None :
27+ """Keep apps/api ahead of apps/worker for the shared `app` package name."""
2328 ensure_import_paths ()
29+ if _API_ROOT in sys .path :
30+ sys .path .remove (_API_ROOT )
31+ sys .path .insert (0 , _API_ROOT )
32+
33+
34+ def _is_api_app_module (module : ModuleType | None ) -> bool :
35+ if module is None :
36+ return False
37+ module_file = getattr (module , "__file__" , None )
38+ if isinstance (module_file , str ) and module_file .startswith (_API_ROOT ):
39+ return True
40+ module_paths = getattr (module , "__path__" , ())
41+ try :
42+ return any (str (path ).startswith (_API_ROOT ) for path in module_paths )
43+ except KeyError :
44+ return False
45+
46+
47+ def _drop_non_api_app_modules () -> None :
48+ for module_name in sorted (sys .modules , key = len , reverse = True ):
49+ if module_name != "app" and not module_name .startswith ("app." ):
50+ continue
51+ if not _is_api_app_module (sys .modules .get (module_name )):
52+ sys .modules .pop (module_name , None )
53+
54+
55+ def _drop_api_app_modules () -> None :
56+ for module_name in sorted (sys .modules , key = len , reverse = True ):
57+ if module_name != "app" and not module_name .startswith ("app." ):
58+ continue
59+ if _is_api_app_module (sys .modules .get (module_name )):
60+ sys .modules .pop (module_name , None )
61+
62+
63+ def _load_api_modules () -> tuple [ModuleType , ModuleType , ModuleType , ModuleType ]:
64+ _prioritize_api_import_root ()
65+ _drop_non_api_app_modules ()
2466 from app .services .auth import api_key_authentication_service
2567 from app .services .rate_limit import (
2668 data_structures ,
@@ -36,6 +78,14 @@ def _load_api_modules() -> tuple[ModuleType, ModuleType, ModuleType, ModuleType]
3678 )
3779
3880
81+ @pytest .fixture (autouse = True )
82+ def _clear_api_app_modules_after_unit_test ():
83+ """Avoid leaving API's `app` package cached for later worker contract tests."""
84+ yield
85+ _drop_api_app_modules ()
86+
87+
88+
3989@pytest .mark .asyncio
4090async def test_get_tier_reuses_provided_session_without_get_db_context () -> None :
4191 _ , _ , _ , tier_service = _load_api_modules ()
0 commit comments