hazrakah#
- class Container(outer_scope=None, frozen=False)#
Bases:
DependencyRegistry,ScopedDependencyResolver,DependencyResolverA dependency-injection container that supports hierarchical scopes and deterministic destruction.
Containers track every object they directly instantiate (via
__create_instance) in an internalset. When a container is used as a context manager (either directly or viacreate_scope(), all tracked objects are torn down by calling theirclose()method at the end of the scope.Example (Basic)#
container = Container() container.register_transient(Foo) foo = container.resolve(Foo) # supports scopes: scoped_container = container.create_scope() scoped_container.register_transient(Foo) foo = scoped_container.resolve(Foo)
Example (Fluent)#
Registrations return
self, so they can be chained. The following demonstrates this:container = ( Container() .register_singleton(Greeter, GreeterImpl) .register_transient(Formatter) ) greeter = c.resolve(Greeter)
Example (Context Manager)#
The container can be used as a context manager for both direct scoping and nested scopes:
with Container() as container: container.register_transient(Foo) with Container() as scoped: scoped.register_transient(Bar) foo = scoped.resolve(Foo) assert foo is not None bar = container.resolve(Bar) # raises Error (not in scope) assert foo.is_closed is True # context manager scope closes
- ivar outer_scope:
The parent container, or
Nonefor the root.- vartype outer_scope:
Optional[Container]
- __exit__(exc_type, exc_val, exc_tb)#
Destroy all tracked instances.
Every object that was directly instantiated by this container (via
__create_instance) is torn down by calling itsclose()method, if present. The tracked set is then cleared so no object is double-cleaned.- Parameters:
exc_type (
Optional[type[BaseException]]) – (OPTIONAL) Exception type, if one was raised inside thewithblock.exc_val (
Optional[BaseException]) – (OPTIONAL) The exception instance, if one was raised.exc_tb (
Optional[TracebackType]) – (OPTIONAL) Traceback object, if one was raised.
- Return type:
None
- is_registered(t)#
Check if type t has a registration already.
- Parameters:
t (
Type[Any]) – The type to check for.- Return type:
bool- Returns:
True if a registration exists.
- register_instance(t, instance=None)#
Register a pre-existing instance for type t.
- Parameters:
t (
Union[Type[Any],object]) – The type to bind the instance to.instance (
Optional[Any]) – (OPTIONAL) An object that must be an instance of t. Omit to construct a t instance automatically.
- Return type:
- Returns:
selffor method chaining.- Raises:
TypeError – When instance is not an instance of t.
Note on @provides#
The
@providesdecorator on the target type is only discovered when *instance* is omitted (no explicit second argument). In that case, the container discovers__hazrakah_providesmetadata and multi-registers the target under every provided interface.When instance IS provided (explicit registration), @provides metadata on the target class is completely ignored. Only the type specified by t is registered. This applies regardless of whether the concrete class implements additional interfaces via @provides.
- register_singleton(t, target=None)#
Create a SINGLETON type registration for type t.
Every resolve of t will result in a single, shared instance of t.
- Parameters:
t (
Type[Any]) – The type to register for.target (
Union[Type[Any],Callable[[DependencyResolver],Any],None]) – The type or factory to be used when resolving type t. Omit to use t as the target (requires t to be a concrete type.)
- Return type:
- Returns:
selffor method chaining.
Note on @provides#
The
@providesdecorator on target is only discovered when *target* is omitted (no explicit second argument). In that case, the container discovers__hazrakah_providesmetadata and multi-registers t under every provided interface.When target IS provided (explicit registration), @provides metadata on the target class is completely ignored. Only the type specified by t is registered. This applies regardless of whether the concrete class implements additional interfaces via @provides.
Examples#
# @provides activates – multi-registers under IFoo, IBar, and MyImpl:
@provides(IFoo, IBar) class MyImpl: … c.register_singleton(MyImpl) # no second arg
# @provides does NOT activate – only IFoo is registered:
c.register_singleton(IFoo, MyImpl) # explicit type override
- register_transient(t, target=None)#
Create a TRANSIENT type registration for type t.
Every resolve of t will result in a new instance of t.
- Parameters:
t (
Type[Any]) – The type to register for.target (
Union[Type[Any],Callable[[DependencyResolver],Any],None]) – The type or factory to be used when resolving type t. Omit to use t as the target (requires t to be a concrete type.)
- Return type:
- Returns:
selffor method chaining.
Note on @provides#
The
@providesdecorator on target is only discovered when *target* is omitted (no explicit second argument). In that case, the container discovers__hazrakah_providesmetadata and multi-registers t under every provided interface.When target IS provided (explicit registration), @provides metadata on the target class is completely ignored. Only the type specified by t is registered. This applies regardless of whether the concrete class implements additional interfaces via @provides.
Examples#
# @provides activates – multi-registers under IFoo, IBar, and MyImpl:
@provides(IFoo, IBar) class MyImpl: … c.register_transient(MyImpl) # no second arg
# @provides does NOT activate – only IFoo is registered:
c.register_transient(IFoo, MyImpl) # explicit type override
- resolve(t)#
- Overloads:
self, t (Type[T]) → T
self, t (Type[Any]) → Any
Resolve a type to its registered implementation.
For union types (e.g.
IFoo | IBar):If the union is
Optional[T](containsNoneType), unwraps toTand resolves normally; returnsNoneifTis unresolvable.For non-Optional unions (e.g.
IFoo | IBar): finds the single registered implementation among the union members. If multiple distinct targets are registered, raisesResolutionError. Unregistered concrete classes are auto-registered as transient.
For non-union types, looks up the registration and dispatches by lifetime:
INSTANCE– returns the stored instance.SINGLETON– creates or returns a shared instance per container scope.TRANSIENT– creates and returns a new instance each time.
- register_decorated()#
Create registrations based on discovered decorators
@singleton,@transient, and@instanced.This method is idempotent – repeated calls overwrite registrations (last-in-wins).
- Return type:
- Returns:
selffor method chaining.
- freeze()#
Freeze the Container.
Any attempt to create registrations after the container has been frozen will result in a
RegistrationError.- Return type:
None
- class DependencyRegistry(*args, **kwargs)#
Bases:
DependencyResolver,ProtocolA protocol for dependency registration (and resolution) tasks.
- is_registered(t)#
Check if type t has a registration already.
- Parameters:
t (
Type[Any]) – The type to check for.- Return type:
bool- Returns:
True if a registration exists.
- register_instance(t, instance)#
Create an INSTANCE type registration for type t.
Every resolve of t will result in the specified object instance.
- Parameters:
t (
Type[Any]) – The type to register for.instance (
Any) – The instance to register.
- Return type:
- Returns:
selffor method chaining (onContainerimplementations).- Raises:
TypeError – When the provided instance is not an instance of type t (type mismatch.)
- register_singleton(t, target=None)#
Create a SINGLETON type registration for type t.
Every resolve of t will result in a single, shared instance of t.
- Parameters:
t (
Type[Any]) – The type to register for.target (
Union[Type[Any],Callable[[DependencyResolver],Any],None]) – The type or factory to be used when resolving type t. Omit to use t as the target (requires t to be a concrete type.)
- Return type:
- Returns:
selffor method chaining (onContainerimplementations).
- register_transient(t, target=None)#
Create a TRANSIENT type registration for type t.
Every resolve of t will result in a new instance of t.
- Parameters:
t (
Type[Any]) – The type to register for.target (
Union[Type[Any],Callable[[DependencyResolver],Any],None]) – The type or factory to be used when resolving type t. Omit to use t as the target (requires t to be a concrete type.)
- Return type:
- Returns:
selffor method chaining (onContainerimplementations).
- class DependencyResolver(*args, **kwargs)#
Bases:
ProtocolA protocol for dependency resolution without exposing registration methods.
- resolve(t)#
Resolve type t using available registrations.
If t has no explicit registration but is a concrete class, create a TRANSIENT instance.
- Parameters:
t (
Type[Any]) – The type to resolve.- Raises:
KeyError – When type t is not a concrete class and has no registration.
RuntimeError – When a registration is malformed.
- Return type:
Any- Returns:
The object instance resolved for type t.
- exception ResolutionError(message, *, cause=None, matched=None)#
Bases:
KeyErrorRaised when a type cannot be resolved.
Typical situations that trigger this error:
No registration found for a concrete or abstract type during
resolve().Multiple registrations for different implementations of a union type alias, making the target ambiguous (e.g.
IFoo | IBarwhere both are registered to different targets).
The
matchedattribute contains all pre-deduplication matches when available, allowing callers to inspect which types were considered during resolution.Create the exception.
- Parameters:
message (
str) – Human-readable description of the problem.cause (
BaseException|None) – Optional original exception that led to this error. It is stored as__cause__so that traceback chaining works automatically.matched (
list[tuple[Type[Any],Any,Lifetime,Any]] |None) – Pre-deduplication list of (type, scope, lifetime, registration) tuples for all matches found during resolution.
- exception RegistrationError(message, *, cause=None)#
Bases:
RuntimeErrorRaised when a registration cannot be processed.
Typical situations that trigger this error:
Attempting to create an instance from a registration that has no
target(e.g. aLifetime.INSTANCEregistration without an associated object).Supplying a factory that does not conform to the expected signature
Callable[[Container], T].Providing an instance to
Container.register_instance()that is not an instance of the registration type.
Create the exception.
- Parameters:
message (
str) – Human-readable description of the problem.cause (
BaseException|None) – Optional original exception that led to this error. It is stored as__cause__so that traceback chaining works automatically.
- class ScopedDependencyResolver(*args, **kwargs)#
Bases:
DependencyResolver,Protocol
- provides(*types)#
Passive marker decorator: declares which protocols cls implements.
Stores metadata on the decorated class via
__hazrakah_provides; zero registration logic at decoration time. Activation depends on how the container registers the class:No explicit type arg on register_* –> @provides triggers multi-registration.
Explicit type arg on register_* –> @provides is ignored.
Usage:
@provides(IFoo, IBar) # stores metadata only class MyClass: ... c.register_singleton(MyClass) # activates: registers IFoo, IBar, MyClass c.register_transient(IBaz, ...) # ignores @provides on other classes @provides() # marker-only, no interfaces (backward compatible)
- Parameters:
types (
Type[Any]) – Protocol types the decorated class implements. Variadic – no tuple wrapping.- Return type:
Callable[[TypeVar(T)],TypeVar(T)]
- singleton(target=None, *, types=None, depends_on=())#
Register target as a singleton.
Usage:
@singleton → self-as (classes only) @singleton(types=IFoo) → explicit interface @singleton(types=(IFoo, IBar)) → multiple interfaces
- Raises:
RegistrationError – If target is already decorated with
@provides— the two decorators are incompatible.- Return type:
Any
- transient(target=None, *, types=None, depends_on=())#
Register target as a transient.
- Return type:
Any
- instanced(target=None, *, types=None, depends_on=())#
Register target as an instance (created once at decoration time).
- Return type:
Any