anydi 0.64.0__py3-none-any.whl → 0.66.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.
anydi/_container.py CHANGED
@@ -553,6 +553,11 @@ class Container:
553
553
  )
554
554
 
555
555
  self._set_provider(provider)
556
+
557
+ # Clear cached resolvers when overriding
558
+ if override:
559
+ self._resolver.clear_caches()
560
+
556
561
  return provider
557
562
 
558
563
  def _validate_provider_scope(
anydi/_resolver.py CHANGED
@@ -62,6 +62,13 @@ class Resolver:
62
62
  def add_unresolved(self, interface: Any) -> None:
63
63
  self._unresolved_interfaces.add(interface)
64
64
 
65
+ def clear_caches(self) -> None:
66
+ """Clear all cached resolvers."""
67
+ self._cache.clear()
68
+ self._async_cache.clear()
69
+ self._override_cache.clear()
70
+ self._async_override_cache.clear()
71
+
65
72
  def get_cached(self, interface: Any, *, is_async: bool) -> CompiledResolver | None:
66
73
  """Get cached resolver if it exists."""
67
74
  if self.override_mode:
@@ -83,9 +90,14 @@ class Resolver:
83
90
  return cache[provider.interface]
84
91
 
85
92
  # Recursively compile dependencies first
86
- for p in provider.parameters:
87
- if p.provider is not None:
88
- self.compile(p.provider, is_async=is_async)
93
+ for param in provider.parameters:
94
+ if param.provider is not None:
95
+ # Look up the current provider to handle overrides
96
+ current_provider = self._container.providers.get(param.annotation)
97
+ if current_provider is not None:
98
+ self.compile(current_provider, is_async=is_async)
99
+ else:
100
+ self.compile(param.provider, is_async=is_async)
89
101
 
90
102
  # Compile the resolver and creator functions
91
103
  compiled = self._compile_resolver(
@@ -155,23 +167,29 @@ class Resolver:
155
167
  else (self._async_cache if is_async else self._cache)
156
168
  )
157
169
 
158
- for idx, p in enumerate(provider.parameters):
159
- param_annotations[idx] = p.annotation
160
- param_defaults[idx] = p.default
161
- param_has_default[idx] = p.has_default
162
- param_names[idx] = p.name
163
- param_shared_scopes[idx] = p.shared_scope
164
-
165
- if p.provider is not None:
166
- compiled = cache.get(p.provider.interface)
170
+ for idx, param in enumerate(provider.parameters):
171
+ param_annotations[idx] = param.annotation
172
+ param_defaults[idx] = param.default
173
+ param_has_default[idx] = param.has_default
174
+ param_names[idx] = param.name
175
+ param_shared_scopes[idx] = param.shared_scope
176
+
177
+ if param.provider is not None:
178
+ # Look up the current provider from the container to handle overrides
179
+ current_provider = self._container.providers.get(param.annotation)
180
+ if current_provider is not None:
181
+ compiled = cache.get(current_provider.interface)
182
+ else:
183
+ # Fallback to the original provider if not in container
184
+ compiled = cache.get(param.provider.interface)
167
185
  if compiled is None:
168
- compiled = self.compile(p.provider, is_async=is_async)
169
- cache[p.provider.interface] = compiled
186
+ compiled = self.compile(param.provider, is_async=is_async)
187
+ cache[param.provider.interface] = compiled
170
188
  param_resolvers[idx] = compiled.resolve
171
189
 
172
190
  unresolved_message = (
173
- f"You are attempting to get the parameter `{p.name}` with the "
174
- f"annotation `{type_repr(p.annotation)}` as a dependency into "
191
+ f"You are attempting to get the parameter `{param.name}` with the "
192
+ f"annotation `{type_repr(param.annotation)}` as a dependency into "
175
193
  f"`{type_repr(provider.call)}` which is not registered or set in the "
176
194
  "scoped context."
177
195
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: anydi
3
- Version: 0.64.0
3
+ Version: 0.66.0
4
4
  Summary: Dependency Injection library
5
5
  Keywords: dependency injection,dependencies,di,async,asyncio,application
6
6
  Author: Anton Ruhlov
@@ -37,7 +37,7 @@ Description-Content-Type: text/markdown
37
37
 
38
38
  <div style="text-align: center;">
39
39
 
40
- Modern, lightweight Dependency Injection library using type annotations.
40
+ Simple Dependency Injection library that uses Python type annotations.
41
41
 
42
42
  [![CI](https://github.com/antonrh/anydi/actions/workflows/ci.yml/badge.svg)](https://github.com/antonrh/anydi/actions/workflows/ci.yml)
43
43
  [![Coverage](https://codecov.io/gh/antonrh/anydi/branch/main/graph/badge.svg)](https://codecov.io/gh/antonrh/anydi)
@@ -53,21 +53,21 @@ http://anydi.readthedocs.io/
53
53
 
54
54
  ---
55
55
 
56
- `AnyDI` is a modern, lightweight Dependency Injection library suitable for any synchronous or asynchronous applications with Python 3.10+, based on type annotations ([PEP 484](https://peps.python.org/pep-0484/)).
56
+ `AnyDI` is a simple Dependency Injection library for Python 3.10+. It works with sync and async applications and uses type annotations ([PEP 484](https://peps.python.org/pep-0484/)).
57
57
 
58
- The key features are:
58
+ Main features:
59
59
 
60
- * **Type-safe**: Dependency resolution is driven by type hints.
61
- * **Async-ready**: Works the same for sync and async providers or injections.
62
- * **Scoped**: Built-in singleton, transient, and request scopes, plus custom scopes.
63
- * **Simple**: Small surface area keeps boilerplate low.
64
- * **Fast**: Has minimal overhead and resolves dependencies quickly.
65
- * **Named**: `Annotated[...]` makes multiple bindings per type simple.
66
- * **Managed**: Providers can open/close resources via context managers.
67
- * **Modular**: Compose containers or modules for large apps.
68
- * **Scanning**: Auto-discovers injectable callables.
69
- * **Integrated**: Extensions for popular frameworks.
70
- * **Testable**: Override providers directly in tests.
60
+ * **Type-safe**: Uses type hints for dependency resolution.
61
+ * **Async support**: Works with both sync and async code.
62
+ * **Scopes**: Provides singleton, transient, and request scopes. Supports custom scope definitions.
63
+ * **Simple**: Minimal boilerplate with straightforward API.
64
+ * **Fast**: Low overhead dependency resolution.
65
+ * **Named providers**: Use `Annotated[...]` for multiple providers per type.
66
+ * **Resource management**: Context manager protocol support for lifecycle management.
67
+ * **Modular**: Container and module composition for large applications.
68
+ * **Auto-scan**: Automatic discovery of injectable callables.
69
+ * **Framework integrations**: Extensions for popular frameworks.
70
+ * **Testing**: Provider override mechanism for test isolation.
71
71
 
72
72
  ## Installation
73
73
 
@@ -266,23 +266,23 @@ urlpatterns = [
266
266
  ]
267
267
  ```
268
268
 
269
- ## What's Next?
269
+ ## Learn More
270
270
 
271
- Ready to learn more? Check out these resources:
271
+ Want to know more? Here are helpful resources:
272
272
 
273
273
  **Core Documentation:**
274
- - [Core Concepts](https://anydi.readthedocs.io/en/latest/concepts/) - Understand containers, providers, scopes, and dependency injection
275
- - [Providers](https://anydi.readthedocs.io/en/latest/usage/providers/) - Learn about registration, named providers, and resource management
276
- - [Scopes](https://anydi.readthedocs.io/en/latest/usage/scopes/) - Master lifecycle management with built-in and custom scopes
277
- - [Dependency Injection](https://anydi.readthedocs.io/en/latest/usage/injection/) - Explore injection patterns and techniques
278
- - [Testing](https://anydi.readthedocs.io/en/latest/usage/testing/) - Write testable code with provider overrides
274
+ - [Core Concepts](https://anydi.readthedocs.io/en/latest/concepts/) - Learn about containers, providers, scopes, and dependency injection
275
+ - [Providers](https://anydi.readthedocs.io/en/latest/usage/providers/) - How to register providers and manage resources
276
+ - [Scopes](https://anydi.readthedocs.io/en/latest/usage/scopes/) - How to use built-in and custom scopes
277
+ - [Dependency Injection](https://anydi.readthedocs.io/en/latest/usage/injection/) - Different ways to inject dependencies
278
+ - [Testing](https://anydi.readthedocs.io/en/latest/usage/testing/) - How to test your code with provider overrides
279
279
 
280
280
  **Framework Integrations:**
281
- - [FastAPI](https://anydi.readthedocs.io/en/latest/extensions/fastapi/) - Build modern APIs with automatic dependency injection
282
- - [Django](https://anydi.readthedocs.io/en/latest/extensions/django/) - Integrate with Django and Django Ninja
283
- - [FastStream](https://anydi.readthedocs.io/en/latest/extensions/faststream/) - Message broker applications
284
- - [Typer](https://anydi.readthedocs.io/en/latest/extensions/typer/) - CLI applications with async support
285
- - [Pydantic Settings](https://anydi.readthedocs.io/en/latest/extensions/pydantic_settings/) - Configuration management
281
+ - [FastAPI](https://anydi.readthedocs.io/en/latest/extensions/fastapi/) - How to use with FastAPI
282
+ - [Django](https://anydi.readthedocs.io/en/latest/extensions/django/) - How to use with Django and Django Ninja
283
+ - [FastStream](https://anydi.readthedocs.io/en/latest/extensions/faststream/) - How to use with message brokers
284
+ - [Typer](https://anydi.readthedocs.io/en/latest/extensions/typer/) - How to use in CLI applications
285
+ - [Pydantic Settings](https://anydi.readthedocs.io/en/latest/extensions/pydantic_settings/) - How to manage configuration
286
286
 
287
287
  **Full Documentation:**
288
- - [Read the Docs](https://anydi.readthedocs.io/) - Complete documentation with examples and guides
288
+ - [Read the Docs](https://anydi.readthedocs.io/) - All documentation with examples and guides
@@ -1,13 +1,13 @@
1
1
  anydi/__init__.py,sha256=KFX8OthKXwBuYDPCV61t-044DpJ88tAOzIxeUWRC5OA,633
2
2
  anydi/_async_lock.py,sha256=3dwZr0KthXFYha0XKMyXf8jMmGb1lYoNC0O5w29V9ic,1104
3
- anydi/_container.py,sha256=VbC5WqVH78TtaPx3JbSyZP8gZA4NbPNuwEiJXZSDSks,29561
3
+ anydi/_container.py,sha256=NFxrzJuWwc4DyT2Ffl0RUU3ecCCF4cl-tLp9LhgKnfQ,29675
4
4
  anydi/_context.py,sha256=-9QqeMWo9OpZVXZxZCQgIsswggl3Ch7lgx1KiFX_ezc,3752
5
5
  anydi/_decorators.py,sha256=J3W261ZAG7q4XKm4tbAv1wsWr9ysx9_5MUbUvSJB_MQ,2809
6
6
  anydi/_injector.py,sha256=1Ux71DhGxu3dLwPJP8gU73olI0pcZ3_tVaVzwKH7100,4411
7
7
  anydi/_marker.py,sha256=xVydjGdkxd_DqqwttnJZRkQbhpCTE9OnrhFmFJMlgvI,3415
8
8
  anydi/_module.py,sha256=2kN5uEXLd2Dsc58gz5IWK43wJewr_QgIVGSO3iWp798,2609
9
9
  anydi/_provider.py,sha256=OV1WFHTYv7W2U0XDk_Kql1r551Vhq8o-pUV5ep1HQcU,1574
10
- anydi/_resolver.py,sha256=fh8pB6gDZ-jWXh_q2QLM--g9tWZ0Dyx8MPjGcLVyiOw,30428
10
+ anydi/_resolver.py,sha256=nKPuEI69ZBLdPubQlnlQTTkhMK15vG0YcW9jgitzIto,31393
11
11
  anydi/_scanner.py,sha256=rbRkHzyd2zMu7AFLffN6_tZJcMaW9gy7E-lVdHLHYrs,4294
12
12
  anydi/_types.py,sha256=lsShY_-_CM2EFajeknAYXvLl-rHfopBT8udnK5_BtS4,1161
13
13
  anydi/ext/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -21,7 +21,7 @@ anydi/ext/starlette/middleware.py,sha256=n_JJ7BcG2Mg2M5HwM_SBboxZ-mnnD6WWJn4khq7
21
21
  anydi/ext/typer.py,sha256=z-sDd3jZMPTE2CyEuJ0f9uIJB43FjoLWbjpnkOvqSKA,6236
22
22
  anydi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  anydi/testing.py,sha256=cHg3mMScZbEep9smRqSNQ81BZMQOkyugHe8TvKdPnEg,1347
24
- anydi-0.64.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
25
- anydi-0.64.0.dist-info/entry_points.txt,sha256=AgOcQYM5KyS4D37QcYb00tiid0QA-pD1VrjHHq4QAps,44
26
- anydi-0.64.0.dist-info/METADATA,sha256=0Ic_f7pbgpkUG3Mp11D1uSJ8VJ98vfPkY6x3_-_w5rU,8142
27
- anydi-0.64.0.dist-info/RECORD,,
24
+ anydi-0.66.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
25
+ anydi-0.66.0.dist-info/entry_points.txt,sha256=AgOcQYM5KyS4D37QcYb00tiid0QA-pD1VrjHHq4QAps,44
26
+ anydi-0.66.0.dist-info/METADATA,sha256=UJVE26FM3Nsn4PgAJDvy5FiwoAQ2oU1U7TIs311y_Zs,8061
27
+ anydi-0.66.0.dist-info/RECORD,,
File without changes