dinkleberg 0.1.0__py3-none-any.whl → 0.2.1__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_type
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,15 @@ 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 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:
131
135
  raise ValueError(f'Cannot resolve generic type {t} without explicit registration.')
132
136
 
137
+ if inspect.isabstract(t) or t is abc.ABC:
138
+ raise ValueError(f'Cannot resolve abstract class {t} without explicit registration.')
139
+
133
140
  is_generator = False
134
141
  lifetime = 'transient'
135
142
  factory = t
@@ -143,9 +150,21 @@ class DependencyConfigurator(DependencyScope):
143
150
  raise RuntimeError(f'Generator {t} did not yield any value.')
144
151
 
145
152
  self._active_generators.append(generator)
153
+ elif asyncio.iscoroutinefunction(factory):
154
+ instance = await factory(**deps, **kwargs)
146
155
  else:
147
156
  instance = factory(**deps, **kwargs)
148
157
 
158
+ if isinstance(instance, AsyncGenerator):
159
+ try:
160
+ if is_generator:
161
+ raise RuntimeError(f'Generator {t} yielded another generator. Nested generators are not supported.')
162
+ else:
163
+ raise RuntimeError(
164
+ f'Callable {t} returned a generator. This is most likely due to an invalid dependency registration.')
165
+ finally:
166
+ await instance.aclose()
167
+
149
168
  self._wrap_instance(instance)
150
169
 
151
170
  if lifetime == 'singleton':
@@ -164,8 +183,10 @@ class DependencyConfigurator(DependencyScope):
164
183
  if not param.annotation or param.annotation is inspect.Parameter.empty:
165
184
  continue
166
185
 
186
+ if is_builtin_type(param.annotation):
187
+ continue
188
+
167
189
  # TODO handle more complex cases (e.g., Union, Optional, etc.)
168
- # TODO handle native types (int, str, etc.)
169
190
  names.append(param.name)
170
191
  tasks.append(self.resolve(param.annotation))
171
192
 
@@ -196,7 +217,7 @@ class DependencyConfigurator(DependencyScope):
196
217
 
197
218
  # TODO handle __slots__
198
219
  def _wrap_instance(self, instance):
199
- if getattr(instance, '__di_wrapped__', False):
220
+ if getattr(instance, '__dinkleberg__', False):
200
221
  return
201
222
 
202
223
  methods = get_public_methods(instance)
@@ -222,7 +243,7 @@ class DependencyConfigurator(DependencyScope):
222
243
  raise NotImplementedError('Synchronous methods with Dependency() defaults are not supported.')
223
244
 
224
245
  try:
225
- setattr(instance, '__di_wrapped__', True)
246
+ setattr(instance, '__dinkleberg__', True)
226
247
  except (AttributeError, TypeError):
227
248
  # Some objects (like those with __slots__) might not allow new attributes
228
249
  pass
@@ -284,3 +305,15 @@ class DependencyConfigurator(DependencyScope):
284
305
  callable: Callable[..., I] = None):
285
306
  self._raise_if_closed()
286
307
  self._add('scoped', t=t, generator=generator, callable=callable)
308
+
309
+ @overload
310
+ def add_transient[I](self, *, callable: Callable[..., I]):
311
+ ...
312
+
313
+ @overload
314
+ def add_transient[T, I](self, *, t: type[T], callable: Callable[..., I]):
315
+ ...
316
+
317
+ def add_transient[T, I](self, *, t: type[T] = None, callable: Callable[..., I] = None):
318
+ self._raise_if_closed()
319
+ 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_type(t: type) -> bool:
7
+ origin = get_origin(t) or t
8
+ return getattr(origin, '__module__', None) in ('builtins', 'typing', 'types')
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.1
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=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,,
@@ -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,,