dinkleberg 0.1.0__py3-none-any.whl → 0.2.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.
@@ -1,3 +1,4 @@
1
+ import abc
1
2
  import asyncio
2
3
  import inspect
3
4
  import logging
@@ -8,7 +9,7 @@ from typing import AsyncGenerator, Callable, overload, get_type_hints, Mapping,
8
9
  from .dependency import Dependency
9
10
  from .dependency_scope import DependencyScope
10
11
  from .descriptor import Descriptor, Lifetime
11
- from .typing import get_static_params, get_public_methods
12
+ from .typing import get_static_params, get_public_methods, is_builtin
12
13
 
13
14
  logger = logging.getLogger(__name__)
14
15
 
@@ -60,7 +61,7 @@ class DependencyConfigurator(DependencyScope):
60
61
  def _add(self, lifetime: Lifetime, *, t: type = None, generator: Callable[..., AsyncGenerator] = None,
61
62
  callable: Callable = None):
62
63
  if generator is None and callable is None:
63
- raise ValueError('Invalid dependency configuration.')
64
+ raise ValueError('Invalid dependency registration. Either generator or callable must be provided.')
64
65
  if t is None:
65
66
  t = self._infer_type(generator=generator, callable=callable)
66
67
  self._descriptors[t] = Descriptor(generator=generator, callable=callable, lifetime=lifetime)
@@ -103,6 +104,7 @@ class DependencyConfigurator(DependencyScope):
103
104
  return None
104
105
 
105
106
  # TODO circular dependency detection
107
+ # TODO singleton race condition prevention (async.Lock)
106
108
  async def resolve[T](self, t: type[T], **kwargs) -> T:
107
109
  self._raise_if_closed()
108
110
 
@@ -126,10 +128,12 @@ class DependencyConfigurator(DependencyScope):
126
128
  factory = descriptor['generator'] or descriptor['callable']
127
129
  deps = await self._resolve_deps(factory)
128
130
  else:
129
- origin = get_origin(t)
130
- if origin is not None:
131
+ if get_origin(t) is not None:
131
132
  raise ValueError(f'Cannot resolve generic type {t} without explicit registration.')
132
133
 
134
+ if inspect.isabstract(t) or t is abc.ABC:
135
+ raise ValueError(f'Cannot resolve abstract class {t} without explicit registration.')
136
+
133
137
  is_generator = False
134
138
  lifetime = 'transient'
135
139
  factory = t
@@ -143,9 +147,21 @@ class DependencyConfigurator(DependencyScope):
143
147
  raise RuntimeError(f'Generator {t} did not yield any value.')
144
148
 
145
149
  self._active_generators.append(generator)
150
+ elif asyncio.iscoroutinefunction(factory):
151
+ instance = await factory(**deps, **kwargs)
146
152
  else:
147
153
  instance = factory(**deps, **kwargs)
148
154
 
155
+ if isinstance(instance, AsyncGenerator):
156
+ try:
157
+ if is_generator:
158
+ raise RuntimeError(f'Generator {t} yielded another generator. Nested generators are not supported.')
159
+ else:
160
+ raise RuntimeError(
161
+ f'Callable {t} returned a generator. This is most likely due to an invalid dependency registration.')
162
+ finally:
163
+ await instance.aclose()
164
+
149
165
  self._wrap_instance(instance)
150
166
 
151
167
  if lifetime == 'singleton':
@@ -164,8 +180,10 @@ class DependencyConfigurator(DependencyScope):
164
180
  if not param.annotation or param.annotation is inspect.Parameter.empty:
165
181
  continue
166
182
 
183
+ if is_builtin(param.annotation):
184
+ continue
185
+
167
186
  # TODO handle more complex cases (e.g., Union, Optional, etc.)
168
- # TODO handle native types (int, str, etc.)
169
187
  names.append(param.name)
170
188
  tasks.append(self.resolve(param.annotation))
171
189
 
@@ -196,7 +214,7 @@ class DependencyConfigurator(DependencyScope):
196
214
 
197
215
  # TODO handle __slots__
198
216
  def _wrap_instance(self, instance):
199
- if getattr(instance, '__di_wrapped__', False):
217
+ if getattr(instance, '__dinkleberg__', False):
200
218
  return
201
219
 
202
220
  methods = get_public_methods(instance)
@@ -222,7 +240,7 @@ class DependencyConfigurator(DependencyScope):
222
240
  raise NotImplementedError('Synchronous methods with Dependency() defaults are not supported.')
223
241
 
224
242
  try:
225
- setattr(instance, '__di_wrapped__', True)
243
+ setattr(instance, '__dinkleberg__', True)
226
244
  except (AttributeError, TypeError):
227
245
  # Some objects (like those with __slots__) might not allow new attributes
228
246
  pass
@@ -284,3 +302,15 @@ class DependencyConfigurator(DependencyScope):
284
302
  callable: Callable[..., I] = None):
