python-injection 0.12.1__tar.gz → 0.12.2__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 (25) hide show
  1. {python_injection-0.12.1 → python_injection-0.12.2}/PKG-INFO +1 -1
  2. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/module.py +15 -13
  3. {python_injection-0.12.1 → python_injection-0.12.2}/injection/integrations/fastapi.py +2 -4
  4. python_injection-0.12.2/injection/py.typed +0 -0
  5. {python_injection-0.12.1 → python_injection-0.12.2}/injection/utils.py +34 -2
  6. {python_injection-0.12.1 → python_injection-0.12.2}/pyproject.toml +1 -1
  7. python_injection-0.12.1/injection/integrations/__init__.py +0 -11
  8. {python_injection-0.12.1 → python_injection-0.12.2}/README.md +0 -0
  9. {python_injection-0.12.1 → python_injection-0.12.2}/injection/__init__.py +0 -0
  10. {python_injection-0.12.1 → python_injection-0.12.2}/injection/__init__.pyi +0 -0
  11. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/__init__.py +0 -0
  12. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/__init__.py +0 -0
  13. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/asynchronous.py +0 -0
  14. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/event.py +0 -0
  15. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/invertible.py +0 -0
  16. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/lazy.py +0 -0
  17. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/threading.py +0 -0
  18. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/common/type.py +0 -0
  19. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/descriptors.py +0 -0
  20. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/hook.py +0 -0
  21. {python_injection-0.12.1 → python_injection-0.12.2}/injection/_core/injectables.py +0 -0
  22. {python_injection-0.12.1 → python_injection-0.12.2}/injection/exceptions.py +0 -0
  23. /python_injection-0.12.1/injection/py.typed → /python_injection-0.12.2/injection/integrations/__init__.py +0 -0
  24. {python_injection-0.12.1 → python_injection-0.12.2}/injection/testing/__init__.py +0 -0
  25. {python_injection-0.12.1 → python_injection-0.12.2}/injection/testing/__init__.pyi +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-injection
3
- Version: 0.12.1
3
+ Version: 0.12.2
4
4
  Summary: Fast and easy dependency injection framework.
5
5
  Home-page: https://github.com/100nm/python-injection
6
6
  License: MIT
@@ -208,18 +208,20 @@ class Updater[T]:
208
208
  return Record(injectable, self.mode)
209
209
 
210
210
 
211
- class LocatorHooks[T](NamedTuple):
212
- on_conflict: Hook[[Record[T], Record[T], InputType[T]], bool]
213
- on_input: Hook[[Iterable[InputType[T]]], Iterable[InputType[T]]]
214
- on_update: Hook[[Updater[T]], Updater[T]]
215
-
216
- @classmethod
217
- def default(cls) -> Self:
218
- return cls(
219
- on_conflict=Hook(),
220
- on_input=Hook(),
221
- on_update=Hook(),
222
- )
211
+ @dataclass(repr=False, eq=False, frozen=True, slots=True)
212
+ class LocatorHooks[T]:
213
+ on_conflict: Hook[[Record[T], Record[T], InputType[T]], bool] = field(
214
+ default_factory=Hook,
215
+ init=False,
216
+ )
217
+ on_input: Hook[[Iterable[InputType[T]]], Iterable[InputType[T]]] = field(
218
+ default_factory=Hook,
219
+ init=False,
220
+ )
221
+ on_update: Hook[[Updater[T]], Updater[T]] = field(
222
+ default_factory=Hook,
223
+ init=False,
224
+ )
223
225
 
224
226
 
225
227
  @dataclass(repr=False, frozen=True, slots=True)
@@ -233,7 +235,7 @@ class Locator(Broker):
233
235
  init=False,
234
236
  )
235
237
 
236
- static_hooks: ClassVar[LocatorHooks[Any]] = LocatorHooks.default()
238
+ static_hooks: ClassVar[LocatorHooks[Any]] = LocatorHooks()
237
239
 
238
240
  def __getitem__[T](self, cls: InputType[T], /) -> Injectable[T]:
239
241
  for input_class in self.__standardize_inputs((cls,)):
@@ -2,15 +2,13 @@ from collections.abc import Awaitable
2
2
  from types import GenericAlias
3
3
  from typing import Any, TypeAliasType
4
4
 
5
+ from fastapi import Depends
6
+
5
7
  from injection import Module, mod
6
8
  from injection.exceptions import InjectionError
7
- from injection.integrations import _is_installed
8
9
 
9
10
  __all__ = ("Inject",)
10
11
 
11
- if _is_installed("fastapi", __name__):
12
- from fastapi import Depends
13
-
14
12
 
15
13
  def Inject[T]( # noqa: N802
16
14
  cls: type[T] | TypeAliasType | GenericAlias,
File without changes
@@ -1,13 +1,15 @@
1
- from collections.abc import Callable, Iterator
1
+ from collections.abc import Callable, Iterable, Iterator
2
2
  from contextlib import contextmanager
3
3
  from importlib import import_module
4
+ from importlib.util import find_spec
4
5
  from pkgutil import walk_packages
5
6
  from types import ModuleType as PythonModule
6
7
  from typing import ContextManager
7
8
 
9
+ from injection import __name__ as injection_package_name
8
10
  from injection import mod
9
11
 
10
- __all__ = ("load_packages", "load_profile")
12
+ __all__ = ("load_modules_with_keywords", "load_packages", "load_profile")
11
13
 
12
14
 
13
15
  def load_profile(*names: str) -> ContextManager[None]:
@@ -33,6 +35,36 @@ def load_profile(*names: str) -> ContextManager[None]:
33
35
  return cleaner()
34
36
 
35
37
 
38
+ def load_modules_with_keywords(
39
+ *packages: PythonModule | str,
40
+ keywords: Iterable[str] | None = None,
41
+ ) -> dict[str, PythonModule]:
42
+ """
43
+ Function to import modules from a Python package if one of the keywords is contained in the Python script.
44
+ The default keywords are:
45
+ - `from injection`
46
+ - `import injection`
47
+ """
48
+
49
+ if keywords is None:
50
+ keywords = f"from {injection_package_name}", f"import {injection_package_name}"
51
+
52
+ b_keywords = tuple(keyword.encode() for keyword in keywords)
53
+
54
+ def predicate(module_name: str) -> bool:
55
+ if (spec := find_spec(module_name)) and (module_path := spec.origin):
56
+ with open(module_path, "rb") as script:
57
+ for line in script:
58
+ line = b" ".join(line.split(b" ")).strip()
59
+
60
+ if line and any(keyword in line for keyword in b_keywords):
61
+ return True
62
+
63
+ return False
64
+
65
+ return load_packages(*packages, predicate=predicate)
66
+
67
+
36
68
  def load_packages(
37
69
  *packages: PythonModule | str,
38
70
  predicate: Callable[[str], bool] = lambda module_name: True,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-injection"
3
- version = "0.12.1"
3
+ version = "0.12.2"
4
4
  description = "Fast and easy dependency injection framework."
5
5
  license = "MIT"
6
6
  readme = "README.md"
@@ -1,11 +0,0 @@
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