Opyoid follows semver guidelines for versioning.
- Fixed an InjectException raised when trying to bind a class with a stringified parameter type
- Fixed MultiBindings not using the correct provider when having multiple ItemBindings to Providers
- Remove support for Python < 3.8
- MultiBindings now have the parameter
override_bindings
set toFalse
by default (wasTrue
)
- Add official support for Python 3.11
- Opyoid is now PEP561 compliant, and as such compatible with mypy
- Added a Context Scope that can be used to control more precisely the scope of created objects:
from opyoid import ContextScope, Injector, SelfBinding
class MyClass:
pass
injector = Injector(bindings=[SelfBinding(MyClass, scope=ContextScope)])
scope = injector.inject(ContextScope)
with scope:
instance_1 = injector.inject(MyClass)
instance_2 = injector.inject(MyClass)
with scope:
instance_3 = injector.inject(MyClass)
assert instance_1 is instance_2
assert instance_1 is not instance_3
- Built-in types such as strings, ints, floats and booleans can be loaded from enviroment variables
- The environment variable name should be
<UPPER_CLASS_NAME_UPPER_PARAMTER_NAME>
- Use InjectorOptions.use_env_vars to enable/disable the feature (activated by default)
- Check the docs for more details
- The environment variable name should be
- Fixed unwanted bindings being automatically created when using InstanceBindings with builtin types
- Added
named
andscope
parameters to item bindings, by default they keep the parent MultiBinding name and scope (as they did before)
- Module classes can now be installed (instances can still be installed), the contained bindings will be created only once if the module class installed multiple times
- Provider bindings can now bind any typed function as a provider, this is now the preferred way to create providers but provider classes are still supported
- Fixed missing bindings in log when adding item bindings to a previously existing multi binding
- Instances created from a class in a MultiBinding with a Singleton scope can now be reused
- If you have a class A that requires List[B], a multibinding on B that binds subclasses B1 and B2, and another class C that requires B1, the same instance of B1 will be shared between A and the list in C
- Added
conditional_on_env_var
decorator that can be put on modules to easily enable / disable them through environment variables
- Added official support for Python 3.10
- Added support for Union[...] type, which injects the first item type for which bindings exist
- Added support for List[Union[...]] type, which injects a list combining all the items types in the union
- Using auto bindings does not ignore existing bindings anymore (bug introduced in
0.10.0
) - The error message in cyclic dependency errors is now displaying the dependencies in a more logical order (from the parent class to the dependencies)
- Renamed
bound_type
argument inClassBinding
andItemBinding
constructors intobound_class
- Several method signatures now have keyword-only arguments:
named
inInjector.inject
to_class
,to_instance
,to_provider
,scope
andnamed
inAbstractModule.bind
scope
,named
andoverride_bindings
inAbstractModule.multi_bind
to_class
,to_instance
andto_provider
inAbstractModule.bind_item
scope
andnamed
inClassBinding.__init__
bound_class
,bound_instance
,bound_provider
inItemBinding.__init__
named
inInstanceBinding.__init__
scope
,named
andoverride_bindings
inMultiBinding.__init__
scope
andnamed
inProviderBinding.__init__
scope
andnamed
inSelfBinding.__init__
auto_bindings
inInjectorOptions.__init__
- Opyoid is now considered stable
- Improved error message when missing a named binding, the underlying type and name is used
- Improved repr of named types, the original type is now used
- Improved repr of generic types, the full name is now used
- Replaced
@annotated_arg
with@named_arg
- Renamed the
annotation
parameter tonamed
in:- all Binding subclasses
- the
AbstractModule.bind
method - the
Injector.inject
method
- Changed the way annotated/named arguments work:
- When injecting a parameter in a constructor, opyoid will first try to find a binding with the same type and the same name as the argument. If none is found, it will then try to find a binding with the same type and no name (this part did not change).
- If the
@named_arg
decorator is used, opyoid will only try to find a binding with this name, if none is found, no unnamed binding will be used (this did not change).
- Cyclic dependencies now raise a
CyclicDependencyError
instead of aRecursionError
- Cleaner and more verbose logs
- Removed duplicate logs about registering bindings
- ClassBindings cannot be used to bind a class to itself anymore, use a SelfBinding instead
- When binding to a target an instance of a subclass of the target type, another InstanceBinding is created with the same instance and its type as a target
- When binding to a target an instance of a provider, another InstanceBinding is created with the same provider and its type as a target
- Fixed Bindings with a target being overriden by
ClassBindings
with the same target as abound_type
- Support for PEP585 style type hints (list[str], set[str], ...)
- MultiBindings can now be exposed by PrivateModules
- Binding Provider classes in ItemBindings now works as expected
- Non hashable instance bindings can be exposed in private modules
- Fixed a bug preventing injection when using strings as type hints
- Using
auto_bindings=True
will only create a new instance for a parameter if there is no default value.
- Renamed library name to
opyoid
- Removed
scopes_by_type
argument from theInjector
constructor, it is not needed anymore to inject custom scopes - Custom scopes must now be bound to
Scope
. By default,SingletonScope
,ThreadScope
,ImmediateScope
andPerLookupScope
are bound, but they can be overridden.SingletonScope
can only be bound in an instance binding. Scope.get_scoped_provider
is now an instance method, it used to be a class method- Renamed
BindingSpec
toModule
- Renamed
binding_specs
argument tomodules
in Injector constructor - Lists, sets and tuples must now be bound using
MultiBinding
. You can create one from your modules:
class MyModule(Module):
def configure(self):
self.multi_bind(MyClass, [
self.bind_item(MySubClass1),
self.bind_item(MySubClass2),
])
More details are available in the documentation.
- Singletons are now shared between bindings. This means that if you bind the same implementation to two different classes, the same instance will be injected for each class.
- Renamed
Factory
toProvider
- Renamed
FactoryBinding
toProviderBinding
- Renamed
to_factory
argument toto_provider
in theModule.bind
method
- Added
MultiBinding
andItemBinding
- Added
PrivateBindingSpec
- Added
options: InjectorOptions
argument to theInjector
constructor, it has anauto_bindings: bool = False
argument that can be used to implicitly bind all classes to themselves in a SingletonScope. - Added
Provider
injection, you can now injectProvider[MyClass]
and it will return a provider that can be used for delayed instantiation. If aProviderBinding
exists with the right type it will be used instead of creating a new provider.
- You can now bind any binding to a Provider class, by default a ClassBinding with the provider class will be created
- Singleton, Immediate and Thread scopes are now guaranteeing that only one instance of a class can be created for each ClassBinding or FactoryBindings, instead of one instance per bound_type. You can now have multiple instance of the same class if you create multiple bindings instantiating it.
- Added
FactoryBinding
- Added
to_factory: Optional[Union[Type[Factory], Factory]]
argument inBindingsSpec.bind
method
- Adding multiple bindings of the same class with different annotations in the SingletonScope will create different instances, one per binding.
- Fixed an exception being raised when injecting a union of generic types
- Added
Tuple
andSet
injection - Added
ImmediateScope
- Added python>=3.7 compatibility
- Added
@annotated_arg(arg_name, annotation)
decorator - Added
annotation: Optional[str]
parameter inInstanceBinding
andClassBinding
constructors - Added
annotation: Optional[str]
parameter inInjector.inject(target_type: Type[InjectedT], annotation: Optional[str] = None)
- Added
annotation: Optional[str]
parameter inBindingsSpec.bind
method
- Added
Injector
- Added
BindingSpec
- Added
ClassBinding
andInstanceBinding
- Added
SingletonScope
,PerLookupScope
andThreadScope