dependency-injection-pattern 0.0.0__tar.gz → 0.0.1__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.
- {dependency_injection_pattern-0.0.0/src/dependency_injection_pattern.egg-info → dependency_injection_pattern-0.0.1}/PKG-INFO +4 -4
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/README.md +2 -2
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/pyproject.toml +1 -1
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1/src/dependency_injection_pattern.egg-info}/PKG-INFO +4 -4
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/dependency_injection_pattern.egg-info/requires.txt +1 -1
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/container.py +14 -6
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/provider.py +1 -1
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_container.py +66 -2
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_examples.py +49 -1
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/LICENSE +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/setup.cfg +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/dependency_injection_pattern.egg-info/SOURCES.txt +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/dependency_injection_pattern.egg-info/dependency_links.txt +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/dependency_injection_pattern.egg-info/top_level.txt +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/__init__.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/default_scope.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/add_exception.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/container_sealed_error.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/factory_provide_exception.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/implementation_exception.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/provide_exception.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/exceptions/seal_exception.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factories/dependency.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factories/factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factories/scoped_factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factories/singleton_factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factories/transient_factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/helpers.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/log.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/named_service.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/protocols/container.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/protocols/factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/protocols/provider.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/__init__.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/parameter.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/parameter_kind.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/parameter_mapper.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/signature.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/reflection/undefined.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/scope.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/service_request.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/exceptions.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_factory.py +0 -0
- {dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_provider.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dependency-injection-pattern
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1
|
|
4
4
|
Summary: Python implementation of the Dependency Injection pattern.
|
|
5
5
|
Author-email: Anders Madsen <anders.madsen@alphavue.com>
|
|
6
6
|
License: MIT
|
|
@@ -25,7 +25,7 @@ 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
|
|
28
|
+
Requires-Dist: typing-utilities<0.1,>=0.0.3
|
|
29
29
|
Provides-Extra: test
|
|
30
30
|
Requires-Dist: pytest>=8.3; extra == "test"
|
|
31
31
|
Requires-Dist: pytest-cov>=6.1; extra == "test"
|
|
@@ -99,6 +99,6 @@ app = provider.provide(Application)
|
|
|
99
99
|
value = app.get_value() # => "Service2 returned: Service1 returned: Some value"
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
##
|
|
102
|
+
## Full documentation
|
|
103
103
|
|
|
104
|
-
[Go to
|
|
104
|
+
[Go to documentation](https://github.com/apmadsen/dependency-injection-pattern/blob/main/docs/documentation.md)
|
|
@@ -66,6 +66,6 @@ app = provider.provide(Application)
|
|
|
66
66
|
value = app.get_value() # => "Service2 returned: Service1 returned: Some value"
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
##
|
|
69
|
+
## Full documentation
|
|
70
70
|
|
|
71
|
-
[Go to
|
|
71
|
+
[Go to documentation](https://github.com/apmadsen/dependency-injection-pattern/blob/main/docs/documentation.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dependency-injection-pattern
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.1
|
|
4
4
|
Summary: Python implementation of the Dependency Injection pattern.
|
|
5
5
|
Author-email: Anders Madsen <anders.madsen@alphavue.com>
|
|
6
6
|
License: MIT
|
|
@@ -25,7 +25,7 @@ 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
|
|
28
|
+
Requires-Dist: typing-utilities<0.1,>=0.0.3
|
|
29
29
|
Provides-Extra: test
|
|
30
30
|
Requires-Dist: pytest>=8.3; extra == "test"
|
|
31
31
|
Requires-Dist: pytest-cov>=6.1; extra == "test"
|
|
@@ -99,6 +99,6 @@ app = provider.provide(Application)
|
|
|
99
99
|
value = app.get_value() # => "Service2 returned: Service1 returned: Some value"
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
##
|
|
102
|
+
## Full documentation
|
|
103
103
|
|
|
104
|
-
[Go to
|
|
104
|
+
[Go to documentation](https://github.com/apmadsen/dependency-injection-pattern/blob/main/docs/documentation.md)
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/container.py
RENAMED
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
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
|
+
from weakref import ref
|
|
5
6
|
|
|
6
7
|
from di.core.log import LOG
|
|
7
8
|
from di.core.reflection import reflect_function
|
|
@@ -34,12 +35,12 @@ class Container:
|
|
|
34
35
|
provider = container.provider() # container is sealed, and no more services can be added beyound this point
|
|
35
36
|
provider.provide(Service) # => Service
|
|
36
37
|
"""
|
|
37
|
-
__slots__ = ["__factories", "__named_factories", "__list_factories", "__default_scope", "__provider"]
|
|
38
|
+
__slots__ = ["__factories", "__named_factories", "__list_factories", "__default_scope", "__provider", "__weakref__"]
|
|
38
39
|
|
|
39
40
|
def __init__(self):
|
|
40
41
|
self.__factories: dict[type[Any], Factory[Any]] = {}
|
|
41
42
|
self.__named_factories: dict[str, tuple[type[Any], Factory[Any]]] = {}
|
|
42
|
-
self.__provider: Provider | None = None
|
|
43
|
+
self.__provider: ref[Provider] | None = None
|
|
43
44
|
self.__default_scope = DefaultScope()
|
|
44
45
|
|
|
45
46
|
@property
|
|
@@ -185,10 +186,11 @@ class Container:
|
|
|
185
186
|
Returns:
|
|
186
187
|
Provider -- The Provider instance
|
|
187
188
|
"""
|
|
189
|
+
from di.core.provider import Provider
|
|
188
190
|
if self.__provider is None:
|
|
189
|
-
|
|
190
|
-
self.__provider =
|
|
191
|
-
self.__add_factory(SingletonFactory, Provider, self.
|
|
191
|
+
provider = Provider(self)
|
|
192
|
+
self.__provider = ref(provider)
|
|
193
|
+
self.__add_factory(SingletonFactory, Provider, self.provider)
|
|
192
194
|
|
|
193
195
|
factories = { **self.__factories, **{ service: factory for service, factory in self.__named_factories.values() } }
|
|
194
196
|
for service, factory in factories.items():
|
|
@@ -204,7 +206,13 @@ class Container:
|
|
|
204
206
|
elif isinstance(factories[dep.service], TransientFactory):
|
|
205
207
|
raise SealException(f"Singleton service '{get_service_name(service)}' depends on transient service {get_service_name(dep.service)}' which is not permitted.")
|
|
206
208
|
|
|
207
|
-
|
|
209
|
+
return provider
|
|
210
|
+
elif provider :=self.__provider():
|
|
211
|
+
return provider
|
|
212
|
+
else:
|
|
213
|
+
provider = Provider(self)
|
|
214
|
+
self.__provider = ref(provider)
|
|
215
|
+
return provider
|
|
208
216
|
|
|
209
217
|
def __add_factory_pre(self, factory_type: type[Factory[T]], *args: Any) -> tuple[str, type[Any]]:
|
|
210
218
|
if self.__provider != None:
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/provider.py
RENAMED
|
@@ -14,7 +14,7 @@ class Provider:
|
|
|
14
14
|
"""
|
|
15
15
|
The Provider is connected to the Container and provides the services defined.
|
|
16
16
|
"""
|
|
17
|
-
__slots__ = ["__container"]
|
|
17
|
+
__slots__ = ["__container", "__weakref__"]
|
|
18
18
|
|
|
19
19
|
def __init__(self, container: Container):
|
|
20
20
|
self.__container = container
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_container.py
RENAMED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
from typing import cast, Sequence
|
|
4
4
|
from pytest import raises as assert_raises
|
|
5
5
|
from threading import Thread
|
|
6
|
+
from weakref import ref
|
|
7
|
+
from gc import get_referrers, collect
|
|
6
8
|
|
|
7
|
-
from di import Container, Provider
|
|
9
|
+
from di import Container, Provider, Factory
|
|
8
10
|
from di.exceptions import ImplementationException, AddException, SealException, ProvideException, ContainerSealedError
|
|
9
11
|
|
|
10
|
-
from tests.classes import Service, Options1, DependentService, DependentServiceFail1, IService, Service2
|
|
12
|
+
from tests.classes import Service, Options1, DependentService, DependentServiceFail1, IService, Service2, Service5, DependentService5, Application
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
|
|
@@ -93,3 +95,65 @@ def test_collections():
|
|
|
93
95
|
with assert_raises(ImplementationException):
|
|
94
96
|
container.add_singleton(Sequence[IService], [ Service, Service2 ])
|
|
95
97
|
|
|
98
|
+
def test_lifetime():
|
|
99
|
+
|
|
100
|
+
container = Container()
|
|
101
|
+
container.add_transient(Service5)
|
|
102
|
+
|
|
103
|
+
provider = container.provider()
|
|
104
|
+
provider_id = id(provider)
|
|
105
|
+
svc = provider.provide(Service5)
|
|
106
|
+
provider = ref(provider)
|
|
107
|
+
|
|
108
|
+
collect()
|
|
109
|
+
|
|
110
|
+
assert not provider() # provider should have been collected
|
|
111
|
+
|
|
112
|
+
provider = container.provider()
|
|
113
|
+
assert id(provider) != provider_id # this provider be a new instance
|
|
114
|
+
|
|
115
|
+
provider = ref(provider)
|
|
116
|
+
container = ref(container)
|
|
117
|
+
|
|
118
|
+
collect()
|
|
119
|
+
|
|
120
|
+
# provider and container should have been collected
|
|
121
|
+
assert not provider()
|
|
122
|
+
assert not container()
|
|
123
|
+
|
|
124
|
+
### cleanup
|
|
125
|
+
del container
|
|
126
|
+
del provider
|
|
127
|
+
del svc
|
|
128
|
+
collect()
|
|
129
|
+
###
|
|
130
|
+
|
|
131
|
+
container = Container()
|
|
132
|
+
container.add_transient(Application)
|
|
133
|
+
container.add_transient(Service5)
|
|
134
|
+
container.add_transient(DependentService5)
|
|
135
|
+
provider = container.provider()
|
|
136
|
+
|
|
137
|
+
app = provider.provide(Application)
|
|
138
|
+
svc = app.service_factory()
|
|
139
|
+
|
|
140
|
+
container = ref(container)
|
|
141
|
+
provider = ref(provider)
|
|
142
|
+
|
|
143
|
+
collect()
|
|
144
|
+
|
|
145
|
+
# app has a live reference to Factory[Service5],
|
|
146
|
+
# so neither container or provider should be collected
|
|
147
|
+
assert container()
|
|
148
|
+
assert provider()
|
|
149
|
+
|
|
150
|
+
app = ref(app)
|
|
151
|
+
|
|
152
|
+
collect()
|
|
153
|
+
|
|
154
|
+
# app has been collected thus any references to container and provider
|
|
155
|
+
# has been removed and container and provider has therefore
|
|
156
|
+
# also been collected
|
|
157
|
+
assert not app()
|
|
158
|
+
assert not provider()
|
|
159
|
+
assert not container()
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_examples.py
RENAMED
|
@@ -175,4 +175,52 @@ def test_example_7():
|
|
|
175
175
|
service1, service2 = app.services # => Service1, Service2
|
|
176
176
|
|
|
177
177
|
assert isinstance(service1, Service1)
|
|
178
|
-
assert isinstance(service2, Service2)
|
|
178
|
+
assert isinstance(service2, Service2)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def test_example_8():
|
|
182
|
+
from di import Container, DefaultScope, Scope, Provider
|
|
183
|
+
from random import Random
|
|
184
|
+
from threading import Thread
|
|
185
|
+
|
|
186
|
+
class RandGen:
|
|
187
|
+
rnd: Random | None
|
|
188
|
+
|
|
189
|
+
def generate(self) -> int:
|
|
190
|
+
if self.rnd:
|
|
191
|
+
return self.rnd.randint(0, 100)
|
|
192
|
+
else:
|
|
193
|
+
return -1
|
|
194
|
+
|
|
195
|
+
def __enter__(self):
|
|
196
|
+
self.rnd = Random()
|
|
197
|
+
return self
|
|
198
|
+
|
|
199
|
+
def __exit__(self):
|
|
200
|
+
del self.rnd
|
|
201
|
+
|
|
202
|
+
container = Container()
|
|
203
|
+
container.add_scoped(RandGen)
|
|
204
|
+
|
|
205
|
+
scope = DefaultScope()
|
|
206
|
+
provider = container.provider()
|
|
207
|
+
|
|
208
|
+
generators: set[int] = set()
|
|
209
|
+
ints: list[int] = []
|
|
210
|
+
|
|
211
|
+
def fn(provider: Provider, scope: Scope):
|
|
212
|
+
for i in range(3):
|
|
213
|
+
gen = provider.provide(RandGen, scope)
|
|
214
|
+
generators.add(id(gen))
|
|
215
|
+
ints.append(gen.generate())
|
|
216
|
+
|
|
217
|
+
thread1 = Thread(target = fn, args = (provider, scope))
|
|
218
|
+
thread1.start()
|
|
219
|
+
thread2 = Thread(target = fn, args = (provider, scope))
|
|
220
|
+
thread2.start()
|
|
221
|
+
thread1.join()
|
|
222
|
+
thread2.join()
|
|
223
|
+
|
|
224
|
+
assert len(generators) == 2
|
|
225
|
+
assert len(ints) == 6
|
|
226
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/factory.py
RENAMED
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/helpers.py
RENAMED
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/log.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/core/scope.py
RENAMED
|
File without changes
|
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/src/di/exceptions.py
RENAMED
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_factory.py
RENAMED
|
File without changes
|
{dependency_injection_pattern-0.0.0 → dependency_injection_pattern-0.0.1}/tests/test_provider.py
RENAMED
|
File without changes
|