dinkleberg 0.3.1__py3-none-any.whl → 0.3.2__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.
@@ -21,10 +21,17 @@ class DependencyConfigurator(DependencyScope):
21
21
  self._descriptors: dict[type, Descriptor] = {}
22
22
  self._singleton_instances = {}
23
23
  self._scoped_instances = {}
24
+ self._configurators: dict[type, list[Callable[[object], object | None]]] = {}
24
25
  self._active_generators = []
25
26
  self._scopes = []
26
27
  self._closed = False
27
28
 
29
+ def configure[T](self, t: type[T], configurator: Callable[[T], T | None]) -> None:
30
+ self._raise_if_closed()
31
+ if t not in self._configurators:
32
+ self._configurators[t] = []
33
+ self._configurators[t].append(configurator)
34
+
28
35
  async def close(self) -> None:
29
36
  if self._closed:
30
37
  return
@@ -51,6 +58,7 @@ class DependencyConfigurator(DependencyScope):
51
58
  self._singleton_instances.clear()
52
59
  self._active_generators.clear()
53
60
  self._scoped_instances.clear()
61
+ self._configurators.clear()
54
62
  self._descriptors.clear()
55
63
  self._scopes.clear()
56
64
 
@@ -58,7 +66,7 @@ class DependencyConfigurator(DependencyScope):
58
66
  raise ExceptionGroup('Errors occurred during closing DependencyConfigurator', exceptions)
59
67
 
60
68
  def _add(self, lifetime: Lifetime, *, t: type = None, i: type = None,
61
- generator: Callable[..., AsyncGenerator] = None, callable: Callable = None):
69
+ generator: Callable[..., AsyncGenerator] = None, callable: Callable = None, override: bool = False):
62
70
  if t is None and i is None and generator is None and callable is None:
63
71
  raise ValueError(
64
72
  'Invalid dependency registration. At least one of t, i, generator, or callable must be provided.')
@@ -82,7 +90,7 @@ class DependencyConfigurator(DependencyScope):
82
90
  t = i
83
91
  else:
84
92
  t = self._infer_type(generator=generator, callable=callable)
85
- elif generator is None and callable is None:
93
+ elif generator is None and callable is None and i is None:
86
94
  if is_builtin_type(t):
87
95
  raise ValueError(
88
96
  f'Cannot register built-in type {t} without explicit implementation, generator or callable.')
@@ -95,6 +103,9 @@ class DependencyConfigurator(DependencyScope):
95
103
  raise ValueError(
96
104
  f'Cannot register abstract class {t} without explicit implementation, generator or callable.')
97
105
 
106
+ if t in self._descriptors and not override:
107
+ raise ValueError(f'Type {t} is already registered.')
108
+
98
109
  self._descriptors[t] = Descriptor(implementation=i, generator=generator, callable=callable, lifetime=lifetime)
99
110
 
100
111
  @staticmethod
@@ -118,12 +129,13 @@ class DependencyConfigurator(DependencyScope):
118
129
 
119
130
  def _raise_if_closed(self):
120
131
  if self._closed:
121
- raise RuntimeError('DependencyConfigurator is already closed.')
132
+ raise RuntimeError('DependencyScope is already closed.')
122
133
 
123
134
  def scope(self) -> 'DependencyConfigurator':
124
135
  self._raise_if_closed()
125
136
  scope = DependencyConfigurator(self)
126
137
  scope._descriptors = self._descriptors.copy()
138
+ scope._configurators = self._configurators.copy()
127
139
  self._scopes.append(scope)
128
140
  return scope
129
141
 
@@ -206,7 +218,7 @@ class DependencyConfigurator(DependencyScope):
206
218
  finally:
207
219
  await instance.aclose()
208
220
 
209
- self._wrap_instance(instance)
221
+ self._wrap_instance(t, instance)
210
222
 
211
223
  if lifetime == 'singleton':
212
224
  self._singleton_instances[t] = instance
@@ -279,10 +291,16 @@ class DependencyConfigurator(DependencyScope):
279
291
  return wrapped_func
280
292
 
281
293
  # TODO handle __slots__
282
- def _wrap_instance(self, instance):
283
- if getattr(instance, '__dinkleberg__', False):
294
+ def _wrap_instance(self, t: type, instance: object):
295
+ if getattr(instance, '__dinkleberg__', False) or is_builtin_type(t):
284
296
  return
285
297
 
298
+ configurators = self._configurators.get(t, [])
299
+ for configurator in configurators:
300
+ result = configurator(instance)
301
+ if result is not None:
302
+ instance = result
303
+
286
304
  methods = get_public_methods(instance)
