Changelog
For any given version N
, all releases N.X.X
guarantee:
API stability: Python code that used to work will continue work.
Namespace stability for
antidote
,antidote.core
andantidote.exceptions
. All other namespaces have no guarantees.best effort for static type hints stability. Meaning that code relying on Antidote that used to pass MyPy or any other static type checker should continue working, but it’s not guaranteed.
Most, if not all, the API is annotated with decorators such as @API.public
specifying whether
the given functionality can be relied upon.
1.2.0 (2022-04-19)
Bug fix
Fix injection error when using the
Klass | None
notation instead ofOptional[Klass]
in Python 3.10.
Features
frozen
keyword argument toworld.test.clone()
which allows one to control whether the cloned world is already frozen or not.Both
inject.get
andworld.get
now strictly follow the same API.interface()
and py:class:implements which provide a cleaner way to separate implementations from the public interface. Qualifiers are also supported out of the box. They can be added withqualified_by
keyword and requested with eitherqualified_by
orqualified_by_one_of
.from antidote import implements, inject, interface, world, QualifiedBy V1 = object() V2 = object() @interface class Service: pass @implements(Service).when(qualified_by=V1) class ServiceImpl(Service): pass @implements(Service).when(QualifiedBy(V2)) class ServiceImplV2(Service): pass world.get[Service].single(qualified_by=V1) world.get[Service].all() @inject def f(service: Service = inject.me(QualifiedBy(V2))) -> Service: return service @inject def f(services: list[Service] = inject.me(qualified_by=[V1, V2])) -> list[Service]: return services
Experimental
Predicate
API is experimental allows you to define your custom logic for selecting the right implementation for a given interface. Qualifiers are implemented with theQualifiedBy
predicate which is part of the public API.
1.1.1 (2022-03-25)
Bug fix
Injected functions/methods with
inject()
did not behave correctly withinspect.isfunction
,inspect.ismethod
,inspect.iscoroutinefunction
andinspect.iscoroutine
.
1.1.0 (2022-03-19)
Breaking static typing change
A function decorated with
factory()
will not have the@
operator anymore from a static typing perspective. It’s unfortunately not possible with the addition of the class support for the decorator.
Deprecation
Service
andABCService
are deprecated in favor ofservice()
.Passing a function to the argument
dependencies
ofinject()
is deprecated. If you want to customize how Antidote injects dependencies, just wrapinject()
instead.inject()
’sauto_provide
argument is deprecated. If you rely on this behavior, wrapinject()
.world.lazy
is deprecated. It never brought a lot of value, one can easily write it oneself.dependency @ factory
anddependency @ implementation
are replaced by the more explicit notation:world.get(dependency, source=factory) @inject(dependencies={'db': Get(dependency, source=factory)}) def (db): ...
Annotation
Provide
has been renamedInject
.world.get
will not support extracting annotated dependencies anymore.Omitting the dependency when a type is specified in
world.get
is deprecated.world.get
provides now better type information.from antidote import world, service @service class Dummy: pass # this will expose the correct type: world.get(Dummy) # so this is deprecated world.get[Dummy]() # you can still specify the type explicitly world.get[Dummy](Dummy)
Change
Both
world.get
andconst
have better type checking behavior, doing it only when the specified type is an actual instance oftype
. For protocols, type check will only be done with those decorated with@typing.runtime_checkable
.Dropped Python 3.6 support.
Features
Add
ignore_type_hints
toinject()
to support cases when type hints cannot be evaluated, typically in circular imports.Adding Markers for
inject()
used as default arguments to declare injections:from antidote import const, Constants, factory, inject, service class Config(Constants): HOST = const[str]("host") @service class Dummy: value: str @factory def dummy_factory() -> Dummy: return Dummy() # inject type hint @inject def f(dummy: Dummy = inject.me()) -> Dummy: return dummy # inject type hint with factory @inject def f2(dummy: Dummy = inject.me(source=dummy_factory)) -> Dummy: return dummy # inject constants @inject def f3(host: str = Config.HOST) -> str: return host # inject a dependency explicitly @inject def f4(x=inject.get(Dummy)) -> Dummy: return x # inject a dependency with a factory explicitly @inject def f5(x=inject.get(Dummy, source=dummy_factory)) -> Dummy: return x
1.0.1 (2021-11-06)
Change
Update
fastrlock
dependency to>=0.7,<0.9
to support Python 3.10 for the compiled version.
1.0.0 (2021-04-29)
No changes. From now on breaking changes will be avoided as much as possible.
0.14.2 (2021-04-28)
Features
0.14.1 (2021-04-25)
Features
Added
ABCService
for services to be easier to work with ABC abstract classes.Added support for a function in
auto_provide
0.14.0 (2021-03-30)
Breaking Change
LazyDependency
andWithWiringMixin
are not part of the public API anymore. For the first just useworld.lazy
instead, and the later was experimental.world.scopes.new()
argumentname
is keyword-only now.
0.13.0 (2021-03-24)
Breaking Change
_with_kwargs()
class method has been replaced byService.parameterized()
andFactory.parameterized()
with a cleaner design. Now parameters must be explicitly defined in their respective configuration. Those will be verified to ensure they don’t have any injections or default values, as sanity checks. Otherwise passing the default value as a parameter or relying on the actual default would not point to the same dependency value.
0.12.1 (2021-03-07)
Change
Improved
world.test.clone()
performance to be as fast as possible to avoid any overhead in tests in the compiled version.
0.12.0 (2021-02-06)
Feature / Breaking Change
Add runtime type checks when a type is explicitly defined with
world.get
,world.lazy
orConstants
.
0.11.0 (2021-02-05)
Features
Add scope support.
Add annotated type hints support (PEP-593).
Add async injection support.
Multiple factories can be defined for the same class.
Cleaner testing support, by separating explicitly the case where test existing dependencies or want to create new ones.
All methods of
Service
,Factory
andConstants
are automatically wired to support annotated type hints anywhere.
Breaking changes
Remove
public
configuration forFactory
andConstants
. They didn’t really bring any value, you hardly hide anything in Python.Removed tags. They didn’t bring enough value.
Reworked
inject()
: it will only inject annotated type, nothing else anymore.use_type_hint
has been replaced byauto_provide
anduse_names
has been removed.Reworked
Constants
to be more flexible.Removed
world.singletons
. There was no way to track back where a singleton was defined.Reworked
Wiring
to be simpler, not super class wiring
0.10.0 (2020-12-24)
Breaking change
In
Wiring
,ignore_missing_methods
has been replaced byattempt_methods
.
Bug fix
Using
inject()
on__init__()
of aService
, or any methods injected by default by Antidote, will not raise a double injection error anymore.
0.9.0 (2020-12-23)
Features
Antidote exposes its type information (PEP 561) and passes strict Mypy (with implicit optionals).
Breaking changes
Antidote exceptions have no public attributes anymore.
Injecting twice the same function/method will raise an error.
Constants
has been simplified,const()
is now simply always required to define a constant.
Changes
Better, simpler
DependencyInstantiationError
when a deeply nested dependency fails.Cleaner packaging: Antidote will only try to compile Cython when the environment variable
ANTIDOTE_COMPILED
is set totrue
and doesn’t require Cython to be pre-installed to do so. Antidote’s version is also hardcoded at publish time.Added a Scope example in the documentation. It is a bit more complicated than I would like, but scopes are hard
0.8.0 (2020-12-09)
Features
- Reworked entirely
world
: Cleaner singletons declarations in
world.singletons
Test utilities in
world.test
. Those allow you to change locally, withing a context manager, dependencies declarations. Hence you can replace an existing dependency by a mock for example.Override utilities in
world.test.override
to be used in tests.Debug utility
world.debug()
which returns a tree of all the dependencies that will/may be retrieved by Antidote.Add type hints to
world.get
which can now be used likeworld.get[<class>]("x")
Add
world.lazy
for dependencies to retrieve dependencies lazily.
- Reworked entirely
implementation()
is more flexible than@implements
and supports changing the implementation at runtime for example.Service
andFactory
expose a handy class methodwith_kwargs()
which allows you to specify some key word argument to customize the service you’re retrieving. Typically you would have only one database service class but use this feature to have two different dependencies which each point to different database.Constants
, formerlyLazyConstantsMeta
, supports a new of defining constants:const()
. It has two purposes, explicitly define constants and optionally specify the actual type.Added
world.freeze()
which will prevent any new dependencies to be added.
Breaking changes
Drop support of Python 3.5.
Singletons do check for duplicates now. Hence one cannot redefine an existing singleton through
world
.world.update_singletons
does not exists anymore, useworld.test.singleton_all()
orworld.test.singleton()
instead.@register
is now replaced by the classService
and provides mostly the same features. The only corner cases are service that used factories, those should now really use a factory, namelyFactory
orfactory
. If you cannot inherit the super class for some reason, you may fallback to the class decoratorservice()
.@factory
for functions behaves the same way, however for factory classes the super classFactory
must be used. The dependency identifier has also been to changed, the factory must now be specified likedependency @ factory
instead ofdependency
.LazyConstantsMeta
has been replaced by the classConstants
. One cannot choose the lazy method anymore, but it is more flexible regarding definition of constants.@implements
has been entirely reworked and split intoimplementation()
andImplementation
. The latter can be used for straightforward cases where only one implementation exists. The first lets you handle all other cases with multiple implementations which can vary during runtime or not.@provider
has been replaced by the class decoratorworld.provider()
.Everything related to the container management has been removed for the public interface.
Changes
Add Python 3.9 support.
public APIs are clearly defined as such, marked by
@API.public
. Overall public API is also better defined.Improved Cython performance
0.7.2 (2020-04-21)
Bug fixes
The wrapper of the injection function didn’t behave exactly like a proxy for the all of the wrapped functions attributes. Furthermore the Cython version didn’t support setting dynamically attributes at all.
0.7.0 (2020-01-15)
Breaking changes
@register
does not wire__init__()
anymore if a function is provided as a factory. This didn’t make a lot of sense,__init__()
is wrapped automatically if and only if it is treated as the “factory” that creates the object.Now when using
dependencies
argument with a sequence (matching dependencies with arguments through their position), the first argument will be ignored for methods (self) and classmethod (cls). So now you can write:from antidote import inject, service class Service: @inject(dependencies=('dependency',)) def method(self, arg1): ... @inject(dependencies=('dependency',)) @classmethod def method(cls, arg1): ... @service(dependencies=('dependency',)) class Service2: def __init__(self, arg1): ...
Hence all other decorators profit from this. No need anymore to explicitly ignore
self
.
Bug fixes
Prevent double
LazyMethodCall
wrapping inLazyConstantsMeta
(Thanks @keelerm84)@inject
cannot be applied on classes. This was never intended as it would not return a class. Use@wire
instead if you relied on this.@inject
returnedValueError
instead ofTypeError
in with erroneous types.@register
now raises an error when using a method as a factory that is neither a classmethod nor a staticmethod. It was never intended to use methods, as it would not make sense.
Changes
When wrapping multiple methods,
@wire
used to raise an error if a sequence was provided fordependencies
. This limitation has been removed.
0.6.1 (2019-12-01)
Add support for Python 3.8
0.6.0 (2019-05-06)
Features
Add
@implements
to define service implementing an interface.Add
IndirectProvider()
which supports@implements
.Add
Container.safe_provide()
which does the same asContainer.provide()
except that it raises an error if the dependency cannot be found instead of returning None.
Breaking changes
Container.provide()
returns aDependencyInstance
not the instance itself anymore.Rename
LazyConfigurationMeta
toLazyConstantsMeta
.LazyConfigurationMeta
default method isget()
.ServiceProvider
renamed toFactoryProvider
and reworkedServiceProvider.register()
with is split intoregister_factory()
,register_class
,register_providable_factory
.
Changes
Moved
is_compiled
toantidote.utils
.Add better type hints.
0.5.1 (2019-04-27)
Features
Add
is_compiled()
to check whether the current version is compiled or pure python.
0.5.0 (2019-04-27)
Breaking changes
@resource
has been removed an replaced byLazyConfigurationMeta
to handle configuration.
Features
Add
LazyMethodCall
andLazyCall
to support output of functions as dependencies.
Changes
Add better type hints for helper decorators.
0.4.0 (2019-02-03)
A lot of internals have changed, but it can roughly be resumed as the following:
Breaking changes
The
DependencyManager
does not exist anymore and has been replaced by multiple helpers which accepts acontainer
argument. By default the global container of Antidote is used. Thus one can easily replacefrom antidote import antidote
toimport antidote
to adapt existing code.The global container of Antidote, previously named
container
, has been renamedworld
.Dependency
does not take additional arguments anymore, for custom dependenciesBuild
,Tagged
must be used instead.Custom providers must inherit
Provider
.register_parameters()
has been replaced by a more general function,resource()
. See the documentation to imitate its functionality.factory()
is more strict. Subclasses are not handled anymore, one should useregister()
with itsfactory
argument instead.
Features
Dependencies can be tagged at registration. Those can then be retrieved as a dependency. This allows one to extend an app by registering a service in special way just by adding a tag.
Type hints usage can now be finely controlled or disabled with
use_type_hints
.Add
resource()
to support custom resources, such as configuration.Dependency providers are more strict for more maintainable code.
Use of Cython for better injection performance.
0.3.0 (2018-04-29)
Initial release