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 and antidote.core. Other namespaces are susceptible to changes.

  • 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 best effort.

Most, if not all, of the API is annotated with decorators such as @API.public specifying whether the given functionality can be relied upon.

2.0.0 (2022-08-31)#

Antidote core has been entirely reworked to be simpler and provide better static typing in addition of several features. The cython had to be dropped though for now by lack of time. It may eventually come back.

Breaking Changes#

Important#

  • All previously deprecated changes have been removed.

  • The previous Scope concept has been replaced by LifeTime and ScopeGlobalVar.

  • world.test environments API have been reworked. Creating one has a similar API and guarantees, but world.test.factory, world.test.singleton and all of world.test.override have been replaced by a better alternative. See TestContextBuilder.

  • Dependencies cannot be specified through inject({...}) and inject([...]) anymore.

  • QualifiedBy/qualified_by for interface/implementation now relies on equality instead of the id().

  • const API has been reworked. const() and cont.env() have API changes and const.provider has been removed.

  • Thread-safety guarantees from Antidote are now simplified. It now only ensures lifetime consistency and some decorators such as injectable() & interface provide some thread-safety guarantees.

  • Provider has been entirely reworked. It keeps the same name and purpose but has a different API and guarantees.

Core#

  • inject
    • removed dependencies, strict_validation and auto_provide parameters.

    • removed source parameter from Inject.me()

  • Wiring
    • removed dependencies parameter.

    • renamed class_in_localns parameter to class_in_locals in Wiring.wire().

  • wire(): removed dependencies parameter

  • renamed Get to dependencyOf. Usage of inject[]/inject.get is recommended instead for annotations.

  • world
    • Providers are not dependencies anymore. Use Catalog.providers.

    • Providers do not check anymore that a dependency wasn’t defined by another one before. They’re expected to be independent.

    • Exception during dependency retrieval are not wrapped in DependencyInstantiationError anymore

    • FrozenWorldError has been renamed FrozenCatalogError.

    • world.test.new() now generates a test environment equivalent to a freshly created Catalog with new_catalog. It only impacts those using a custom Provider.

    • Removed dependency cycle detection and DependencyCycleError. It wasn’t perfectly accurate and it’s not really worth it. world.debug does a better job at detecting and presenting those cycles.

  • validate_injection() and validated_scope() functions have been removed.

  • DependencyGetter, TypedDependencyGetter are not part of the API anymore.

Injectable#

  • The first argument klass of injectable() is now positional-only.

  • singleton and scope parameters have been replaced by lifetime.

Interface#

Lazy#

  • singleton and scope parameters have been replaced by lifetime.

  • call() function was removed from lazy functions, use the __wrapped__ attribute instead.

  • In test contexts such as world.test.empty() and world.test.new(), previously defined lazy/const dependencies will not be available anymore.

