dinkleberg 0.2.1__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 +105 -33
- dinkleberg/descriptor.py +1 -0
- dinkleberg/fastapi/__init__.py +13 -0
- dinkleberg/typing.py +5 -0
- {dinkleberg-0.2.1.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.1.dist-info/RECORD +0 -10
- {dinkleberg-0.2.1.dist-info → dinkleberg-0.3.0.dist-info}/WHEEL +0 -0
- {dinkleberg-0.2.1.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, is_builtin_type
|
|
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,20 +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 is_builtin_type(t):
|
|
132
|
-
raise ValueError(f'Cannot resolve built-in type {t} without explicit registration.')
|
|
133
|
-
|
|
134
|
-
if get_origin(t) is not None:
|
|
135
|
-
raise ValueError(f'Cannot resolve generic type {t} without explicit registration.')
|
|
136
|
-
|
|
137
|
-
if inspect.isabstract(t) or t is abc.ABC:
|
|
138
|
-
raise ValueError(f'Cannot resolve abstract class {t} without explicit registration.')
|
|
139
|
-
|
|
140
|
-
is_generator = False
|
|
141
|
-
lifetime = 'transient'
|
|
142
|
-
factory = t
|
|
143
|
-
deps = await self._resolve_deps(t.__init__)
|
|
144
178
|
|
|
145
179
|
if is_generator:
|
|
146
180
|
generator = factory(**deps, **kwargs)
|
|
@@ -256,6 +290,18 @@ class DependencyConfigurator(DependencyScope):
|
|
|
256
290
|
def add_singleton[T, I](self, *, t: type[T], instance: I):
|
|
257
291
|
...
|
|
258
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
|
+
|
|
259
305
|
@overload
|
|
260
306
|
def add_singleton[I](self, *, callable: Callable[..., I]):
|
|
261
307
|
...
|
|
@@ -272,11 +318,13 @@ class DependencyConfigurator(DependencyScope):
|
|
|
272
318
|
def add_singleton[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
|
|
273
319
|
...
|
|
274
320
|
|
|
275
|
-
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,
|
|
276
323
|
callable: Callable[..., I] = None, instance: I = None):
|
|
277
324
|
self._raise_if_closed()
|
|
325
|
+
|
|
278
326
|
if instance is None:
|
|
279
|
-
self._add('singleton', t=t, generator=generator, callable=callable)
|
|
327
|
+
self._add('singleton', t=t, i=i, generator=generator, callable=callable)
|
|
280
328
|
return
|
|
281
329
|
elif t is None:
|
|
282
330
|
t = type(instance)
|
|
@@ -285,6 +333,18 @@ class DependencyConfigurator(DependencyScope):
|
|
|
285
333
|
|
|
286
334
|
self._singleton_instances[t] = instance
|
|
287
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
|
+
|
|
288
348
|
@overload
|
|
289
349
|
def add_scoped[I](self, *, callable: Callable[..., I]):
|
|
290
350
|
...
|
|
@@ -301,10 +361,22 @@ class DependencyConfigurator(DependencyScope):
|
|
|
301
361
|
def add_scoped[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
|
|
302
362
|
...
|
|
303
363
|
|
|
304
|
-
def add_scoped[T, I](self, *, t: type[T] = None,
|
|
305
|
-
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):
|
|
306
366
|
self._raise_if_closed()
|
|
307
|
-
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
|
+
...
|
|
308
380
|
|
|
309
381
|
@overload
|
|
310
382
|
def add_transient[I](self, *, callable: Callable[..., I]):
|
|
@@ -314,6 +386,6 @@ class DependencyConfigurator(DependencyScope):
|
|
|
314
386
|
def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I]):
|
|
315
387
|
...
|
|
316
388
|
|
|
317
|
-
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):
|
|
318
390
|
self._raise_if_closed()
|
|
319
|
-
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,8 +1,13 @@
|
|
|
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
|
|
|
7
|
+
def is_abstract(t: type) -> bool:
|
|
8
|
+
return inspect.isabstract(t) or t is abc.ABC
|
|
9
|
+
|
|
10
|
+
|
|
6
11
|
def is_builtin_type(t: type) -> bool:
|
|
7
12
|
origin = get_origin(t) or t
|
|
8
13
|
return getattr(origin, '__module__', None) in ('builtins', 'typing', 'types')
|
|
@@ -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=N0mF78B9HnCKPwhDo4DTt8aDGbLwKEPFqEfo5ZtrrxA,11877
|
|
4
|
-
dinkleberg/dependency_scope.py,sha256=sufXjQ6F62ZfohItUnrV7Fvh8gSSc7a6orO6PXu19Vw,318
|
|
5
|
-
dinkleberg/descriptor.py,sha256=mVI00K1M2m4Rl5ANatGMeB_HpzeFONoULwg0UmNxfQ0,313
|
|
6
|
-
dinkleberg/typing.py,sha256=_T2plzKBU_GTMNazpU8bqKuqTvQotJPuWEHQH2dF76g,841
|
|
7
|
-
dinkleberg-0.2.1.dist-info/METADATA,sha256=Mv6RezK3xmMBpnRY0DKkwXSxPnm6mTezMRcMWFMiNs8,1430
|
|
8
|
-
dinkleberg-0.2.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
9
|
-
dinkleberg-0.2.1.dist-info/top_level.txt,sha256=6TjbaJ_eyRzoxzz2r1Eu0hgYfxBBM2bOV3u_TJ8yjjw,11
|
|
10
|
-
dinkleberg-0.2.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|