python-injection 0.10.4__py3-none-any.whl → 0.10.5__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.
injection/_core/hook.py CHANGED
@@ -2,7 +2,7 @@ import itertools
2
2
  from collections.abc import Callable, Generator, Iterator
3
3
  from dataclasses import dataclass, field
4
4
  from inspect import isclass, isgeneratorfunction
5
- from typing import Self
5
+ from typing import Any, Self
6
6
 
7
7
  from injection.exceptions import HookError
8
8
 
@@ -48,11 +48,11 @@ class Hook[**P, T]:
48
48
  handler: Callable[P, T],
49
49
  function: HookFunction[P, T],
50
50
  ) -> Callable[P, T]:
51
- if not isgeneratorfunction(function):
51
+ if not cls.__is_generator_function(function):
52
52
  return function # type: ignore[return-value]
53
53
 
54
54
  def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
55
- hook = function(*args, **kwargs)
55
+ hook: HookGenerator[T] = function(*args, **kwargs) # type: ignore[assignment]
56
56
 
57
57
  try:
58
58
  next(hook)
@@ -87,6 +87,14 @@ class Hook[**P, T]:
87
87
 
88
88
  return handler
89
89
 
90
+ @staticmethod
91
+ def __is_generator_function(obj: Any) -> bool:
92
+ for o in obj, getattr(obj, "__call__", None):
93
+ if isgeneratorfunction(o):
94
+ return True
95
+
96
+ return False
97
+
90
98
 
