python-injection 0.7.3__py3-none-any.whl → 0.7.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of python-injection might be problematic. Click here for more details.

injection/_pkg.py CHANGED
@@ -1,9 +1,9 @@
1
- from .core import Injectable, Module, ModulePriorities
1
+ from .core import Injectable, Module, ModulePriority
2
2
 
3
3
  __all__ = (
4
4
  "Injectable",
5
5
  "Module",
6
- "ModulePriorities",
6
+ "ModulePriority",
7
7
  "default_module",
8
8
  "get_instance",
9
9
  "get_lazy_instance",
injection/_pkg.pyi CHANGED
@@ -85,14 +85,7 @@ class Module:
85
85
  always be the same.
86
86
  """
87
87
 
88
- def should_be_injectable(
89
- self,
90
- wrapped: Callable[..., Any] = ...,
91
- /,
92
- *,
93
- on: type | Iterable[type] | UnionType = ...,
94
- override: bool = ...,
95
- ):
88
+ def should_be_injectable(self, wrapped: type = ..., /):
96
89
  """
97
90
  Decorator applicable to a class. It is used to specify whether an injectable
98
91
  should be registered. Raise an exception at injection time if the class isn't
@@ -128,7 +121,7 @@ class Module:
128
121
  Example: instance = ~lazy_instance
129
122
  """
130
123
 
131
- def use(self, module: Module, priority: ModulePriorities = ...):
124
+ def use(self, module: Module, priority: ModulePriority = ...):
132
125
  """
133
126
  Function for using another module. Using another module replaces the module's
134
127
  dependencies with those of the module used. If the dependency is not found, it
@@ -143,13 +136,13 @@ class Module:
143
136
  def use_temporarily(
144
137
  self,
145
138
  module: Module,
146
- priority: ModulePriorities = ...,
139
+ priority: ModulePriority = ...,
147
140
  ) -> ContextManager | ContextDecorator:
148
141
  """
149
142
  Context manager or decorator for temporary use of a module.
150
143
  """
151
144
 
152
- def change_priority(self, module: Module, priority: ModulePriorities):
145
+ def change_priority(self, module: Module, priority: ModulePriority):
153
146
  """
154
147
  Function for changing the priority of a module in use.
155
148
  There are two priority values:
@@ -164,7 +157,7 @@ class Module:
164
157
  """
165
158
 
166
159
  @final
167
- class ModulePriorities(Enum):
160
+ class ModulePriority(Enum):
168
161
  HIGH = ...
169
162
  LOW = ...
170
163
 
injection/core/module.py CHANGED
@@ -11,6 +11,7 @@ from collections.abc import (
11
11
  Iterator,
12
12
  Mapping,
13
13
  MutableMapping,
14
+ Set,
14
15
  )
15
16
  from contextlib import ContextDecorator, contextmanager, suppress
16
17
  from dataclasses import dataclass, field
@@ -41,7 +42,7 @@ from injection.exceptions import (
41
42
  NoInjectable,
42
43
  )
43
44
 
44
- __all__ = ("Injectable", "Module", "ModulePriorities")
45
+ __all__ = ("Injectable", "Module", "ModulePriority")
45
46
 
46
47
  _logger = logging.getLogger(__name__)
47
48
  _thread_lock = RLock()
@@ -117,7 +118,7 @@ class ModuleRemoved(ModuleEvent):
117
118
  @dataclass(frozen=True, slots=True)
118
119
  class ModulePriorityUpdated(ModuleEvent):
119
120
  module_updated: Module
120
- priority: ModulePriorities
121
+ priority: ModulePriority
121
122
 
122
123
  def __str__(self) -> str:
123
124
  return (
@@ -135,13 +136,15 @@ Injectables
135
136
  class Injectable(Protocol[_T]):
136
137
  __slots__ = ()
137
138
 
138
- def __init__(self, __factory: Callable[[], _T] = ..., /): ...
139
+ def __init__(self, __factory: Callable[[], _T] = None, /):
140
+ pass
139
141
 
140
142
  @property
141
143
  def is_locked(self) -> bool:
142
144
  return False
143
145
 
144
- def unlock(self): ...
146
+ def unlock(self):
147
+ pass
145
148
 
146
149
  @abstractmethod
147
150
  def get_instance(self) -> _T:
@@ -187,31 +190,15 @@ class SingletonInjectable(BaseInjectable[_T]):
187
190
  return instance
188
191
 
189
192
 
190
- class InjectableWarning(BaseInjectable[_T], ABC):
191
- __slots__ = ()
193
+ @dataclass(repr=False, frozen=True, slots=True)
194
+ class ShouldBeInjectable(Injectable[_T]):
195
+ cls: type[_T]
192
196
 
193
197
  def __bool__(self) -> bool:
194
198
  return False
195
199
 
196
- @property
197
- def formatted_type(self) -> str:
198
- return format_type(self.factory)
199
-
200
- @property
201
- @abstractmethod
202
- def exception(self) -> BaseException:
203
- raise NotImplementedError
204
-
205
200
  def get_instance(self) -> NoReturn:
206
- raise self.exception
207
-
208
-
209
- class ShouldBeInjectable(InjectableWarning[_T]):
210
- __slots__ = ()
211
-
212
- @property
213
- def exception(self) -> BaseException:
214
- return InjectionError(f"`{self.formatted_type}` should be an injectable.")
201
+ raise InjectionError(f"`{format_type(self.cls)}` should be an injectable.")
215
202
 
216
203
 
217
204
  """
@@ -265,23 +252,30 @@ class Container(Broker):
265
252
  def is_locked(self) -> bool:
266
253
  return any(injectable.is_locked for injectable in self.__injectables)
267
254
 
255
+ @property
256
+ def __classes(self) -> frozenset[type]:
257
+ return frozenset(self.__data.keys())
258
+
268
259
  @property
269
260
  def __injectables(self) -> frozenset[Injectable]:
270
261
  return frozenset(self.__data.values())
271
262
 
272
- def update(self, classes: Types, injectable: Injectable, override: bool):
273
- values = MappingProxyType(
274
- {origin: injectable for origin in get_origins(*classes)}
275
- )
263
+ def update(self, classes: Iterable[type], injectable: Injectable, override: bool):
264
+ classes = frozenset(get_origins(*classes))
265
+
266
+ with _thread_lock:
267
+ if not injectable:
268
+ classes -= self.__classes
269
+ override = True
276
270
 
277
- if values:
278
- event = ContainerDependenciesUpdated(self, values, override)
271
+ if classes:
272
+ event = ContainerDependenciesUpdated(self, classes, override)
279
273
 
280
- with self.notify(event):
281
- if not override:
282
- self.__check_if_exists(*values)
274
+ with self.notify(event):
275
+ if not override:
276
+ self.__check_if_exists(classes)
283
277
 
284
- self.__data.update(values)
278
+ self.__data.update((cls, injectable) for cls in classes)
285
279
 
286
280
  return self
287
281
 
@@ -296,9 +290,11 @@ class Container(Broker):
296
290
  def notify(self, event: Event) -> ContextManager | ContextDecorator:
297
291
  return self.__channel.dispatch(event)
298
292
 
299
- def __check_if_exists(self, *classes: type):
300
- for cls in classes:
301
- if self.__data.get(cls):
293
+ def __check_if_exists(self, classes: Set[type]):
294
+ intersection = classes & self.__classes
295
+
296
+ for cls in intersection:
297
+ if self.__data[cls]:
302
298
  raise RuntimeError(
303
299
  f"An injectable already exists for the class `{format_type(cls)}`."
304
300
  )
@@ -309,7 +305,7 @@ Module
309
305
  """
310
306
 
311
307
 
312
- class ModulePriorities(Enum):
308
+ class ModulePriority(Enum):
313
309
  HIGH = auto()
314
310
  LOW = auto()
315
311
 
@@ -339,7 +335,7 @@ class Module(EventListener, Broker):
339
335
  raise NoInjectable(cls)
340
336
 
341
337
  def __setitem__(self, cls: type | UnionType, injectable: Injectable, /):
342
- self.update((cls,), injectable, override=True)
338
+ self.update((cls,), injectable)
343
339
 
344
340
  def __contains__(self, cls: type | UnionType, /) -> bool:
345
341
  return any(cls in broker for broker in self.__brokers)
@@ -376,11 +372,13 @@ class Module(EventListener, Broker):
376
372
  return decorator(wrapped) if wrapped else decorator
377
373
 
378
374
  singleton = partialmethod(injectable, cls=SingletonInjectable)
379
- should_be_injectable = partialmethod(
380
- injectable,
381
- cls=ShouldBeInjectable,
382
- inject=False,
383
- )
375
+
376
+ def should_be_injectable(self, wrapped: type = None, /):
377
+ def decorator(wp):
378
+ self[wp] = ShouldBeInjectable(wp)
379
+ return wp
380
+
381
+ return decorator(wrapped) if wrapped else decorator
384
382
 
385
383
  def set_constant(
386
384
  self,
@@ -437,14 +435,19 @@ class Module(EventListener, Broker):
437
435
  def get_lazy_instance(self, cls: type[_T]) -> Lazy[_T | None]:
438
436
  return Lazy(lambda: self.get_instance(cls))
439
437
 
440
- def update(self, classes: Types, injectable: Injectable, override: bool = False):
438
+ def update(
439
+ self,
440
+ classes: Iterable[type],
441
+ injectable: Injectable,
442
+ override: bool = False,
443
+ ):
441
444
  self.__container.update(classes, injectable, override)
442
445
  return self
443
446
 
444
447
  def use(
445
448
  self,
446
449
  module: Module,
447
- priority: ModulePriorities = ModulePriorities.get_default(),
450
+ priority: ModulePriority = ModulePriority.get_default(),
448
451
  ):
449
452
  if module is self:
450
453
  raise ModuleError("Module can't be used by itself.")
@@ -475,13 +478,13 @@ class Module(EventListener, Broker):
475
478
  def use_temporarily(
476
479
  self,
477
480
  module: Module,
478
- priority: ModulePriorities = ModulePriorities.get_default(),
481
+ priority: ModulePriority = ModulePriority.get_default(),
479
482
  ) -> ContextManager | ContextDecorator:
480
483
  self.use(module, priority)
481
484
  yield
482
485
  self.stop_using(module)
483
486
 
484
- def change_priority(self, module: Module, priority: ModulePriorities):
487
+ def change_priority(self, module: Module, priority: ModulePriority):
485
488
  event = ModulePriorityUpdated(self, module, priority)
486
489
 
487
490
  with self.notify(event):
@@ -517,8 +520,8 @@ class Module(EventListener, Broker):
517
520
  if self.is_locked:
518
521
  raise ModuleLockError(f"`{self}` is locked.")
519
522
 
520
- def __move_module(self, module: Module, priority: ModulePriorities):
521
- last = priority == ModulePriorities.LOW
523
+ def __move_module(self, module: Module, priority: ModulePriority):
524
+ last = priority == ModulePriority.LOW
522
525
 
523
526
  try:
524
527
  self.__modules.move_to_end(module, last=last)
@@ -617,11 +620,14 @@ class Binder(EventListener):
617
620
  return Arguments(bound.args, bound.kwargs)
618
621
 
619
622
  def update(self, module: Module):
620
- self.__dependencies = Dependencies.resolve(self.__signature, module)
623
+ with _thread_lock:
624
+ self.__dependencies = Dependencies.resolve(self.__signature, module)
625
+
621
626
  return self
622
627
 
623
628
  @singledispatchmethod
624
- def on_event(self, event: Event, /): ...
629
+ def on_event(self, event: Event, /):
630
+ pass
625
631
 
626
632
  @on_event.register
627
633
  @contextmanager
injection/exceptions.py CHANGED
@@ -10,7 +10,7 @@ __all__ = (
10
10
 
11
11
 
12
12
  class InjectionError(Exception):
13
- __slots__ = ()
13
+ pass
14
14
 
15
15
 
16
16
  class NoInjectable(KeyError, InjectionError):
@@ -26,12 +26,12 @@ class NoInjectable(KeyError, InjectionError):
26
26
 
27
27
 
28
28
  class ModuleError(InjectionError):
29
- __slots__ = ()
29
+ pass
30
30
 
31
31
 
32
32
  class ModuleLockError(ModuleError):
33
- __slots__ = ()
33
+ pass
34
34
 
35
35
 
36
36
  class ModuleNotUsedError(KeyError, ModuleError):
37
- __slots__ = ()
37
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-injection
3
- Version: 0.7.3
3
+ Version: 0.7.4
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Home-page: https://github.com/100nm/python-injection
6
6
  License: MIT
@@ -1,17 +1,17 @@
1
1
  injection/__init__.py,sha256=9_AVJILxKIBiL_6KJSh2RRydgSHXH38uahAGD0S1-dI,20
2
- injection/_pkg.py,sha256=VOgHhc4YXs4g0jIhXnqYllI64szC_cyO05IC2qE5BBg,651
3
- injection/_pkg.pyi,sha256=LcSXTYS7Bg7oAECClxrTq-uoW_DwMQZ99ksksBTwks4,5474
2
+ injection/_pkg.py,sha256=nMIRLAQG6096bcR2Mz1egxe5FItBUsw8zR9yzjt1HDM,647
3
+ injection/_pkg.pyi,sha256=zxbidnUvr-8x7F8hLJUgEBzyefXtNW6Ajtuin6Z0cf8,5327
4
4
  injection/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  injection/common/event.py,sha256=uFoGRnxxkohH53JEStn4tN2Pn79HlgGExh7VkXdBwVQ,1316
6
6
  injection/common/lazy.py,sha256=HIefQ1z7ivgU791MDSwBmUcdST3bOv0sivSMyR2DfHc,1493
7
7
  injection/common/tools/__init__.py,sha256=S2y9DaQ4EaTRty9fKpBtPXA7hSjkzgM5N2jFf5jcmJU,21
8
8
  injection/common/tools/_type.py,sha256=-zL0dtoVZme71Mscvav7iEWxY2-JltzNTekbWOCPSFo,1276
9
9
  injection/core/__init__.py,sha256=zuf0ubI2dHnbjn1059eduhS-ACIkkROa6-dhp10krh0,22
10
- injection/core/module.py,sha256=Rx3Ys1WrYpTBR7QNojpyn18wGettKxxqZdRh7_egP3M,16443
11
- injection/exceptions.py,sha256=wd4OxmpneGEmlZ0yeNBfnCYfPYqUksfbmA2mopLNm_s,688
10
+ injection/core/module.py,sha256=lEBJ6QGjPyp7bwEWE0RrOr26yrpJr1GKqsA-EV2LOAM,16594
11
+ injection/exceptions.py,sha256=lm79jrBkvK52BpcAo1kx7GeDCUtskNBRt9rQ6IE3B4A,648
12
12
  injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  injection/integrations/blacksheep.py,sha256=vcLil1IccS7JtXpuVu7s2LqN5Zravfe_7xpAt5cTIU0,723
14
14
  injection/utils.py,sha256=_79aiciimZpuoUTz5lojKySUMMzpkU-e7SotiHIFTI8,676
15
- python_injection-0.7.3.dist-info/METADATA,sha256=Bh5D-zSRRwFxOcjWMqNg3LQvgaNr-hdTLJp82wnt0jI,3433
16
- python_injection-0.7.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
17
- python_injection-0.7.3.dist-info/RECORD,,
15
+ python_injection-0.7.4.dist-info/METADATA,sha256=JXV2O9HN1D8LGa6CSA5KaQ4lDmm4flzuZioxG4z4hBY,3433
16
+ python_injection-0.7.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
17
+ python_injection-0.7.4.dist-info/RECORD,,