dependency-injection-pattern 0.0.3__tar.gz → 0.0.5__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 (41) hide show
  1. {dependency_injection_pattern-0.0.3/src/dependency_injection_pattern.egg-info → dependency_injection_pattern-0.0.5}/PKG-INFO +3 -3
  2. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/pyproject.toml +2 -2
  3. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5/src/dependency_injection_pattern.egg-info}/PKG-INFO +3 -3
  4. dependency_injection_pattern-0.0.5/src/dependency_injection_pattern.egg-info/requires.txt +6 -0
  5. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/container.py +20 -20
  6. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/default_scope.py +1 -2
  7. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factories/factory.py +5 -5
  8. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/helpers.py +1 -2
  9. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/provider.py +1 -1
  10. dependency_injection_pattern-0.0.5/src/di/core/scope.py +24 -0
  11. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/tests/test_container.py +1 -1
  12. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/tests/test_examples.py +1 -0
  13. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/tests/test_factory.py +1 -0
  14. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/tests/test_provider.py +1 -0
  15. dependency_injection_pattern-0.0.3/src/dependency_injection_pattern.egg-info/requires.txt +0 -6
  16. dependency_injection_pattern-0.0.3/src/di/core/scope.py +0 -15
  17. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/LICENSE +0 -0
  18. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/README.md +0 -0
  19. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/setup.cfg +0 -0
  20. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/dependency_injection_pattern.egg-info/SOURCES.txt +0 -0
  21. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/dependency_injection_pattern.egg-info/dependency_links.txt +0 -0
  22. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/dependency_injection_pattern.egg-info/top_level.txt +0 -0
  23. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/__init__.py +0 -0
  24. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/add_exception.py +0 -0
  25. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/container_sealed_error.py +0 -0
  26. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/factory_provide_exception.py +0 -0
  27. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/implementation_exception.py +0 -0
  28. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/provide_exception.py +0 -0
  29. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/exceptions/seal_exception.py +0 -0
  30. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factories/dependency.py +0 -0
  31. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factories/scoped_factory.py +0 -0
  32. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factories/singleton_factory.py +0 -0
  33. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factories/transient_factory.py +0 -0
  34. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/factory.py +0 -0
  35. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/log.py +0 -0
  36. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/named_service.py +0 -0
  37. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/protocols/container.py +0 -0
  38. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/protocols/factory.py +0 -0
  39. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/protocols/provider.py +0 -0
  40. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/core/service_request.py +0 -0
  41. {dependency_injection_pattern-0.0.3 → dependency_injection_pattern-0.0.5}/src/di/exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dependency-injection-pattern
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: Python implementation of the Dependency Injection pattern.
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License-Expression: MIT
@@ -25,8 +25,8 @@ Classifier: Typing :: Typed
25
25
  Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
- Requires-Dist: typing-utilities<0.1,>=0.0.3
29
- Requires-Dist: runtime-reflection-lite<0.2,>=0.1.0
28
+ Requires-Dist: typing-utilities<0.2,>=0.1.0
29
+ Requires-Dist: runtime-reflection-lite<0.2,>=0.1.2
30
30
  Provides-Extra: test
31
31
  Requires-Dist: pytest>=8.3; extra == "test"
32
32
  Requires-Dist: pytest-cov>=6.1; extra == "test"
@@ -28,8 +28,8 @@ classifiers = [
28
28
  "Typing :: Typed"
29
29
  ]
30
30
  dependencies = [
31
- "typing-utilities >= 0.0.3, < 0.1",
32
- "runtime-reflection-lite >= 0.1.0, < 0.2"
31
+ "typing-utilities >= 0.1.0, < 0.2",
32
+ "runtime-reflection-lite >= 0.1.2, < 0.2"
33
33
  ]
34
34
  requires-python = ">=3.10"
35
35
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dependency-injection-pattern
3
- Version: 0.0.3
3
+ Version: 0.0.5
4
4
  Summary: Python implementation of the Dependency Injection pattern.
5
5
  Author-email: Anders Madsen <anders.madsen@alphavue.com>
6
6
  License-Expression: MIT
@@ -25,8 +25,8 @@ Classifier: Typing :: Typed
25
25
  Requires-Python: >=3.10
26
26
  Description-Content-Type: text/markdown
27
27
  License-File: LICENSE
28
- Requires-Dist: typing-utilities<0.1,>=0.0.3
29
- Requires-Dist: runtime-reflection-lite<0.2,>=0.1.0
28
+ Requires-Dist: typing-utilities<0.2,>=0.1.0
29
+ Requires-Dist: runtime-reflection-lite<0.2,>=0.1.2
30
30
  Provides-Extra: test
