python-injection 0.14.2__tar.gz → 0.14.3__tar.gz

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.
Files changed (27) hide show
  1. {python_injection-0.14.2 → python_injection-0.14.3}/PKG-INFO +1 -1
  2. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/module.py +15 -28
  3. python_injection-0.14.3/injection/py.typed +0 -0
  4. {python_injection-0.14.2 → python_injection-0.14.3}/pyproject.toml +1 -1
  5. python_injection-0.14.2/injection/_core/__init__.py +0 -53
  6. python_injection-0.14.2/injection/_core/hook.py +0 -106
  7. {python_injection-0.14.2 → python_injection-0.14.3}/.gitignore +0 -0
  8. {python_injection-0.14.2 → python_injection-0.14.3}/README.md +0 -0
  9. {python_injection-0.14.2 → python_injection-0.14.3}/injection/__init__.py +0 -0
  10. {python_injection-0.14.2 → python_injection-0.14.3}/injection/__init__.pyi +0 -0
  11. {python_injection-0.14.2/injection/_core/common → python_injection-0.14.3/injection/_core}/__init__.py +0 -0
  12. {python_injection-0.14.2/injection/integrations → python_injection-0.14.3/injection/_core/common}/__init__.py +0 -0
  13. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/asynchronous.py +0 -0
  14. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/event.py +0 -0
  15. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/invertible.py +0 -0
  16. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/key.py +0 -0
  17. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/lazy.py +0 -0
  18. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/common/type.py +0 -0
  19. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/descriptors.py +0 -0
  20. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/injectables.py +0 -0
  21. {python_injection-0.14.2 → python_injection-0.14.3}/injection/_core/scope.py +0 -0
  22. {python_injection-0.14.2 → python_injection-0.14.3}/injection/exceptions.py +0 -0
  23. /python_injection-0.14.2/injection/py.typed → /python_injection-0.14.3/injection/integrations/__init__.py +0 -0
  24. {python_injection-0.14.2 → python_injection-0.14.3}/injection/integrations/fastapi.py +0 -0
  25. {python_injection-0.14.2 → python_injection-0.14.3}/injection/testing/__init__.py +0 -0
  26. {python_injection-0.14.2 → python_injection-0.14.3}/injection/testing/__init__.pyi +0 -0
  27. {python_injection-0.14.2 → python_injection-0.14.3}/injection/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-injection
3
- Version: 0.14.2
3
+ Version: 0.14.3
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Project-URL: Repository, https://github.com/100nm/python-injection
6
6
  Author: remimd
@@ -57,8 +57,8 @@ from injection._core.common.type import (
57
57
  TypeInfo,
58
58
  get_return_types,
59
59
  get_yield_hint,
60
+ standardize_types,
60
61
  )
