Skip to main content

Automated dependency injection for Python

Project description

Autoinject

Documentation Status

CircleCI

A clean, simple framework for automatically injecting dependencies into objects and functions based around Python's type-hinting system. The framework provides caching of injectable objects, though this may be disabled on a class-by-class basis. It also supports managing independent caches for different contexts.

Define Injectable Classes

# Easy mode

from autoinject import injector

@injector.injectable
class MyInjectableClass:

    # __init__() should have no additional required arguments
    def __init__(self):
        pass


# Hard mode, must specify the fully-qualified name of the class,
# but gain control over the arguments

@injector.register("example.MyInjectableClass", os.environ("MY_CONFIG_FILE"))
class MyInjectableClass:

    def __init__(self, config_file):
        # we receive os.environ("MY_CONFIG_FILE") as config_file here
        # positional and keyword arguments to @injector.register() are supported
        pass

Inject Objects With Decorators

# Decorate with @injector.inject for functions/methods:

@injector.inject
def inject_me(param1, param2, injected_param: MyInjectableClass):
    # injected_param is set to an instance of MyInjectableClass
    pass

# Omit the injected parameters when calling it:

inject_me("arg1", "arg2")


# For classes, use @injector.construct to set instance attributes 
# based on the class attributes   
class InjectMe:

    injected_attribute: MyInjectableClass = None

    @injector.construct
    def __init__(self):
        # self.injected_attribute is set to an instance of MyInjectableClass
        pass

# No need to do anything special here:
obj = InjectMe()
# obj.injected_attribute is set by the decorator before __init__() is called.

Read the full documentation for more details.

Changelog

v1.2.0

  • Contextvar-driven contexts are now respected by default
  • Several wrappers exist to better support using contextvars. All of them provide for a separate set of injected CONTEXT_CACHE dependencies. In addition, each is a wrapper around @injector.inject, so both are not needed.
    • @injector.with_contextvars: Creates a new context that is a copy of the current one
    • @injector.with_same_contextvars: Uses the current context
    • @injector.with_empty_contextvars: Creates a new empty context
  • When using a with_contextvars wrapper, you can inject the context object using type-hinting (e.g. ctx: contextvars.Context). Note that this is actually an instance of ContextVarsManager which is a context manager that delegates most functionality to the current contextvars.Context object with a few modifications:
    • It provides the method set(context_var, value) -> token and the complementary reset(context_var, token) to handle variable setting and resetting within the context manager.
      • If the "same" context is used, these methods are equivalent to calling the methods directly on the context_var
      • In all other cases, they are equivalent to calling ctx.run(context_var.METHOD, *args, **kwargs).
      • In essence, this makes sure the set() and reset() operations are performed in the context that the manager is managing (since the manager doesn't run the inner block in the context).
    • If the "same" context is used:
      • run() will just directly call the function (it is in the current context essentially)
      • copy() is an alias for contextvars.copy_context()
      • Other functions besides set() and reset() make a copy of the current context and return the results of its method. This copy is transient and remade each time, so modules making extensive use of it can call copy() and check the copy.
  • Note that, unlike the context manager, the decorators also RUN the inner code in the given context.
  • Thread-handling was improved significantly and now also includes a wrapper function for your run() methods to ensure clean-up (@injector.as_thread_run()). This also is a wrapper around @injector.inject so you can inject variables into your run() method directly.

v1.1.0

  • Injectable objects may now define a __cleanup__() method which will be invoked when the global cache or context cache is cleared.
  • Note that __cleanup__() IS NOT INVOKED for one-time use objects at the moment, but this is planned as a feature.

v1.0.1

  • Inherited injectable class members are now supported properly

v1.0.0

  • Official initial release
  • Added support for @injector.injectable_global which registers with GLOBAL cache instead of context-specific cache
  • Added support for @injector.injectable_nocache which registers with NO_CACHE instead
  • Added support for injector.override() as a helper function to replace one constructor with another.
  • Added support for any constructor argument (e.g. via override() or register_constructor()) to be specified by fully-qualified Python name (e.g. package.module.MyInjectableClass) to better support systems where injected classes are specified by name.
  • Fixed a bug whereby the cache wasn't cleared

v0.2.2

  • Fixed a bug for injection when a non-truthy default value needed to be used.

v0.2.1

  • Fixed a bug in Python 3.8 and 3.9 where entry_points(group=?) was not supported

v0.2.0

  • Objects with a cache strategy of CONTEXT_CACHE will now have separate instances within threads
  • Added injector.get() as a fast way to get the object that would be injected (useful if operating outside of a function or method)
  • Added injector.register_constructor() as a wrapper to register a class in a non-decorated fashion
  • Added the entry point autoinject.injectables to directly register injectable classes
  • Added the entry point autoinject.registrars
  • Support for overriding injectables and for injecting functions
  • Added a weight keyword argument to register() and register_construct() to control overriding order
  • There is now a cleanup() function in the ContextManager() class which triggers informant objects to check for old items that are no longer needed. This was added mostly to support the thread-based context informant, since it has no easy way of calling destroy() whenever the thread ends (unless one manually calls it). It is the best practice if you can call destroy() directly whenever a context ceases to exist instead of relying on cleanup().

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

autoinject-1.2.0.tar.gz (22.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

autoinject-1.2.0-py3-none-any.whl (17.4 kB view details)

Uploaded Python 3

File details

Details for the file autoinject-1.2.0.tar.gz.

File metadata

  • Download URL: autoinject-1.2.0.tar.gz
  • Upload date:
  • Size: 22.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.0 CPython/3.7.9

File hashes

Hashes for autoinject-1.2.0.tar.gz
Algorithm Hash digest
SHA256 c511a3d568ef86965ebe3c882531a2b3ff446e42efd324300b3a0c0149b1e50a
MD5 f6bbbace2335e30efb541ced954e0aa3
BLAKE2b-256 7cca12fb6eded1c043be3927c14ed4bc6b392b1ac4f115c9ca90bb57f81d8198

See more details on using hashes here.

File details

Details for the file autoinject-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: autoinject-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.0 CPython/3.7.9

File hashes

Hashes for autoinject-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2a63945c522c92531e558fae2834499bd30279e80963f66b6f961e5cebb9223d
MD5 95c4c3fb470b46449e6368e91203ba05
BLAKE2b-256 78acde1efe795b389312cdbd9ea0819b32ca6c6146cf57ac01f11077dbf57f58

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page