1
1
import typing as t
2
- from collections import OrderedDict , defaultdict
3
2
from inspect import isabstract
4
3
5
- from injector import (
6
- Binder as InjectorBinder ,
7
- Binding ,
8
- Injector ,
9
- Module as InjectorModule ,
10
- )
4
+ from injector import Binder as InjectorBinder , Binding , Module as InjectorModule
11
5
12
- from ellar .compatible import asynccontextmanager
13
- from ellar .constants import MODULE_REF_TYPES
14
6
from ellar .helper import get_name
15
- from ellar .logger import logger as log
16
7
from ellar .types import T
17
8
18
- from .providers import InstanceProvider , Provider
19
- from .scopes import (
9
+ from .. providers import Provider
10
+ from .. scopes import (
20
11
DIScope ,
21
12
RequestScope ,
22
13
ScopeDecorator ,
23
14
SingletonScope ,
24
15
TransientScope ,
25
16
)
26
- from .service_config import get_scope
17
+ from .. service_config import get_scope
27
18
28
19
if t .TYPE_CHECKING : # pragma: no cover
29
- from ellar .core .modules import ModuleBase , ModuleRefBase , ModuleTemplateRef
30
-
31
-
32
- class RequestServiceProvider (InjectorBinder ):
33
- __slots__ = ("_bindings" , "_log_prefix" , "_context" )
20
+ from ellar .core .modules import ModuleBase
34
21
35
- def __init__ (self , container : "Container" , auto_bind : bool = False ) -> None :
36
- super (RequestServiceProvider , self ).__init__ (
37
- injector = container .injector , parent = container , auto_bind = auto_bind
38
- )
39
- self ._context : t .Dict = {}
40
- self ._log_prefix = container .injector ._log_prefix
41
-
42
- def get (self , interface : t .Type [T ]) -> T :
43
- binding , binder = self .get_binding (interface )
44
- scope = binding .scope
45
- if isinstance (scope , ScopeDecorator ):
46
- scope = scope .scope
47
- # Fetch the corresponding Scope instance from the Binder.
48
- scope_binding , _ = binder .get_binding (scope )
49
- scope_instance = t .cast (DIScope , scope_binding .provider .get (self ))
50
-
51
- log .debug (
52
- "%EllarInjector.get(%r, scope=%r) using %r" ,
53
- self ._log_prefix ,
54
- interface ,
55
- scope ,
56
- binding .provider ,
57
- )
58
- result = scope_instance .get (
59
- interface , binding .provider , context = self ._context
60
- ).get (self .injector )
61
- log .debug ("%s -> %r" , self ._log_prefix , result )
62
- return t .cast (T , result )
63
-
64
- def update_context (self , interface : t .Type [T ], value : T ) -> None :
65
- assert not isinstance (value , type ), f"value must be an object of { interface } "
66
- _context = {
67
- interface : Binding (interface , InstanceProvider (value ), RequestScope )
68
- }
69
- if isinstance (value , Provider ):
70
- _context = {interface : Binding (interface , value , RequestScope )}
71
- self ._bindings .update (_context )
72
-
73
- def dispose (self ) -> None :
74
- del self ._context
75
- del self .parent
76
- del self .injector
22
+ from .ellar_injector import EllarInjector
77
23
78
24
79
25
class Container (InjectorBinder ):
80
- __slots__ = ("injector" , "_auto_bind" , "_bindings" , "parent" )
26
+ __slots__ = (
27
+ "injector" ,
28
+ "_auto_bind" ,
29
+ "_bindings" ,
30
+ "parent" ,
31
+ "_aliases" ,
32
+ "_exact_aliases" ,
33
+ )
81
34
82
35
injector : "EllarInjector"
83
36
@@ -132,6 +85,12 @@ def register_singleton(
132
85
base_type : t .Type [T ],
133
86
concrete_type : t .Union [t .Type [T ], T , Provider ] = None ,
134
87
) -> None :
88
+ """
89
+
90
+ :param base_type:
91
+ :param concrete_type:
92
+ :return:
93
+ """
135
94
if not concrete_type :
136
95
self .register_exact_singleton (base_type )
137
96
self .register (base_type , concrete_type , scope = SingletonScope )
@@ -141,6 +100,12 @@ def register_transient(
141
100
base_type : t .Type ,
142
101
concrete_type : t .Union [t .Type , Provider ] = None ,
143
102
) -> None :
103
+ """
104
+
105
+ :param base_type:
106
+ :param concrete_type:
107
+ :return:
108
+ """
144
109
if not concrete_type :
145
110
self .register_exact_transient (base_type )
146
111
self .register (base_type , concrete_type , scope = TransientScope )
@@ -150,19 +115,40 @@ def register_scoped(
150
115
base_type : t .Type ,
151
116
concrete_type : t .Union [t .Type , Provider ] = None ,
152
117
) -> None :
118
+ """
119
+
120
+ :param base_type:
121
+ :param concrete_type:
122
+ :return:
123
+ """
153
124
if not concrete_type :
154
125
self .register_exact_scoped (base_type )
155
126
self .register (base_type , concrete_type , scope = RequestScope )
156
127
157
128
def register_exact_singleton (self , concrete_type : t .Type ) -> None :
129
+ """
130
+
131
+ :param concrete_type:
132
+ :return:
133
+ """
158
134
assert not isabstract (concrete_type )
159
135
self .register (base_type = concrete_type , scope = SingletonScope )
160
136
161
137
def register_exact_transient (self , concrete_type : t .Type ) -> None :
138
+ """
139
+
140
+ :param concrete_type:
141
+ :return:
142
+ """
162
143
assert not isabstract (concrete_type )
163
144
self .register (base_type = concrete_type , scope = TransientScope )
164
145
165
146
def register_exact_scoped (self , concrete_type : t .Type ) -> None :
147
+ """
148
+
149
+ :param concrete_type:
150
+ :return:
151
+ """
166
152
assert not isabstract (concrete_type )
167
153
self .register (base_type = concrete_type , scope = RequestScope )
168
154
@@ -215,74 +201,3 @@ def register_services(self, container):
215
201
216
202
instance (self )
217
203
return instance
218
-
219
-
220
- class EllarInjector (Injector ):
221
- __slots__ = ("_stack" , "parent" , "app" , "container" , "_modules" )
222
-
223
- def __init__ (
224
- self ,
225
- auto_bind : bool = True ,
226
- parent : "Injector" = None ,
227
- ) -> None :
228
- self ._stack = ()
229
-
230
- self .parent = parent
231
- # Binder
232
- self .container = Container (
233
- self ,
234
- auto_bind = auto_bind ,
235
- parent = parent .binder if parent is not None else None ,
236
- )
237
- # Bind some useful types
238
- self .container .register_instance (self , EllarInjector )
239
- self .container .register_instance (self .binder )
240
- self ._modules : t .DefaultDict = defaultdict (OrderedDict )
241
- self ._modules [MODULE_REF_TYPES .TEMPLATE ] = OrderedDict ()
242
- self ._modules [MODULE_REF_TYPES .PLAIN ] = OrderedDict ()
243
-
244
- def get_modules (
245
- self ,
246
- ) -> t .Dict [t .Type ["ModuleBase" ], "ModuleRefBase" ]:
247
- modules = dict (
248
- self ._modules [MODULE_REF_TYPES .TEMPLATE ],
249
- )
250
- modules .update (self ._modules [MODULE_REF_TYPES .PLAIN ])
251
- return modules
252
-
253
- def get_module (self , module : t .Type ) -> t .Optional ["ModuleRefBase" ]:
254
- result : t .Optional ["ModuleRefBase" ] = None
255
- if module in self ._modules [MODULE_REF_TYPES .TEMPLATE ]:
256
- result = self ._modules [MODULE_REF_TYPES .TEMPLATE ][module ]
257
- return result
258
-
259
- if module in self ._modules [MODULE_REF_TYPES .PLAIN ]:
260
- result = self ._modules [MODULE_REF_TYPES .PLAIN ][module ]
261
- return result
262
- return result
263
-
264
- def get_templating_modules (
265
- self ,
266
- ) -> t .Dict [t .Type ["ModuleBase" ], "ModuleTemplateRef" ]:
267
- return self ._modules .get (MODULE_REF_TYPES .TEMPLATE , {})
268
-
269
- def add_module (self , module_ref : "ModuleRefBase" ) -> None :
270
- self ._modules [module_ref .ref_type ].update ({module_ref .module : module_ref })
271
-
272
- @property # type: ignore
273
- def binder (self ) -> Container : # type: ignore
274
- return self .container
275
-
276
- @binder .setter
277
- def binder (self , value : t .Any ) -> None :
278
- """Nothing happens"""
279
-
280
- @asynccontextmanager
281
- async def create_request_service_provider (
282
- self ,
283
- ) -> t .AsyncGenerator [RequestServiceProvider , None ]:
284
- request_provider = RequestServiceProvider (self .container )
285
- try :
286
- yield request_provider
287
- finally :
288
- request_provider .dispose ()
0 commit comments