61
- from injection._core.hook import Hook, apply_hooks
62
62
  from injection._core.injectables import (
63
63
  AsyncCMScopedInjectable,
64
64
  CMScopedInjectable,
@@ -223,22 +223,6 @@ class Updater[T]:
223
223
  return Record(self.injectable, self.mode)
224
224
 
225
225
 
226
- @dataclass(repr=False, eq=False, frozen=True, slots=True)
227
- class LocatorHooks[T]:
228
- on_conflict: Hook[[Record[T], Record[T], InputType[T]], bool] = field(
229
- default_factory=Hook,
230
- init=False,
231
- )
232
- on_input: Hook[[Iterable[InputType[T]]], Iterable[InputType[T]]] = field(
233
- default_factory=Hook,
234
- init=False,
235
- )
236
- on_update: Hook[[Updater[T]], Updater[T]] = field(
237
- default_factory=Hook,
238
- init=False,
239
- )
240
-
241
-
242
226
  @dataclass(repr=False, frozen=True, slots=True)
243
227
  class Locator(Broker):
244
228
  __records: dict[InputType[Any], Record[Any]] = field(
@@ -250,8 +234,6 @@ class Locator(Broker):
250
234
  init=False,
251
235
  )
252
236
 
253
- static_hooks: ClassVar[LocatorHooks[Any]] = LocatorHooks()
254
-
255
237
  def __getitem__[T](self, cls: InputType[T], /) -> Injectable[T]:
256
238
  for input_class in self.__standardize_inputs((cls,)):
257
239
  try:
@@ -326,25 +308,30 @@ class Locator(Broker):
326
308
 
327
309
  yield cls, record
328
310
 
311
+ @staticmethod
329
312
  def __keep_new_record[T](
330
- self,
331
313
  new: Record[T],
332
314
  existing: Record[T],
333
315
  cls: InputType[T],
334
316
  ) -> bool:
335
- return apply_hooks(
336
- lambda *args, **kwargs: False,
337
- self.static_hooks.on_conflict,
338
- )(new, existing, cls)
317
+ new_mode, existing_mode = new.mode, existing.mode
318
+ is_override = new_mode == Mode.OVERRIDE
319
+
320
+ if new_mode == existing_mode and not is_override:
321
+ raise RuntimeError(f"An injectable already exists for the class `{cls}`.")
339
322
 
323
+ return is_override or new_mode.rank > existing_mode.rank
324
+
325
+ @staticmethod
340
326
  def __standardize_inputs[T](
341
- self,
342
327
  classes: Iterable[InputType[T]],
343
328
  ) -> Iterable[InputType[T]]:
344
- return apply_hooks(lambda c: c, self.static_hooks.on_input)(classes)
329
+ return tuple(standardize_types(*classes, with_origin=True))
345
330
 
346
- def __update_preprocessing[T](self, updater: Updater[T]) -> Updater[T]:
347
- return apply_hooks(lambda u: u, self.static_hooks.on_update)(updater)
331
+ @staticmethod
332
+ def __update_preprocessing[T](updater: Updater[T]) -> Updater[T]:
333
+ updater.classes = frozenset(standardize_types(*updater.classes))
334
+ return updater
348
335
 
349
336
 
350
337
  """
File without changes
@@ -24,7 +24,7 @@ test = [
24
24
 
25
25
  [project]
26
26
  name = "python-injection"
27
- version = "0.14.2"
27
+ version = "0.14.3"
28
28
  description = "Fast and easy dependency injection framework."
29
29
  license = { text = "MIT" }
30
30
  readme = "README.md"
@@ -1,53 +0,0 @@
1
- from collections.abc import Iterable
2
- from typing import Any
3
-
4
- from injection._core.common.type import InputType, standardize_types
5
- from injection._core.hook import HookGenerator
6
- from injection._core.module import Locator, Mode, Record, Updater
7
-
8
- __all__ = ()
9
-
10
-
11
- @Locator.static_hooks.on_conflict
12
- def check_mode[T](
13
- new: Record[T],
14
- existing: Record[T],
15
- cls: InputType[T],
16
- *_: Any,
17
- **__: Any,
18
- ) -> HookGenerator[bool]:
19
- new_mode = new.mode
20
- is_override = new_mode == Mode.OVERRIDE
21
-
22
- if new_mode == existing.mode and not is_override:
23
- raise RuntimeError(f"An injectable already exists for the class `{cls}`.")
24
-
25
- value = yield
26
- return value or is_override
27
-
28
-
29
- @Locator.static_hooks.on_conflict
30
- def compare_mode_rank[T](
31
- new: Record[T],
32
- existing: Record[T],
33
- *_: Any,
34
- **__: Any,
35
- ) -> HookGenerator[bool]:
36
- value = yield
37
- return value or new.mode.rank > existing.mode.rank
38
-
39
-
40
- @Locator.static_hooks.on_input
41
- def standardize_input_classes[T](
42
- *_: Any,
43
- **__: Any,
44
- ) -> HookGenerator[Iterable[InputType[T]]]:
45
- classes = yield
46
- return tuple(standardize_types(*classes, with_origin=True))
47
-
48
-
49
- @Locator.static_hooks.on_update
50
- def standardize_classes[T](*_: Any, **__: Any) -> HookGenerator[Updater[T]]:
51
- updater = yield
52
- updater.classes = frozenset(standardize_types(*updater.classes))
53
- return updater
@@ -1,106 +0,0 @@
1
- import itertools
2
- from collections.abc import Callable, Generator, Iterator
3
- from dataclasses import dataclass, field
4
- from inspect import isclass, isgeneratorfunction
5
- from typing import Any, Self, TypeGuard
6
-
7
- from injection.exceptions import HookError
8
-
9
- type HookGenerator[T] = Generator[None, T, T]
10
- type HookGeneratorFunction[**P, T] = Callable[P, HookGenerator[T]]
11
- type HookFunction[**P, T] = Callable[P, T] | HookGeneratorFunction[P, T]
12
-
13
-
14
- @dataclass(eq=False, frozen=True, slots=True)
15
- class Hook[**P, T]:
16
- __functions: list[HookFunction[P, T]] = field(
17
- default_factory=list,
18
- init=False,
19
- repr=False,
20
- )
21
-
22
- def __call__(
23
- self,
24
- wrapped: HookFunction[P, T] | type[HookFunction[P, T]] | None = None,
25
- /,
26
- ) -> Any:
27
- def decorator(wp: Any) -> Any:
28
- self.add(wp() if isclass(wp) else wp)
29
- return wp
30
-
31
- return decorator(wrapped) if wrapped else decorator
32
-
33
- @property
34
- def __stack(self) -> Iterator[HookFunction[P, T]]:
35
- return iter(self.__functions)
36
-
37
- def add(self, *functions: HookFunction[P, T]) -> Self:
38
- self.__functions.extend(reversed(functions))
39
- return self
40
-
41
- @classmethod
42
- def apply_several(cls, handler: Callable[P, T], *hooks: Self) -> Callable[P, T]:
43
- stack = itertools.chain.from_iterable((hook.__stack for hook in hooks))
44
- return cls.__apply_stack(handler, stack)
45
-
46
- @classmethod
47
- def __apply_function(
48
- cls,
49
- handler: Callable[P, T],
50
- function: HookFunction[P, T],
51
- ) -> Callable[P, T]:
52
- if not cls.__is_hook_generator_function(function):
53
- return function # type: ignore[return-value]
54
-
55
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
56
- hook: HookGenerator[T] = function(*args, **kwargs)
57
-
58
- try:
59
- next(hook)
60
-
61
- try:
62
- value = handler(*args, **kwargs)
63
- except BaseException as exc:
64
- hook.throw(exc)
65
- else:
66
- hook.send(value)
67
-
68
- except StopIteration as stop:
69
- return stop.value
70
-
71
- finally:
72
- hook.close()
73
-
74
- raise HookError("Missing return value.")
75
-
76
- return wrapper
77
-
78
- @classmethod
79
- def __apply_stack(
80
- cls,
81
- handler: Callable[P, T],
82
- stack: Iterator[HookFunction[P, T]],
83
- ) -> Callable[P, T]:
84
- for function in stack:
85
- new_handler = cls.__apply_function(handler, function)
86
- return cls.__apply_stack(new_handler, stack)
87
-
88
- return handler
89
-
90
- @staticmethod
91
- def __is_hook_generator_function[**_P, _T](
92
- function: HookFunction[_P, _T],
93
- ) -> TypeGuard[HookGeneratorFunction[_P, _T]]:
94
- for fn in function, getattr(function, "__call__", None):
95
- if isgeneratorfunction(fn):
96
- return True
97
-
98
- return False
99
-
100
-
101
- def apply_hooks[**P, T](
102
- handler: Callable[P, T],
103
- hook: Hook[P, T],
104
- *hooks: Hook[P, T],
105
- ) -> Callable[P, T]:
106
- return Hook.apply_several(handler, hook, *hooks)