Type-based dependency injection
Project description
.. figure:: https://github.com/Dobiasd/enterprython/raw/master/logo/enterprython.png :alt: logo
logo
|Build Status| |(License MIT 1.0)|
enterprython
Python library providing type-based dependency injection
Table of contents
Introduction <#introduction>
__Features <#features>
__Abstract base classes <#abstract-base-classes>
__Factories <#factories>
__Non-singleton services <#non-singleton-services>
__Service lists <#service-lists>
__Mixing managed and manual injection <#mixing-managed-and-manual-injection>
__Free functions as clients <#free-functions-as-clients>
__Requirements and Installation <#requirements-and-installation>
__
Introduction
If you plan to develop SOLID <https://en.wikipedia.org/wiki/SOLID>
__ /
domain-driven <https://en.wikipedia.org/wiki/Domain-driven_design>
__
(i.e., enterprisey) software, you probably
want <why_you_want_formal_dependency_injection_in_python_too.md>
__ to
apply inversion of control <https://en.wikipedia.org/wiki/Inversion_of_control>
__ in the
form of dependency injection <https://en.wikipedia.org/wiki/Dependency_injection>
__ when
writing the constructors of your classes. Also you likely want to use a
library doing the needed lookups for you based on static type
annotations, instead of manually configuring the object graph.
enterprython
provides exactly that.
.. code:: python
from enterprython import assemble, component
@component()
class Service:
def __init__(self) -> None:
self._greeting: str = 'Hello'
def greet(self, name: str) -> str:
return f'{self._greeting}, {name}!'
class Client:
def __init__(self, service: Service) -> None:
self._service = service
def run(self) -> None:
print(self._service.greet('World'))
assemble(Client).run()
Output:
.. code:: text
Hello, World!
Features
Abstract base classes
A client may depend on an abstract base class. Enterprython will inject
the matching implementation.
.. code:: python
from abc import ABC
from enterprython import assemble, component
class ServiceInterface(ABC):
...
@component()
class ServiceImpl(ServiceInterface):
...
class Client:
def __init__(self, services: ServiceInterface) -> None:
...
assemble(Client)
One singleton instance of ``ServiceImpl`` is created and injected into
``Client``.
Factories
~~~~~~~~~
Annotating a function with ``@factory()`` registers a factory for its
return type.
.. code:: python
from enterprython import assemble, component
class Service:
...
@factory()
def service_factory() -> Service:
return Service()
class Client:
def __init__(self, service: Service) -> None:
...
assemble(Client)
``service_factory`` is used to create the ``Service`` instance for
calling the constructor of ``Client``.
Non-singleton services
If a service is annotated with @component(singleton=False)
a new
instance of it is created with every injection.
.. code:: python
@component(singleton=False)
class Service:
...
class Client:
def __init__(self, service: Service) -> None:
...
Service lists
A client may depend on a list of implementations of a service interface.
.. code:: python
from abc import ABC
from typing import List
from enterprython import assemble, component
class ServiceInterface(ABC):
pass
@component()
class ServiceA(ServiceInterface):
...
@component()
class ServiceB(ServiceInterface):
...
class Client:
def __init__(self, services: List[ServiceInterface]) -> None:
...
assemble(Client)
``[ServiceA(), ServiceB()]`` is injected into ``Client``.
Mixing managed and manual injection
One part of a client's dependencies might be injected manually, the rest automatically.
.. code:: python
from enterprython import assemble, component
@component()
class ServiceA:
...
class ServiceB:
...
class Client:
def __init__(self, service_a: ServiceA, service_b: ServiceB) -> None:
...
assemble(Client, service_b=ServiceB())
service_a
comes from the DI container, service_b
from user code.
If ServiceB
also has a @component()
annotation, the manually
provided object is preferred.
Free functions as clients
Since class constructors are fundamentally just normal functions, we can
inject dependencies into free functions too.
.. code:: python
from enterprython import assemble, component
@component()
class Service:
...
def client(service: Service) -> None:
...
assemble(client)
A singleton instance of ``Service`` is created and used to call
``client``.
Requirements and Installation
-----------------------------
You need Python 3.6.5 or higher.
.. code:: bash
python3 -m pip install enterprython
Or, if you like to use latest version from this repository:
.. code:: bash
git clone https://github.com/Dobiasd/enterprython
cd enterprython
python3 -m pip install .
License
-------
Distributed under the MIT License. (See accompanying file
```LICENSE`` <https://github.com/Dobiasd/enterprython/blob/master/LICENSE>`__
or at https://opensource.org/licenses/MIT)
.. |Build Status| image:: https://travis-ci.org/Dobiasd/enterprython.svg?branch=master
:target: https://travis-ci.org/Dobiasd/enterprython
.. |(License MIT 1.0)| image:: https://img.shields.io/badge/license-MIT%201.0-blue.svg
:target: LICENSE
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file enterprython-0.5.3.tar.gz
.
File metadata
- Download URL: enterprython-0.5.3.tar.gz
- Upload date:
- Size: 10.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | bcbe3def95151f2b4bd4718c0d9333488e5bef1d2557712467eaa2de1c4ce6c3 |
|
MD5 | 79267385e04955cf54d3a75b8aff4ba0 |
|
BLAKE2b-256 | 1173413492a6d6cd2ae12eff264659b2466f38d4f1295f3fb127d51aad3f2df0 |
File details
Details for the file enterprython-0.5.3-py3-none-any.whl
.
File metadata
- Download URL: enterprython-0.5.3-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 29c33c3c0ea1dead72d5de4eaae224a7dcc8bb31f1d7be3b20dd61e1e9f039b4 |
|
MD5 | 55266a411fb33f45d2541daaba9ad4ed |
|
BLAKE2b-256 | 6a6ae79237c8434c0330eea6cc990b348d5dea20519ac5d60927566708cedec7 |