285
303
  self._raise_if_closed()
286
304
  self._add('scoped', t=t, generator=generator, callable=callable)
305
+
306
+ @overload
307
+ def add_transient[I](self, *, callable: Callable[..., I]):
308
+ ...
309
+
310
+ @overload
311
+ def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I]):
312
+ ...
313
+
314
+ def add_transient[T, I](self, *, t: type[T] = None, callable: Callable[..., I] = None):
315
+ self._raise_if_closed()
316
+ self._add('transient', t=t, callable=callable)
dinkleberg/typing.py CHANGED
@@ -1,6 +1,11 @@
1
1
  import inspect
2
2
  from inspect import Parameter, signature
3
- from typing import Callable
3
+ from typing import Callable, get_origin
4
+
5
+
6
+ def is_builtin(t: type) -> bool:
7
+ origin = get_origin(t) or t
8
+ return getattr(origin, '__module__', None) == 'builtins'
4
9
 
5
10
 
6
11
  def get_static_params(func: Callable) -> list[Parameter]:
@@ -1,34 +1,34 @@
1
- Metadata-Version: 2.4
2
- Name: dinkleberg
3
- Version: 0.1.0
4
- Summary: Your friendly neighbour when it comes to dependency management.
5
- Project-URL: Homepage, https://github.com/DavidVollmers/dinkleberg
6
- Project-URL: Documentation, https://github.com/DavidVollmers/dinkleberg/blob/main/libs/dinkleberg/README.md
7
- Project-URL: Repository, https://github.com/DavidVollmers/dinkleberg.git
8
- Project-URL: Issues, https://github.com/DavidVollmers/dinkleberg/issues
9
- Project-URL: Changelog, https://github.com/DavidVollmers/dinkleberg/blob/main/CHANGELOG.md
10
- Keywords: automation,dependency,package-management
11
- Classifier: Development Status :: 3 - Alpha
12
- Classifier: Intended Audience :: Developers
13
- Classifier: License :: OSI Approved :: MIT License
14
- Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.13
17
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
- Requires-Python: >=3.13
19
- Description-Content-Type: text/markdown
20
-
21
- # dinkleberg
22
-
23
- > "And this is where I'd put my working dependencies... IF I HAD ANY!"
24
-
25
- **dinkleberg** is a lightweight Python utility designed to make dependency management less of a neighborhood feud. Built
26
- to work seamlessly in any project, it ensures your environment stays green—unlike the guy's next door.
27
-
28
- ## Installation
29
-
30
- ```bash
31
- pip install dinkleberg
32
-
33
- uv add dinkleberg
34
- ```
1
+ Metadata-Version: 2.4
2
+ Name: dinkleberg
3
+ Version: 0.2.0
4
+ Summary: Your friendly neighbour when it comes to dependency management.
5
+ Project-URL: Homepage, https://github.com/DavidVollmers/dinkleberg
6
+ Project-URL: Documentation, https://github.com/DavidVollmers/dinkleberg/blob/main/libs/dinkleberg/README.md
7
+ Project-URL: Repository, https://github.com/DavidVollmers/dinkleberg.git
8
+ Project-URL: Issues, https://github.com/DavidVollmers/dinkleberg/issues
9
+ Project-URL: Changelog, https://github.com/DavidVollmers/dinkleberg/blob/main/CHANGELOG.md
10
+ Keywords: dependency,package-management,automation
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Requires-Python: >=3.13
19
+ Description-Content-Type: text/markdown
20
+
21
+ # dinkleberg
22
+
23
+ > "And this is where I'd put my working dependencies... IF I HAD ANY!"
24
+
25
+ **dinkleberg** is a lightweight Python utility designed to make dependency management less of a neighborhood feud. Built
26
+ to work seamlessly in any project, it ensures your environment stays green—unlike the guy's next door.
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ pip install dinkleberg
32
+
33
+ uv add dinkleberg
34
+ ```
@@ -0,0 +1,10 @@
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,,
@@ -1,4 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.28.0
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ dinkleberg
@@ -1,9 +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=IeGSUUbaaxbcb1I6NcIqWyqGs0iWygVzjXzsj0VmOGg,10473
4
- dinkleberg/dependency_scope.py,sha256=sufXjQ6F62ZfohItUnrV7Fvh8gSSc7a6orO6PXu19Vw,318
5
- dinkleberg/descriptor.py,sha256=mVI00K1M2m4Rl5ANatGMeB_HpzeFONoULwg0UmNxfQ0,313
6
- dinkleberg/typing.py,sha256=9AGDNz_aQ8p7ToyJwkj2fg92o0L3-zXwZBEmoTNS1to,670
7
- dinkleberg-0.1.0.dist-info/METADATA,sha256=vU4SQ-0fafwgtOETUAtr_-zuPTEJX4Haesa4i8OT8L8,1396
8
- dinkleberg-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
9
- dinkleberg-0.1.0.dist-info/RECORD,,