287
305
  for name, value in methods:
288
306
  instance_method = getattr(instance, name)
@@ -298,109 +316,117 @@ class DependencyConfigurator(DependencyScope):
298
316
  pass
299
317
 
300
318
  @overload
301
- def add_singleton[I](self, *, instance: I):
319
+ def add_singleton[I](self, *, instance: I, override: bool = False):
302
320
  ...
303
321
 
304
322
  @overload
305
- def add_singleton[T, I](self, *, t: type[T], instance: I):
323
+ def add_singleton[T, I](self, *, t: type[T], instance: I, override: bool = False):
306
324
  ...
307
325
 
308
326
  @overload
309
- def add_singleton[T](self, *, t: type[T]):
327
+ def add_singleton[T](self, *, t: type[T], override: bool = False):
310
328
  ...
311
329
 
312
330
  @overload
313
- def add_singleton[I](self, *, i: type[I]):
331
+ def add_singleton[I](self, *, i: type[I], override: bool = False):
314
332
  ...
315
333
 
316
334
  @overload
317
- def add_singleton[T, I](self, *, t: type[T], i: type[I]):
335
+ def add_singleton[T, I](self, *, t: type[T], i: type[I], override: bool = False):
318
336
  ...
319
337
 
320
338
  @overload
321
- def add_singleton[I](self, *, callable: Callable[..., I]):
339
+ def add_singleton[I](self, *, callable: Callable[..., I], override: bool = False):
322
340
  ...
323
341
 
324
342
  @overload
325
- def add_singleton[T, I](self, *, t: type[T], callable: Callable[..., I]):
343
+ def add_singleton[T, I](self, *, t: type[T], callable: Callable[..., I], override: bool = False):
326
344
  ...
327
345
 
328
346
  @overload
329
- def add_singleton[I](self, *, generator: Callable[..., AsyncGenerator[I]]):
347
+ def add_singleton[I](self, *, generator: Callable[..., AsyncGenerator[I]], override: bool = False):
330
348
  ...
331
349
 
332
350
  @overload
333
- def add_singleton[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
351
+ def add_singleton[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]], override: bool = False):
334
352
  ...
335
353
 
336
354
  def add_singleton[T, I](self, *, t: type[T] = None, i: type[I] = None,
337
355
  generator: Callable[..., AsyncGenerator[I]] = None,
338
- callable: Callable[..., I] = None, instance: I = None):
356
+ callable: Callable[..., I] = None, instance: I = None, override: bool = False):
339
357
  self._raise_if_closed()
340
358
 
341
359
  if instance is None:
342
- self._add('singleton', t=t, i=i, generator=generator, callable=callable)
360
+ self._add('singleton', t=t, i=i, generator=generator, callable=callable, override=override)
343
361
  return
344
362
  elif t is None:
345
363
  t = type(instance)
346
364
 
347
- self._wrap_instance(instance)
365
+ if t in self._descriptors:
366
+ raise ValueError(f'Type {t} is already registered with a descriptor. Cannot register singleton instance.')
367
+
368
+ if t in self._singleton_instances and not override:
369
+ raise ValueError(f'Type {t} already has a singleton instance registered.')
370
+
371
+ self._wrap_instance(t, instance)
348
372
 
349
373
  self._singleton_instances[t] = instance
350
374
 
351
375
  @overload
352
- def add_scoped[T](self, *, t: type[T]):
376
+ def add_scoped[T](self, *, t: type[T], override: bool = False):
353
377
  ...
354
378
 
355
379
  @overload
356
- def add_scoped[I](self, *, i: type[I]):
380
+ def add_scoped[I](self, *, i: type[I], override: bool = False):
357
381
  ...
358
382
 
359
383
  @overload
360
- def add_scoped[T, I](self, *, t: type[T], i: type[I]):
384
+ def add_scoped[T, I](self, *, t: type[T], i: type[I], override: bool = False):
361
385
  ...
362
386
 
363
387
  @overload
364
- def add_scoped[I](self, *, callable: Callable[..., I]):
388
+ def add_scoped[I](self, *, callable: Callable[..., I], override: bool = False):
365
389
  ...
366
390
 
367
391
  @overload
368
- def add_scoped[T, I](self, *, t: type[T], callable: Callable[..., I]):
392
+ def add_scoped[T, I](self, *, t: type[T], callable: Callable[..., I], override: bool = False):
369
393
  ...
370
394
 
371
395
  @overload