Const#

  • To specify a type for Const.env() use the convert argument.

  • When defining static constant values such as HOST = const('localhost'), it’s NOT possible to:

    • define the type (const[str]('localhost))

    • define a default value

    • not provide value at all anymore

  • const.provider has been removed. Use Lazy.method() instead. The only difference is that the const provider would return different objects even with the same arguments, while the lazy method won’t.

Features#

Core#

  • AEP1: Instead of hack of module/functions world is now a proper instance of PublicCatalog. Alternative catalogs can be created and included in one another. Dependencies can also now be private or public. The main goal is for now to expose a whole group of dependencies through a custom catalog.

    from antidote import new_catalog, inject, injectable, world
    
    # Includes by default all of Antidote
    catalog = new_catalog()
    
    
    # Only accessible from providers by default.
    @injectable(catalog=catalog.private)
    class PrivateDummy:
        ...
    
    
    @injectable(catalog=catalog)  # if catalog is not specified, world is used.
    class Dummy:
        def __init__(self, private_dummy: PrivateDummy = inject.me()) -> None:
            self.private_dummy = private_dummy
    
    
    # Not directly accessible
    assert PrivateDummy not in catalog
    assert isinstance(catalog[Dummy], Dummy)
    
    
    # app_catalog is propagated downwards for all @inject that don't specify it.
    @inject(app_catalog=catalog)
    def f(dummy: Dummy = inject.me()) -> Dummy:
        return dummy
    
    
    assert f() is catalog[Dummy]
    
    # Not inside world yet
    assert Dummy not in world
    world.include(catalog)
    assert world[Dummy] is catalog[Dummy]
    
  • AEP2 (reworked): Antidote now defines a ScopeGlobalVar which has a similar interface to ContextVar and three kind of lifetimes to replace scopes:

    • 'singleton': instantiated only once

    • 'transient': instantiated on every request

    • 'scoped': used by dependencies depending on one or multiple ScopeGlobalVar. When any of them changes, the value is re-computed otherwise it’s cached.

    ScopeGlobalVar isn’t a ContextVar though, it’s a global variable. It’s planned to add a ScopeContextVar.

    from antidote import inject, lazy, ScopeGlobalVar, world
    
    counter = ScopeGlobalVar(default=0)
    
    # Until update, the value stays the same.
    assert world[counter] == 0
    assert world[counter] == 0
    token = counter.set(1)
    assert world[counter] == 1
    
    
    @lazy(lifetime='scoped')
    def dummy(count: int = inject[counter]) -> str:
        return f"Version {count}"
    
    
    # dummy will not be re-computed until counter changes.
    assert world[dummy()] == 'Version 1'
    assert world[dummy()] == 'Version 1'
    counter.reset(token)  # same interface as ContextVar
    assert world[dummy()] == 'Version 0'
    
  • Catalogs, such as world and inject, expose a dict-like read-only API. Typing has also been improved:

    from typing import Optional
    
    from antidote import const, inject, injectable, world
    
    
    class Conf:
        HOST = const('localhost')
        STATIC = 1
    
    
    assert Conf.HOST in world
    assert Conf.STATIC not in world
    assert world[Conf.HOST] == 'localhost'
    assert world.get(Conf.HOST) == 'localhost'
    assert world.get(Conf.STATIC) is None
    assert world.get(Conf.STATIC, default=12) == 12
    
    try:
        world[Conf.STATIC]
    except KeyError:
        pass
    
    
    @injectable
    class Dummy:
        pass
    
    
    assert isinstance(world[Dummy], Dummy)
    assert isinstance(world.get(Dummy), Dummy)
    
    
    @inject
    def f(host: str = inject[Conf.HOST]) -> str:
        return host
    
    
    @inject
    def g(host: Optional[int] = inject.get(Conf.STATIC)) -> Optional[int]:
        return host
    
    
    assert f() == 'localhost'
    assert g() is None
    
  • Testing has a simplified dict-like write-only API:

    from antidote import world
    
    with world.test.new() as overrides:
        # add a singleton / override existing dependency
        overrides['hello'] = 'world'
        # add multiple singletons
        overrides.update({'second': object()})
        # delete a dependency
        del overrides['x']
    
    
        # add a factory
        @overrides.factory('greeting')
        def build() -> str:
            return "Hello!"
    
  • Added Inject.method() which will inject the first argument, commonly self of a method with the dependency defined by the class. It won’t inject when used as instance method though.

    from antidote import inject, injectable, world
    
    
    @injectable
    class Dummy:
        @inject.method
        def method(self) -> 'Dummy':
            return self
    
    
    assert Dummy.method() is world[Dummy]
    dummy = Dummy()
    assert dummy.method() is dummy
    
  • inject now supports wrapping function with *args.

  • inject has now kwargs and fallback keywords to replace the old dependencies. kwargs takes priority over alternative injections styles and fallback is used in the same way as dependencies, after defaults and type hints.

Interface#

  • interface now supports function and lazy calls. It also supports defining the interface as the default function with Interface.as_default():

    from antidote import interface, world, implements
    
    
    @interface
    def callback(x: int) -> int:
        ...
    
    
    @implements(callback)
    def callback_impl(x: int) -> int:
        return x * 2
    
    
    assert world[callback] is callback_impl
    assert world[callback.single()] is callback_impl
    
    
    @interface.lazy.as_default
    def template(name: str) -> str:
        return f"Template {name!r}"
    
    
    assert world[template(name='test')] == "Template 'test'"
    
    
    @implements.lazy(template)
    def template_impl(name: str) -> str:
        return f"Alternative template {name!r}"
    
    
    assert world[template.all()(name='root')] == ["Alternative template 'root'"]
    
  • Better API for Protocol static typing:

    from typing import Protocol
    
    from antidote import implements, instanceOf, interface, world
    
    
    @interface
    class Dummy(Protocol):
        ...
    
    
    @implements.protocol[Dummy]()
    class MyDummy:
        ...
    
    
    assert isinstance(world[instanceOf[Dummy]()], MyDummy)
    assert isinstance(world[instanceOf[Dummy]().single()], MyDummy)
    
  • QualifiedBy relies on equality instead of the id of the objects now. Limitations on the type of qualifiers has also been removed.

    from antidote import implements, interface
    
    
    @interface
    class Dummy:
        ...
    
    
    @implements(Dummy).when(qualified_by='a')
    class A(Dummy):
        ...
    
    
    @implements(Dummy).when(qualified_by='b')
    class B(Dummy):
        ...
    
  • implements has a wiring argument to prevent any wiring.

Lazy#

  • lazy can now wrap (static-)methods and define values/properties:

    from antidote import injectable, lazy, world
    
    
    @lazy.value
    def name() -> str:
        return "John"
    
    
    @injectable  # required for lazy.property & lazy.method
    class Templates:
        @lazy.property
        def main(self) -> str:
            return "Lazy Main Template"
    
        @lazy.method
        def load(self, name: str) -> name:  # has access to self
            return f"Lazy Method Template {name}"
    
        @staticmethod
        @lazy
        def static_load(name: str) -> str:
            return f"Lazy Static Template {name}"
    
    
    world[name]
    world[Templates.main]
    world[Templates.load(name='Alice')]
    world[Templates.static_load(name='Bob')]
    
  • lazy has now an inject argument which can be used to prevent any injection.

1.4.2 (2022-06-26)#

Bug fix#

  • Fix injection error for some union type hints such as str | List[str].

1.4.1 (2022-06-01)#

Bug fix#

1.4.0 (2022-05-22)#

Deprecation#

  • Constants is deprecated as not necessary anymore with the new const.

  • factory() is deprecated in favor of lazy().

Features#

  • lazy() has been added to replace factory() and the parameterized() methods of both Factory and Service.

    from antidote import lazy, inject
    
    class Redis:
        pass
    
    @lazy  # singleton by default
    def load_redis() -> Redis:
        return Redis()
    
    @inject
    def task(redis = load_redis()):
        ...
    
  • const has been entirely reworked for better typing and ease of use:

    • it doesn’t require Constants anymore.

    • environment variables are supported out of the box with Const.env().

    • custom logic for retrieval can be defined with Const.provider().

    Here’s a rough overview:

    from typing import Optional, TypeVar, Type
    
    from antidote import const, injectable
    
    T = TypeVar('T')
    
    class Conf:
        THREADS = const(12)  # static const
        PORT = const.env[int]()  # converted to int automatically
        HOST = const.env("HOSTNAME")  # define environment variable name explicitly,
    
    
    @injectable
    class Conf2:
        # stateful factory. It can also be stateless outside of Conf2.
        @const.provider
        def get(self, name: str, arg: Optional[str]) -> str:
            return arg or name
    
        DUMMY = get.const()
        NUMBER = get.const[int]("90")  # value will be 90
    
  • implements.overriding() overrides an existing implementation, and will be used in exactly the same conditions as the overridden one: default or not, predicates…

  • implements.by_default() defines a default implementation for an interface outside of the weight system.

Experimental#

  • ConstantValueProvider.converter() provides a similar to feature to the legacy auto_cast from Constants.

Bug fix#

  • Better behavior of inject and world.debug() with function wrappers, having a __wrapped__ attribute.

1.3.0 (2022-04-26)#

Deprecation#

  • service() is deprecated in favor of injectable() which is a drop-in replacement.

  • inject() used to raise a RuntimeError when specifying ignore_type_hints=True and no injections were found. It now raises NoInjectionsFoundError

  • Wiring.wire() used to return the wired class, it won’t be the case anymore.

Features#

  • Add local type hint support with type_hints_locals argument for inject(), injectable(), implements and wire(). The default behavior can be configured globally with config. Auto-detection is done through inspect and frame manipulation. It’s mostly helpful inside tests.

    from __future__ import annotations
    
    from antidote import config, inject, injectable, world
    
    
    def function() -> None:
        @injectable
        class Dummy:
            pass
    
        @inject(type_hints_locals='auto')
        def f(dummy: Dummy = inject.me()) -> Dummy:
            return dummy
    
        assert f() is world.get(Dummy)
    
    
    function()
    
    config.auto_detect_type_hints_locals = True
    
    
    def function2() -> None:
        @injectable
        class Dummy:
            pass
    
        @inject
        def f(dummy: Dummy = inject.me()) -> Dummy:
            return dummy
    
        assert f() is world.get(Dummy)
    
    
    function2()
    
  • Add factory_method to injectable() (previous service())

    from __future__ import annotations
    
    from antidote import injectable
    
    
    @injectable(factory_method='build')
    class Dummy:
        @classmethod
        def build(cls) -> Dummy:
            return cls()
    
  • Added ignore_type_hints argument to Wiring and wire().

  • Added type_hints_locals and class_in_localns argument to Wiring.wire.

Bug fix#

  • Fix Optional detection in predicate constraints.

1.2.0 (2022-04-19)#

Bug fix#

  • Fix injection error when using the Klass | None notation instead of Optional[Klass] in Python 3.10.

Features#

  • frozen keyword argument to world.test.clone() which allows one to control whether the cloned world is already frozen or not.

  • Both inject.get and world.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 with qualified_by keyword and requested with either qualified_by or qualified_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 the QualifiedBy 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 with inspect.isfunction, inspect.ismethod, inspect.iscoroutinefunction and inspect.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 and ABCService are deprecated in favor of service().

  • Passing a function to the argument dependencies of inject() is deprecated. If you want to customize how Antidote injects dependencies, just wrap inject() instead.

  • inject()’s auto_provide argument is deprecated. If you rely on this behavior, wrap inject().

  • world.lazy is deprecated. It never brought a lot of value, one can easily write it oneself.

  • dependency @ factory and dependency @ 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 renamed Inject.

  • 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 and const have better type checking behavior, doing it only when the specified type is an actual instance of type. 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 to inject() 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#

  • Added wiring argument to service() and auto-wiring like Service.

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 and WithWiringMixin are not part of the public API anymore. For the first just use world.lazy instead, and the later was experimental.

  • world.scopes.new() argument name is keyword-only now.

0.13.0 (2021-03-24)#

Breaking Change#

  • _with_kwargs() class method has been replaced by Service.parameterized() and Factory.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 or Constants.

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 and Constants are automatically wired to support annotated type hints anywhere.

Breaking changes#

  • Remove public configuration for Factory and Constants. 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 by auto_provide and use_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 by attempt_methods.

Bug fix#

  • Using inject() on __init__() of a Service, 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 to true 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 like world.get[<class>]("x")

    • Add world.lazy for dependencies to retrieve dependencies lazily.

  • implementation() is more flexible than @implements and supports changing the implementation at runtime for example.

  • Service and Factory expose a handy class method with_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, formerly LazyConstantsMeta, 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, use world.test.singleton_all() or world.test.singleton() instead.

  • @register is now replaced by the class Service and provides mostly the same features. The only corner cases are service that used factories, those should now really use a factory, namely Factory or factory. If you cannot inherit the super class for some reason, you may fallback to the class decorator service().

  • @factory for functions behaves the same way, however for factory classes the super class Factory must be used. The dependency identifier has also been to changed, the factory must now be specified like dependency @ factory instead of dependency.

  • LazyConstantsMeta has been replaced by the class Constants. One cannot choose the lazy method anymore, but it is more flexible regarding definition of constants.

  • @implements has been entirely reworked and split into implementation() and Implementation. 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 decorator world.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 in LazyConstantsMeta (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 returned ValueError instead of TypeError 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 for dependencies. 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 as Container.provide() except that it raises an error if the dependency cannot be found instead of returning None.

Breaking changes#

  • Container.provide() returns a DependencyInstance not the instance itself anymore.

  • Rename LazyConfigurationMeta to LazyConstantsMeta.

  • LazyConfigurationMeta default method is get().

  • ServiceProvider renamed to FactoryProvider and reworked ServiceProvider.register() with is split into register_factory(), register_class, register_providable_factory.

Changes#

  • Moved is_compiled to antidote.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 by LazyConfigurationMeta to handle configuration.

Features#

  • Add LazyMethodCall and LazyCall 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 a container argument. By default the global container of Antidote is used. Thus one can easily replace from antidote import antidote to import antidote to adapt existing code.

  • The global container of Antidote, previously named container, has been renamed world.

  • Dependency does not take additional arguments anymore, for custom dependencies Build, 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 use register() with its factory 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