mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2024-11-23 01:56:58 +03:00
Merge branch 'release/3.22.0' into master
This commit is contained in:
commit
3ee629eb5d
12
README.rst
12
README.rst
|
@ -55,10 +55,12 @@ What is ``Dependency Injector``?
|
||||||
Why do I need it?
|
Why do I need it?
|
||||||
=================
|
=================
|
||||||
|
|
||||||
``Dependency Injector`` helps you improve application structure.
|
``Dependency Injector`` helps you understand and change the structure of the application.
|
||||||
|
|
||||||
With the ``Dependency Injector`` you keep **application structure in one place**.
|
With the ``Dependency Injector`` you keep **application structure in one place**.
|
||||||
This place is called **the container**. You use the container to manage all the components of the application. All the component dependencies are defined explicitly. This provides the control on the application structure. It is **easy to understand and change** it.
|
This place is called **the container**. You use the container to manage all the components of the
|
||||||
|
application. All the component dependencies are defined explicitly. This provides the control on
|
||||||
|
the application structure. It is **easy to understand and change** it.
|
||||||
|
|
||||||
.. figure:: https://raw.githubusercontent.com/wiki/ets-labs/python-dependency-injector/img/di-map.svg
|
.. figure:: https://raw.githubusercontent.com/wiki/ets-labs/python-dependency-injector/img/di-map.svg
|
||||||
:target: https://github.com/ets-labs/python-dependency-injector
|
:target: https://github.com/ets-labs/python-dependency-injector
|
||||||
|
@ -72,6 +74,7 @@ This place is called **the container**. You use the container to manage all the
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from dependency_injector.ext import flask
|
from dependency_injector.ext import flask
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
from flask_bootstrap import Bootstrap
|
||||||
from github import Github
|
from github import Github
|
||||||
|
|
||||||
from . import views, services
|
from . import views, services
|
||||||
|
@ -82,6 +85,8 @@ This place is called **the container**. You use the container to manage all the
|
||||||
|
|
||||||
app = flask.Application(Flask, __name__)
|
app = flask.Application(Flask, __name__)
|
||||||
|
|
||||||
|
bootstrap = flask.Extension(Bootstrap)
|
||||||
|
|
||||||
config = providers.Configuration()
|
config = providers.Configuration()
|
||||||
|
|
||||||
github_client = providers.Factory(
|
github_client = providers.Factory(
|
||||||
|
@ -118,6 +123,9 @@ Running such container looks like this:
|
||||||
app = container.app()
|
app = container.app()
|
||||||
app.container = container
|
app.container = container
|
||||||
|
|
||||||
|
bootstrap = container.bootstrap()
|
||||||
|
bootstrap.init_app(app)
|
||||||
|
|
||||||
app.add_url_rule('/', view_func=container.index_view.as_view())
|
app.add_url_rule('/', view_func=container.index_view.as_view())
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
1
docs/_static/logo.svg
vendored
Normal file
1
docs/_static/logo.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 5.6 KiB |
|
@ -1,5 +1,5 @@
|
||||||
``dependency_injector.containers``
|
dependency_injector.containers
|
||||||
----------------------------------
|
==============================
|
||||||
|
|
||||||
.. automodule:: dependency_injector.containers
|
.. automodule:: dependency_injector.containers
|
||||||
:members:
|
:members:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
``dependency_injector.errors``
|
dependency_injector.errors
|
||||||
------------------------------
|
==========================
|
||||||
|
|
||||||
.. automodule:: dependency_injector.errors
|
.. automodule:: dependency_injector.errors
|
||||||
:members:
|
:members:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
``dependency_injector.ext.flask``
|
dependency_injector.ext.flask
|
||||||
---------------------------------
|
=============================
|
||||||
|
|
||||||
.. automodule:: dependency_injector.ext.flask
|
.. automodule:: dependency_injector.ext.flask
|
||||||
:members:
|
:members:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
``dependency_injector.providers``
|
dependency_injector.providers
|
||||||
---------------------------------
|
=============================
|
||||||
|
|
||||||
.. automodule:: dependency_injector.providers
|
.. automodule:: dependency_injector.providers
|
||||||
:members:
|
:members:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
``dependency_injector``
|
dependency_injector
|
||||||
-----------------------
|
===================
|
||||||
|
|
||||||
.. automodule:: dependency_injector
|
.. automodule:: dependency_injector
|
||||||
:members: __version__
|
:members: __version__
|
||||||
|
|
26
docs/conf.py
26
docs/conf.py
|
@ -15,6 +15,7 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import alabaster
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
# add these directories to sys.path here. If the directory is relative to the
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
@ -29,8 +30,11 @@ sys.path.insert(0, os.path.abspath('..'))
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = ['sphinx.ext.autodoc',
|
extensions = [
|
||||||
'sphinxcontrib.disqus']
|
'alabaster',
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
'sphinxcontrib.disqus',
|
||||||
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
@ -112,7 +116,8 @@ todo_include_todos = False
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'sphinx_rtd_theme'
|
# html_theme = 'sphinx_rtd_theme'
|
||||||
|
html_theme = 'alabaster'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
@ -120,7 +125,7 @@ html_theme = 'sphinx_rtd_theme'
|
||||||
# html_context = {}
|
# html_context = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
#html_theme_path = ['_themes']
|
html_theme_path = [alabaster.get_path()]
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
|
@ -291,6 +296,13 @@ autodoc_member_order = 'bysource'
|
||||||
|
|
||||||
disqus_shortname = 'python-dependency-injector'
|
disqus_shortname = 'python-dependency-injector'
|
||||||
|
|
||||||
|
html_theme_options = {
|
||||||
def setup(app):
|
'github_user': 'ets-labs',
|
||||||
app.add_css_file('sphinx_rtd_theme-hotfix.css')
|
'github_repo': 'python-dependency-injector',
|
||||||
|
'github_type': 'star',
|
||||||
|
'github_button': True,
|
||||||
|
'github_banner': True,
|
||||||
|
'logo': 'logo.svg',
|
||||||
|
'description': 'Dependency injection framework for Python',
|
||||||
|
'code_font_size': '10pt',
|
||||||
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ factories:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/declarative.py
|
.. literalinclude:: ../../examples/containers/declarative.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example of declarative containers inheritance:
|
Example of declarative containers inheritance:
|
||||||
|
|
||||||
|
@ -42,7 +41,6 @@ Example of declarative containers inheritance:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/declarative_inheritance.py
|
.. literalinclude:: ../../examples/containers/declarative_inheritance.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example of declarative containers's provider injections:
|
Example of declarative containers's provider injections:
|
||||||
|
|
||||||
|
@ -52,7 +50,6 @@ Example of declarative containers's provider injections:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/declarative_injections.py
|
.. literalinclude:: ../../examples/containers/declarative_injections.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -17,14 +17,12 @@ Here is an simple example of defining dynamic container with several factories:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/dynamic.py
|
.. literalinclude:: ../../examples/containers/dynamic.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Next example demonstrates creation of dynamic container based on some
|
Next example demonstrates creation of dynamic container based on some
|
||||||
configuration:
|
configuration:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/dynamic_runtime_creation.py
|
.. literalinclude:: ../../examples/containers/dynamic_runtime_creation.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -18,13 +18,11 @@ method:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/override_declarative.py
|
.. literalinclude:: ../../examples/containers/override_declarative.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example of overriding container using :py:func:`override` decorator:
|
Example of overriding container using :py:func:`override` decorator:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/override_declarative_decorator.py
|
.. literalinclude:: ../../examples/containers/override_declarative_decorator.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Also there are several useful :py:class:`DeclarativeContainer` methods and
|
Also there are several useful :py:class:`DeclarativeContainer` methods and
|
||||||
properties that help to work with container overridings:
|
properties that help to work with container overridings:
|
||||||
|
|
|
@ -14,14 +14,12 @@ for limitation of its provided type:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/declarative_provider_type.py
|
.. literalinclude:: ../../examples/containers/declarative_provider_type.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Limitation for providers type could be used with :py:class:`DynamicContainer`
|
Limitation for providers type could be used with :py:class:`DynamicContainer`
|
||||||
as well:
|
as well:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/containers/dynamic_provider_type.py
|
.. literalinclude:: ../../examples/containers/dynamic_provider_type.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -37,7 +37,6 @@ Listing of ``bundles/users/__init__.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/bundles/bundles/users/__init__.py
|
.. literalinclude:: ../../examples/miniapps/bundles/bundles/users/__init__.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -47,7 +46,6 @@ Listing of ``bundles/photos/__init__.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/bundles/bundles/photos/__init__.py
|
.. literalinclude:: ../../examples/miniapps/bundles/bundles/photos/__init__.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -65,7 +63,6 @@ Listing of ``run.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/bundles/run.py
|
.. literalinclude:: ../../examples/miniapps/bundles/run.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Links
|
Links
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
|
@ -10,14 +10,12 @@ Listing of ``data.py``, demonstrates sample classes structure:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``chained_factories.py``, demonstrates "Chained Factories"
|
Listing of ``chained_factories.py``, demonstrates "Chained Factories"
|
||||||
pattern and provide some explanation:
|
pattern and provide some explanation:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/chained_factories.py
|
.. literalinclude:: ../../examples/miniapps/factory_patterns/chained_factories.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -9,14 +9,12 @@ Listing of ``data.py``, demonstrates sample classes structure:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
.. literalinclude:: ../../examples/miniapps/factory_patterns/data.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``factory_of_factories.py``, demonstrates "Chained Factories"
|
Listing of ``factory_of_factories.py``, demonstrates "Chained Factories"
|
||||||
pattern and provide some explanation:
|
pattern and provide some explanation:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/factory_patterns/factory_of_factories.py
|
.. literalinclude:: ../../examples/miniapps/factory_patterns/factory_of_factories.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -70,7 +70,6 @@ Listing of ``movies/__init__.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/movies/__init__.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/movies/__init__.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example application
|
Example application
|
||||||
~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -88,13 +87,11 @@ Listing of ``examples/main.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/example/main.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/example/main.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``examples/db.py``:
|
Listing of ``examples/db.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/example/db.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/example/db.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Csv application
|
Csv application
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
@ -103,7 +100,6 @@ Listing of ``app_csv.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_csv.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_csv.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Database application
|
Database application
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -112,7 +108,6 @@ Listing of ``app_db.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Csv and database application
|
Csv and database application
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -121,7 +116,6 @@ Listing of ``app_db_csv.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db_csv.py
|
.. literalinclude:: ../../examples/miniapps/movie_lister/app_db_csv.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -14,6 +14,5 @@ Listing of ``example.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/password_hashing/example.py
|
.. literalinclude:: ../../examples/miniapps/password_hashing/example.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -47,13 +47,11 @@ Listing of ``example/services.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v1/example/services.py
|
.. literalinclude:: ../../examples/miniapps/services_v1/example/services.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``example/main.py``:
|
Listing of ``example/main.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v1/example/main.py
|
.. literalinclude:: ../../examples/miniapps/services_v1/example/main.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
IoC containers
|
IoC containers
|
||||||
~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~
|
||||||
|
@ -62,7 +60,6 @@ Listing of ``containers.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v1/containers.py
|
.. literalinclude:: ../../examples/miniapps/services_v1/containers.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Run application
|
Run application
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
@ -71,7 +68,6 @@ Listing of ``run.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v1/run.py
|
.. literalinclude:: ../../examples/miniapps/services_v1/run.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -47,13 +47,11 @@ Listing of ``example/services.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v2/example/services.py
|
.. literalinclude:: ../../examples/miniapps/services_v2/example/services.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``example/main.py``:
|
Listing of ``example/main.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v2/example/main.py
|
.. literalinclude:: ../../examples/miniapps/services_v2/example/main.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
IoC container
|
IoC container
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
@ -62,7 +60,6 @@ Listing of ``container.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v2/container.py
|
.. literalinclude:: ../../examples/miniapps/services_v2/container.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Run application
|
Run application
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
@ -71,7 +68,6 @@ Listing of ``run.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/services_v2/run.py
|
.. literalinclude:: ../../examples/miniapps/services_v2/run.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -29,7 +29,6 @@ Listing of ``use_cases/containers.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/use_cases/containers.py
|
.. literalinclude:: ../../examples/miniapps/use_cases/containers.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Run application
|
Run application
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
@ -38,7 +37,6 @@ Listing of ``run.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/use_cases/run.py
|
.. literalinclude:: ../../examples/miniapps/use_cases/run.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Instructions for running:
|
Instructions for running:
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ Dependency Injector --- Dependency injection framework for Python
|
||||||
|
|
||||||
.. _index:
|
.. _index:
|
||||||
|
|
||||||
.. figure:: https://raw.githubusercontent.com/wiki/ets-labs/python-dependency-injector/img/logo.svg
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/dependency_injector.svg
|
.. image:: https://img.shields.io/pypi/v/dependency_injector.svg
|
||||||
:target: https://pypi.org/project/dependency-injector/
|
:target: https://pypi.org/project/dependency-injector/
|
||||||
:alt: Latest Version
|
:alt: Latest Version
|
||||||
|
@ -63,27 +61,21 @@ Dependency Injector --- Dependency injection framework for Python
|
||||||
:target: https://coveralls.io/github/ets-labs/python-dependency-injector?branch=master
|
:target: https://coveralls.io/github/ets-labs/python-dependency-injector?branch=master
|
||||||
:alt: Coverage Status
|
:alt: Coverage Status
|
||||||
|
|
||||||
What is ``Dependency Injector``?
|
``Dependency Injector`` is a dependency injection framework for Python.
|
||||||
================================
|
|
||||||
|
|
||||||
``Dependency Injector`` is a dependency injection microframework for Python.
|
It helps you understand and change the structure of the application.
|
||||||
It was designed to be a unified and developer-friendly tool that helps
|
|
||||||
implement a dependency injection design pattern in a formal, pretty, and
|
|
||||||
Pythonic way.
|
|
||||||
|
|
||||||
The key features of the *Dependency Injector* framework are:
|
With the ``Dependency Injector`` you keep **application structure in one place**.
|
||||||
|
This place is called **the container**. You use the container to manage all the components of the
|
||||||
|
application. All the component dependencies are defined explicitly. This provides the control on
|
||||||
|
the application structure. It is **easy to understand and change** it.
|
||||||
|
|
||||||
+ Easy, smart, and pythonic style.
|
.. figure:: https://raw.githubusercontent.com/wiki/ets-labs/python-dependency-injector/img/di-map.svg
|
||||||
+ Obvious and clear structure.
|
:target: https://github.com/ets-labs/python-dependency-injector
|
||||||
+ Extensibility and flexibility.
|
|
||||||
+ High performance.
|
|
||||||
+ Memory efficiency.
|
|
||||||
+ Thread safety.
|
|
||||||
+ Documented.
|
|
||||||
+ Semantically versioned.
|
|
||||||
|
|
||||||
*Dependency Injector* containers and providers are implemented as C extension
|
*The container is like a map of your application. You always know what depends on what.*
|
||||||
types using Cython.
|
|
||||||
|
Explore the documentation to know more about the ``Dependency Injector``.
|
||||||
|
|
||||||
Contents
|
Contents
|
||||||
--------
|
--------
|
||||||
|
@ -93,6 +85,7 @@ Contents
|
||||||
|
|
||||||
introduction/index
|
introduction/index
|
||||||
main/installation
|
main/installation
|
||||||
|
tutorials/index
|
||||||
providers/index
|
providers/index
|
||||||
containers/index
|
containers/index
|
||||||
examples/index
|
examples/index
|
||||||
|
|
|
@ -103,19 +103,16 @@ Listing of ``example.engines`` module:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/engines_cars/example/engines.py
|
.. literalinclude:: ../../examples/miniapps/engines_cars/example/engines.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``example.cars`` module:
|
Listing of ``example.cars`` module:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/engines_cars/example/cars.py
|
.. literalinclude:: ../../examples/miniapps/engines_cars/example/cars.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Next example demonstrates creation of several cars with different engines:
|
Next example demonstrates creation of several cars with different engines:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/engines_cars/example_di.py
|
.. literalinclude:: ../../examples/miniapps/engines_cars/example_di.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
While previous example demonstrates advantages of dependency injection, there
|
While previous example demonstrates advantages of dependency injection, there
|
||||||
is a disadvantage demonstration as well - creation of car requires additional
|
is a disadvantage demonstration as well - creation of car requires additional
|
||||||
|
@ -128,7 +125,6 @@ using :doc:`Dependency Injector <../index>`:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/miniapps/engines_cars/example_ioc_containers.py
|
.. literalinclude:: ../../examples/miniapps/engines_cars/example_ioc_containers.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Useful links
|
Useful links
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Key features of Dependency Injector
|
Key features
|
||||||
-----------------------------------
|
------------
|
||||||
|
|
||||||
.. meta::
|
.. meta::
|
||||||
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
:keywords: Python,DI,Dependency injection,IoC,Inversion of Control
|
||||||
|
@ -7,13 +7,16 @@ Key features of Dependency Injector
|
||||||
framework. It also provides some cases and recommendations
|
framework. It also provides some cases and recommendations
|
||||||
about usage of "Dependency Injector" framework.
|
about usage of "Dependency Injector" framework.
|
||||||
|
|
||||||
*Dependency Injector* is a dependency injection framework for Python projects.
|
|
||||||
It was designed to be unified, developer-friendly tool for managing any kind
|
|
||||||
of Python objects and their dependencies in formal, pretty way.
|
|
||||||
|
|
||||||
*Dependency Injector* framework key features are:
|
``Dependency Injector`` is a dependency injection framework for Python.
|
||||||
|
It was designed to be a unified and developer-friendly tool that helps
|
||||||
|
implement a dependency injection design pattern in a formal, pretty, and
|
||||||
|
Pythonic way.
|
||||||
|
|
||||||
+ Easy, smart, and pythonic style.
|
The key features of the ``Dependency Injector`` framework are:
|
||||||
|
|
||||||
|
+ Easy, smart, and Pythonic style.
|
||||||
|
+ Does NOT pollute client code.
|
||||||
+ Obvious and clear structure.
|
+ Obvious and clear structure.
|
||||||
+ Extensibility and flexibility.
|
+ Extensibility and flexibility.
|
||||||
+ High performance.
|
+ High performance.
|
||||||
|
@ -21,29 +24,28 @@ of Python objects and their dependencies in formal, pretty way.
|
||||||
+ Thread safety.
|
+ Thread safety.
|
||||||
+ Documented.
|
+ Documented.
|
||||||
+ Semantically versioned.
|
+ Semantically versioned.
|
||||||
|
+ Distributed as pre-compiled wheels.
|
||||||
|
|
||||||
*Dependency Injector* framework could be used in different application types:
|
``Dependency Injector`` containers and providers are implemented as C extension
|
||||||
|
types using ``Cython``.
|
||||||
|
|
||||||
+ Web applications based on Flask, Django or any other web framework.
|
``Dependency Injector`` framework can be used in the different application types:
|
||||||
+ Asynchronous applications based on asyncio, Tornado and Twisted.
|
|
||||||
|
+ Web applications based on the ``Flask``, ``Django`` or any other web framework.
|
||||||
|
+ Asynchronous applications ``asyncio``, ``aiohttp``, ``Tornado``, or ``Twisted``.
|
||||||
+ Standalone frameworks and libraries.
|
+ Standalone frameworks and libraries.
|
||||||
+ GUI applications.
|
+ GUI applications.
|
||||||
|
|
||||||
*Dependency Injector* framework could be integrated on different project
|
``Dependency Injector`` framework can be integrated on the different project
|
||||||
stages:
|
stages:
|
||||||
|
|
||||||
+ It could be used in the beginning of development of new applications.
|
+ It can be used in the beginning of the development of a new application.
|
||||||
+ It could be integrated into applications that are in active development
|
+ It can be integrated into application that is on its active development stage.
|
||||||
stage.
|
+ It can be used for refactoring of legacy application.
|
||||||
+ It could be used for refactoring of legacy applications.
|
|
||||||
|
|
||||||
Components of *Dependency Injector* framework could be used:
|
Components of ``Dependency Injector`` framework could be used:
|
||||||
|
|
||||||
+ In composition with each other.
|
+ In composition with each other.
|
||||||
+ Separately between each other.
|
+ Independently from each other.
|
||||||
|
|
||||||
Main idea of *Dependency Injector* framework is to be useful tool for the
|
|
||||||
right thing.
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -83,14 +83,12 @@ Let's go through the code of ``example.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/di_demo/example.py
|
.. literalinclude:: ../../examples/di_demo/example.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
At some point, things defined above mean, that the code from ``example.py``,
|
At some point, things defined above mean, that the code from ``example.py``,
|
||||||
could look different, like in ``example_di.py``:
|
could look different, like in ``example_di.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/di_demo/example_di.py
|
.. literalinclude:: ../../examples/di_demo/example_di.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Best explanation, ever
|
Best explanation, ever
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -7,6 +7,12 @@ 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.22.0
|
||||||
|
------
|
||||||
|
- Migrate docs to ``alabaster`` theme.
|
||||||
|
- Add ``Bootstrap`` extension to the ``ghnav-flask`` example.
|
||||||
|
- Add stubs for the tutorials to the docs.
|
||||||
|
|
||||||
3.21.2
|
3.21.2
|
||||||
------
|
------
|
||||||
- Hotfix changelog typo.
|
- Hotfix changelog typo.
|
||||||
|
|
|
@ -30,7 +30,6 @@ injections:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/callable_args.py
|
.. literalinclude:: ../../examples/providers/callable_args.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Next one example shows usage of :py:class:`Callable` with keyword argument
|
Next one example shows usage of :py:class:`Callable` with keyword argument
|
||||||
injections:
|
injections:
|
||||||
|
@ -41,7 +40,6 @@ injections:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/callable_kwargs.py
|
.. literalinclude:: ../../examples/providers/callable_kwargs.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. _callable_providers_delegation:
|
.. _callable_providers_delegation:
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ Configuration providers
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 4,9-10
|
:emphasize-lines: 4,9-10
|
||||||
:lines: 4-14
|
:lines: 4-14
|
||||||
:linenos:
|
|
||||||
|
|
||||||
It implements "use first, define later" principle.
|
It implements "use first, define later" principle.
|
||||||
|
|
||||||
|
@ -23,13 +22,11 @@ Loading from ``ini`` file
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-5,6-
|
:lines: 3-5,6-
|
||||||
:emphasize-lines: 6
|
:emphasize-lines: 6
|
||||||
:linenos:
|
|
||||||
|
|
||||||
where ``examples/providers/configuration/config.ini`` is:
|
where ``examples/providers/configuration/config.ini`` is:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
.. literalinclude:: ../../examples/providers/configuration/config.ini
|
||||||
:language: ini
|
:language: ini
|
||||||
:linenos:
|
|
||||||
|
|
||||||
:py:meth:`Configuration.from_ini` supports environment variables interpolation. Use
|
:py:meth:`Configuration.from_ini` supports environment variables interpolation. Use
|
||||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
||||||
|
@ -45,13 +42,11 @@ Loading from ``yaml`` file
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-5,6-
|
:lines: 3-5,6-
|
||||||
:emphasize-lines: 6
|
:emphasize-lines: 6
|
||||||
:linenos:
|
|
||||||
|
|
||||||
where ``examples/providers/configuration/config.yml`` is:
|
where ``examples/providers/configuration/config.yml`` is:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
.. literalinclude:: ../../examples/providers/configuration/config.yml
|
||||||
:language: ini
|
:language: ini
|
||||||
:linenos:
|
|
||||||
|
|
||||||
:py:meth:`Configuration.from_yaml` supports environment variables interpolation. Use
|
:py:meth:`Configuration.from_yaml` supports environment variables interpolation. Use
|
||||||
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
``${ENV_NAME}`` format in the configuration file to substitute value of environment
|
||||||
|
@ -73,7 +68,6 @@ Loading from ``dict``
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-5,6-
|
:lines: 3-5,6-
|
||||||
:emphasize-lines: 6-13
|
:emphasize-lines: 6-13
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Loading from environment variable
|
Loading from environment variable
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -85,7 +79,6 @@ Loading from environment variable
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 5-7,13-21
|
:lines: 5-7,13-21
|
||||||
:emphasize-lines: 6-8
|
:emphasize-lines: 6-8
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Loading from multiple sources
|
Loading from multiple sources
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -97,12 +90,10 @@ configuration is merged recursively over existing configuration.
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-5,6-14
|
:lines: 3-5,6-14
|
||||||
:emphasize-lines: 6-7
|
:emphasize-lines: 6-7
|
||||||
:linenos:
|
|
||||||
|
|
||||||
where ``examples/providers/configuration/config.local.yml`` is:
|
where ``examples/providers/configuration/config.local.yml`` is:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
.. literalinclude:: ../../examples/providers/configuration/config.local.yml
|
||||||
:language: ini
|
:language: ini
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -18,7 +18,6 @@ coroutine:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
|
.. literalinclude:: ../../examples/providers/coroutine_async_await.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Coroutine providers and injections
|
Coroutine providers and injections
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -30,7 +30,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/custom_factory.py
|
.. literalinclude:: ../../examples/providers/custom_factory.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -39,6 +39,5 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/dependency.py
|
.. literalinclude:: ../../examples/providers/dependency.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -14,7 +14,6 @@ Nothing could be better than brief example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory.py
|
.. literalinclude:: ../../examples/providers/factory.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Factory providers and __init__ injections
|
Factory providers and __init__ injections
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -48,7 +47,6 @@ injectable values are also provided by another factories:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_init_injections.py
|
.. literalinclude:: ../../examples/providers/factory_init_injections.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. _factory_providers_delegation:
|
.. _factory_providers_delegation:
|
||||||
|
|
||||||
|
@ -92,7 +90,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_delegation.py
|
.. literalinclude:: ../../examples/providers/factory_delegation.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. _factory_providers_specialization:
|
.. _factory_providers_specialization:
|
||||||
|
|
||||||
|
@ -107,7 +104,6 @@ provided type:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_provided_type.py
|
.. literalinclude:: ../../examples/providers/factory_provided_type.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. _abstract_factory_providers:
|
.. _abstract_factory_providers:
|
||||||
|
|
||||||
|
@ -142,13 +138,11 @@ Listing of ``cache.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/abstract_factory/cache.py
|
.. literalinclude:: ../../examples/providers/abstract_factory/cache.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``example.py``:
|
Listing of ``example.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/abstract_factory/example.py
|
.. literalinclude:: ../../examples/providers/abstract_factory/example.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Factory aggregate providers
|
Factory aggregate providers
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -167,7 +161,6 @@ Next prototype might be the best demonstration of
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_aggregate/prototype.py
|
.. literalinclude:: ../../examples/providers/factory_aggregate/prototype.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example below shows one of the :py:class:`FactoryAggregate` use cases, when
|
Example below shows one of the :py:class:`FactoryAggregate` use cases, when
|
||||||
concrete implementation (game) must be selected based on dynamic input (CLI).
|
concrete implementation (game) must be selected based on dynamic input (CLI).
|
||||||
|
@ -176,12 +169,10 @@ Listing of ``games.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_aggregate/games.py
|
.. literalinclude:: ../../examples/providers/factory_aggregate/games.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Listing of ``example.py``:
|
Listing of ``example.py``:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/factory_aggregate/example.py
|
.. literalinclude:: ../../examples/providers/factory_aggregate/example.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -9,7 +9,6 @@ List providers
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 6-9
|
:emphasize-lines: 6-9
|
||||||
:lines: 6-8, 23-29
|
:lines: 6-8, 23-29
|
||||||
:linenos:
|
|
||||||
|
|
||||||
:py:class:`List` provider is needed for injecting a list of dependencies. It handles
|
:py:class:`List` provider is needed for injecting a list of dependencies. It handles
|
||||||
positional argument injections the same way as :py:class:`Factory` provider:
|
positional argument injections the same way as :py:class:`Factory` provider:
|
||||||
|
@ -27,7 +26,6 @@ Full example:
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 23-26
|
:emphasize-lines: 23-26
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/object.py
|
.. literalinclude:: ../../examples/providers/object.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -33,7 +33,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/overriding_simple.py
|
.. literalinclude:: ../../examples/providers/overriding_simple.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -43,7 +42,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/overriding_users_model.py
|
.. literalinclude:: ../../examples/providers/overriding_users_model.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -9,7 +9,6 @@ Selector providers
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 6-10
|
:emphasize-lines: 6-10
|
||||||
:lines: 3-5,14-20
|
:lines: 3-5,14-20
|
||||||
:linenos:
|
|
||||||
|
|
||||||
:py:class:`Selector` provider has a callable called ``selector`` and a dictionary of providers.
|
:py:class:`Selector` provider has a callable called ``selector`` and a dictionary of providers.
|
||||||
|
|
||||||
|
@ -26,6 +25,5 @@ Full example:
|
||||||
:language: python
|
:language: python
|
||||||
:emphasize-lines: 14-18
|
:emphasize-lines: 14-18
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:linenos:
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -14,7 +14,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/singleton.py
|
.. literalinclude:: ../../examples/providers/singleton.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Singleton providers resetting
|
Singleton providers resetting
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -28,7 +27,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/singleton_resetting.py
|
.. literalinclude:: ../../examples/providers/singleton_resetting.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
Singleton providers and injections
|
Singleton providers and injections
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -108,7 +106,6 @@ Example:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/singleton_thread_locals.py
|
.. literalinclude:: ../../examples/providers/singleton_thread_locals.py
|
||||||
:language: python
|
:language: python
|
||||||
:linenos:
|
|
||||||
|
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
4
docs/tutorials/aiohttp.rst
Normal file
4
docs/tutorials/aiohttp.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Aiohttp tutorial
|
||||||
|
================
|
||||||
|
|
||||||
|
Coming soon...
|
4
docs/tutorials/asyncio.rst
Normal file
4
docs/tutorials/asyncio.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Asyncio tutorial
|
||||||
|
================
|
||||||
|
|
||||||
|
Coming soon...
|
4
docs/tutorials/flask.rst
Normal file
4
docs/tutorials/flask.rst
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
Flask tutorial
|
||||||
|
==============
|
||||||
|
|
||||||
|
Coming soon...
|
12
docs/tutorials/index.rst
Normal file
12
docs/tutorials/index.rst
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
Tutorials
|
||||||
|
=========
|
||||||
|
|
||||||
|
This section contains tutorials that show how to apply dependency injection for popular Python
|
||||||
|
frameworks.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
flask
|
||||||
|
aiohttp
|
||||||
|
asyncio
|
|
@ -2,16 +2,16 @@
|
||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
"""Some "Service"."""
|
"""The Service."""
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
"""Some "Client" that uses "Service"."""
|
"""The Client that uses the Service."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize instance."""
|
"""Initialize the Client."""
|
||||||
self.service = Service() # Service instance is created inside Client
|
self.service = Service() # The Service is created by the Client
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
client = Client() # Application creates Client's instance
|
client = Client() # Application creates the Client
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
"""The Code, that demonstrates dependency injection pattern."""
|
"""The Code that demonstrates dependency injection pattern."""
|
||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
"""Some "Service"."""
|
"""The Service."""
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
class Client:
|
||||||
"""Some "Client" that uses "Service"."""
|
"""The Client that uses the Service."""
|
||||||
|
|
||||||
def __init__(self, service): # Service instance is injected into Client
|
def __init__(self, service): # The Service is injected into the Client
|
||||||
"""Initialize instance."""
|
"""Initialize the Client."""
|
||||||
self.service = service
|
self.service = service
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
service = Service() # Application creates Service instance
|
service = Service() # Application creates the Service
|
||||||
client = Client(service) # and inject Service instance into the Client
|
client = Client(service) # and inject the Service into the Client
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
class Engine:
|
class Engine:
|
||||||
"""Example engine base class.
|
"""Example engine base class.
|
||||||
|
|
||||||
Engine is a heart of every car. Engine is a very common term and could be
|
Engine is a heart of every car. Engine is a very common term and
|
||||||
implemented in very different ways.
|
could be implemented in very different ways.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ def create_app():
|
||||||
app = container.app()
|
app = container.app()
|
||||||
app.container = container
|
app.container = container
|
||||||
|
|
||||||
|
bootstrap = container.bootstrap()
|
||||||
|
bootstrap.init_app(app)
|
||||||
|
|
||||||
app.add_url_rule('/', view_func=container.index_view.as_view())
|
app.add_url_rule('/', view_func=container.index_view.as_view())
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from dependency_injector.ext import flask
|
from dependency_injector.ext import flask
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
|
from flask_bootstrap import Bootstrap
|
||||||
from github import Github
|
from github import Github
|
||||||
|
|
||||||
from . import views, services
|
from . import views, services
|
||||||
|
@ -13,6 +14,8 @@ class ApplicationContainer(containers.DeclarativeContainer):
|
||||||
|
|
||||||
app = flask.Application(Flask, __name__)
|
app = flask.Application(Flask, __name__)
|
||||||
|
|
||||||
|
bootstrap = flask.Extension(Bootstrap)
|
||||||
|
|
||||||
config = providers.Configuration()
|
config = providers.Configuration()
|
||||||
|
|
||||||
github_client = providers.Factory(
|
github_client = providers.Factory(
|
||||||
|
|
|
@ -29,7 +29,6 @@ class SearchService:
|
||||||
'url': repository.owner.html_url,
|
'url': repository.owner.html_url,
|
||||||
'avatar_url': repository.owner.avatar_url,
|
'avatar_url': repository.owner.avatar_url,
|
||||||
},
|
},
|
||||||
'created_at': repository.created_at,
|
|
||||||
'latest_commit': self._format_commit(commits[0]) if commits else {},
|
'latest_commit': self._format_commit(commits[0]) if commits else {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
{% block head %}
|
||||||
|
<!-- Required meta tags -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
{{ bootstrap.load_css() }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Your page content -->
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<!-- Optional JavaScript -->
|
||||||
|
{{ bootstrap.load_js() }}
|
||||||
|
{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,40 +1,55 @@
|
||||||
<!DOCTYPE html>
|
{% extends "base.html" %}
|
||||||
<html>
|
|
||||||
<head>
|
{% block title %}Github Navigator{% endblock %}
|
||||||
<title>Github Navigator</title>
|
|
||||||
</head>
|
{% block content %}
|
||||||
<body>
|
<div class="container">
|
||||||
<h1>Github Navigator</h1>
|
<h1 class="mb-4">Github Navigator</h1>
|
||||||
<form method="get">
|
|
||||||
|
<form>
|
||||||
|
<div class="form-group form-row">
|
||||||
|
<label for="mySearch" class="col-form-label">Search for:</label>
|
||||||
|
<div class="col-10">
|
||||||
|
<input class="form-control" type="text" id="mySearch"
|
||||||
|
placeholder="Type something to search on GitHub"
|
||||||
|
name="search_term"
|
||||||
|
value="{{ search_term if search_term }}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if repositories|length == 0 %}
|
||||||
|
<small>No search results</small>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Search term: <input type="text" name="search_term" value="{{ search_term if search_term }}">
|
<small>Results found: {{ repositories|length }}</small>
|
||||||
Limit: <input type="text" name="limit" value="{{ limit }}">
|
|
||||||
<input type="submit">
|
|
||||||
</p>
|
</p>
|
||||||
</form>
|
|
||||||
<h2>Search results</h2>
|
<table class="table table-striped">
|
||||||
{% if repositories|length == 0 %}
|
<thead>
|
||||||
<small>No search results</small>
|
<tr>
|
||||||
{% endif %}
|
<th>#</th>
|
||||||
{% for repository in repositories %} {{n}}
|
<th>Repository</th>
|
||||||
<p>
|
<th class="text-nowrap">Repository owner</th>
|
||||||
<small>Search result # {{ loop.index }} from {{ repositories|length }}</small>
|
<!-- <th class="text-nowrap">Created at</th>-->
|
||||||
</p>
|
<th class="text-nowrap">Last commit</th>
|
||||||
<p>
|
</tr>
|
||||||
Repository: <a href="{{ repository.url }}">{{ repository.name }}</a>
|
</thead>
|
||||||
</p>
|
<tbody>
|
||||||
<p>
|
{% for repository in repositories %} {{n}}
|
||||||
Repository owner:
|
<tr>
|
||||||
<a href="{{ repository.owner.url }}"><img src="{{ repository.owner.avatar_url }}" alt="avatar" height="24" width="24"/></a>
|
<th>{{ loop.index }}</th>
|
||||||
|
<td><a href="{{ repository.url }}">{{ repository.name }}</a></td>
|
||||||
|
<td><a href="{{ repository.owner.url }}"><img src="{{ repository.owner.avatar_url }}" alt="avatar" height="24" width="24"/></a>
|
||||||
<a href="{{ repository.owner.url }}">{{ repository.owner.login }}</a>
|
<a href="{{ repository.owner.url }}">{{ repository.owner.login }}</a>
|
||||||
</p>
|
</td>
|
||||||
<p>
|
<td><a href="{{ repository.latest_commit.url }}">{{ repository.latest_commit.sha }}</a> {{ repository.latest_commit['message'] }} {{ repository.latest_commit.author_name }}</td>
|
||||||
Created at: {{ repository.created_at }}
|
</tr>
|
||||||
</p>
|
{% endfor %}
|
||||||
<p>
|
|
||||||
LastCommit: <a href="{{ repository.latest_commit.url }}">{{ repository.latest_commit.sha }}</a> {{ repository.latest_commit['message'] }} {{ repository.latest_commit.author_name }}
|
</tbody>
|
||||||
</p>
|
</table>
|
||||||
<hr/>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
</body>
|
{% endblock %}
|
||||||
</html>
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ def test_index(client, app):
|
||||||
html_url='owner1-url',
|
html_url='owner1-url',
|
||||||
avatar_url='owner1-avatar-url',
|
avatar_url='owner1-avatar-url',
|
||||||
),
|
),
|
||||||
created_at='repo1-created-at',
|
|
||||||
get_commits=mock.Mock(return_value=[mock.Mock()]),
|
get_commits=mock.Mock(return_value=[mock.Mock()]),
|
||||||
),
|
),
|
||||||
mock.Mock(
|
mock.Mock(
|
||||||
|
@ -36,7 +35,6 @@ def test_index(client, app):
|
||||||
html_url='owner2-url',
|
html_url='owner2-url',
|
||||||
avatar_url='owner2-avatar-url',
|
avatar_url='owner2-avatar-url',
|
||||||
),
|
),
|
||||||
created_at='repo2-created-at',
|
|
||||||
get_commits=mock.Mock(return_value=[mock.Mock()]),
|
get_commits=mock.Mock(return_value=[mock.Mock()]),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -51,14 +49,12 @@ def test_index(client, app):
|
||||||
assert b'owner1-login' in response.data
|
assert b'owner1-login' in response.data
|
||||||
assert b'owner1-url' in response.data
|
assert b'owner1-url' in response.data
|
||||||
assert b'owner1-avatar-url' in response.data
|
assert b'owner1-avatar-url' in response.data
|
||||||
assert b'repo1-created-at' in response.data
|
|
||||||
|
|
||||||
assert b'repo2-url' in response.data
|
assert b'repo2-url' in response.data
|
||||||
assert b'repo2-name' in response.data
|
assert b'repo2-name' in response.data
|
||||||
assert b'owner2-login' in response.data
|
assert b'owner2-login' in response.data
|
||||||
assert b'owner2-url' in response.data
|
assert b'owner2-url' in response.data
|
||||||
assert b'owner2-avatar-url' in response.data
|
assert b'owner2-avatar-url' in response.data
|
||||||
assert b'repo2-created-at' in response.data
|
|
||||||
|
|
||||||
|
|
||||||
def test_index_no_results(client, app):
|
def test_index_no_results(client, app):
|
||||||
|
|
|
@ -10,19 +10,27 @@ cache_client_factory = providers.AbstractFactory(cache.AbstractCacheClient)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Override abstract factory with redis client factory:
|
# Override abstract factory with redis client factory:
|
||||||
cache_client_factory.override(providers.Factory(cache.RedisCacheClient,
|
cache_client_factory.override(
|
||||||
|
providers.Factory(
|
||||||
|
cache.RedisCacheClient,
|
||||||
host='localhost',
|
host='localhost',
|
||||||
port=6379,
|
port=6379,
|
||||||
db=0))
|
db=0,
|
||||||
|
),
|
||||||
|
)
|
||||||
redis_cache = cache_client_factory()
|
redis_cache = cache_client_factory()
|
||||||
print(redis_cache) # <cache.RedisCacheClient object at 0x10975bc50>
|
print(redis_cache)
|
||||||
|
# <cache.RedisCacheClient object at 0x10975bc50>
|
||||||
|
|
||||||
# Override abstract factory with memcache client factory:
|
# Override abstract factory with memcache client factory:
|
||||||
cache_client_factory.override(providers.Factory(cache.MemcacheCacheClient,
|
cache_client_factory.override(
|
||||||
hosts=['10.0.1.1',
|
providers.Factory(
|
||||||
'10.0.1.2',
|
cache.MemcacheCacheClient,
|
||||||
'10.0.1.3'],
|
hosts=['10.0.1.1', '10.0.1.2', '10.0.1.3'],
|
||||||
port=11211,
|
port=11211,
|
||||||
prefix='my_app'))
|
prefix='my_app',
|
||||||
|
),
|
||||||
|
)
|
||||||
memcache_cache = cache_client_factory()
|
memcache_cache = cache_client_factory()
|
||||||
print(memcache_cache) # <cache.MemcacheCacheClient object at 0x10975bc90>
|
print(memcache_cache)
|
||||||
|
# <cache.MemcacheCacheClient object at 0x10975bc90>
|
||||||
|
|
|
@ -7,9 +7,11 @@ import dependency_injector.providers as providers
|
||||||
from games import Chess, Checkers, Ludo
|
from games import Chess, Checkers, Ludo
|
||||||
|
|
||||||
|
|
||||||
game_factory = providers.FactoryAggregate(chess=providers.Factory(Chess),
|
game_factory = providers.FactoryAggregate(
|
||||||
|
chess=providers.Factory(Chess),
|
||||||
checkers=providers.Factory(Checkers),
|
checkers=providers.Factory(Checkers),
|
||||||
ludo=providers.Factory(Ludo))
|
ludo=providers.Factory(Ludo),
|
||||||
|
)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
game_type = sys.argv[1].lower()
|
game_type = sys.argv[1].lower()
|
||||||
|
|
|
@ -26,27 +26,36 @@ class User:
|
||||||
|
|
||||||
# Defining User and Photo factories using DelegatedFactory provider:
|
# Defining User and Photo factories using DelegatedFactory provider:
|
||||||
photos_factory = providers.DelegatedFactory(Photo)
|
photos_factory = providers.DelegatedFactory(Photo)
|
||||||
users_factory = providers.DelegatedFactory(User,
|
users_factory = providers.DelegatedFactory(
|
||||||
photos_factory=photos_factory)
|
User,
|
||||||
|
photos_factory=photos_factory,
|
||||||
|
)
|
||||||
|
|
||||||
# or using Delegate(Factory(...))
|
# or using Delegate(Factory(...))
|
||||||
|
|
||||||
photos_factory = providers.Factory(Photo)
|
photos_factory = providers.Factory(Photo)
|
||||||
users_factory = providers.Factory(User,
|
users_factory = providers.Factory(
|
||||||
photos_factory=providers.Delegate(
|
User,
|
||||||
photos_factory))
|
photos_factory=providers.Delegate(photos_factory),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# or using Factory(...).delegate()
|
# or using Factory(...).delegate()
|
||||||
|
|
||||||
photos_factory = providers.Factory(Photo)
|
photos_factory = providers.Factory(Photo)
|
||||||
users_factory = providers.Factory(User,
|
users_factory = providers.Factory(
|
||||||
photos_factory=photos_factory.delegate())
|
User,
|
||||||
|
photos_factory=photos_factory.delegate(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Creating several User objects:
|
# Creating several User objects:
|
||||||
user1 = users_factory() # Same as: user1 = User(photos_factory=photos_factory)
|
user1 = users_factory()
|
||||||
user2 = users_factory() # Same as: user2 = User(photos_factory=photos_factory)
|
user2 = users_factory()
|
||||||
|
|
||||||
|
# Same as:
|
||||||
|
# user1 = User(photos_factory=photos_factory)
|
||||||
|
# user2 = User(photos_factory=photos_factory)
|
||||||
|
|
||||||
# Making some asserts:
|
# Making some asserts:
|
||||||
assert isinstance(user1.main_photo, Photo)
|
assert isinstance(user1.main_photo, Photo)
|
||||||
|
@ -55,13 +64,18 @@ assert isinstance(user2.main_photo, Photo)
|
||||||
# or using Factory(...).provider
|
# or using Factory(...).provider
|
||||||
|
|
||||||
photos_factory = providers.Factory(Photo)
|
photos_factory = providers.Factory(Photo)
|
||||||
users_factory = providers.Factory(User,
|
users_factory = providers.Factory(
|
||||||
photos_factory=photos_factory.provider)
|
User,
|
||||||
|
photos_factory=photos_factory.provider,
|
||||||
|
)
|
||||||
|
|
||||||
# Creating several User objects:
|
# Creating several User objects:
|
||||||
user1 = users_factory() # Same as: user1 = User(photos_factory=photos_factory)
|
user1 = users_factory()
|
||||||
user2 = users_factory() # Same as: user2 = User(photos_factory=photos_factory)
|
user2 = users_factory()
|
||||||
|
|
||||||
|
# Same as:
|
||||||
|
# user1 = User(photos_factory=photos_factory)
|
||||||
|
# user2 = User(photos_factory=photos_factory)
|
||||||
|
|
||||||
# Making some asserts:
|
# Making some asserts:
|
||||||
assert isinstance(user1.main_photo, Photo)
|
assert isinstance(user1.main_photo, Photo)
|
||||||
|
|
|
@ -7,8 +7,8 @@ import dependency_injector.providers as providers
|
||||||
|
|
||||||
UsersService = collections.namedtuple('UsersService', [])
|
UsersService = collections.namedtuple('UsersService', [])
|
||||||
|
|
||||||
# Singleton provider creates new instance of specified class on first call and
|
# Singleton provider creates new instance of specified class on first call
|
||||||
# returns same instance on every next call.
|
# and returns same instance on every next call.
|
||||||
users_service_provider = providers.Singleton(UsersService)
|
users_service_provider = providers.Singleton(UsersService)
|
||||||
|
|
||||||
# Retrieving several UserService objects:
|
# Retrieving several UserService objects:
|
||||||
|
|
|
@ -18,19 +18,22 @@ thread_local_object = providers.ThreadLocalSingleton(object)
|
||||||
queue_factory = providers.ThreadSafeSingleton(queue.Queue)
|
queue_factory = providers.ThreadSafeSingleton(queue.Queue)
|
||||||
|
|
||||||
# Create callable provider for example(), inject dependencies:
|
# Create callable provider for example(), inject dependencies:
|
||||||
example = providers.DelegatedCallable(example,
|
example = providers.DelegatedCallable(
|
||||||
|
example,
|
||||||
example_object=thread_local_object,
|
example_object=thread_local_object,
|
||||||
queue_object=queue_factory)
|
queue_object=queue_factory,
|
||||||
|
)
|
||||||
|
|
||||||
# Create factory provider for threads that are targeted to execute example():
|
# Create factory for threads that are targeted to execute example():
|
||||||
thread_factory = providers.Factory(threading.Thread,
|
thread_factory = providers.Factory(threading.Thread, target=example)
|
||||||
target=example)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Create 10 threads for concurrent execution of example():
|
# Create 10 threads for concurrent execution of example():
|
||||||
threads = []
|
threads = []
|
||||||
for thread_number in range(10):
|
for thread_number in range(10):
|
||||||
threads.append(thread_factory(name='Thread{0}'.format(thread_number)))
|
threads.append(
|
||||||
|
thread_factory(name='Thread{0}'.format(thread_number)),
|
||||||
|
)
|
||||||
|
|
||||||
# Start execution of all created threads:
|
# Start execution of all created threads:
|
||||||
for thread in threads:
|
for thread in threads:
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
sphinx
|
sphinx
|
||||||
sphinx_rtd_theme>=0.2.5b2
|
alabaster>=0.7.12
|
||||||
-e git://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus
|
-e git://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus
|
||||||
|
|
||||||
-r requirements-ext.txt
|
-r requirements-ext.txt
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Dependency injector top-level package."""
|
"""Dependency injector top-level package."""
|
||||||
|
|
||||||
__version__ = '3.21.2'
|
__version__ = '3.22.0'
|
||||||
"""Version number that follows semantic versioning.
|
"""Version number that follows semantic versioning.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
Loading…
Reference in New Issue
Block a user