11import typing as t
2- from collections import OrderedDict
32from pathlib import Path
43
54import click
5+ from ellar .app .core_module import get_core_module
66from ellar .common import IApplicationReady , Module
7- from ellar .common .constants import MODULE_METADATA , MODULE_WATERMARK
7+ from ellar .common .constants import MODULE_METADATA
8+ from ellar .common .exceptions import ImproperConfiguration
89from ellar .common .models import GuardCanActivate
9- from ellar .core import Config , DynamicModule , LazyModuleImport , ModuleBase , ModuleSetup
10- from ellar .core .context import ApplicationContext
11- from ellar .core .modules import ModuleRefBase
10+ from ellar .core import (
11+ Config ,
12+ DynamicModule ,
13+ ForwardRefModule ,
14+ LazyModuleImport ,
15+ ModuleBase ,
16+ ModuleSetup ,
17+ )
18+ from ellar .core .modules import ModuleRefBase , ModuleTemplateRef
1219from ellar .di import EllarInjector , ProviderConfig
20+ from ellar .di .injector .tree_manager import ModuleTreeManager
1321from ellar .reflect import reflect
1422from ellar .threading .sync_worker import execute_async_context_manager
1523from ellar .utils import get_name , get_unique_type
16- from starlette .routing import BaseRoute , Host , Mount
24+ from starlette .routing import Host , Mount
1725
1826from .main import App
19- from .services import EllarAppService
2027
2128if t .TYPE_CHECKING : # pragma: no cover
2229 from ellar .common import ModuleRouter
@@ -29,30 +36,31 @@ class AppFactory:
2936 """
3037
3138 @classmethod
32- def get_all_modules ( cls , module_config : ModuleSetup ) -> t . List [ ModuleSetup ]:
33- """
34- Gets all registered modules from a particular module in their order of dependencies
35- :param module_config: Module Type
36- :return: t.List[t.Type[ModuleBase]]
39+ def read_all_module (
40+ cls ,
41+ module_config : t . Union [ ModuleSetup , ModuleRefBase ],
42+ tree_manager : t . Optional [ ModuleTreeManager ] = None ,
43+ ) -> ModuleTreeManager :
3744 """
38- module_dependency = [module_config ] + list (
39- cls .read_all_module (module_config ).values ()
40- )
41- return module_dependency
45+ Retrieves all module dependencies registered in another module
4246
43- @classmethod
44- def read_all_module (cls , module_config : ModuleSetup ) -> t .Dict [t .Type , ModuleSetup ]:
45- """
46- Retrieves all modules dependencies registered in another module
47+ :param tree_manager: Module Tree Manager
4748 :param module_config: Module Type
4849 :return: t.Dict[t.Type, t.Type[ModuleBase]]
4950 """
5051 global_module_config = module_config
52+ tree_manager = tree_manager or ModuleTreeManager ().add_module (
53+ global_module_config .module , value = module_config
54+ )
55+
5156 modules = (
5257 reflect .get_metadata (MODULE_METADATA .MODULES , module_config .module ) or []
5358 )
54- module_dependency = OrderedDict ()
5559 for module in modules :
60+ if isinstance (module , ForwardRefModule ):
61+ # will be initialized using module_config moduleRef setup
62+ continue
63+
5664 if isinstance (module , LazyModuleImport ):
5765 module = module .get_module (global_module_config .module .__name__ )
5866
@@ -64,60 +72,14 @@ def read_all_module(cls, module_config: ModuleSetup) -> t.Dict[t.Type, ModuleSet
6472 else :
6573 module_config = ModuleSetup (module )
6674
67- module_dependency [module_config .module ] = module_config
68- module_dependency .update (cls .read_all_module (module_config ))
69- return module_dependency
70-
71- @classmethod
72- def _build_modules (
73- cls ,
74- app_module : t .Type [t .Union [ModuleBase , t .Any ]],
75- config : "Config" ,
76- injector : EllarInjector ,
77- ) -> t .List [BaseRoute ]:
78- """
79- builds application module and registers them to EllarInjector
80- :param app_module: Root App Module
81- :param config: App Configuration instance
82- :param injector: App Injector instance
83- :return: `None`
84- """
85- if isinstance (app_module , LazyModuleImport ):
86- app_module = app_module .get_module ("AppFactory" )
87-
88- assert reflect .get_metadata (
89- MODULE_WATERMARK , app_module
90- ), "Only Module is allowed"
91-
92- app_module_config = ModuleSetup (app_module )
93- module_dependency = cls .get_all_modules (app_module_config )
94- routes = []
95-
96- for module_config in reversed (module_dependency ):
97- if injector .get_module (module_config .module ): # pragma: no cover
98- continue
99-
100- module_ref = module_config .get_module_ref (
101- container = injector .container , config = config
102- )
103-
104- if isinstance (module_ref , ModuleRefBase ):
105- routes .extend (module_ref .routes )
106-
107- injector .add_module (module_ref )
108-
109- for module_config in reversed (list (injector .get_dynamic_modules ())):
110- if injector .get_module (module_config .module ): # pragma: no cover
111- continue
112-
113- module_ref = module_config .configure_with_factory (
114- config , injector .container
75+ tree_manager .add_module (
76+ module_type = module_config .module ,
77+ value = module_config ,
78+ parent_module = global_module_config .module ,
11579 )
116- # module_ref.run_module_register_services()
117- routes .extend (module_ref .routes )
118- injector .add_module (module_ref )
11980
120- return routes
81+ cls .read_all_module (module_config , tree_manager )
82+ return tree_manager
12183
12284 @classmethod
12385 @t .no_type_check
@@ -145,51 +107,56 @@ def _get_config_kwargs() -> t.Dict:
145107
146108 config = Config (app_configured = True , ** _get_config_kwargs ())
147109
148- injector = EllarInjector (auto_bind = config .INJECTOR_AUTO_BIND , parent = injector )
149- injector .container .register_instance (config , concrete_type = Config )
110+ # injector = EllarInjector(auto_bind=config.INJECTOR_AUTO_BIND, parent=injector)
111+ # injector.container.register_instance(config, concrete_type=Config)
150112
151- service = EllarAppService (injector , config )
152- service .register_core_services ()
113+ core_module_ref = ModuleTemplateRef (
114+ module_type = get_core_module (module , config ),
115+ parent_container = injector .container if injector else None ,
116+ config = config ,
117+ )
118+ core_module_ref .initiate_module_build ()
153119
154- with execute_async_context_manager (ApplicationContext (injector )) as context :
155- routes = cls ._build_modules (
156- app_module = module , injector = injector , config = config
157- )
120+ # service = EllarAppService(injector, config)
121+ # service.register_core_services()
122+
123+ with execute_async_context_manager (core_module_ref .context ()) as context :
124+ tree_manager : ModuleTreeManager = core_module_ref .get (ModuleTreeManager )
125+ cls .read_all_module (core_module_ref , tree_manager )
126+ # Build application first level. This will trigger ApplicationModule to be built
127+ core_module_ref .build_dependencies (step = 1 )
128+ app_module_ref = tree_manager .get_root_module ()
158129
159130 app = App (
160- routes = routes ,
131+ routes = [] ,
161132 config = config ,
162- injector = injector ,
133+ injector = app_module_ref . container . injector ,
163134 lifespan = config .DEFAULT_LIFESPAN_HANDLER ,
164135 global_guards = global_guards ,
165136 )
166137 # tag application instance by ApplicationModule name
167- context .injector .container .register_instance (app , App , tag = get_name (module ))
168-
169- for module_config in reversed (
170- list (context .injector .get_app_dependent_modules ())
171- ):
172- if context .injector .get_module (
173- module_config .module
174- ): # pragma: no cover
175- continue
176-
177- module_ref = module_config .configure_with_factory (
178- config , context .injector .container
179- )
138+ core_module_ref .add_provider (
139+ ProviderConfig (App , use_value = app , tag = get_name (module ), export = True )
140+ )
141+ app_module_ref .build_dependencies ()
142+
143+ routes = core_module_ref .get_routes ()
144+ app .router .extend (routes )
180145
181- assert isinstance (
182- module_ref , ModuleRefBase
183- ), f"{ module_config .module } is not properly configured."
146+ for item in config .OVERRIDE_CORE_SERVICE :
147+ provider_type = item .get_type ()
148+ if provider_type not in core_module_ref .providers :
149+ raise ImproperConfiguration (
150+ f"There is not core service identify as { provider_type } "
151+ )
184152
185- context .injector .add_module (module_ref )
186- app .router .extend (module_ref .routes )
153+ core_module_ref .add_provider (item , export = True )
187154
188155 # app.setup_jinja_environment
189156 app .setup_jinja_environment ()
190157
191- for module , module_ref in context .injector .get_modules () .items ():
192- module_ref .run_module_register_services ()
158+ for module , data in context .injector .tree_manager . modules .items ():
159+ data . value .run_module_register_services ()
193160
194161 if issubclass (module , IApplicationReady ):
195162 context .injector .get (module ).on_ready (app )
0 commit comments