dinkleberg 0.2.0__py3-none-any.whl → 0.3.0__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.
- dinkleberg/__init__.py +2 -2
- dinkleberg/dependency_configurator.py +106 -31
- dinkleberg/descriptor.py +1 -0
- dinkleberg/fastapi/__init__.py +13 -0
- dinkleberg/typing.py +7 -2
- {dinkleberg-0.2.0.dist-info → dinkleberg-0.3.0.dist-info}/METADATA +4 -1
- dinkleberg-0.3.0.dist-info/RECORD +9 -0
- dinkleberg/dependency.py +0 -2
- dinkleberg/dependency_scope.py +0 -15
- dinkleberg-0.2.0.dist-info/RECORD +0 -10
- {dinkleberg-0.2.0.dist-info → dinkleberg-0.3.0.dist-info}/WHEEL +0 -0
- {dinkleberg-0.2.0.dist-info → dinkleberg-0.3.0.dist-info}/top_level.txt +0 -0
dinkleberg/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from
|
|
1
|
+
from dinkleberg_abc import Dependency, DependencyScope
|
|
2
|
+
|
|
2
3
|
from .dependency_configurator import DependencyConfigurator
|
|
3
|
-
from .dependency_scope import DependencyScope
|
|
4
4
|
|
|
5
5
|
__all__ = ['DependencyScope', 'DependencyConfigurator', 'Dependency']
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import abc
|
|
2
1
|
import asyncio
|
|
3
2
|
import inspect
|
|
4
3
|
import logging
|
|
@@ -6,10 +5,9 @@ from inspect import Signature
|
|
|
6
5
|
from types import MappingProxyType
|
|
7
6
|
from typing import AsyncGenerator, Callable, overload, get_type_hints, Mapping, get_origin
|
|
8
7
|
|
|
9
|
-
from
|
|
10
|
-
from .dependency_scope import DependencyScope
|
|
8
|
+
from dinkleberg_abc import DependencyScope, Dependency
|
|
11
9
|
from .descriptor import Descriptor, Lifetime
|
|
12
|
-
from .typing import get_static_params, get_public_methods,
|
|
10
|
+
from .typing import get_static_params, get_public_methods, is_builtin_type, is_abstract
|
|
13
11
|
|
|
14
12
|
logger = logging.getLogger(__name__)
|
|
15
13
|
|
|
@@ -58,13 +56,45 @@ class DependencyConfigurator(DependencyScope):
|
|
|
58
56
|
if exceptions:
|
|
59
57
|
raise ExceptionGroup('Errors occurred during closing DependencyConfigurator', exceptions)
|
|
60
58
|
|
|
61
|
-
def _add(self, lifetime: Lifetime, *, t: type = None,
|
|
62
|
-
callable: Callable = None):
|
|
63
|
-
if generator is None and callable is None:
|
|
64
|
-
raise ValueError(
|
|
59
|
+
def _add(self, lifetime: Lifetime, *, t: type = None, i: type = None,
|
|
60
|
+
generator: Callable[..., AsyncGenerator] = None, callable: Callable = None):
|
|
61
|
+
if t is None and i is None and generator is None and callable is None:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
'Invalid dependency registration. At least one of t, i, generator, or callable must be provided.')
|
|
64
|
+
|
|
65
|
+
if lifetime == 'singleton' and self._parent is not None:
|
|
66
|
+
raise RuntimeError(
|
|
67
|
+
'Singleton dependencies, which are not instances, can only be registered in the root DependencyConfigurator.')
|
|
68
|
+
|
|
69
|
+
if i is not None:
|
|
70
|
+
if is_builtin_type(i):
|
|
71
|
+
raise ValueError(f'Cannot use built-in type {i} as implementation.')
|
|
72
|
+
|
|
73
|
+
if get_origin(i) is not None:
|
|
74
|
+
raise ValueError(f'Cannot use generic type {i} as implementation.')
|
|
75
|
+
|
|
76
|
+
if is_abstract(i):
|
|
77
|
+
raise ValueError(f'Cannot use abstract class {i} as implementation.')
|
|
78
|
+
|
|
65
79
|
if t is None:
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
if i is not None:
|
|
81
|
+
t = i
|
|
82
|
+
else:
|
|
83
|
+
t = self._infer_type(generator=generator, callable=callable)
|
|
84
|
+
elif generator is None and callable is None:
|
|
85
|
+
if is_builtin_type(t):
|
|
86
|
+
raise ValueError(
|
|
87
|
+
f'Cannot register built-in type {t} without explicit implementation, generator or callable.')
|
|
88
|
+
|
|
89
|
+
if get_origin(t) is not None:
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f'Cannot register generic type {t} without explicit implementation, generator or callable.')
|
|
92
|
+
|
|
93
|
+
if is_abstract(t):
|
|
94
|
+
raise ValueError(
|
|
95
|
+
f'Cannot register abstract class {t} without explicit implementation, generator or callable.')
|
|
96
|
+
|
|
97
|
+
self._descriptors[t] = Descriptor(implementation=i, generator=generator, callable=callable, lifetime=lifetime)
|
|
68
98
|
|
|
69
99
|
@staticmethod
|
|
70
100
|
def _infer_type(*, generator: Callable[..., AsyncGenerator], callable: Callable) -> type:
|
|
@@ -117,8 +147,26 @@ class DependencyConfigurator(DependencyScope):
|
|
|
117
147
|
if t in self._scoped_instances:
|
|
118
148
|
return self._scoped_instances[t]
|
|
119
149
|
|
|
120
|
-
|
|
121
|
-
|
|
150
|
+
descriptor = self._descriptors.get(t)
|
|
151
|
+
if descriptor is None or descriptor['generator'] is None and descriptor['callable'] is None:
|
|
152
|
+
if descriptor is None:
|
|
153
|
+
if is_builtin_type(t):
|
|
154
|
+
raise ValueError(f'Cannot resolve built-in type {t} without explicit registration.')
|
|
155
|
+
|
|
156
|
+
if get_origin(t) is not None:
|
|
157
|
+
raise ValueError(f'Cannot resolve generic type {t} without explicit registration.')
|
|
158
|
+
|
|
159
|
+
if is_abstract(t):
|
|
160
|
+
raise ValueError(f'Cannot resolve abstract class {t} without explicit registration.')
|
|
161
|
+
|
|
162
|
+
factory = t
|
|
163
|
+
else:
|
|
164
|
+
factory = descriptor['implementation'] or t
|
|
165
|
+
|
|
166
|
+
is_generator = False
|
|
167
|
+
lifetime = descriptor['lifetime'] if descriptor else 'transient'
|
|
168
|
+
deps = await self._resolve_deps(factory.__init__)
|
|
169
|
+
else:
|
|
122
170
|
lifetime = descriptor['lifetime']
|
|
123
171
|
if lifetime == 'singleton' and self._parent:
|
|
124
172
|
# we need to resolve singleton from the root scope
|
|
@@ -127,17 +175,6 @@ class DependencyConfigurator(DependencyScope):
|
|
|
127
175
|
is_generator = descriptor['generator'] is not None
|
|
128
176
|
factory = descriptor['generator'] or descriptor['callable']
|
|
129
177
|
deps = await self._resolve_deps(factory)
|
|
130
|
-
else:
|
|
131
|
-
if get_origin(t) is not None:
|
|
132
|
-
raise ValueError(f'Cannot resolve generic type {t} without explicit registration.')
|
|
133
|
-
|
|
134
|
-
if inspect.isabstract(t) or t is abc.ABC:
|
|
135
|
-
raise ValueError(f'Cannot resolve abstract class {t} without explicit registration.')
|
|
136
|
-
|
|
137
|
-
is_generator = False
|
|
138
|
-
lifetime = 'transient'
|
|
139
|
-
factory = t
|
|
140
|
-
deps = await self._resolve_deps(t.__init__)
|
|
141
178
|
|
|
142
179
|
if is_generator:
|
|
143
180
|
generator = factory(**deps, **kwargs)
|
|
@@ -180,7 +217,7 @@ class DependencyConfigurator(DependencyScope):
|
|
|
180
217
|
if not param.annotation or param.annotation is inspect.Parameter.empty:
|
|
181
218
|
continue
|
|
182
219
|
|
|
183
|
-
if
|
|
220
|
+
if is_builtin_type(param.annotation):
|
|
184
221
|
continue
|
|
185
222
|
|
|
186
223
|
# TODO handle more complex cases (e.g., Union, Optional, etc.)
|
|
@@ -253,6 +290,18 @@ class DependencyConfigurator(DependencyScope):
|
|
|
253
290
|
def add_singleton[T, I](self, *, t: type[T], instance: I):
|
|
254
291
|
...
|
|
255
292
|
|
|
293
|
+
@overload
|
|
294
|
+
def add_singleton[T](self, *, t: type[T]):
|
|
295
|
+
...
|
|
296
|
+
|
|
297
|
+
@overload
|
|
298
|
+
def add_singleton[I](self, *, i: type[I]):
|
|
299
|
+
...
|
|
300
|
+
|
|
301
|
+
@overload
|
|
302
|
+
def add_singleton[T, I](self, *, t: type[T], i: type[I]):
|
|
303
|
+
...
|
|
304
|
+
|
|
256
305
|
@overload
|
|
257
306
|
def add_singleton[I](self, *, callable: Callable[..., I]):
|
|
258
307
|
...
|
|
@@ -269,11 +318,13 @@ class DependencyConfigurator(DependencyScope):
|
|
|
269
318
|
def add_singleton[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
|
|
270
319
|
...
|
|
271
320
|
|
|
272
|
-
def add_singleton[T, I](self, *, t: type[T] = None,
|
|
321
|
+
def add_singleton[T, I](self, *, t: type[T] = None, i: type[I] = None,
|
|
322
|
+
generator: Callable[..., AsyncGenerator[I]] = None,
|
|
273
323
|
callable: Callable[..., I] = None, instance: I = None):
|
|
274
324
|
self._raise_if_closed()
|
|
325
|
+
|
|
275
326
|
if instance is None:
|
|
276
|
-
self._add('singleton', t=t, generator=generator, callable=callable)
|
|
327
|
+
self._add('singleton', t=t, i=i, generator=generator, callable=callable)
|
|
277
328
|
return
|
|
278
329
|
elif t is None:
|
|
279
330
|
t = type(instance)
|
|
@@ -282,6 +333,18 @@ class DependencyConfigurator(DependencyScope):
|
|
|
282
333
|
|
|
283
334
|
self._singleton_instances[t] = instance
|
|
284
335
|
|
|
336
|
+
@overload
|
|
337
|
+
def add_scoped[T](self, *, t: type[T]):
|
|
338
|
+
...
|
|
339
|
+
|
|
340
|
+
@overload
|
|
341
|
+
def add_scoped[I](self, *, i: type[I]):
|
|
342
|
+
...
|
|
343
|
+
|
|
344
|
+
@overload
|
|
345
|
+
def add_scoped[T, I](self, *, t: type[T], i: type[I]):
|
|
346
|
+
...
|
|
347
|
+
|
|
285
348
|
@overload
|
|
286
349
|
def add_scoped[I](self, *, callable: Callable[..., I]):
|
|
287
350
|
...
|
|
@@ -298,10 +361,22 @@ class DependencyConfigurator(DependencyScope):
|
|
|
298
361
|
def add_scoped[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
|
|
299
362
|
...
|
|
300
363
|
|
|
301
|
-
def add_scoped[T, I](self, *, t: type[T] = None,
|
|
302
|
-
callable: Callable[..., I] = None):
|
|
364
|
+
def add_scoped[T, I](self, *, t: type[T] = None, i: type[I] = None,
|
|
365
|
+
generator: Callable[..., AsyncGenerator[I]] = None, callable: Callable[..., I] = None):
|
|
303
366
|
self._raise_if_closed()
|
|
304
|
-
self._add('scoped', t=t, generator=generator, callable=callable)
|
|
367
|
+
self._add('scoped', t=t, i=i, generator=generator, callable=callable)
|
|
368
|
+
|
|
369
|
+
@overload
|
|
370
|
+
def add_transient[T](self, *, t: type[T]):
|
|
371
|
+
...
|
|
372
|
+
|
|
373
|
+
@overload
|
|
374
|
+
def add_transient[I](self, *, i: type[I]):
|
|
375
|
+
...
|
|
376
|
+
|
|
377
|
+
@overload
|
|
378
|
+
def add_transient[T, I](self, *, t: type[T], i: type[I]):
|
|
379
|
+
...
|
|
305
380
|
|
|
306
381
|
@overload
|
|
307
382
|
def add_transient[I](self, *, callable: Callable[..., I]):
|
|
@@ -311,6 +386,6 @@ class DependencyConfigurator(DependencyScope):
|
|
|
311
386
|
def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I]):
|
|
312
387
|
...
|
|
313
388
|
|
|
314
|
-
def add_transient[T, I](self, *, t: type[T] = None, callable: Callable[..., I] = None):
|
|
389
|
+
def add_transient[T, I](self, *, t: type[T] = None, i: type[I] = None, callable: Callable[..., I] = None):
|
|
315
390
|
self._raise_if_closed()
|
|
316
|
-
self._add('transient', t=t, callable=callable)
|
|
391
|
+
self._add('transient', i=i, t=t, callable=callable)
|
dinkleberg/descriptor.py
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from _dinkleberg_fastapi import di
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from _dinkleberg_fastapi import di
|
|
8
|
+
|
|
9
|
+
__all__ = ['di']
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError(
|
|
12
|
+
"dinkleberg-fastapi is not installed. Please install it with 'pip install dinkleberg[fastapi]' to use FastAPI integration."
|
|
13
|
+
)
|
dinkleberg/typing.py
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import abc
|
|
1
2
|
import inspect
|
|
2
3
|
from inspect import Parameter, signature
|
|
3
4
|
from typing import Callable, get_origin
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
def
|
|
7
|
+
def is_abstract(t: type) -> bool:
|
|
8
|
+
return inspect.isabstract(t) or t is abc.ABC
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def is_builtin_type(t: type) -> bool:
|
|
7
12
|
origin = get_origin(t) or t
|
|
8
|
-
return getattr(origin, '__module__', None)
|
|
13
|
+
return getattr(origin, '__module__', None) in ('builtins', 'typing', 'types')
|
|
9
14
|
|
|
10
15
|
|
|
11
16
|
def get_static_params(func: Callable) -> list[Parameter]:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dinkleberg
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Your friendly neighbour when it comes to dependency management.
|
|
5
5
|
Project-URL: Homepage, https://github.com/DavidVollmers/dinkleberg
|
|
6
6
|
Project-URL: Documentation, https://github.com/DavidVollmers/dinkleberg/blob/main/libs/dinkleberg/README.md
|
|
@@ -17,6 +17,9 @@ Classifier: Operating System :: OS Independent
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Requires-Python: >=3.13
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
+
Requires-Dist: dinkleberg-abc>=0.3.0
|
|
21
|
+
Provides-Extra: fastapi
|
|
22
|
+
Requires-Dist: dinkleberg-fastapi>=0.3.0; extra == "fastapi"
|
|
20
23
|
|
|
21
24
|
# dinkleberg
|
|
22
25
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
dinkleberg/__init__.py,sha256=6gowHoL3xTWd2iyU09upgjXKUv_WWp6Tw1iqw2uz7Vc,192
|
|
2
|
+
dinkleberg/dependency_configurator.py,sha256=vsXTHFUkhW5_bR95qFYOzaio-UwupIkS9qjPL2e8s4o,14356
|
|
3
|
+
dinkleberg/descriptor.py,sha256=ZtVwJihvCLugakHx201iX7Jm4A50Z0SzPu9zeHfD320,349
|
|
4
|
+
dinkleberg/typing.py,sha256=qAdSQomntQfI4bSWc9X32DXGftuyj56WP7nG3Pia7ZE,942
|
|
5
|
+
dinkleberg/fastapi/__init__.py,sha256=boj1ywpWhuuOjHLwdUha2EPBG2f1zbc374N35k1CJxk,352
|
|
6
|
+
dinkleberg-0.3.0.dist-info/METADATA,sha256=sGBRFKAmbtQS1vc79a5tyotUivlciNlhZAbwYqSC1FQ,1555
|
|
7
|
+
dinkleberg-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
dinkleberg-0.3.0.dist-info/top_level.txt,sha256=6TjbaJ_eyRzoxzz2r1Eu0hgYfxBBM2bOV3u_TJ8yjjw,11
|
|
9
|
+
dinkleberg-0.3.0.dist-info/RECORD,,
|
dinkleberg/dependency.py
DELETED
dinkleberg/dependency_scope.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class DependencyScope(ABC):
|
|
5
|
-
@abstractmethod
|
|
6
|
-
async def resolve[T](self, t: type[T], **kwargs) -> T:
|
|
7
|
-
pass
|
|
8
|
-
|
|
9
|
-
@abstractmethod
|
|
10
|
-
async def close(self) -> None:
|
|
11
|
-
pass
|
|
12
|
-
|
|
13
|
-
@abstractmethod
|
|
14
|
-
def scope(self) -> 'DependencyScope':
|
|
15
|
-
pass
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
dinkleberg/__init__.py,sha256=HGu8mjYt-Fa0y9_aMtJZFYo3s9Yb0q5dmbMKtHrAV_k,217
|
|
2
|
-
dinkleberg/dependency.py,sha256=YcGvuvhoBRxShgSRaznKyZg49GCgOWy_L8HD0sXAMYo,29
|
|
3
|
-
dinkleberg/dependency_configurator.py,sha256=vc3m23BopF0rSFDRO-Fj-8cGmU4bbGve1Qa1ymYsF0g,11727
|
|
4
|
-
dinkleberg/dependency_scope.py,sha256=sufXjQ6F62ZfohItUnrV7Fvh8gSSc7a6orO6PXu19Vw,318
|
|
5
|
-
dinkleberg/descriptor.py,sha256=mVI00K1M2m4Rl5ANatGMeB_HpzeFONoULwg0UmNxfQ0,313
|
|
6
|
-
dinkleberg/typing.py,sha256=kVawkc46Jblqa4XUdangv3ZL8X3RyP8TpZ08EU7RbP0,815
|
|
7
|
-
dinkleberg-0.2.0.dist-info/METADATA,sha256=aVA9a_YmlnDJPMFVirD81BwTPBMBizhmnv02mf7Mkwc,1430
|
|
8
|
-
dinkleberg-0.2.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
-
dinkleberg-0.2.0.dist-info/top_level.txt,sha256=6TjbaJ_eyRzoxzz2r1Eu0hgYfxBBM2bOV3u_TJ8yjjw,11
|
|
10
|
-
dinkleberg-0.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|