31
31
  Requires-Dist: pytest>=8.3; extra == "test"
32
32
  Requires-Dist: pytest-cov>=6.1; extra == "test"
@@ -0,0 +1,6 @@
1
+ typing-utilities<0.2,>=0.1.0
2
+ runtime-reflection-lite<0.2,>=0.1.2
3
+
4
+ [test]
5
+ pytest>=8.3
6
+ pytest-cov>=6.1
@@ -1,9 +1,9 @@
1
1
  from __future__ import annotations
2
2
  from typing import TypeVar, Callable, Any, cast, overload, TYPE_CHECKING
3
- from typingutils import is_type, isinstance_typing, get_optional_type, AnyFunction
3
+ from typingutils import is_type, isinstance_typing, get_optional_type
4
4
  from types import FunctionType
5
5
  from weakref import ref
6
- from runtime.reflection.lite import reflect_function
6
+ from runtime.reflection.lite import get_signature
7
7
 
8
8
  from di.core.log import LOG
9
9
  from di.core.scope import Scope
@@ -48,19 +48,19 @@ class Container:
48
48
  return self.__default_scope
49
49
 
50
50
  @overload
51
- def add_singleton(self, service: type, /) -> None:
51
+ def add_singleton(self, service: type[Any], /) -> None:
52
52
  """Adds a singleton service to provider, which will result in same instance every time it's provided.
53
53
 
54
54
  Args:
55
- service (type): The service interface
55
+ service (type[Any]): The service interface
56
56
  """
57
57
  ...
58
58
  @overload
59
- def add_singleton(self, implementation: AnyFunction, /) -> None:
59
+ def add_singleton(self, implementation: Callable[..., T], /) -> None:
60
60
  """Adds a singleton service to provider, which will result in same instance every time it's provided.
61
61
 
62
62
  Args:
63
- implementation (AnyFunction) The service implementation
63
+ implementation (Callable[..., T]) The service implementation
64
64
  """
65
65
  ...
66
66
  @overload
@@ -87,20 +87,20 @@ class Container:
87
87
  self.__add_factory_pre(SingletonFactory, *args)
88
88
 
89
89
  @overload
90
- def add_transient(self, service: type, /) -> None:
90
+ def add_transient(self, service: type[Any], /) -> None:
91
91
  """Adds a transient service to provider, which will result in a new instance every time it's provided.
92
92
 
93
93
  Args:
94
- service (type) The service interface
94
+ service (type[Any]) The service interface
95
95
 
96
96
  """
97
97
  ...
98
98
  @overload
99
- def add_transient(self, implementation: AnyFunction, /) -> None:
99
+ def add_transient(self, implementation: Callable[..., T], /) -> None:
100
100
  """Adds a transient service to provider, which will result in a new instance every time it's provided.
101
101
 
102
102
  Args:
103
- implementation (AnyFunction) The service implementation
103
+ implementation (Callable[..., T]) The service implementation
104
104
  """
105
105
  ...
106
106
  @overload
@@ -127,25 +127,25 @@ class Container:
127
127
  self.__add_factory_pre(TransientFactory, *args)
128
128
 
129
129
  @overload
130
- def add_scoped(self, service: type, /) -> None:
130
+ def add_scoped(self, service: type[Any], /) -> None:
131
131
  """Adds a scoped service to provider, which will result in one instance every time it's provided in the same scope.
132
132
  The default scope is thread-based, and bound to the lifetime of the thread in which a given service is provided.
133
133
 
134
134
  Note: Scoped services should implement the ContextManager pattern.
135
135
 
136
136
  Args:
137
- service (type) The service interface
137
+ service (type[Any]) The service interface
138
138
  """
139
139
  ...
140
140
  @overload
141
- def add_scoped(self, implementation: AnyFunction, /) -> None:
141
+ def add_scoped(self, implementation: Callable[..., T], /) -> None:
142
142
  """Adds a scoped service to provider, which will result in one instance every time it's provided in the same scope.
143
143
  The default scope is thread-based, and bound to the lifetime of the thread in which a given service is provided.
144
144
 
145
145
  Note: Scoped services should implement the ContextManager pattern.
146
146
 
147
147
  Args:
148
- implementation (AnyFunction) The service implementation
148
+ implementation (Callable[..., T]) The service implementation
149
149
  """
150
150
  ...
151
151
  @overload
