mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-02-18 04:20:46 +03:00
Merge branch 'release/3.41.0' into master
This commit is contained in:
commit
31f15c0a13
68
docs/examples-other/chained-factories.rst
Normal file
68
docs/examples-other/chained-factories.rst
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
Chained Factories pattern
|
||||||
|
=========================
|
||||||
|
|
||||||
|
This example demonstrates "Chained Factories" pattern.
|
||||||
|
|
||||||
|
The idea of the pattern is in wrapping ``Factory`` into another ``Factory`` that adds
|
||||||
|
additional arguments.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
base_factory = providers.Factory(
|
||||||
|
SomeClass,
|
||||||
|
base_argument=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
concrete_factory = providers.Factory(
|
||||||
|
base_factory,
|
||||||
|
extra_argument=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
instance = concrete_factory()
|
||||||
|
# Same as: # instance = SomeClass(base_argument=1, extra_argument=2)
|
||||||
|
|
||||||
|
Sample code
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Listing of the pattern example:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/factory-patterns/chained_factories.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
Arguments priority
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Passing of the arguments works the same way like for any other :ref:`factory-provider`.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# 1. Keyword arguments of upper level factory are added to lower level factory
|
||||||
|
chained_dict_factory = providers.Factory(
|
||||||
|
providers.Factory(dict, arg1=1),
|
||||||
|
arg2=2,
|
||||||
|
)
|
||||||
|
print(chained_dict_factory()) # prints: {'arg1': 1, 'arg2': 2}
|
||||||
|
|
||||||
|
# 2. Keyword arguments of upper level factory have priority
|
||||||
|
chained_dict_factory = providers.Factory(
|
||||||
|
providers.Factory(dict, arg1=1),
|
||||||
|
arg1=2,
|
||||||
|
)
|
||||||
|
print(chained_dict_factory()) # prints: {'arg1': 2}
|
||||||
|
|
||||||
|
# 3. Keyword arguments provided from context have the most priority
|
||||||
|
chained_dict_factory = providers.Factory(
|
||||||
|
providers.Factory(dict, arg1=1),
|
||||||
|
arg1=2,
|
||||||
|
)
|
||||||
|
print(chained_dict_factory(arg1=3)) # prints: {'arg1': 3}
|
||||||
|
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
The "Chained Factories" pattern was suggested by the ``Dependency Injector`` users.
|
||||||
|
|
||||||
|
.. disqus::
|
|
@ -1,21 +0,0 @@
|
||||||
Chained Factories pattern
|
|
||||||
=========================
|
|
||||||
|
|
||||||
This example demonstrate implementation of "Chained Factories" pattern.
|
|
||||||
Main idea of this pattern is about wrapping :py:class:`Factory` into
|
|
||||||
another :py:class:`Factory` that mix additional arguments or keyword
|
|
||||||
arguments to a wrapped one.
|
|
||||||
|
|
||||||
Listing of ``data.py``, demonstrates sample classes structure:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Listing of ``chained_factories.py``, demonstrates "Chained Factories"
|
|
||||||
pattern and provide some explanation:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/chained_factories.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
|
74
docs/examples-other/factory-of-factories.rst
Normal file
74
docs/examples-other/factory-of-factories.rst
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
Factory of Factories pattern
|
||||||
|
============================
|
||||||
|
|
||||||
|
This example demonstrates "Factory of Factories" pattern.
|
||||||
|
|
||||||
|
The idea of the pattern is in creating a ``Factory`` that creates another ``Factory`` and adds
|
||||||
|
additional arguments.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
base_factory = providers.Factory(
|
||||||
|
providers.Factory
|
||||||
|
SomeClass,
|
||||||
|
base_argument=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
concrete_factory = providers.Factory(
|
||||||
|
OtherClass,
|
||||||
|
instance=base_factory(extra_argument=1),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
instance = concrete_factory()
|
||||||
|
# Same as: # instance = SomeClass(base_argument=1, extra_argument=2)
|
||||||
|
|
||||||
|
Sample code
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Listing of the pattern example:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/factory-patterns/factory_of_factories.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
Arguments priority
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Passing of the arguments works the same way like for any other :ref:`factory-provider`.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# 1. Keyword arguments of upper level factory are added to lower level factory
|
||||||
|
factory_of_dict_factories = providers.Factory(
|
||||||
|
providers.Factory,
|
||||||
|
dict,
|
||||||
|
arg1=1,
|
||||||
|
)
|
||||||
|
dict_factory = factory_of_dict_factories(arg2=2)
|
||||||
|
print(dict_factory()) # prints: {'arg1': 1, 'arg2': 2}
|
||||||
|
|
||||||
|
# 2. Keyword arguments of upper level factory have priority
|
||||||
|
factory_of_dict_factories = providers.Factory(
|
||||||
|
providers.Factory,
|
||||||
|
dict,
|
||||||
|
arg1=1,
|
||||||
|
)
|
||||||
|
dict_factory = factory_of_dict_factories(arg1=2)
|
||||||
|
print(dict_factory()) # prints: {'arg1': 2}
|
||||||
|
|
||||||
|
# 3. Keyword arguments provided from context have the most priority
|
||||||
|
factory_of_dict_factories = providers.Factory(
|
||||||
|
providers.Factory,
|
||||||
|
dict,
|
||||||
|
arg1=1,
|
||||||
|
)
|
||||||
|
dict_factory = factory_of_dict_factories(arg1=2)
|
||||||
|
print(dict_factory(arg1=3)) # prints: {'arg1': 3}
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
The "Factory of Factories" pattern was suggested by the ``Dependency Injector`` users.
|
||||||
|
|
||||||
|
.. disqus::
|
|
@ -1,20 +0,0 @@
|
||||||
Factory of Factories pattern
|
|
||||||
============================
|
|
||||||
|
|
||||||
This example demonstrate implementation of "Factory of Factories" pattern.
|
|
||||||
Main idea of this pattern is about creation of a :py:class:`Factory` that
|
|
||||||
creates another :py:class:`Factory` and mix additional arguments to it.
|
|
||||||
|
|
||||||
Listing of ``data.py``, demonstrates sample classes structure:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Listing of ``factory_of_factories.py``, demonstrates "Chained Factories"
|
|
||||||
pattern and provide some explanation:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/factory_of_factories.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
|
|
@ -2,18 +2,16 @@ Other examples
|
||||||
==============
|
==============
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
:keywords: Python,Dependency Injection,Inversion of Control,Container,Example,Application,
|
||||||
:description: Current section of documentation is designed to provide
|
Framework
|
||||||
several example mini applications that are built on the top
|
:description: This sections contains assorted Dependency Injector examples.
|
||||||
of inversion of control principle and powered by
|
|
||||||
"Dependency Injector" framework.
|
|
||||||
|
|
||||||
This sections contains assorted ``Dependency Injector`` examples.
|
This sections contains assorted ``Dependency Injector`` examples.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
use_cases_miniapp
|
use-cases
|
||||||
password_hashing_miniapp
|
password-hashing
|
||||||
chained_factories
|
chained-factories
|
||||||
factory_of_factories
|
factory-of-factories
|
||||||
|
|
30
docs/examples-other/password-hashing.rst
Normal file
30
docs/examples-other/password-hashing.rst
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Password hashing example
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,Dependency Injection,Inversion of Control,Container,Example,Application,
|
||||||
|
Framework,Callable
|
||||||
|
:description: This example demonstrates a usage of the Callable provider.
|
||||||
|
|
||||||
|
This example demonstrates an injection of the ``Callable`` provider.
|
||||||
|
|
||||||
|
The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/password-hashing>`_.
|
||||||
|
|
||||||
|
Sample code
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Listing of the pattern example:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/password-hashing/example.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
Run the example
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Instructions for running:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python example.py
|
||||||
|
|
||||||
|
.. disqus::
|
|
@ -1,18 +0,0 @@
|
||||||
Dependency injection and password hashing in Python
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
Small example that demonstrates using of dependency injection for user
|
|
||||||
password hashing.
|
|
||||||
|
|
||||||
Instructions for running:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python example.py
|
|
||||||
|
|
||||||
Listing of ``example.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/password_hashing/example.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
.. disqus::
|
|
74
docs/examples-other/use-cases.rst
Normal file
74
docs/examples-other/use-cases.rst
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
Use cases example
|
||||||
|
=================
|
||||||
|
|
||||||
|
.. meta::
|
||||||
|
:keywords: Python,Dependency Injection,Inversion of Control,Container,Example,Application,
|
||||||
|
Framework,DependenciesContainer
|
||||||
|
:description: This example demonstrates a usage of the DependenciesContainer provider.
|
||||||
|
|
||||||
|
This example demonstrates a usage of the ``DependenciesContainer`` provider.
|
||||||
|
|
||||||
|
The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/decoupled-packages>`_.
|
||||||
|
|
||||||
|
Application structure
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Example application has next structure:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
|
||||||
|
./
|
||||||
|
└── example/
|
||||||
|
├── __init__.py
|
||||||
|
├── __main__.py
|
||||||
|
├── adapters.py
|
||||||
|
├── containers.py
|
||||||
|
└── usecases.py
|
||||||
|
|
||||||
|
Containers
|
||||||
|
----------
|
||||||
|
|
||||||
|
Listing of the ``example/containers.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/use-cases/example/containers.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
Main module
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Listing of the ``example/__main__.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/use-cases/example/__main__.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
|
||||||
|
Run the application
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Instructions for running in the "test" mode:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python run.py test example@example.com
|
||||||
|
|
||||||
|
Instructions for running in the "prod" mode:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python run.py prod example@example.com
|
||||||
|
|
||||||
|
Adapters and use cases
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Listing of the ``example/adapters.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/use-cases/example/adapters.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
Listing of the ``example/usecases.py``:
|
||||||
|
|
||||||
|
.. literalinclude:: ../../examples/miniapps/use-cases/example/usecases.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
.. disqus::
|
|
@ -1,55 +0,0 @@
|
||||||
Use cases mini application example
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
.. currentmodule:: dependency_injector.providers
|
|
||||||
|
|
||||||
"Use cases" miniapp demonstrate usage of :py:class:`DependenciesContainer`
|
|
||||||
provider.
|
|
||||||
|
|
||||||
Example application
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
"Use cases" mini application has next structure:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
use_cases/
|
|
||||||
example/ <-- Example package
|
|
||||||
__init__.py
|
|
||||||
adapters.py
|
|
||||||
use_cases.py
|
|
||||||
containers.py <-- Dependency injection containers
|
|
||||||
run.py <-- Entrypoint
|
|
||||||
|
|
||||||
|
|
||||||
IoC containers
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Listing of ``use_cases/containers.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/use_cases/containers.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Run application
|
|
||||||
~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Listing of ``run.py``:
|
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/use_cases/run.py
|
|
||||||
:language: python
|
|
||||||
|
|
||||||
Instructions for running:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python run.py prod example@example.com # Running in "production" environment
|
|
||||||
python run.py test example@example.com # Running in "testing" environment
|
|
||||||
|
|
||||||
Links
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
+ `Dependency Injector <https://github.com/ets-labs/python-dependency-injector/>`_
|
|
||||||
+ `Full example sources <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/use_cases>`_
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _decoupled-packages:
|
||||||
|
|
||||||
Decoupled packages example (multiple containers)
|
Decoupled packages example (multiple containers)
|
||||||
================================================
|
================================================
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,7 @@ Choose one of the following as a next step:
|
||||||
- Look at application examples:
|
- Look at application examples:
|
||||||
- :ref:`application-single-container`
|
- :ref:`application-single-container`
|
||||||
- :ref:`application-multiple-containers`
|
- :ref:`application-multiple-containers`
|
||||||
|
- :ref:`decoupled-packages`
|
||||||
- Pass the tutorials:
|
- Pass the tutorials:
|
||||||
- :ref:`flask-tutorial`
|
- :ref:`flask-tutorial`
|
||||||
- :ref:`aiohttp-tutorial`
|
- :ref:`aiohttp-tutorial`
|
||||||
|
|
|
@ -178,6 +178,7 @@ Choose one of the following as a next step:
|
||||||
- Look at application examples:
|
- Look at application examples:
|
||||||
- :ref:`application-single-container`
|
- :ref:`application-single-container`
|
||||||
- :ref:`application-multiple-containers`
|
- :ref:`application-multiple-containers`
|
||||||
|
- :ref:`decoupled-packages`
|
||||||
- Pass the tutorials:
|
- Pass the tutorials:
|
||||||
- :ref:`flask-tutorial`
|
- :ref:`flask-tutorial`
|
||||||
- :ref:`aiohttp-tutorial`
|
- :ref:`aiohttp-tutorial`
|
||||||
|
|
|
@ -7,6 +7,17 @@ that were made in every particular version.
|
||||||
From version 0.7.6 *Dependency Injector* framework strictly
|
From version 0.7.6 *Dependency Injector* framework strictly
|
||||||
follows `Semantic versioning`_
|
follows `Semantic versioning`_
|
||||||
|
|
||||||
|
3.41.0
|
||||||
|
------
|
||||||
|
- Refactor "use cases" example.
|
||||||
|
- Refactor "password hashing" example.
|
||||||
|
- Refactor "chained factories" pattern example.
|
||||||
|
- Refactor "factory of factories" pattern example.
|
||||||
|
- Fix declarative container mypy stub to ``__init__`` to accept not only providers.
|
||||||
|
- Refactor main module of the "decoupled packages" example.
|
||||||
|
- Delete "api client" example mini app.
|
||||||
|
- Delete "mail service" example mini app.
|
||||||
|
|
||||||
3.40.0
|
3.40.0
|
||||||
------
|
------
|
||||||
- Add "Decoupled packages" example.
|
- Add "Decoupled packages" example.
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
"""API client module."""
|
|
||||||
|
|
||||||
|
|
||||||
class ApiClient:
|
|
||||||
"""Some API client."""
|
|
||||||
|
|
||||||
def __init__(self, host, api_key):
|
|
||||||
"""Initialize instance."""
|
|
||||||
self.host = host
|
|
||||||
self.api_key = api_key
|
|
||||||
|
|
||||||
def call(self, operation, data):
|
|
||||||
"""Make some network operations."""
|
|
||||||
print('API call [{0}:{1}], method - {2}, data - {3}'.format(
|
|
||||||
self.host, self.api_key, operation, repr(data)))
|
|
|
@ -1,36 +0,0 @@
|
||||||
"""Main module."""
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
import api
|
|
||||||
import models
|
|
||||||
|
|
||||||
|
|
||||||
# Creating ApiClient and User providers:
|
|
||||||
api_client = providers.Singleton(api.ApiClient,
|
|
||||||
host='production.com',
|
|
||||||
api_key='PROD_API_KEY')
|
|
||||||
user_factory = providers.Factory(models.User,
|
|
||||||
api_client=api_client)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# Creating several users and register them:
|
|
||||||
user1 = user_factory(1)
|
|
||||||
user1.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data -
|
|
||||||
# {'id': 1}
|
|
||||||
|
|
||||||
user2 = user_factory(2)
|
|
||||||
user2.register()
|
|
||||||
# API call [production.com:PROD_API_KEY], method - register, data -
|
|
||||||
# {'id': 2}
|
|
||||||
|
|
||||||
# Overriding of ApiClient on dev environment:
|
|
||||||
api_client.override(providers.Singleton(api.ApiClient,
|
|
||||||
host='localhost',
|
|
||||||
api_key='DEV_API_KEY'))
|
|
||||||
|
|
||||||
user3 = user_factory(3)
|
|
||||||
user3.register()
|
|
||||||
# API call [localhost:DEV_API_KEY], method - register, data - {'id': 3}
|
|
|
@ -1,14 +0,0 @@
|
||||||
"""Models module."""
|
|
||||||
|
|
||||||
|
|
||||||
class User:
|
|
||||||
"""User model."""
|
|
||||||
|
|
||||||
def __init__(self, id, api_client):
|
|
||||||
"""Initialize instance."""
|
|
||||||
self.id = id
|
|
||||||
self.api_client = api_client
|
|
||||||
|
|
||||||
def register(self):
|
|
||||||
"""Register user."""
|
|
||||||
self.api_client.call('register', {'id': self.id})
|
|
|
@ -1,12 +0,0 @@
|
||||||
"""Tests module."""
|
|
||||||
|
|
||||||
from unittest.mock import Mock
|
|
||||||
|
|
||||||
import main
|
|
||||||
import api
|
|
||||||
|
|
||||||
# Mock ApiClient for testing:
|
|
||||||
with main.api_client.override(Mock(api.ApiClient)) as api_client_mock:
|
|
||||||
user = main.user_factory('test')
|
|
||||||
user.register()
|
|
||||||
api_client_mock().call.assert_called_with('register', {'id': 'test'})
|
|
|
@ -3,7 +3,7 @@
|
||||||
from .containers import ApplicationContainer
|
from .containers import ApplicationContainer
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main() -> None:
|
||||||
application = ApplicationContainer()
|
application = ApplicationContainer()
|
||||||
application.config.from_ini('config.ini')
|
application.config.from_ini('config.ini')
|
||||||
|
|
||||||
|
@ -22,3 +22,7 @@ if __name__ == '__main__':
|
||||||
assert aggregation_service.user_repository is user_repository
|
assert aggregation_service.user_repository is user_repository
|
||||||
assert aggregation_service.photo_repository is photo_repository
|
assert aggregation_service.photo_repository is photo_repository
|
||||||
print('Aggregate analytics from user and photo packages')
|
print('Aggregate analytics from user and photo packages')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
73
examples/miniapps/factory-patterns/chained_factories.py
Normal file
73
examples/miniapps/factory-patterns/chained_factories.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
"""`Chained Factories` pattern."""
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
|
class SqlAlchemyDatabaseService:
|
||||||
|
|
||||||
|
def __init__(self, session, base_class):
|
||||||
|
self.session = session
|
||||||
|
self.base_class = base_class
|
||||||
|
|
||||||
|
|
||||||
|
class TokensService:
|
||||||
|
|
||||||
|
def __init__(self, id_generator, database):
|
||||||
|
self.id_generator = id_generator
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
|
||||||
|
class Token:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class UsersService:
|
||||||
|
|
||||||
|
def __init__(self, id_generator, database):
|
||||||
|
self.id_generator = id_generator
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
|
||||||
|
class User:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Sample objects
|
||||||
|
session = object()
|
||||||
|
id_generator = object()
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
database = providers.Factory(
|
||||||
|
SqlAlchemyDatabaseService,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
|
||||||
|
token_service = providers.Factory(
|
||||||
|
TokensService,
|
||||||
|
id_generator=id_generator,
|
||||||
|
database=providers.Factory(
|
||||||
|
database,
|
||||||
|
base_class=Token,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UsersService,
|
||||||
|
id_generator=id_generator,
|
||||||
|
database=providers.Factory(
|
||||||
|
database,
|
||||||
|
base_class=User,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
token_service = container.token_service()
|
||||||
|
assert token_service.database.base_class is Token
|
||||||
|
|
||||||
|
user_service = container.user_service()
|
||||||
|
assert user_service.database.base_class is User
|
68
examples/miniapps/factory-patterns/factory_of_factories.py
Normal file
68
examples/miniapps/factory-patterns/factory_of_factories.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
"""`Factory of Factories` pattern."""
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
|
class SqlAlchemyDatabaseService:
|
||||||
|
|
||||||
|
def __init__(self, session, base_class):
|
||||||
|
self.session = session
|
||||||
|
self.base_class = base_class
|
||||||
|
|
||||||
|
|
||||||
|
class TokensService:
|
||||||
|
|
||||||
|
def __init__(self, id_generator, database):
|
||||||
|
self.id_generator = id_generator
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
|
||||||
|
class Token:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class UsersService:
|
||||||
|
|
||||||
|
def __init__(self, id_generator, database):
|
||||||
|
self.id_generator = id_generator
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
|
||||||
|
class User:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Sample objects
|
||||||
|
session = object()
|
||||||
|
id_generator = object()
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
database_factory = providers.Factory(
|
||||||
|
providers.Factory,
|
||||||
|
SqlAlchemyDatabaseService,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
|
||||||
|
token_service = providers.Factory(
|
||||||
|
TokensService,
|
||||||
|
id_generator=id_generator,
|
||||||
|
database=database_factory(base_class=Token),
|
||||||
|
)
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UsersService,
|
||||||
|
id_generator=id_generator,
|
||||||
|
database=database_factory(base_class=User),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
token_service = container.token_service()
|
||||||
|
assert token_service.database.base_class is Token
|
||||||
|
|
||||||
|
user_service = container.user_service()
|
||||||
|
assert user_service.database.base_class is User
|
|
@ -1,59 +0,0 @@
|
||||||
"""`Chained Factories` pattern."""
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
from data import (
|
|
||||||
id_generator,
|
|
||||||
session,
|
|
||||||
SqlAlchemyDatabaseService,
|
|
||||||
TokensService,
|
|
||||||
Token,
|
|
||||||
UsersService,
|
|
||||||
User,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# "Chained Factories" pattern
|
|
||||||
|
|
||||||
database = providers.Factory(SqlAlchemyDatabaseService, session=session)
|
|
||||||
|
|
||||||
tokens = providers.Factory(
|
|
||||||
TokensService,
|
|
||||||
id_generator=id_generator,
|
|
||||||
database=providers.Factory(database, base_class=Token),
|
|
||||||
)
|
|
||||||
|
|
||||||
users = providers.Factory(
|
|
||||||
UsersService,
|
|
||||||
id_generator=id_generator,
|
|
||||||
database=providers.Factory(database, base_class=User),
|
|
||||||
)
|
|
||||||
|
|
||||||
tokens_service = tokens()
|
|
||||||
assert tokens_service.database.base_class is Token
|
|
||||||
|
|
||||||
users_service = users()
|
|
||||||
assert users_service.database.base_class is User
|
|
||||||
|
|
||||||
# Explanation & some more examples
|
|
||||||
|
|
||||||
# 1. Keyword arguments of upper level factory are added to lower level factory
|
|
||||||
chained_dict_factory = providers.Factory(
|
|
||||||
providers.Factory(dict, arg1=1),
|
|
||||||
arg2=2,
|
|
||||||
)
|
|
||||||
print(chained_dict_factory()) # prints: {'arg1': 1, 'arg2': 2}
|
|
||||||
|
|
||||||
# 2. Keyword arguments of upper level factory have priority
|
|
||||||
chained_dict_factory = providers.Factory(
|
|
||||||
providers.Factory(dict, arg1=1),
|
|
||||||
arg1=2,
|
|
||||||
)
|
|
||||||
print(chained_dict_factory()) # prints: {'arg1': 2}
|
|
||||||
|
|
||||||
# 3. Keyword arguments provided from context have most priority
|
|
||||||
chained_dict_factory = providers.Factory(
|
|
||||||
providers.Factory(dict, arg1=1),
|
|
||||||
arg1=2,
|
|
||||||
)
|
|
||||||
print(chained_dict_factory(arg1=3)) # prints: {'arg1': 3}
|
|
|
@ -1,41 +0,0 @@
|
||||||
"""Sample data classes."""
|
|
||||||
|
|
||||||
|
|
||||||
class SqlAlchemyDatabaseService:
|
|
||||||
"""Database service of an entity."""
|
|
||||||
|
|
||||||
def __init__(self, session, base_class):
|
|
||||||
"""Initialize object."""
|
|
||||||
self.session = session
|
|
||||||
self.base_class = base_class
|
|
||||||
|
|
||||||
|
|
||||||
class TokensService:
|
|
||||||
"""Tokens service."""
|
|
||||||
|
|
||||||
def __init__(self, id_generator, database):
|
|
||||||
"""Initialize object."""
|
|
||||||
self.id_generator = id_generator
|
|
||||||
self.database = database
|
|
||||||
|
|
||||||
|
|
||||||
class Token:
|
|
||||||
"""Token entity."""
|
|
||||||
|
|
||||||
|
|
||||||
class UsersService:
|
|
||||||
"""Users service."""
|
|
||||||
|
|
||||||
def __init__(self, id_generator, database):
|
|
||||||
"""Initialize object."""
|
|
||||||
self.id_generator = id_generator
|
|
||||||
self.database = database
|
|
||||||
|
|
||||||
|
|
||||||
class User:
|
|
||||||
"""User entity."""
|
|
||||||
|
|
||||||
|
|
||||||
# Sample objects
|
|
||||||
session = object()
|
|
||||||
id_generator = object()
|
|
|
@ -1,69 +0,0 @@
|
||||||
"""`Factory of Factories` pattern."""
|
|
||||||
|
|
||||||
from dependency_injector import providers
|
|
||||||
|
|
||||||
from data import (
|
|
||||||
id_generator,
|
|
||||||
session,
|
|
||||||
SqlAlchemyDatabaseService,
|
|
||||||
TokensService,
|
|
||||||
Token,
|
|
||||||
UsersService,
|
|
||||||
User,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# "Factory of Factories" pattern
|
|
||||||
|
|
||||||
database_factory = providers.Factory(
|
|
||||||
providers.Factory,
|
|
||||||
SqlAlchemyDatabaseService,
|
|
||||||
session=session,
|
|
||||||
)
|
|
||||||
|
|
||||||
tokens = providers.Factory(
|
|
||||||
TokensService,
|
|
||||||
id_generator=id_generator,
|
|
||||||
database=database_factory(base_class=Token),
|
|
||||||
)
|
|
||||||
|
|
||||||
users = providers.Factory(
|
|
||||||
UsersService,
|
|
||||||
id_generator=id_generator,
|
|
||||||
database=database_factory(base_class=User),
|
|
||||||
)
|
|
||||||
|
|
||||||
tokens_service = tokens()
|
|
||||||
assert tokens_service.database.base_class is Token
|
|
||||||
|
|
||||||
users_service = users()
|
|
||||||
assert users_service.database.base_class is User
|
|
||||||
|
|
||||||
# Explanation & some more examples
|
|
||||||
|
|
||||||
# 1. Keyword arguments of upper level factory are added to lower level factory
|
|
||||||
factory_of_dict_factories = providers.Factory(
|
|
||||||
providers.Factory,
|
|
||||||
dict,
|
|
||||||
arg1=1,
|
|
||||||
)
|
|
||||||
dict_factory = factory_of_dict_factories(arg2=2)
|
|
||||||
print(dict_factory()) # prints: {'arg1': 1, 'arg2': 2}
|
|
||||||
|
|
||||||
# 2. Keyword arguments of upper level factory have priority
|
|
||||||
factory_of_dict_factories = providers.Factory(
|
|
||||||
providers.Factory,
|
|
||||||
dict,
|
|
||||||
arg1=1,
|
|
||||||
)
|
|
||||||
dict_factory = factory_of_dict_factories(arg1=2)
|
|
||||||
print(dict_factory()) # prints: {'arg1': 2}
|
|
||||||
|
|
||||||
# 3. Keyword arguments provided from context have most priority
|
|
||||||
factory_of_dict_factories = providers.Factory(
|
|
||||||
providers.Factory,
|
|
||||||
dict,
|
|
||||||
arg1=1,
|
|
||||||
)
|
|
||||||
dict_factory = factory_of_dict_factories(arg1=2)
|
|
||||||
print(dict_factory(arg1=3)) # prints: {'arg1': 3}
|
|
|
@ -1,41 +0,0 @@
|
||||||
"""Mail service and user registration DI container example."""
|
|
||||||
|
|
||||||
from dependency_injector.containers import DeclarativeContainer
|
|
||||||
from dependency_injector.providers import Callable, Singleton
|
|
||||||
|
|
||||||
import example
|
|
||||||
|
|
||||||
|
|
||||||
class Container(DeclarativeContainer):
|
|
||||||
"""DI container."""
|
|
||||||
|
|
||||||
mail_service = Singleton(example.MailService,
|
|
||||||
host='localhost',
|
|
||||||
port=587,
|
|
||||||
login='my_login',
|
|
||||||
password='super_secret_password')
|
|
||||||
|
|
||||||
add_user = Callable(example.add_user,
|
|
||||||
mailer=mail_service)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print('Using real mail service:')
|
|
||||||
Container.add_user('sample@mail.com', 'password')
|
|
||||||
# Using real mail service:
|
|
||||||
# Connecting server localhost:587 with my_login:super_secret_password
|
|
||||||
# Sending "Your password is password" to "sample@mail.com"
|
|
||||||
|
|
||||||
print('Using mail service stub:')
|
|
||||||
Container.add_user('sample@mail.com', 'password',
|
|
||||||
mailer=example.MailServiceStub())
|
|
||||||
# Using mail service stub:
|
|
||||||
# Emulating sending "Your password is password" to "sample@mail.com"
|
|
||||||
|
|
||||||
# Also you can override provider by another provider:
|
|
||||||
Container.mail_service.override(Singleton(example.MailServiceStub))
|
|
||||||
print('Using mail service stub by overriding mail service provider:')
|
|
||||||
Container.add_user('sample@mail.com', 'password')
|
|
||||||
# Using mail service stub by overriding mail service provider:
|
|
||||||
# Emulating sending "Your password is password" to "sample@mail.com"
|
|
||||||
Container.mail_service.reset_override() # Resetting provider overriding
|
|
|
@ -1,39 +0,0 @@
|
||||||
"""Mail service and user registration example."""
|
|
||||||
|
|
||||||
|
|
||||||
class AbstractMailService:
|
|
||||||
"""Abstract mail service."""
|
|
||||||
|
|
||||||
def send(self, email, body):
|
|
||||||
"""Send email."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class MailService(AbstractMailService):
|
|
||||||
"""Mail service."""
|
|
||||||
|
|
||||||
def __init__(self, host, port, login, password):
|
|
||||||
"""Initialize instance."""
|
|
||||||
self._host = host
|
|
||||||
self._port = port
|
|
||||||
self._login = login
|
|
||||||
self._password = password
|
|
||||||
|
|
||||||
def send(self, email, body):
|
|
||||||
"""Send email."""
|
|
||||||
print('Connecting server {0}:{1} with {2}:{3}'.format(
|
|
||||||
self._host, self._port, self._login, self._password))
|
|
||||||
print('Sending "{0}" to "{1}"'.format(body, email))
|
|
||||||
|
|
||||||
|
|
||||||
class MailServiceStub(AbstractMailService):
|
|
||||||
"""Mail service stub."""
|
|
||||||
|
|
||||||
def send(self, email, body):
|
|
||||||
"""Send email."""
|
|
||||||
print('Emulating sending "{0}" to "{1}"'.format(body, email))
|
|
||||||
|
|
||||||
|
|
||||||
def add_user(email, password, mailer):
|
|
||||||
"""Register user."""
|
|
||||||
mailer.send(email, 'Your password is {0}'.format(password))
|
|
10
examples/miniapps/password-hashing/README.rst
Normal file
10
examples/miniapps/password-hashing/README.rst
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Password hashing
|
||||||
|
================
|
||||||
|
|
||||||
|
This example demonstrates an injection of the ``Callable`` provider.
|
||||||
|
|
||||||
|
Instructions for running:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python example.py
|
50
examples/miniapps/password-hashing/example.py
Normal file
50
examples/miniapps/password-hashing/example.py
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
"""Password hashing example."""
|
||||||
|
|
||||||
|
from typing import Callable, Dict
|
||||||
|
|
||||||
|
import passlib.hash
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
|
||||||
|
class UserService:
|
||||||
|
|
||||||
|
def __init__(self, password_hasher: Callable[[str], str]) -> None:
|
||||||
|
self._password_hasher = password_hasher
|
||||||
|
|
||||||
|
def create_user(self, name: str, password: str) -> Dict[str, str]:
|
||||||
|
hashed_password = self._password_hasher(password)
|
||||||
|
return {
|
||||||
|
'name': name,
|
||||||
|
'password': hashed_password,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
config = providers.Configuration()
|
||||||
|
|
||||||
|
password_hasher = providers.Callable(
|
||||||
|
passlib.hash.sha256_crypt.hash,
|
||||||
|
salt_size=config.salt_size,
|
||||||
|
rounds=config.rounds,
|
||||||
|
)
|
||||||
|
|
||||||
|
user_service = providers.Factory(
|
||||||
|
UserService,
|
||||||
|
password_hasher=password_hasher.provider,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
container = Container(
|
||||||
|
config={
|
||||||
|
'salt_size': 16,
|
||||||
|
'rounds': 10000,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
user_service = container.user_service()
|
||||||
|
|
||||||
|
user = user_service.create_user(name='Roman', password='secret1')
|
||||||
|
print(user)
|
|
@ -1,12 +0,0 @@
|
||||||
Dependency injection and password hashing in Python
|
|
||||||
===================================================
|
|
||||||
|
|
||||||
Small example that demonstrates using of dependency injection for user
|
|
||||||
password hashing.
|
|
||||||
|
|
||||||
|
|
||||||
instructions for running:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python example.py
|
|
|
@ -1,42 +0,0 @@
|
||||||
"""Example of dependency injection and password hashing in Python."""
|
|
||||||
|
|
||||||
import passlib.hash
|
|
||||||
|
|
||||||
import dependency_injector.containers as containers
|
|
||||||
import dependency_injector.providers as providers
|
|
||||||
|
|
||||||
|
|
||||||
class UsersService:
|
|
||||||
"""Users service."""
|
|
||||||
|
|
||||||
def __init__(self, password_hasher):
|
|
||||||
"""Initialize instance."""
|
|
||||||
self._password_hasher = password_hasher
|
|
||||||
|
|
||||||
def create_user(self, name, password):
|
|
||||||
"""Create user with hashed password."""
|
|
||||||
hashed_password = self._password_hasher(password)
|
|
||||||
return dict(name=name, password=hashed_password)
|
|
||||||
|
|
||||||
|
|
||||||
class Container(containers.DeclarativeContainer):
|
|
||||||
"""Inversion of control container."""
|
|
||||||
|
|
||||||
password_hasher = providers.Callable(
|
|
||||||
passlib.hash.sha256_crypt.hash,
|
|
||||||
salt_size=16,
|
|
||||||
rounds=10000)
|
|
||||||
|
|
||||||
users_service = providers.Factory(
|
|
||||||
UsersService,
|
|
||||||
password_hasher=password_hasher.provider)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
container = Container()
|
|
||||||
users_service = container.users_service()
|
|
||||||
|
|
||||||
user1 = users_service.create_user(name='Roman', password='secret1')
|
|
||||||
user2 = users_service.create_user(name='Vitaly', password='secret2')
|
|
||||||
|
|
||||||
print(user1, user2)
|
|
11
examples/miniapps/use-cases/README.rst
Normal file
11
examples/miniapps/use-cases/README.rst
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Use cases
|
||||||
|
=========
|
||||||
|
|
||||||
|
This example demonstrates a usage of the ``DependenciesContainer`` provider.
|
||||||
|
|
||||||
|
Instructions for running:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python -m example prod example@example.com
|
||||||
|
python -m example test example@example.com
|
1
examples/miniapps/use-cases/example/__init__.py
Normal file
1
examples/miniapps/use-cases/example/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"""Top-level package."""
|
|
@ -1,19 +1,23 @@
|
||||||
"""Run 'Use Cases' example application."""
|
"""Main module."""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from containers import Adapters, TestAdapters, UseCases
|
from .containers import UseCases, Adapters, TestAdapters
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main(environment: str, email: str) -> None:
|
||||||
environment, email = sys.argv[1:]
|
|
||||||
|
|
||||||
if environment == 'prod':
|
if environment == 'prod':
|
||||||
adapters = Adapters()
|
adapters = Adapters()
|
||||||
elif environment == 'test':
|
elif environment == 'test':
|
||||||
adapters = TestAdapters()
|
adapters = TestAdapters()
|
||||||
|
else:
|
||||||
|
raise RuntimeError('Unknown environment')
|
||||||
|
|
||||||
use_cases = UseCases(adapters=adapters)
|
use_cases = UseCases(adapters=adapters)
|
||||||
|
|
||||||
use_case = use_cases.signup()
|
use_case = use_cases.signup()
|
||||||
use_case.execute(email)
|
use_case.execute(email)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(*sys.argv[1:])
|
22
examples/miniapps/use-cases/example/adapters.py
Normal file
22
examples/miniapps/use-cases/example/adapters.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Adapters module."""
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
|
||||||
|
class EmailSender(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def send(self, to: str, body: str) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class SmtpEmailSender:
|
||||||
|
|
||||||
|
def send(self, to: str, body: str) -> None:
|
||||||
|
print(f'Sending an email to {to} over SMTP, body="{body}"')
|
||||||
|
|
||||||
|
|
||||||
|
class EchoEmailSender:
|
||||||
|
|
||||||
|
def send(self, to: str, body: str) -> None:
|
||||||
|
print(f'Fake sending an email to {to}, body="{body}"')
|
25
examples/miniapps/use-cases/example/containers.py
Normal file
25
examples/miniapps/use-cases/example/containers.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
"""Containers module."""
|
||||||
|
|
||||||
|
from dependency_injector import containers, providers
|
||||||
|
|
||||||
|
from . import adapters, usecases
|
||||||
|
|
||||||
|
|
||||||
|
class Adapters(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
email_sender = providers.Singleton(adapters.SmtpEmailSender)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAdapters(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
email_sender = providers.Singleton(adapters.EchoEmailSender)
|
||||||
|
|
||||||
|
|
||||||
|
class UseCases(containers.DeclarativeContainer):
|
||||||
|
|
||||||
|
adapters = providers.DependenciesContainer()
|
||||||
|
|
||||||
|
signup = providers.Factory(
|
||||||
|
usecases.SignupUseCase,
|
||||||
|
email_sender=adapters.email_sender,
|
||||||
|
)
|
22
examples/miniapps/use-cases/example/usecases.py
Normal file
22
examples/miniapps/use-cases/example/usecases.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
"""Use cases module."""
|
||||||
|
|
||||||
|
import abc
|
||||||
|
|
||||||
|
from .adapters import EmailSender
|
||||||
|
|
||||||
|
|
||||||
|
class UseCase(metaclass=abc.ABCMeta):
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def execute(self) -> None:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class SignupUseCase:
|
||||||
|
|
||||||
|
def __init__(self, email_sender: EmailSender) -> None:
|
||||||
|
self.email_sender = email_sender
|
||||||
|
|
||||||
|
def execute(self, email: str) -> None:
|
||||||
|
print(f'Sign up user {email}')
|
||||||
|
self.email_sender.send(email, f'Welcome, {email}')
|
|
@ -1,9 +0,0 @@
|
||||||
Dependency Injector Use Cases example
|
|
||||||
=====================================
|
|
||||||
|
|
||||||
Instructions for running
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
python run.py prod example@example.com # Running in "production" environment
|
|
||||||
python run.py test example@example.com # Running in "testing" environment
|
|
|
@ -1,30 +0,0 @@
|
||||||
"""Dependency injection containers for 'Use Cases' example application."""
|
|
||||||
|
|
||||||
from dependency_injector import containers, providers
|
|
||||||
|
|
||||||
from example.adapters import SmtpEmailSender, EchoEmailSender
|
|
||||||
from example.use_cases import SignupUseCase
|
|
||||||
|
|
||||||
|
|
||||||
class Adapters(containers.DeclarativeContainer):
|
|
||||||
"""Adapters container."""
|
|
||||||
|
|
||||||
email_sender = providers.Singleton(SmtpEmailSender)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAdapters(containers.DeclarativeContainer):
|
|
||||||
"""Adapters container.
|
|
||||||
|
|
||||||
This container is used for testing purposes.
|
|
||||||
"""
|
|
||||||
|
|
||||||
email_sender = providers.Singleton(EchoEmailSender)
|
|
||||||
|
|
||||||
|
|
||||||
class UseCases(containers.DeclarativeContainer):
|
|
||||||
"""Use cases container."""
|
|
||||||
|
|
||||||
adapters = providers.DependenciesContainer()
|
|
||||||
|
|
||||||
signup = providers.Factory(SignupUseCase,
|
|
||||||
email_sender=adapters.email_sender)
|
|
|
@ -1 +0,0 @@
|
||||||
"""Example top-level package."""
|
|
|
@ -1,25 +0,0 @@
|
||||||
"""Example adapters package."""
|
|
||||||
|
|
||||||
|
|
||||||
class EmailSender:
|
|
||||||
"""Abstract email sender."""
|
|
||||||
|
|
||||||
def send(self, to, body):
|
|
||||||
"""Send email to specified email."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class SmtpEmailSender:
|
|
||||||
"""SMTP email sender uses SMTP protocol for sending emails."""
|
|
||||||
|
|
||||||
def send(self, to, body):
|
|
||||||
"""Send email to specified email."""
|
|
||||||
# Send email via SMTP
|
|
||||||
|
|
||||||
|
|
||||||
class EchoEmailSender:
|
|
||||||
"""Echo email sender prints emails to stdout."""
|
|
||||||
|
|
||||||
def send(self, to, body):
|
|
||||||
"""Send email to specified email."""
|
|
||||||
print('Sending email to "{0}", body = "{1}"'.format(to, body))
|
|
|
@ -1,22 +0,0 @@
|
||||||
"""Example use cases package."""
|
|
||||||
|
|
||||||
|
|
||||||
class UseCase:
|
|
||||||
"""Abstract use case."""
|
|
||||||
|
|
||||||
def execute(self):
|
|
||||||
"""Execute use case handling."""
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
|
|
||||||
class SignupUseCase:
|
|
||||||
"""Sign up use cases registers users."""
|
|
||||||
|
|
||||||
def __init__(self, email_sender):
|
|
||||||
"""Initialize instance."""
|
|
||||||
self.email_sender = email_sender
|
|
||||||
|
|
||||||
def execute(self, email):
|
|
||||||
"""Execute use case handling."""
|
|
||||||
print('Sign up user {0}'.format(email))
|
|
||||||
self.email_sender.send(email, 'Welcome, "{}"'.format(email))
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Dependency injector top-level package."""
|
"""Dependency injector top-level package."""
|
||||||
|
|
||||||
__version__ = '3.40.0'
|
__version__ = '3.41.0'
|
||||||
"""Version number that follows semantic versioning.
|
"""Version number that follows semantic versioning.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
|
@ -24,7 +24,7 @@ class DynamicContainer(Container): ...
|
||||||
class DeclarativeContainer(Container):
|
class DeclarativeContainer(Container):
|
||||||
cls_providers: ClassVar[Dict[str, Provider]]
|
cls_providers: ClassVar[Dict[str, Provider]]
|
||||||
inherited_providers: ClassVar[Dict[str, Provider]]
|
inherited_providers: ClassVar[Dict[str, Provider]]
|
||||||
def __init__(self, **overriding_providers: Provider) -> None: ...
|
def __init__(self, **overriding_providers: Union[Provider, Any]) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
def override(container: Container) -> _Callable[[Container], Container]: ...
|
def override(container: Container) -> _Callable[[Container], Container]: ...
|
||||||
|
|
Loading…
Reference in New Issue
Block a user