dependency-injection-pattern 0.0.1__tar.gz → 0.0.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 (45) hide show
  1. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/LICENSE +1 -1
  2. {dependency_injection_pattern-0.0.1/src/dependency_injection_pattern.egg-info → dependency_injection_pattern-0.0.2}/PKG-INFO +2 -1
  3. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/pyproject.toml +2 -1
  4. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2/src/dependency_injection_pattern.egg-info}/PKG-INFO +2 -1
  5. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/dependency_injection_pattern.egg-info/SOURCES.txt +0 -6
  6. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/dependency_injection_pattern.egg-info/requires.txt +1 -0
  7. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/container.py +1 -1
  8. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factories/dependency.py +1 -1
  9. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factories/factory.py +1 -1
  10. dependency_injection_pattern-0.0.1/src/di/core/reflection/__init__.py +0 -126
  11. dependency_injection_pattern-0.0.1/src/di/core/reflection/parameter.py +0 -66
  12. dependency_injection_pattern-0.0.1/src/di/core/reflection/parameter_kind.py +0 -9
  13. dependency_injection_pattern-0.0.1/src/di/core/reflection/parameter_mapper.py +0 -55
  14. dependency_injection_pattern-0.0.1/src/di/core/reflection/signature.py +0 -45
  15. dependency_injection_pattern-0.0.1/src/di/core/reflection/undefined.py +0 -24
  16. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/README.md +0 -0
  17. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/setup.cfg +0 -0
  18. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/dependency_injection_pattern.egg-info/dependency_links.txt +0 -0
  19. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/dependency_injection_pattern.egg-info/top_level.txt +0 -0
  20. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/__init__.py +0 -0
  21. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/default_scope.py +0 -0
  22. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/add_exception.py +0 -0
  23. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/container_sealed_error.py +0 -0
  24. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/factory_provide_exception.py +0 -0
  25. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/implementation_exception.py +0 -0
  26. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/provide_exception.py +0 -0
  27. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/exceptions/seal_exception.py +0 -0
  28. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factories/scoped_factory.py +0 -0
  29. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factories/singleton_factory.py +0 -0
  30. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factories/transient_factory.py +0 -0
  31. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/factory.py +0 -0
  32. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/helpers.py +0 -0
  33. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/log.py +0 -0
  34. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/named_service.py +0 -0
  35. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/protocols/container.py +0 -0
  36. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/protocols/factory.py +0 -0
  37. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/protocols/provider.py +0 -0
  38. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/provider.py +0 -0
  39. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/scope.py +0 -0
  40. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/core/service_request.py +0 -0
  41. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/src/di/exceptions.py +0 -0
  42. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/tests/test_container.py +0 -0
  43. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/tests/test_examples.py +0 -0
  44. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/tests/test_factory.py +0 -0
  45. {dependency_injection_pattern-0.0.1 → dependency_injection_pattern-0.0.2}/tests/test_provider.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Dagrofa BI
3
+ Copyright (c) 2025 Anders Madsen
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dependency-injection-pattern
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: Python implementation of the Dependency Injection pattern.
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License: MIT
@@ -26,6 +26,7 @@ Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: typing-utilities<0.1,>=0.0.3
29
+ Requires-Dist: runtime-reflection-lite<0.1,>=0.0.0
29
30
  Provides-Extra: test
30
31
  Requires-Dist: pytest>=8.3; extra == "test"
31
32
  Requires-Dist: pytest-cov>=6.1; extra == "test"
@@ -27,7 +27,8 @@ classifiers = [
27
27
  "Typing :: Typed"
28
28
  ]
29
29
  dependencies = [
30
- "typing-utilities >= 0.0.3, < 0.1"
30
+ "typing-utilities >= 0.0.3, < 0.1",
31
+ "runtime-reflection-lite >= 0.0.0, < 0.1"
31
32
  ]
32
33
  requires-python = ">=3.10"
33
34
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dependency-injection-pattern
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: Python implementation of the Dependency Injection pattern.
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License: MIT
@@ -26,6 +26,7 @@ Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
28
  Requires-Dist: typing-utilities<0.1,>=0.0.3
29
+ Requires-Dist: runtime-reflection-lite<0.1,>=0.0.0
29
30
  Provides-Extra: test
30
31
  Requires-Dist: pytest>=8.3; extra == "test"
31
32
  Requires-Dist: pytest-cov>=6.1; extra == "test"
@@ -31,12 +31,6 @@ src/di/core/factories/transient_factory.py
31
31
  src/di/core/protocols/container.py
32
32
  src/di/core/protocols/factory.py
33
33
  src/di/core/protocols/provider.py