@@ -195,7 +195,7 @@ class Container:
195
195
  factories = { **self.__factories, **{ service: factory for service, factory in self.__named_factories.values() } }
196
196
  for service, factory in factories.items():
197
197
  for dep in factory.dependencies.values():
198
- if not dep.service in factories:
198
+ if dep.service not in factories:
199
199
  if not dep.is_optional and not dep.has_default:
200
200
  raise SealException(f"Service '{get_service_name(service)}' depends on service '{get_service_name(dep.service)}' which is not defined in container.")
201
201
  else:
@@ -207,7 +207,7 @@ class Container:
207
207
  raise SealException(f"Singleton service '{get_service_name(service)}' depends on transient service {get_service_name(dep.service)}' which is not permitted.")
208
208
 
209
209
  return provider
210
- elif provider :=self.__provider():
210
+ elif provider := self.__provider():
211
211
  return provider
212
212
  else:
213
213
  provider = Provider(self)
@@ -215,7 +215,7 @@ class Container:
215
215
  return provider
216
216
 
217
217
  def __add_factory_pre(self, factory_type: type[Factory[T]], *args: Any) -> tuple[str, type[Any]]:
218
- if self.__provider != None:
218
+ if self.__provider is not None:
219
219
  raise ContainerSealedError
220
220
 
221
221
  if len(args) == 2:
@@ -231,7 +231,7 @@ class Container:
231
231
  if not isinstance(args[0], FunctionType):
232
232
  raise AddException("Implementation must be a function or a type when no service is specified.")
233
233
  implementation = cast(Callable[..., Any], args[0])
234
- signature = reflect_function(implementation)
234
+ signature = get_signature(implementation)
235
235
  service, _ = get_optional_type(cast(type, signature.return_type))
236
236
 
237
237
  return get_service_name(service), self.__add_factory(factory_type, cast(str | type[Any], service), implementation)
@@ -248,7 +248,7 @@ class Container:
248
248
  if is_type(implementation):
249
249
  svc_type = cast(type[T], implementation)
250
250
  elif callable(implementation):
251
- signature = reflect_function(implementation)
251
+ signature = get_signature(implementation)
252
252
  svc_type = cast(type[T], signature.return_type)
253
253
  else:
254
254
  svc_type = cast(type[T], type(implementation))
@@ -335,7 +335,7 @@ class Container:
335
335
 
336
336
  if factory:
337
337
  return factory
338
- elif default != None:
338
+ elif default is not None:
339
339
  return default
340
340
  elif not is_optional:
341
341
  if isinstance(service, ServiceRequest):
@@ -9,7 +9,6 @@ from di.core.helpers import is_context, get_service_name
9
9
 
10
10
  T = TypeVar('T')
11
11
 
12
-
13
12
  class DefaultScope(Scope):