372
- def add_scoped[I](self, *, generator: Callable[..., AsyncGenerator[I]]):
396
+ def add_scoped[I](self, *, generator: Callable[..., AsyncGenerator[I]], override: bool = False):
373
397
  ...
374
398
 
375
399
  @overload
376
- def add_scoped[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]]):
400
+ def add_scoped[T, I](self, *, t: type[T], generator: Callable[..., AsyncGenerator[I]], override: bool = False):
377
401
  ...
378
402
 
379
403
  def add_scoped[T, I](self, *, t: type[T] = None, i: type[I] = None,
380
- generator: Callable[..., AsyncGenerator[I]] = None, callable: Callable[..., I] = None):
404
+ generator: Callable[..., AsyncGenerator[I]] = None, callable: Callable[..., I] = None,
405
+ override: bool = False):
381
406
  self._raise_if_closed()
382
- self._add('scoped', t=t, i=i, generator=generator, callable=callable)
407
+ self._add('scoped', t=t, i=i, generator=generator, callable=callable, override=override)
383
408
 
384
409
  @overload
385
- def add_transient[T](self, *, t: type[T]):
410
+ def add_transient[T](self, *, t: type[T], override: bool = False):
386
411
  ...
387
412
 
388
413
  @overload
389
- def add_transient[I](self, *, i: type[I]):
414
+ def add_transient[I](self, *, i: type[I], override: bool = False):
390
415
  ...
391
416
 
392
417
  @overload
393
- def add_transient[T, I](self, *, t: type[T], i: type[I]):
418
+ def add_transient[T, I](self, *, t: type[T], i: type[I], override: bool = False):
394
419
  ...
395
420
 
396
421
  @overload
397
- def add_transient[I](self, *, callable: Callable[..., I]):
422
+ def add_transient[I](self, *, callable: Callable[..., I], override: bool = False):
398
423
  ...
399
424
 
400
425
  @overload
401
- def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I]):
426
+ def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I], override: bool = False):
402
427
  ...
403
428
 
404
- def add_transient[T, I](self, *, t: type[T] = None, i: type[I] = None, callable: Callable[..., I] = None):
429
+ def add_transient[T, I](self, *, t: type[T] = None, i: type[I] = None, callable: Callable[..., I] = None,
430
+ override: bool = False):
405
431
  self._raise_if_closed()
406
- self._add('transient', i=i, t=t, callable=callable)
432
+ self._add('transient', i=i, t=t, callable=callable, override=override)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dinkleberg
3
- Version: 0.3.1
3
+ Version: 0.3.2
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
@@ -1,9 +1,9 @@
1
1
  dinkleberg/__init__.py,sha256=6gowHoL3xTWd2iyU09upgjXKUv_WWp6Tw1iqw2uz7Vc,192
2
- dinkleberg/dependency_configurator.py,sha256=gSuizzr28qwO9Q5Z1IYytxaIRB5dAAKiPKe3GozKUuk,14660
2
+ dinkleberg/dependency_configurator.py,sha256=lS_IPK2nLdVPQZpYOxlk6pv1fzQ9MK2PdJ9ucOrptww,16514
3
3
  dinkleberg/descriptor.py,sha256=ZtVwJihvCLugakHx201iX7Jm4A50Z0SzPu9zeHfD320,349
4
4
  dinkleberg/typing.py,sha256=qAdSQomntQfI4bSWc9X32DXGftuyj56WP7nG3Pia7ZE,942
5
5
  dinkleberg/fastapi/__init__.py,sha256=boj1ywpWhuuOjHLwdUha2EPBG2f1zbc374N35k1CJxk,352
6
- dinkleberg-0.3.1.dist-info/METADATA,sha256=zK12ZPnFptOjz9QiF8i13yqHnG2UtWz1qSMzUkzE8rQ,1555
7
- dinkleberg-0.3.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
- dinkleberg-0.3.1.dist-info/top_level.txt,sha256=6TjbaJ_eyRzoxzz2r1Eu0hgYfxBBM2bOV3u_TJ8yjjw,11
9
- dinkleberg-0.3.1.dist-info/RECORD,,
6
+ dinkleberg-0.3.2.dist-info/METADATA,sha256=sKUDY2mt75smvk6Em79QVJXf8kgL16M1KYDxCVUvCes,1555
7
+ dinkleberg-0.3.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
+ dinkleberg-0.3.2.dist-info/top_level.txt,sha256=6TjbaJ_eyRzoxzz2r1Eu0hgYfxBBM2bOV3u_TJ8yjjw,11
9
+ dinkleberg-0.3.2.dist-info/RECORD,,