34
- src/di/core/reflection/__init__.py
35
- src/di/core/reflection/parameter.py
36
- src/di/core/reflection/parameter_kind.py
37
- src/di/core/reflection/parameter_mapper.py
38
- src/di/core/reflection/signature.py
39
- src/di/core/reflection/undefined.py
40
34
  tests/test_container.py
41
35
  tests/test_examples.py
42
36
  tests/test_factory.py
@@ -1,4 +1,5 @@
1
1
  typing-utilities<0.1,>=0.0.3
2
+ runtime-reflection-lite<0.1,>=0.0.0
2
3
 
3
4
  [test]
4
5
  pytest>=8.3
@@ -3,9 +3,9 @@ from typing import TypeVar, Callable, Any, cast, overload, TYPE_CHECKING
3
3
  from typingutils import is_type, isinstance_typing, get_optional_type, AnyFunction
4
4
  from types import FunctionType
5
5
  from weakref import ref
6
+ from runtime.reflection.lite import reflect_function
6
7
 
7
8
  from di.core.log import LOG
8
- from di.core.reflection import reflect_function
9
9
  from di.core.scope import Scope
10
10
  from di.core.service_request import ServiceRequest
11
11
  from di.core.factories.singleton_factory import SingletonFactory
@@ -1,8 +1,8 @@
1
1
  from typing import Any, cast
2
2
  from typingutils import get_optional_type
3
+ from runtime.reflection.lite import Undefined
3
4
 
4
5
  from di.core.helpers import get_provided_service_from_annotation
5
- from di.core.reflection.undefined import Undefined
6
6
 
7
7
  class Dependency:
8
8
  __slots__ = [ "__name", "__service", "__factory", "__optional", "__default" ]
@@ -1,7 +1,7 @@
1
1
  from typing import TypeVar, Callable, Generic, Any, cast
2
2
  from typingutils import get_optional_type, issubclass_typing, isinstance_typing
3
+ from runtime.reflection.lite import Undefined, ParameterKind, reflect_function, get_constructor
3
4
 
4
- from di.core.reflection import Undefined, ParameterKind, reflect_function, get_constructor
5
5
  from di.core.scope import Scope
6
6
  from di.core.named_service import NamedService
7
7
  from di.core.service_request import ServiceRequest