14
13
  """
15
14
  DefaultScope is as the name implies the default scope. This scope is thread-based, meaning it will supply
@@ -56,7 +55,7 @@ class DefaultScope(Scope):
56
55
  self.__local.finalizer = Thread(target = finalize, args = [ current_thread(), dict ])
57
56
  self.__local.finalizer.start()
58
57
 
59
- if not service in self.__local.dict:
58
+ if service not in self.__local.dict:
60
59
  impl = factory()
61
60
  if current_thread() != main_thread() and is_context(service):
62
61
  # finalizer is only implemented when thread is not main thread, otherwise object would never be exited (eg. finalized)
@@ -1,6 +1,6 @@
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
+ from runtime.reflection.lite import Undefined, ParameterKind, get_signature, get_constructor
4
4
 
5
5
  from di.core.scope import Scope
6
6
  from di.core.named_service import NamedService
@@ -25,19 +25,19 @@ class Factory(Generic[T]):
25
25
 
26
26
  if not implementation:
27
27
  if hasattr(service, "__origin__"):
28
- sig = reflect_function(getattr(service, "__call__"), service)
28
+ sig = get_signature(getattr(service, "__call__"), service)
29
29
  else:
30
30
  sig = get_constructor(service)
31
31
  elif isinstance(implementation, type):
32
32
  sig = get_constructor(cast(type, implementation))
33
- if not service is NamedService and not issubclass_typing(implementation, service):
33
+ if service is not NamedService and not issubclass_typing(implementation, service):
34
34
  raise ImplementationException(service, implementation, "Implementation class is not derived from service")
35
35
  elif implementation is service:
36
36
  raise ImplementationException(service, implementation, "Implementation equals service")
37
37
  elif isinstance_typing(implementation, service, recursive=True):
38
38
  sig = None
39
39
  elif callable(implementation):
40
- sig = reflect_function(implementation)
40
+ sig = get_signature(implementation)
41
41
  if sig.return_type:
42
42
  implementation_type, _ = get_optional_type(sig.return_type)
43
43
  else:
@@ -54,7 +54,7 @@ class Factory(Generic[T]):
54
54
  else:
55
55
  raise ImplementationException(service, implementation, "Implementation does not resolve into a class derived from service")
56
56
 
57
- if sig != None:
57
+ if sig is not None:
58
58
  parameters = [ p for p in sig.parameters if p.kind == ParameterKind.POSITIONAL_OR_KEYWORD ]
59
59
  missing_annotations = [ p.name for p in parameters if not p.parameter_type ]
60
60
  self.__dependencies = { p.name: Dependency(p.name, p.parameter_type, p.default) for p in parameters }
@@ -1,5 +1,4 @@
1
1
  from typing import MutableMapping, Protocol, TypeVar, cast, runtime_checkable
2
- from di.core.factory import Factory
3
2
  from types import TracebackType
4
3
  from typingutils import AnyType, issubclass_typing, get_type_name
5
4
 
@@ -35,7 +34,7 @@ def get_provided_service_from_annotation(annotation: AnyType) -> tuple[AnyType,
35
34
  __CONTEXT_SERVICES__: MutableMapping[type, bool] = {}
36
35
 
37
36
  def is_context(cls: type) -> bool:
38
- if not cls in __CONTEXT_SERVICES__:
37
+ if cls not in __CONTEXT_SERVICES__:
39
38
  # reflection = reflect_class(cls)
40
39
 
41
40
  # if "__enter__" in reflection.functions and "__exit__" in reflection.functions:
@@ -68,7 +68,7 @@ class Provider:
68
68
  else:
69
69
  result = self.__container._get(cast(type[T], service)) # pyright: ignore[reportPrivateUsage]
70
70
 
71
- if result == None:
71
+ if result is None:
72
72
  # optional requirements may return None
73
73
  if is_optional:
74
74
  return None # pyright: ignore[reportReturnType]
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+ from abc import ABC, abstractmethod
3
+ from typing import Callable, TypeVar
4
+
5
+ T = TypeVar('T')
6
+
7
+ class Scope(ABC):
8
+ """
9
+ Scope is the base class from which scopes are derived, and its superclasses handle provision of
10
+ scoped services.
11
+ """
12
+
13
+ @abstractmethod
14
+ def provide(self, service: type[T], factory: Callable[[], T]) -> T:
15
+ """This function function is used by the `ScopedFactory` factory to provide and cleanup services.
16
+
17
+ Args:
18
+ service (type[T]): The service type.
19
+ factory (Callable[[], T]): The factory function.
20
+
21
+ Returns:
22
+ T: Returns an object.
23
+ """
24
+ ...
@@ -1,5 +1,5 @@
1
1
  # pyright: basic
2
- # from __future__ import annotations
2
+ # ruff: noqa
3
3
  from typing import cast, Sequence
4
4
  from pytest import raises as assert_raises
5
5
  from threading import Thread
@@ -1,4 +1,5 @@
1
1
  # pyright: basic
2
+ # ruff: noqa
2
3
 
3
4
  def test_example_1():
4
5
  from logging import Logger
@@ -1,4 +1,5 @@
1
1
  # pyright: basic
2
+ # ruff: noqa
2
3
  from __future__ import annotations
3
4
  from time import sleep
4
5
  from threading import Thread
@@ -1,4 +1,5 @@
1
1
  # pyright: basic
2
+ # ruff: noqa
2
3
  from typing import cast, Sequence, MutableSequence, Generic, TypeVar, Any, ClassVar
3
4
  from pytest import raises as assert_raises
4
5
 
@@ -1,6 +0,0 @@
1
- typing-utilities<0.1,>=0.0.3
2
- runtime-reflection-lite<0.2,>=0.1.0
3
-
4
- [test]
5
- pytest>=8.3
6
- pytest-cov>=6.1
@@ -1,15 +0,0 @@
1
- from __future__ import annotations
2
- from abc import ABC, abstractmethod
3
- from typing import Callable, TypeVar
4
-
5
- T = TypeVar('T')
6
-
7
- class Scope(ABC):
8
- """
9
- Scope is the base class from which scopes are derived, and its superclasses handle provision of
10
- scoped services.
11
- """
12
-
13
- @abstractmethod
14
- def provide(self, service: type[T], factory: Callable[..., T]) -> T:
15
- ...