Releases: maldoinc/wireup
v2.8.0
What's Changed
- Allow nested overrides #93 by @smokyabdulrahman in #108
as_typeregistration now validates compatibility at runtime and raises clearer errors for invalid or mismatched types.- Added
wireup.integration.typerintegration - Added
wireup.integration.fastmcpintegration for FastMCP HTTP apps. - Added
WireupTasksupport in FastAPI and Starlette integrations for dependency injection in background tasks. - Added
wireup.integration.fastapi.injectfor injecting into any function during request lifetime. - Added
wireup.integration.django.inject_appfor app-level Django callables (commands, signals, checks, scripts). - Added Strawberry integration documentation.
- New migration guides:
- FastAPI
Dependsto Wireup - Dependency Injector to Wireup
- FastAPI
- Benchmark suite, generated benchmark data, and a new benchmarks documentation page.
Changed
- You can now call setup in fastapi integration even before registering all the routes.
- AIOHTTP integration now supports
middleware_mode: - Django and FastAPI integration documentation was fully reorganized and expanded (setup, lifecycle patterns, testing, troubleshooting).
Fixed
- Falsy handling for
as_typechecks was fixed. - FastAPI request-container/setup error messages improved, including clearer failure messaging when setup/request context is missing.
Full Changelog: v2.7.1...v2.8.0
v2.7.1
- Fix overriding async scoped dependencies
- Improve singleton lookup performance by using an instance factory once the object is created.
Full Changelog: v2.7.0...v2.7.1
v2.7.0
What's new
- Added support for injecting into generator / async-generator functions
- Added new opt-in
concurrent_scoped_accessparameter for locking scopes accessed concurrently oncreate_sync_container/
create_async_container. - Function injection (
inject_from_containerand framework integrations) now generates specialized wrappers at
decoration time, reducing per-call runtime overhead and skipping container lookups when possible. - Exit stack cleanup avoids runtime
inspect.isasyncgen().
Bugfixes
- Fixed a bug where an async container injecting into a
deffunction would not inject async dependencies already
cached in the container. - Qualifiers with falsy values (e.g.
0,"",False) are now handled correctly during injection. - Wireup now raises when encountering positional-only parameters in injectables or injected callables.
Full Changelog: v2.6.0...v2.7.0
v2.6.0
What's Changed
- Enable dot notation in parameters by @smokyabdulrahman in #66
- Fix overriding indirect dependencies by @maldoinc in #107
- Use
teardown_requestin flask to handle resource cleanup
New Contributors
- @smokyabdulrahman made their first contribution in #66
Full Changelog: v2.4.0...v2.6.0
v2.5.0
- Wireup is now fully thread-safe. It uses a double-checked locking mechanism that guarantee safe instantiation and resolution in high-concurrency environments (threaded or async).
- This also allows Wireup to be used in No-GIL Python.
Full Changelog: v2.4.0...v2.5.0
v2.4.0
What's Changed
1. @service -> @injectable
The @service decorator will be renamed to @injectable. The name service carries architectural baggage and is misleading for many injected values. Even in Wireup's own docs the usage of @service is confusing.
AuthenticatedUsername = NewType("AuthenticatedUsername", str)
-@service(lifetime="scoped")
+@injectable(lifetime="scoped")
def authenticated_username_factory(auth: SomeAuthService) -> AuthenticatedUsername:
return AuthenticatedUsername(...)Many injected values such as AuthenticatedUsername from the example, are not really "services".
The name injectable is strictly about capability: A thing that can be injected. It is agnostic to the produced object's role in the system architecture making it overall less confusing.
Note: This is a pure rename and the behavior is unchanged.
2. Inject(param=...) -> Inject(config=)
Same as "service", injecting "parameters" is somewhat ambiguous for users. The name itself is also very overloaded especially in the context of a web application: You have query parameters, path parameters, function parameters in the signature and now Wireup parameters.
The feature remains to enable co-located definitions, but it is renamed to config to make it explicit that values come from Wireup’s configuration rather than some runtime or function parameters.
-container = wireup.create_{a}sync_container(params={"api_key": "secret"})
+container = wireup.create_{a}sync_container(config={"api_key": "secret"})
@wireup.inject_from_container(container)
-def main(api_key: Annotated[str, Inject(param="api_key")]) -> None:
+def main(api_key: Annotated[str, Inject(config="api_key")]) -> None:
passSimilarly container.params is deprecated in favor of container.config.
Note: Same as above, this is a pure rename and the behavior is unchanged.
3. Better support for abstractions
Currently Wireup requires tagging classes to be used as "interfaces" with @abstract. The linking between the two is indirect, wireup scans bases to see if any of them was marked with @abstract to do the wiring. This also has the side-effect that the container knows both about the implementation and the abstraction.
This is now deprecated in favor of explicit binding via as_type.
- You can now bind classes or protocols without owning/decorating them.
- Unlike
@abstract,as_typereplaces the registration rather than creating an alias. The concrete type will no longer be visible to the container unless explicitly exposed (see example below). - If the factory where this is used returns an optional type
FooImpl | None,as_type=Fooautomatically registers the key asFoo | Noneto ensure runtime safety.
-@abstract
class Cache(abc.ABC):
def get(self, key): ...
def set(self, key, value): ...
-@service
+@injectable(as_type=Cache) # as_type can be any regular class, abc or protocol.
class InMemoryCache(Cache):
...For factories, you can control the registration by setting the return type or using as_type. You may choose to keep the concrete type visible (e.g. for tests) while exposing only the abstraction to the container.
@injectable(as_type=Cache, qualifier="redis")
def make_redis_cache(...) -> Redis:
return Redis(...)With functions since you can control the return type (unlike @injectable on a class), instead of using as_type=Cache, you can have the function return Cache for the same effect.
-@injectable(as_type=Cache, qualifier="redis")
+@injectable(qualifier="redis")
def make_redis_cache(...) -> Cache:
return Redis(...)If you need to keep both the implementation and the abstraction visible to the container you can explicitly expose both by writing a small adapter.
@injectable
class FooImpl: ...
@injectable
def make_foo_protocol(impl: FooImpl) -> FooProtocol:
return implBoth FooImpl and FooProtocol are visible to the container and will reuse the same instance.
Improved container creation signature
Given the "service" rename, the signatures must be updated as well. The new api exposes a new injectables parameter where you can place either injectables themselves or modules for wireup to scan for injectables rather than scattering them in two parameters (services and service_modules).
-container = wireup.create_{a}sync_container(service_modules=[services, repositories], services=[AuthService])
+container = wireup.create_{a}sync_container(injectables=[services, repositories, AuthService])4. Improved handling of optional values
Wireup supports optional values as first-class citizens, with one caveat:
@injectable
def make_cache(
redis_url: Annotated[str | None, Inject(config="redis_url")],
) -> Redis | None:
return Redis.from_url(redis_url) if redis_url else NoneThis dependency can be injected into function signatures as Redis | None.
However, when using the container as a service locator, users previously had to write container.get(Redis) This meant the type checker was unaware that the value could be absent.
This is now fixed: container.get(Redis | None) is supported.
Calling container.get(T) for a dependency registered as T | None will continue to work, but will emit a deprecation warning.
PRs
- add support for unknown dependencies that provide a default value by @iverberk in #99
- Wireup vNext API Modernization by @maldoinc in #100
New Contributors
Full Changelog: v2.3.0...v2.4.0
v2.3.0
What's Changed
- feat: Add integration for Django-based frameworks such as DRF/Ninja by @MuriloScarpaSitonio in #89
Full Changelog: v2.2.2...v2.3.0
v2.2.2
What's Changed
- Fix: prevent TypeError: Cannot subclass ForwardRef on Python 3.14 by @Macktireh in #88
- fix: django async class based views by @MuriloScarpaSitonio in #96
New Contributors
- @Macktireh made their first contribution in #88
Full Changelog: v2.2.1...v2.2.2
v2.2.1
- Fixed a bug with overriding async dependencies
- Fixed a bug with overriding when using class-based handlers in FastAPI/aiohttp.
Full Changelog: v2.2.0...v2.2.1
v2.2.0
What's Changed
- New compiled container architecture. Wireup will compute ahead of time all factories and generate optimized code for object creation. This results in a 125% increased performance compared to v2.1.0 and 546% compared to v2.0.0.
- fix
asyncio.iscoroutinefunctionDeprecationWarningby @MuriloScarpaSitonio in #90 - fix
wireup.ioc.util.get_globalsby @MuriloScarpaSitonio in #92
Full Changelog: v2.1.0...v2.2.0