@@ -1,126 +0,0 @@
1
- from typing import Any, cast
2
- from typingutils import AnyFunction
3
- from types import FrameType, MethodType
4
- from sys import modules
5
- from inspect import Parameter as InspectParameter, FrameInfo, signature as get_signature, stack, unwrap
6
-
7
- from di.core.reflection.undefined import Undefined
8
- from di.core.reflection.signature import Signature
9
- from di.core.reflection.parameter import Parameter
10
- from di.core.reflection.parameter_kind import ParameterKind
11
- from di.core.reflection.parameter_mapper import ParameterMapper
12
-
13
-
14
- def resolve(
15
- annotation: str,
16
- globals: dict[str, Any] | None = None,
17
- builtins: dict[str, Any] | None = None,
18
- locals: dict[str, Any] | None = None
19
- ) -> Any:
20
- if globals: # pragma: no cover
21
- globals = { **globals , **(builtins or __builtins__)}
22
-
23
- try:
24
- result = eval(annotation, globals, locals)
25
- return result
26
- except:
27
- pass
28
-
29
- # fallback
30
- for frame in stack()[1:]: # pragma: no cover
31
- if frame.filename == __file__:
32
- continue
33
-
34
- globals = { **frame.frame.f_globals , **frame.frame.f_builtins}
35
- locals = frame.frame.f_locals
36
-
37
- try:
38
- return eval(annotation, globals, locals)
39
- except:
40
- pass
41
-
42
- raise Exception(f"Unable to resolve {annotation}") # pragma: no cover
43
-
44
-
45
-
46
-
47
- def get_frame(fn: Any, stack: list[FrameInfo], cls: Any | None) -> FrameType | None: # pragma: no cover
48
- module = None
49
-
50
- if hasattr(fn, "__module__"):
51
- module = modules[getattr(fn, "__module__")]
52
- elif cls and hasattr(cls, "__module__"):
53
- module = modules[getattr(cls, "__module__")]
54
-
55
- if module and hasattr(module, "__file__"):
56
- for frame in stack:
57
- if frame.filename == module.__file__:
58
- frame_locals = frame.frame.f_locals.values()
59
- if cls is not None and cls in frame_locals:
60
- return frame.frame
61
- elif fn in frame_locals:
62
- return frame.frame
63
-
64
-
65
- def reflect_function(fn: AnyFunction, cls: object | None = None) -> Signature:
66
- fn = unwrap(fn)
67
- sig = get_signature(fn)
68
-
69
- if hasattr(fn, "__self__") and ( self := getattr(fn, "__self__") ):
70
- cls = self
71
-
72
- parameters = list(sig.parameters.values())
73
- globals: dict[str, Any] | None = getattr(fn, "__globals__") if hasattr(fn, "__globals__") else None
74
- builtins: dict[str, Any] | None = getattr(fn, "__builtins__") if hasattr(fn, "__builtins__") else None
75
- locals: dict[str, Any] | None = None
76
-
77
- if frame := get_frame(fn, stack()[1:], cls): # pragma: no cover
78
- locals = frame.f_locals
79
-
80
- if parameters:
81
- first_param = parameters[0].name.lower()
82
-
83
- if isinstance(fn, MethodType) and first_param in ("self", "cls"):
84
- parameters = parameters[1:] # pragma: no cover
85
- elif first_param in ("self", "cls") and hasattr(fn, "__self__"):
86
- parameters = parameters[1:] # pragma: no cover
87
- elif first_param == "self":
88
- if hasattr(fn, "__call__") and ( call := getattr(fn, "__call__") ): # pragma: no cover
89
- if hasattr(call, "__text_signature__") and ( text_sig := getattr(call, "__text_signature__") ):
90
- if cast(str, text_sig).startswith("($self"):
91
- parameters = parameters[1:]
92
-
93
- for index, parameter in enumerate(parameters):
94
- changed = False
95
-
96
- if isinstance(parameter.annotation, str):
97
- parameter_type = resolve(parameter.annotation, globals, builtins, locals)
98
- parameter = parameter.replace(annotation = parameter_type)
99
- changed = True
100
-
101
- if changed:
102
- parameters[index] = parameter
103
-
104
- if sig.return_annotation is InspectParameter.empty:
105
- return_type = Undefined
106
- elif isinstance(sig.return_annotation, str):
107
- return_type = resolve(sig.return_annotation, globals, builtins, locals)
108
- else:
109
- return_type = sig.return_annotation
110
-
111
- return Signature(
112
- ParameterMapper(
113
- [
114
- Parameter(
115
- p.name,
116
- ParameterKind(p.kind),
117
- Undefined if p.annotation is InspectParameter.empty else p.annotation,
118
- Undefined if p.default is InspectParameter.empty else p.default
119
- ) for p in parameters
120
- ]
121
- ), return_type
122
- )
123
-
124
-
125
- def get_constructor(cls: type[Any]) -> Signature:
126
- return reflect_function(getattr(cls, "__init__"), cls)
@@ -1,66 +0,0 @@
1
- from typing import Any, cast
2
- from typingutils import get_type_name
3
- from inspect import Parameter as InspectParameter
4
-
5
- from di.core.reflection.undefined import Undefined
6
- from di.core.reflection.parameter_kind import ParameterKind
7
-
8
- class Parameter:
9
- __slots__ = ["__name", "__kind", "__doc", "__type", "__default"]
10
-
11
- def __init__(
12
- self,
13
- name: str,
14
- kind: ParameterKind,
15
- parameter_type: type[Any],
16
- default: Any
17
- ):
18
- self.__name = name
19
- self.__kind = kind
20
- self.__type = parameter_type
21
- self.__default = default
22
-
23
- @property
24
- def name(self) -> str:
25
- """The parameter name
26
- """
27
- return self.__name
28
-
29
- @property
30
- def kind(self) -> ParameterKind:
31
- """The parameter kind
32
- """
33
- return self.__kind
34
-
35
- @property
36
- def parameter_type(self) -> type[Any]:
37
- """The parameter type
38
- """
39
- return self.__type
40
-
41
- @property
42
- def default(self) -> Any:
43
- """The parameter default
44
- """
45
- return self.__default
46
-
47
- def __repr__(self) -> str:
48
- str_type = f": {get_type_name(cast(type, self.__type))}" if self.__type and self.__type != Undefined else ""
49
- str_default = f"={self.__default}" if self.__default else ""
50
- return f"{self.__name}{str_type}{str_default}"
51
-
52
- def __eq__(self, o: object) -> bool: # pragma: no cover
53
- if isinstance(o, Parameter):
54
- return (
55
- self.name == o.name
56
- and self.kind == o.kind
57
- and self.parameter_type == o.parameter_type
58
- )
59
- elif isinstance(o, InspectParameter):
60
- return (
61
- self.name == o.name
62
- and cast(int, self.kind) == o.kind
63
- and self.parameter_type == o.annotation
64
- )
65
-
66
- return False
@@ -1,9 +0,0 @@
1
- from enum import Enum
2
- from inspect import Parameter
3
-
4
- class ParameterKind(Enum):
5
- POSITIONAL = Parameter.POSITIONAL_ONLY
6
- KEYWORD = Parameter.KEYWORD_ONLY
7
- POSITIONAL_OR_KEYWORD = Parameter.POSITIONAL_OR_KEYWORD
8
- ARGS = Parameter.VAR_POSITIONAL
9
- KWARGS = Parameter.VAR_KEYWORD
@@ -1,55 +0,0 @@
1
- from typing import Iterator, Mapping, Iterable, Sequence
2
-
3
- from di.core.reflection.parameter import Parameter
4
-
5
- class ParameterMapper(Iterable[Parameter]):
6
- __slots__ = ["__parameters", "__index"]
7
-
8
- def __init__(self, parameters: Sequence[Parameter]):
9
- self.__parameters = list(parameters)
10
- self.__index: Mapping[str, int] | None = None
11
-
12
- def __get_index(self) -> Mapping[str, int]:
13
- if not self.__index:
14
- self.__index = {
15
- parameter.name: self.__parameters.index(parameter)
16
- for parameter in self.__parameters
17
- }
18
- return self.__index # pragma: no cover
19
-
20
- def __getitem__(self, index: int | str) -> Parameter: # pragma: no cover
21
- if isinstance(index, int):
22
- return self.__parameters[index]
23
- else:
24
- p_index = self.__get_index()
25
-
26
- if index in p_index:
27
- return self.__parameters[p_index[index]]
28
- else:
29
- raise KeyError(index)
30
-
31
- def __iter__(self) -> Iterator[Parameter]:
32
- return iter(self.__parameters)
33
-
34
- def __len__(self) -> int: # pragma: no cover
35
- return len(self.__parameters)
36
-
37
- def __delitem__(self, index: int | str) -> None: # pragma: no cover
38
- if isinstance(index, int):
39
- del self.__parameters[index]
40
- else:
41
- p_index = self.__get_index()
42
-
43
- if index in p_index:
44
- del self.__parameters[p_index[index]]
45
- else:
46
- raise KeyError(index)
47
-
48
- def __contains__(self, name: str) -> bool: # pragma: no cover
49
- p_index = self.__get_index()
50
- return name in p_index
51
-
52
- def __eq__(self, o: object) -> bool: # pragma: no cover
53
- if isinstance(o, ParameterMapper):
54
- return self.__parameters == o.__parameters
55
- return False
@@ -1,45 +0,0 @@
1
- from typing import Any
2
- from typingutils import get_type_name
3
-
4
- from di.core.reflection.parameter_mapper import ParameterMapper
5
-
6
- class Signature:
7
- __slots__ = ["__parameters", "__return_type"]
8
-
9
- def __init__(
10
- self,
11
- parameters: ParameterMapper,
12
- return_type: type[Any]
13
- ):
14
- self.__parameters = parameters
15
- self.__return_type = return_type
16
-
17
- @property
18
- def parameters(self) -> ParameterMapper:
19
- """The signature parameters
20
- """
21
- return self.__parameters
22
-
23
- @property
24
- def return_type(self) -> type[Any]:
25
- """The signature return type
26
- """
27
- return self.__return_type
28
-
29
-
30
-
31
- def __repr__(self) -> str:
32
- str_parameters = ", ".join([ str(p) for p in self.__parameters ]) if self.__parameters else ""
33
- str_return = f" -> {get_type_name(self.__return_type)}" if self.__return_type else ""
34
- return f"({str_parameters}){str_return}"
35
-
36
- def __eq__(self, o: object) -> bool: # pragma: no cover
37
- if self is o:
38
- return True
39
- elif isinstance(o, Signature):
40
- return (
41
- self.parameters == o.parameters
42
- and self.return_type == o.return_type
43
- )
44
- return False
45
-
@@ -1,24 +0,0 @@
1
- from inspect import Signature, Parameter
2
-
3
- class Meta(type): # pragma: no cover
4
-
5
- def __bool__(self):
6
- return False
7
-
8
- def __eq__(self, other: object) -> bool:
9
- return other is Undefined or other in [ Signature.empty, Parameter.empty, None ]
10
-
11
- def __repr__(cls):
12
- return "Undefined"
13
-
14
- def __str__(self) -> str:
15
- return "Undefined"
16
-
17
- def __hash__(self) -> int:
18
- return type.__hash__(self)
19
-
20
-
21
- class Undefined(metaclass=Meta):
22
- def __new__(cls):
23
- raise Exception("Undefined type is not supposed to be instantiated") # pragma: no cover
24
-