91
99
  def apply_hooks[**P, T](
92
100
  handler: Callable[P, T],
@@ -0,0 +1,11 @@
1
+ from importlib.util import find_spec
2
+ from typing import Literal
3
+
4
+ __all__ = ("_is_installed",)
5
+
6
+
7
+ def _is_installed(package: str, needed_for: object, /) -> Literal[True]:
8
+ if find_spec(package) is None:
9
+ raise RuntimeError(f"To use `{needed_for}`, {package} must be installed.")
10
+
11
+ return True
@@ -1,15 +1,11 @@
1
1
  from typing import Any, override
2
2
 
3
3
  from injection import Module, mod
4
+ from injection.integrations import _is_installed
4
5
 
5
6
  __all__ = ("InjectionServices",)
6
7
 
7
-
8
- try:
9
- import blacksheep # noqa: F401
10
- except ImportError as exc: # pragma: no cover
11
- raise ImportError(f"To use `{__name__}`, blacksheep must be installed.") from exc
12
- else:
8
+ if _is_installed("blacksheep", __name__):
13
9
  from rodi import ContainerProtocol
14
10
 
15
11
 
@@ -0,0 +1,37 @@
1
+ from collections.abc import Callable
2
+ from typing import Any
3
+
4
+ from injection import Module, mod
5
+ from injection.exceptions import InjectionError
6
+ from injection.integrations import _is_installed
7
+
8
+ __all__ = ("Inject",)
9
+
10
+ if _is_installed("fastapi", __name__):
11
+ from fastapi import Depends
12
+
13
+
14
+ def Inject[T](cls: type[T] | Any, /, module: Module | None = None) -> Any: # noqa: N802
15
+ """
16
+ Declare a FastAPI dependency with `python-injection`.
17
+ """
18
+
19
+ dependency: InjectionDependency[T] = InjectionDependency(cls, module or mod())
20
+ return Depends(dependency)
21
+
22
+
23
+ class InjectionDependency[T]:
24
+ __slots__ = ("__call__",)
25
+
26
+ __call__: Callable[[], T]
27
+
28
+ def __init__(self, cls: type[T] | Any, module: Module):
29
+ lazy_instance = module.get_lazy_instance(cls)
30
+ self.__call__ = lambda: self.__ensure(~lazy_instance, cls)
31
+
32
+ @staticmethod
33
+ def __ensure[_T](instance: _T | None, cls: type[_T] | Any) -> _T:
34
+ if instance is None:
35
+ raise InjectionError(f"`{cls}` is an unknown dependency.")
36
+
37
+ return instance
@@ -1,4 +1,3 @@
1
- from contextlib import ContextDecorator
2
1
  from typing import ContextManager, Final
3
2
 
4
3
  from injection import mod
@@ -22,7 +21,5 @@ test_injectable = mod(_TEST_PROFILE_NAME).injectable
22
21
  test_singleton = mod(_TEST_PROFILE_NAME).singleton
23
22
 
24
23
 
25
- def load_test_profile(
26
- *other_profile_names: str,
27
- ) -> ContextManager[None] | ContextDecorator:
24
+ def load_test_profile(*other_profile_names: str) -> ContextManager[None]:
28
25
  return load_profile(_TEST_PROFILE_NAME, *other_profile_names)
@@ -1,4 +1,3 @@
1
- from contextlib import ContextDecorator
2
1
  from typing import ContextManager
3
2
 
4
3
  import injection as _
@@ -9,9 +8,7 @@ test_constant = _.constant
9
8
  test_injectable = _.injectable
10
9
  test_singleton = _.singleton
11
10
 
12
- def load_test_profile(
13
- *additional_names: str,
14
- ) -> ContextManager[None] | ContextDecorator:
11
+ def load_test_profile(*other_profile_names: str) -> ContextManager[None]:
15
12
  """
16
13
  Context manager or decorator for temporary use test module.
17
14
  """
injection/utils.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Callable, Iterator
2
- from contextlib import ContextDecorator, contextmanager
2
+ from contextlib import contextmanager
3
3
  from importlib import import_module
4
4
  from pkgutil import walk_packages
5
5
  from types import ModuleType as PythonModule
@@ -10,11 +10,7 @@ from injection import mod
10
10
  __all__ = ("load_packages", "load_profile")
11
11
 
12
12
 
13
- def load_profile(
14
- name: str,
15
- /,
16
- *other_profile_names: str,
17
- ) -> ContextManager[None] | ContextDecorator:
13
+ def load_profile(name: str, /, *other_profile_names: str) -> ContextManager[None]:
18
14
  """
19
15
  Injection module initialization function based on profile name.
20
16
  A profile name is equivalent to an injection module name.
@@ -27,12 +23,14 @@ def load_profile(
27
23
 
28
24
  target = mod().unlock().init_modules(*modules)
29
25
 
26
+ del module, modules
27
+
30
28
  @contextmanager
31
- def teardown() -> Iterator[None]:
29
+ def cleaner() -> Iterator[None]:
32
30
  yield
33
31
  target.unlock().init_modules()
34
32
 
35
- return teardown()
33
+ return cleaner()
36
34
 
37
35
 
38
36
  def load_packages(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-injection
3
- Version: 0.10.4
3
+ Version: 0.10.5
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Home-page: https://github.com/100nm/python-injection
6
6
  License: MIT
@@ -63,7 +63,6 @@ class Printer:
63
63
  self.history.append(message)
64
64
  print(message)
65
65
 
66
-
67
66
  @injectable
68
67
  class Service:
69
68
  def __init__(self, printer: Printer):
@@ -72,12 +71,10 @@ class Service:
72
71
  def hello(self):
73
72
  self.printer.print("Hello world!")
74
73
 
75
-
76
74
  @inject
77
75
  def main(service: Service):
78
76
  service.hello()
79
77
 
80
-
81
78
  if __name__ == "__main__":
82
79
  main()
83
80
  ```
@@ -7,15 +7,16 @@ injection/_core/common/invertible.py,sha256=QYXMqLrkAkz_7mq-jEYKtBr1CQ5aqzplP0FG
7
7
  injection/_core/common/lazy.py,sha256=kCO1q4S6AdBhsP5RrihBJpgfeR4hxvMqSz1cpCgBdjo,1482
8
8
  injection/_core/common/threading.py,sha256=OXm7L3p8c7O7eSkU-RTR7cobqIGMhuo-7gpDXsWKDNQ,214
9
9
  injection/_core/common/type.py,sha256=TQTD-f_rnAHS0VgfkWxNFU8HAWPvkAktNDQ9_23JLHM,1705
10
- injection/_core/hook.py,sha256=yk_X6rwcGqL3LYthX4yeYasDCfd0IhioOjFNjtH6bYU,2727
10
+ injection/_core/hook.py,sha256=p9pC1zb9tDZykHs5HGM5VpRxWyvuajC45vilvkvatkY,2999
11
11
  injection/_core/module.py,sha256=1x5d3xlIwJxNiTHEIuHzZR4HOxXk6fMd45oZOiBYBUM,25376
12
12
  injection/exceptions.py,sha256=-5Shs7R5rctQXhpMLfcjiMBCzrtFWxC88qETUIHz57s,692
13
- injection/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- injection/integrations/blacksheep.py,sha256=0cYXR_RRuUKGKaVpTjNmJwAqJfc7BQNbZldXuRgSp9U,1013
13
+ injection/integrations/__init__.py,sha256=NYLcstr4ESdLj326LlDub143z6JGM1z1pCOVWhBXK10,304
14
+ injection/integrations/blacksheep.py,sha256=yO5gLb_l4W3bNPFt-v2qWIL9R8PNon4JmOxQEHdi-5o,923
15
+ injection/integrations/fastapi.py,sha256=5vocISPsQqJjD4g-QjXMKLa-rHqU1Rpysm2gb4VDI10,1056
15
16
  injection/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- injection/testing/__init__.py,sha256=tVyoWBeJJ_GK6ms8AvK7knoKdt2moxNEeLFnXU9LWx0,813
17
- injection/testing/__init__.pyi,sha256=dhGVz0PqKQZz9UGS1lk7yRP1zVDlkN7EM8w4JKMUfLI,449
18
- injection/utils.py,sha256=4Go2EPkC7MBJIUD42x_RPT1yoJphqKDMftx4eN-6xos,2000
19
- python_injection-0.10.4.dist-info/METADATA,sha256=EZAPHGEk-5wiGb6hlliZbQM76KgmgEnMyCnmTWwsDDU,3062
20
- python_injection-0.10.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
21
- python_injection-0.10.4.dist-info/RECORD,,
17
+ injection/testing/__init__.py,sha256=-C38gmZJwDtLDAWJhqiaosOZWQZwwFa1M34tODcrASs,747
18
+ injection/testing/__init__.pyi,sha256=6ZXbbS-9ppMdkxd03I6yBNurmR3Xw7sM_qiokibkLeY,386
19
+ injection/utils.py,sha256=gPcxGIdrGz4irbJXGTYPw33jNy8jg56u_c61eb1MBSE,1971
20
+ python_injection-0.10.5.dist-info/METADATA,sha256=Ka-CEnqFl0WybTXNsVRKEAp9UfEEsQungF6RVgATvBA,3059
21
+ python_injection-0.10.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
22
+ python_injection-0.10.5.dist-info/RECORD,,