mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 09:57:37 +03:00 
			
		
		
		
	Merge branch 'release/4.4.0' into master
This commit is contained in:
		
						commit
						262c035bc1
					
				
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -69,3 +69,6 @@ src/dependency_injector/containers/*.h
 | 
				
			||||||
src/dependency_injector/containers/*.so
 | 
					src/dependency_injector/containers/*.so
 | 
				
			||||||
src/dependency_injector/providers/*.h
 | 
					src/dependency_injector/providers/*.h
 | 
				
			||||||
src/dependency_injector/providers/*.so
 | 
					src/dependency_injector/providers/*.so
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Workspace for samples
 | 
				
			||||||
 | 
					.workspace/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector import containers, providers
 | 
					   from dependency_injector import containers, providers
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   class Container(containers.DeclarativeContainer):
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
| 
						 | 
					@ -97,6 +97,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(service: Service = Provide[Container.service]):
 | 
					   def main(service: Service = Provide[Container.service]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								docs/examples/flask-blueprints.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								docs/examples/flask-blueprints.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					.. _flask-blueprints-example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flask blueprints example
 | 
				
			||||||
 | 
					========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. meta::
 | 
				
			||||||
 | 
					   :keywords: Python,Dependency Injection,Flask,Blueprints,Example
 | 
				
			||||||
 | 
					   :description: This example demonstrates a usage of the Flask Blueprints and Dependency Injector.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This example shows how to use ``Dependency Injector`` with `Flask <https://flask.palletsprojects.com/en/1.1.x/>`_
 | 
				
			||||||
 | 
					blueprints.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The example application helps to search for repositories on the Github.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. image:: images/flask.png
 | 
				
			||||||
 | 
					    :width: 100%
 | 
				
			||||||
 | 
					    :align: center
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask-blueprints>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application structure
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application has next structure:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ./
 | 
				
			||||||
 | 
					   ├── githubnavigator/
 | 
				
			||||||
 | 
					   │   ├── blueprints
 | 
				
			||||||
 | 
					   │   │   ├── __init__.py
 | 
				
			||||||
 | 
					   │   │   └── example.py
 | 
				
			||||||
 | 
					   │   ├── templates
 | 
				
			||||||
 | 
					   │   │   ├── base.html
 | 
				
			||||||
 | 
					   │   │   └── index.py
 | 
				
			||||||
 | 
					   │   ├── __init__.py
 | 
				
			||||||
 | 
					   │   ├── application.py
 | 
				
			||||||
 | 
					   │   ├── containers.py
 | 
				
			||||||
 | 
					   │   ├── services.py
 | 
				
			||||||
 | 
					   │   └── tests.py
 | 
				
			||||||
 | 
					   ├── config.yml
 | 
				
			||||||
 | 
					   └── requirements.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Container
 | 
				
			||||||
 | 
					---------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Declarative container is defined in ``githubnavigator/containers.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/flask-blueprints/githubnavigator/containers.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Blueprints
 | 
				
			||||||
 | 
					----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Blueprint's view has dependencies on search service and some config options. The dependencies are injected
 | 
				
			||||||
 | 
					using :ref:`wiring` feature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Listing of ``githubnavigator/blueprints/example.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/flask-blueprints/githubnavigator/blueprints/example.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application factory
 | 
				
			||||||
 | 
					-------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application factory creates container, wires it with the blueprints, creates
 | 
				
			||||||
 | 
					``Flask`` app, and setup routes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Listing of ``githubnavigator/application.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/flask-blueprints/githubnavigator/application.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tests
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tests use :ref:`provider-overriding` feature to replace github client with a mock ``githubnavigator/tests.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/flask-blueprints/githubnavigator/tests.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					   :emphasize-lines: 44,67
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sources
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask-blueprints>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. disqus::
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ Explore the examples to see the ``Dependency Injector`` in action.
 | 
				
			||||||
    decoupled-packages
 | 
					    decoupled-packages
 | 
				
			||||||
    django
 | 
					    django
 | 
				
			||||||
    flask
 | 
					    flask
 | 
				
			||||||
 | 
					    flask-blueprints
 | 
				
			||||||
    aiohttp
 | 
					    aiohttp
 | 
				
			||||||
    sanic
 | 
					    sanic
 | 
				
			||||||
    fastapi
 | 
					    fastapi
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,7 +85,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector import containers, providers
 | 
					   from dependency_injector import containers, providers
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   class Container(containers.DeclarativeContainer):
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
| 
						 | 
					@ -104,6 +104,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(service: Service = Provide[Container.service]):
 | 
					   def main(service: Service = Provide[Container.service]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -162,7 +162,7 @@ the dependency.
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector import containers, providers
 | 
					   from dependency_injector import containers, providers
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   class Container(containers.DeclarativeContainer):
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
| 
						 | 
					@ -181,6 +181,7 @@ the dependency.
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(service: Service = Provide[Container.service]):
 | 
					   def main(service: Service = Provide[Container.service]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -282,6 +283,7 @@ Choose one of the following as a next step:
 | 
				
			||||||
    - :ref:`decoupled-packages`
 | 
					    - :ref:`decoupled-packages`
 | 
				
			||||||
    - :ref:`django-example`
 | 
					    - :ref:`django-example`
 | 
				
			||||||
    - :ref:`flask-example`
 | 
					    - :ref:`flask-example`
 | 
				
			||||||
 | 
					    - :ref:`flask-blueprints-example`
 | 
				
			||||||
    - :ref:`aiohttp-example`
 | 
					    - :ref:`aiohttp-example`
 | 
				
			||||||
    - :ref:`sanic-example`
 | 
					    - :ref:`sanic-example`
 | 
				
			||||||
    - :ref:`fastapi-example`
 | 
					    - :ref:`fastapi-example`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4.4.0
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					- Add ``@inject`` decorator. It helps to fix a number of wiring bugs and make wiring be more resilient.
 | 
				
			||||||
 | 
					- Refactor ``wiring`` module.
 | 
				
			||||||
 | 
					- Update documentation and examples to use ``@inject`` decorator.
 | 
				
			||||||
 | 
					- Add ``Flask`` blueprints example.
 | 
				
			||||||
 | 
					- Fix wiring bug when wiring doesn't work with the class-based decorators.
 | 
				
			||||||
 | 
					- Fix wiring bug when wiring doesn't work with the decorators that doesn't use ``functools.wraps(...)``.
 | 
				
			||||||
 | 
					- Fix wiring bug with ``@app.route(...)`` -style decorators (Flask, Sanic, FastAPI, etc.).
 | 
				
			||||||
 | 
					- Fix wiring bug when wiring doesn't work with Flask blueprints.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4.3.9
 | 
					4.3.9
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
- Add ``FastAPI`` example.
 | 
					- Add ``FastAPI`` example.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -216,7 +216,7 @@ execution scope. For doing this you need to use additional ``Closing`` marker fr
 | 
				
			||||||
.. literalinclude:: ../../examples/wiring/flask_resource_closing.py
 | 
					.. literalinclude:: ../../examples/wiring/flask_resource_closing.py
 | 
				
			||||||
   :language: python
 | 
					   :language: python
 | 
				
			||||||
   :lines: 3-
 | 
					   :lines: 3-
 | 
				
			||||||
   :emphasize-lines: 23
 | 
					   :emphasize-lines: 24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Framework initializes and injects the resource into the function. With the ``Closing`` marker
 | 
					Framework initializes and injects the resource into the function. With the ``Closing`` marker
 | 
				
			||||||
framework calls resource ``shutdown()`` method when function execution is over.
 | 
					framework calls resource ``shutdown()`` method when function execution is over.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -526,17 +526,18 @@ the ``index`` handler. We will use :ref:`wiring` feature.
 | 
				
			||||||
Edit ``handlers.py``:
 | 
					Edit ``handlers.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 4-7,10-13,17
 | 
					   :emphasize-lines: 4-7,10-14,18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Handlers module."""
 | 
					   """Handlers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from aiohttp import web
 | 
					   from aiohttp import web
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .services import SearchService
 | 
					   from .services import SearchService
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   async def index(
 | 
					   async def index(
 | 
				
			||||||
           request: web.Request,
 | 
					           request: web.Request,
 | 
				
			||||||
           search_service: SearchService = Provide[Container.search_service],
 | 
					           search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
| 
						 | 
					@ -645,17 +646,18 @@ Let's make some refactoring. We will move these values to the config.
 | 
				
			||||||
Edit ``handlers.py``:
 | 
					Edit ``handlers.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 13-14,16-17
 | 
					   :emphasize-lines: 14-15,17-18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Handlers module."""
 | 
					   """Handlers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from aiohttp import web
 | 
					   from aiohttp import web
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .services import SearchService
 | 
					   from .services import SearchService
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   async def index(
 | 
					   async def index(
 | 
				
			||||||
           request: web.Request,
 | 
					           request: web.Request,
 | 
				
			||||||
           search_service: SearchService = Provide[Container.search_service],
 | 
					           search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
| 
						 | 
					@ -821,11 +823,11 @@ You should see:
 | 
				
			||||||
   giphynavigator/application.py      12      0   100%
 | 
					   giphynavigator/application.py      12      0   100%
 | 
				
			||||||
   giphynavigator/containers.py        6      0   100%
 | 
					   giphynavigator/containers.py        6      0   100%
 | 
				
			||||||
   giphynavigator/giphy.py            14      9    36%
 | 
					   giphynavigator/giphy.py            14      9    36%
 | 
				
			||||||
   giphynavigator/handlers.py          9      0   100%
 | 
					   giphynavigator/handlers.py         10      0   100%
 | 
				
			||||||
   giphynavigator/services.py          9      1    89%
 | 
					   giphynavigator/services.py          9      1    89%
 | 
				
			||||||
   giphynavigator/tests.py            37      0   100%
 | 
					   giphynavigator/tests.py            37      0   100%
 | 
				
			||||||
   ---------------------------------------------------
 | 
					   ---------------------------------------------------
 | 
				
			||||||
   TOTAL                              87     10    89%
 | 
					   TOTAL                              88     10    89%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -442,18 +442,19 @@ and call the ``run()`` method. We will use :ref:`wiring` feature.
 | 
				
			||||||
Edit ``__main__.py``:
 | 
					Edit ``__main__.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 3-7,11-12,19
 | 
					   :emphasize-lines: 3-7,11-13,20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Main module."""
 | 
					   """Main module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   import sys
 | 
					   import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .dispatcher import Dispatcher
 | 
					   from .dispatcher import Dispatcher
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(dispatcher: Dispatcher = Provide[Container.dispatcher]) -> None:
 | 
					   def main(dispatcher: Dispatcher = Provide[Container.dispatcher]) -> None:
 | 
				
			||||||
       dispatcher.run()
 | 
					       dispatcher.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -992,14 +993,14 @@ You should see:
 | 
				
			||||||
   Name                             Stmts   Miss  Cover
 | 
					   Name                             Stmts   Miss  Cover
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   monitoringdaemon/__init__.py         0      0   100%
 | 
					   monitoringdaemon/__init__.py         0      0   100%
 | 
				
			||||||
   monitoringdaemon/__main__.py        12     12     0%
 | 
					   monitoringdaemon/__main__.py        13     13     0%
 | 
				
			||||||
   monitoringdaemon/containers.py      11      0   100%
 | 
					   monitoringdaemon/containers.py      11      0   100%
 | 
				
			||||||
   monitoringdaemon/dispatcher.py      44      5    89%
 | 
					   monitoringdaemon/dispatcher.py      44      5    89%
 | 
				
			||||||
   monitoringdaemon/http.py             6      3    50%
 | 
					   monitoringdaemon/http.py             6      3    50%
 | 
				
			||||||
   monitoringdaemon/monitors.py        23      1    96%
 | 
					   monitoringdaemon/monitors.py        23      1    96%
 | 
				
			||||||
   monitoringdaemon/tests.py           37      0   100%
 | 
					   monitoringdaemon/tests.py           37      0   100%
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   TOTAL                              133     21    84%
 | 
					   TOTAL                              134     22    84%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -575,18 +575,19 @@ Let's inject the ``lister`` into the  ``main()`` function.
 | 
				
			||||||
Edit ``__main__.py``:
 | 
					Edit ``__main__.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 3-7,11,18
 | 
					   :emphasize-lines: 3-7,11-12,19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Main module."""
 | 
					   """Main module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   import sys
 | 
					   import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .listers import MovieLister
 | 
					   from .listers import MovieLister
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
					   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -606,18 +607,19 @@ Francis Lawrence and movies released in 2016.
 | 
				
			||||||
Edit ``__main__.py``:
 | 
					Edit ``__main__.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 12-18
 | 
					   :emphasize-lines: 13-19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Main module."""
 | 
					   """Main module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   import sys
 | 
					   import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .listers import MovieLister
 | 
					   from .listers import MovieLister
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
					   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
				
			||||||
       print('Francis Lawrence movies:')
 | 
					       print('Francis Lawrence movies:')
 | 
				
			||||||
       for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
					       for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
				
			||||||
| 
						 | 
					@ -861,18 +863,19 @@ Now we need to read the value of the ``config.finder.type`` option from the envi
 | 
				
			||||||
Edit ``__main__.py``:
 | 
					Edit ``__main__.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 24
 | 
					   :emphasize-lines: 25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Main module."""
 | 
					   """Main module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   import sys
 | 
					   import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .listers import MovieLister
 | 
					   from .listers import MovieLister
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
					   def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
				
			||||||
       print('Francis Lawrence movies:')
 | 
					       print('Francis Lawrence movies:')
 | 
				
			||||||
       for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
					       for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
				
			||||||
| 
						 | 
					@ -1023,14 +1026,14 @@ You should see:
 | 
				
			||||||
   Name                   Stmts   Miss  Cover
 | 
					   Name                   Stmts   Miss  Cover
 | 
				
			||||||
   ------------------------------------------
 | 
					   ------------------------------------------
 | 
				
			||||||
   movies/__init__.py         0      0   100%
 | 
					   movies/__init__.py         0      0   100%
 | 
				
			||||||
   movies/__main__.py        17     17     0%
 | 
					   movies/__main__.py        18     18     0%
 | 
				
			||||||
   movies/containers.py       9      0   100%
 | 
					   movies/containers.py       9      0   100%
 | 
				
			||||||
   movies/entities.py         7      1    86%
 | 
					   movies/entities.py         7      1    86%
 | 
				
			||||||
   movies/finders.py         26     13    50%
 | 
					   movies/finders.py         26     13    50%
 | 
				
			||||||
   movies/listers.py          8      0   100%
 | 
					   movies/listers.py          8      0   100%
 | 
				
			||||||
   movies/tests.py           24      0   100%
 | 
					   movies/tests.py           24      0   100%
 | 
				
			||||||
   ------------------------------------------
 | 
					   ------------------------------------------
 | 
				
			||||||
   TOTAL                     91     31    66%
 | 
					   TOTAL                     92     32    65%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -707,17 +707,19 @@ Let's inject ``SearchService`` into the ``index`` view. We will use :ref:`Wiring
 | 
				
			||||||
Edit ``views.py``:
 | 
					Edit ``views.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 4,6-7,10,14
 | 
					   :emphasize-lines: 4,6-7,10-11,15
 | 
				
			||||||
 | 
					   :emphasize-lines: 4,6-7,10-11,15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Views module."""
 | 
					   """Views module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from flask import request, render_template
 | 
					   from flask import request, render_template
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .services import SearchService
 | 
					   from .services import SearchService
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def index(search_service: SearchService = Provide[Container.search_service]):
 | 
					   def index(search_service: SearchService = Provide[Container.search_service]):
 | 
				
			||||||
       query = request.args.get('query', 'Dependency Injector')
 | 
					       query = request.args.get('query', 'Dependency Injector')
 | 
				
			||||||
       limit = request.args.get('limit', 10, int)
 | 
					       limit = request.args.get('limit', 10, int)
 | 
				
			||||||
| 
						 | 
					@ -783,17 +785,18 @@ Let's make some refactoring. We will move these values to the config.
 | 
				
			||||||
Edit ``views.py``:
 | 
					Edit ``views.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 10-16
 | 
					   :emphasize-lines: 11-17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   """Views module."""
 | 
					   """Views module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from flask import request, render_template
 | 
					   from flask import request, render_template
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from .services import SearchService
 | 
					   from .services import SearchService
 | 
				
			||||||
   from .containers import Container
 | 
					   from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def index(
 | 
					   def index(
 | 
				
			||||||
           search_service: SearchService = Provide[Container.search_service],
 | 
					           search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
           default_query: str = Provide[Container.config.default.query],
 | 
					           default_query: str = Provide[Container.config.default.query],
 | 
				
			||||||
| 
						 | 
					@ -972,9 +975,9 @@ You should see:
 | 
				
			||||||
   githubnavigator/containers.py        7      0   100%
 | 
					   githubnavigator/containers.py        7      0   100%
 | 
				
			||||||
   githubnavigator/services.py         14      0   100%
 | 
					   githubnavigator/services.py         14      0   100%
 | 
				
			||||||
   githubnavigator/tests.py            34      0   100%
 | 
					   githubnavigator/tests.py            34      0   100%
 | 
				
			||||||
   githubnavigator/views.py             9      0   100%
 | 
					   githubnavigator/views.py            10      0   100%
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   TOTAL                               79      0   100%
 | 
					   TOTAL                               80      0   100%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,8 @@ Wiring feature provides a way to inject container providers into the functions a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To use wiring you need:
 | 
					To use wiring you need:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **Place markers in the code**. Wiring marker specifies what provider to inject,
 | 
					- **Place @inject decorator**. Decorator ``@inject`` injects the dependencies.
 | 
				
			||||||
 | 
					- **Place markers**. Wiring marker specifies what dependency to inject,
 | 
				
			||||||
  e.g. ``Provide[Container.bar]``. This helps container to find the injections.
 | 
					  e.g. ``Provide[Container.bar]``. This helps container to find the injections.
 | 
				
			||||||
- **Wire the container with the markers in the code**. Call ``container.wire()``
 | 
					- **Wire the container with the markers in the code**. Call ``container.wire()``
 | 
				
			||||||
  specifying modules and packages you would like to wire it with.
 | 
					  specifying modules and packages you would like to wire it with.
 | 
				
			||||||
| 
						 | 
					@ -25,9 +26,10 @@ a function or method argument:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provide
 | 
					   from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(bar: Bar = Provide[Container.bar]):
 | 
					   def foo(bar: Bar = Provide[Container.bar]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,9 +42,10 @@ There are two types of markers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   from dependency_injector.wiring import Provider
 | 
					   from dependency_injector.wiring import inject, Provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(bar_provider: Callable[..., Bar] = Provider[Container.bar]):
 | 
					   def foo(bar_provider: Callable[..., Bar] = Provider[Container.bar]):
 | 
				
			||||||
       bar = bar_provider()
 | 
					       bar = bar_provider()
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
| 
						 | 
					@ -51,18 +54,22 @@ You can use configuration, provided instance and sub-container providers as you
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(token: str = Provide[Container.config.api_token]):
 | 
					   def foo(token: str = Provide[Container.config.api_token]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(timeout: int = Provide[Container.config.timeout.as_(int)]):
 | 
					   def foo(timeout: int = Provide[Container.config.timeout.as_(int)]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(baz: Baz = Provide[Container.bar.provided.baz]):
 | 
					   def foo(baz: Baz = Provide[Container.bar.provided.baz]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(bar: Bar = Provide[Container.subcontainer.bar]):
 | 
					   def foo(bar: Bar = Provide[Container.subcontainer.bar]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,6 +107,7 @@ When wiring is done functions and methods with the markers are patched to provid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
   def foo(bar: Bar = Provide[Container.bar]):
 | 
					   def foo(bar: Bar = Provide[Container.bar]):
 | 
				
			||||||
       ...
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,6 +207,7 @@ Take a look at other application examples:
 | 
				
			||||||
- :ref:`decoupled-packages`
 | 
					- :ref:`decoupled-packages`
 | 
				
			||||||
- :ref:`django-example`
 | 
					- :ref:`django-example`
 | 
				
			||||||
- :ref:`flask-example`
 | 
					- :ref:`flask-example`
 | 
				
			||||||
 | 
					- :ref:`flask-blueprints-example`
 | 
				
			||||||
- :ref:`aiohttp-example`
 | 
					- :ref:`aiohttp-example`
 | 
				
			||||||
- :ref:`sanic-example`
 | 
					- :ref:`sanic-example`
 | 
				
			||||||
- :ref:`fastapi-example`
 | 
					- :ref:`fastapi-example`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import sys
 | 
				
			||||||
from unittest import mock
 | 
					from unittest import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import containers, providers
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from after import ApiClient, Service
 | 
					from after import ApiClient, Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ class Container(containers.DeclarativeContainer):
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(service: Service = Provide[Container.service]):
 | 
					def main(service: Service = Provide[Container.service]):
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,8 +111,8 @@ The output should be something like:
 | 
				
			||||||
   giphynavigator/application.py      12      0   100%
 | 
					   giphynavigator/application.py      12      0   100%
 | 
				
			||||||
   giphynavigator/containers.py        6      0   100%
 | 
					   giphynavigator/containers.py        6      0   100%
 | 
				
			||||||
   giphynavigator/giphy.py            14      9    36%
 | 
					   giphynavigator/giphy.py            14      9    36%
 | 
				
			||||||
   giphynavigator/handlers.py          9      0   100%
 | 
					   giphynavigator/handlers.py         10      0   100%
 | 
				
			||||||
   giphynavigator/services.py          9      1    89%
 | 
					   giphynavigator/services.py          9      1    89%
 | 
				
			||||||
   giphynavigator/tests.py            37      0   100%
 | 
					   giphynavigator/tests.py            37      0   100%
 | 
				
			||||||
   ---------------------------------------------------
 | 
					   ---------------------------------------------------
 | 
				
			||||||
   TOTAL                              87     10    89%
 | 
					   TOTAL                              88     10    89%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,13 @@
 | 
				
			||||||
"""Handlers module."""
 | 
					"""Handlers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from aiohttp import web
 | 
					from aiohttp import web
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .services import SearchService
 | 
					from .services import SearchService
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
async def index(
 | 
					async def index(
 | 
				
			||||||
        request: web.Request,
 | 
					        request: web.Request,
 | 
				
			||||||
        search_service: SearchService = Provide[Container.search_service],
 | 
					        search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .services import UserService, AuthService, PhotoService
 | 
					from .services import UserService, AuthService, PhotoService
 | 
				
			||||||
from .containers import Application
 | 
					from .containers import Application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(
 | 
					def main(
 | 
				
			||||||
        email: str,
 | 
					        email: str,
 | 
				
			||||||
        password: str,
 | 
					        password: str,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .services import UserService, AuthService, PhotoService
 | 
					from .services import UserService, AuthService, PhotoService
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(
 | 
					def main(
 | 
				
			||||||
        email: str,
 | 
					        email: str,
 | 
				
			||||||
        password: str,
 | 
					        password: str,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -76,11 +76,11 @@ The output should be something like:
 | 
				
			||||||
   Name                             Stmts   Miss  Cover
 | 
					   Name                             Stmts   Miss  Cover
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   monitoringdaemon/__init__.py         0      0   100%
 | 
					   monitoringdaemon/__init__.py         0      0   100%
 | 
				
			||||||
   monitoringdaemon/__main__.py        12     12     0%
 | 
					   monitoringdaemon/__main__.py        13     13     0%
 | 
				
			||||||
   monitoringdaemon/containers.py      11      0   100%
 | 
					   monitoringdaemon/containers.py      11      0   100%
 | 
				
			||||||
   monitoringdaemon/dispatcher.py      44      5    89%
 | 
					   monitoringdaemon/dispatcher.py      44      5    89%
 | 
				
			||||||
   monitoringdaemon/http.py             6      3    50%
 | 
					   monitoringdaemon/http.py             6      3    50%
 | 
				
			||||||
   monitoringdaemon/monitors.py        23      1    96%
 | 
					   monitoringdaemon/monitors.py        23      1    96%
 | 
				
			||||||
   monitoringdaemon/tests.py           37      0   100%
 | 
					   monitoringdaemon/tests.py           37      0   100%
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   TOTAL                              133     21    84%
 | 
					   TOTAL                              134     22    84%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .dispatcher import Dispatcher
 | 
					from .dispatcher import Dispatcher
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(dispatcher: Dispatcher = Provide[Container.dispatcher]) -> None:
 | 
					def main(dispatcher: Dispatcher = Provide[Container.dispatcher]) -> None:
 | 
				
			||||||
    dispatcher.run()
 | 
					    dispatcher.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .user.repositories import UserRepository
 | 
					from .user.repositories import UserRepository
 | 
				
			||||||
from .photo.repositories import PhotoRepository
 | 
					from .photo.repositories import PhotoRepository
 | 
				
			||||||
| 
						 | 
					@ -10,6 +10,7 @@ from .analytics.services import AggregationService
 | 
				
			||||||
from .containers import ApplicationContainer
 | 
					from .containers import ApplicationContainer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(
 | 
					def main(
 | 
				
			||||||
        user_repository: UserRepository = Provide[
 | 
					        user_repository: UserRepository = Provide[
 | 
				
			||||||
            ApplicationContainer.user_package.user_repository
 | 
					            ApplicationContainer.user_package.user_repository
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,6 @@ The output should be something like:
 | 
				
			||||||
   web/apps.py                         7      0   100%
 | 
					   web/apps.py                         7      0   100%
 | 
				
			||||||
   web/tests.py                       28      0   100%
 | 
					   web/tests.py                       28      0   100%
 | 
				
			||||||
   web/urls.py                         3      0   100%
 | 
					   web/urls.py                         3      0   100%
 | 
				
			||||||
   web/views.py                       11      0   100%
 | 
					   web/views.py                       12      0   100%
 | 
				
			||||||
   ---------------------------------------------------
 | 
					   ---------------------------------------------------
 | 
				
			||||||
   TOTAL                             120     10    92%
 | 
					   TOTAL                             121     10    92%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,13 @@ from typing import List
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.http import HttpRequest, HttpResponse
 | 
					from django.http import HttpRequest, HttpResponse
 | 
				
			||||||
from django.shortcuts import render
 | 
					from django.shortcuts import render
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from githubnavigator.containers import Container
 | 
					from githubnavigator.containers import Container
 | 
				
			||||||
from githubnavigator.services import SearchService
 | 
					from githubnavigator.services import SearchService
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def index(
 | 
					def index(
 | 
				
			||||||
        request: HttpRequest,
 | 
					        request: HttpRequest,
 | 
				
			||||||
        search_service: SearchService = Provide[Container.search_service],
 | 
					        search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,9 +113,9 @@ The output should be something like:
 | 
				
			||||||
   giphynavigator/__init__.py          0      0   100%
 | 
					   giphynavigator/__init__.py          0      0   100%
 | 
				
			||||||
   giphynavigator/application.py      13      0   100%
 | 
					   giphynavigator/application.py      13      0   100%
 | 
				
			||||||
   giphynavigator/containers.py        6      0   100%
 | 
					   giphynavigator/containers.py        6      0   100%
 | 
				
			||||||
   giphynavigator/endpoints.py         5      0   100%
 | 
					   giphynavigator/endpoints.py         6      0   100%
 | 
				
			||||||
   giphynavigator/giphy.py            14      9    36%
 | 
					   giphynavigator/giphy.py            14      9    36%
 | 
				
			||||||
   giphynavigator/services.py          9      1    89%
 | 
					   giphynavigator/services.py          9      1    89%
 | 
				
			||||||
   giphynavigator/tests.py            38      0   100%
 | 
					   giphynavigator/tests.py            38      0   100%
 | 
				
			||||||
   ---------------------------------------------------
 | 
					   ---------------------------------------------------
 | 
				
			||||||
   TOTAL                              85     10    88%
 | 
					   TOTAL                              86     10    88%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,11 @@
 | 
				
			||||||
"""Endpoints module."""
 | 
					"""Endpoints module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
async def index(
 | 
					async def index(
 | 
				
			||||||
        query: str = Provide[Container.config.default.query],
 | 
					        query: str = Provide[Container.config.default.query],
 | 
				
			||||||
        limit: int = Provide[Container.config.default.limit.as_int()],
 | 
					        limit: int = Provide[Container.config.default.limit.as_int()],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										100
									
								
								examples/miniapps/flask-blueprints/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								examples/miniapps/flask-blueprints/README.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					Flask Blueprints + Dependency Injector Example
 | 
				
			||||||
 | 
					==============================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a `Flask <https://flask.palletsprojects.com/>`_ Blueprints +
 | 
				
			||||||
 | 
					`Dependency Injector <https://python-dependency-injector.ets-labs.org/>`_ example application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The example application helps to search for repositories on the Github.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. image:: screenshot.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Create virtual environment:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   virtualenv venv
 | 
				
			||||||
 | 
					   . venv/bin/activate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Install requirements:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pip install -r requirements.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run the application do:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export FLASK_APP=githubnavigator.application
 | 
				
			||||||
 | 
					    export FLASK_ENV=development
 | 
				
			||||||
 | 
					    flask run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The output should be something like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    * Serving Flask app "githubnavigator.application" (lazy loading)
 | 
				
			||||||
 | 
					    * Environment: development
 | 
				
			||||||
 | 
					    * Debug mode: on
 | 
				
			||||||
 | 
					    * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 | 
				
			||||||
 | 
					    * Restarting with fsevents reloader
 | 
				
			||||||
 | 
					    * Debugger is active!
 | 
				
			||||||
 | 
					    * Debugger PIN: 473-587-859
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After that visit http://127.0.0.1:5000/ in your browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Github has a rate limit. When the rate limit is exceed you will see an exception
 | 
				
			||||||
 | 
					   ``github.GithubException.RateLimitExceededException``. For unauthenticated requests, the rate
 | 
				
			||||||
 | 
					   limit allows for up to 60 requests per hour. To extend the limit to 5000 requests per hour you
 | 
				
			||||||
 | 
					   need to set personal access token.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   It's easy:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   - Follow this `guide <https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token>`_ to create a token.
 | 
				
			||||||
 | 
					   - Set a token to the environment variable:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      export GITHUB_TOKEN=<your token>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   - Restart the app with ``flask run``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   `Read more on Github rate limit <https://developer.github.com/v3/#rate-limiting>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Test
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This application comes with the unit tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run the tests do:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   py.test githubnavigator/tests.py --cov=githubnavigator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The output should be something like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
 | 
				
			||||||
 | 
					   plugins: flask-1.0.0, cov-2.10.0
 | 
				
			||||||
 | 
					   collected 2 items
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   githubnavigator/tests.py ..                                     [100%]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ---------- coverage: platform darwin, python 3.8.3-final-0 -----------
 | 
				
			||||||
 | 
					   Name                             Stmts   Miss  Cover
 | 
				
			||||||
 | 
					   ----------------------------------------------------
 | 
				
			||||||
 | 
					   githubnavigator/__init__.py                 0      0   100%
 | 
				
			||||||
 | 
					   githubnavigator/application.py             15      0   100%
 | 
				
			||||||
 | 
					   githubnavigator/blueprints/example.py      12      0   100%
 | 
				
			||||||
 | 
					   githubnavigator/containers.py               7      0   100%
 | 
				
			||||||
 | 
					   githubnavigator/services.py                14      0   100%
 | 
				
			||||||
 | 
					   githubnavigator/tests.py                   34      0   100%
 | 
				
			||||||
 | 
					   -----------------------------------------------------------
 | 
				
			||||||
 | 
					   TOTAL                                      82      0   100%
 | 
				
			||||||
							
								
								
									
										5
									
								
								examples/miniapps/flask-blueprints/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								examples/miniapps/flask-blueprints/config.yml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					github:
 | 
				
			||||||
 | 
					  request_timeout: 10
 | 
				
			||||||
 | 
					default:
 | 
				
			||||||
 | 
					  query: "Dependency Injector"
 | 
				
			||||||
 | 
					  limit: 10
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					"""Top-level package."""
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					"""Application module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from flask import Flask
 | 
				
			||||||
 | 
					from flask_bootstrap import Bootstrap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					from .blueprints import example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def create_app() -> Flask:
 | 
				
			||||||
 | 
					    container = Container()
 | 
				
			||||||
 | 
					    container.config.from_yaml('config.yml')
 | 
				
			||||||
 | 
					    container.config.github.auth_token.from_env('GITHUB_TOKEN')
 | 
				
			||||||
 | 
					    container.wire(modules=[example])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    app = Flask(__name__)
 | 
				
			||||||
 | 
					    app.container = container
 | 
				
			||||||
 | 
					    app.register_blueprint(example.blueprint)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bootstrap = Bootstrap()
 | 
				
			||||||
 | 
					    bootstrap.init_app(app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return app
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					"""Blueprints package."""
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					"""Example blueprint."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from flask import Blueprint, request, render_template
 | 
				
			||||||
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from githubnavigator.services import SearchService
 | 
				
			||||||
 | 
					from githubnavigator.containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					blueprint = Blueprint('example', __name__, template_folder='templates/')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@blueprint.route('/')
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
 | 
					def index(
 | 
				
			||||||
 | 
					        search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
 | 
					        default_query: str = Provide[Container.config.default.query],
 | 
				
			||||||
 | 
					        default_limit: int = Provide[Container.config.default.limit.as_int()],
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    query = request.args.get('query', default_query)
 | 
				
			||||||
 | 
					    limit = request.args.get('limit', default_limit, int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    repositories = search_service.search_repositories(query, limit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return render_template(
 | 
				
			||||||
 | 
					        'index.html',
 | 
				
			||||||
 | 
					        query=query,
 | 
				
			||||||
 | 
					        limit=limit,
 | 
				
			||||||
 | 
					        repositories=repositories,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					"""Containers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
 | 
					from github import Github
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config = providers.Configuration()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    github_client = providers.Factory(
 | 
				
			||||||
 | 
					        Github,
 | 
				
			||||||
 | 
					        login_or_token=config.github.auth_token,
 | 
				
			||||||
 | 
					        timeout=config.github.request_timeout,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search_service = providers.Factory(
 | 
				
			||||||
 | 
					        services.SearchService,
 | 
				
			||||||
 | 
					        github_client=github_client,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,44 @@
 | 
				
			||||||
 | 
					"""Services module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from github import Github
 | 
				
			||||||
 | 
					from github.Repository import Repository
 | 
				
			||||||
 | 
					from github.Commit import Commit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SearchService:
 | 
				
			||||||
 | 
					    """Search service performs search on Github."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, github_client: Github):
 | 
				
			||||||
 | 
					        self._github_client = github_client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_repositories(self, query, limit):
 | 
				
			||||||
 | 
					        """Search for repositories and return formatted data."""
 | 
				
			||||||
 | 
					        repositories = self._github_client.search_repositories(
 | 
				
			||||||
 | 
					            query=query,
 | 
				
			||||||
 | 
					            **{'in': 'name'},
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            self._format_repo(repository)
 | 
				
			||||||
 | 
					            for repository in repositories[:limit]
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _format_repo(self, repository: Repository):
 | 
				
			||||||
 | 
					        commits = repository.get_commits()
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'url': repository.html_url,
 | 
				
			||||||
 | 
					            'name': repository.name,
 | 
				
			||||||
 | 
					            'owner': {
 | 
				
			||||||
 | 
					                'login': repository.owner.login,
 | 
				
			||||||
 | 
					                'url': repository.owner.html_url,
 | 
				
			||||||
 | 
					                'avatar_url': repository.owner.avatar_url,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            'latest_commit': self._format_commit(commits[0]) if commits else {},
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _format_commit(self, commit: Commit):
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            'sha': commit.sha,
 | 
				
			||||||
 | 
					            'url': commit.html_url,
 | 
				
			||||||
 | 
					            'message': commit.commit.message,
 | 
				
			||||||
 | 
					            'author_name': commit.commit.author.name,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -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>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,70 @@
 | 
				
			||||||
 | 
					{% extends "base.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block title %}Github Navigator{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block content %}
 | 
				
			||||||
 | 
					<div class="container">
 | 
				
			||||||
 | 
					    <h1 class="mb-4">Github Navigator</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <form>
 | 
				
			||||||
 | 
					        <div class="form-group form-row">
 | 
				
			||||||
 | 
					            <div class="col-10">
 | 
				
			||||||
 | 
					                <label for="search_query" class="col-form-label">
 | 
				
			||||||
 | 
					                    Search for:
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <input class="form-control" type="text" id="search_query"
 | 
				
			||||||
 | 
					                       placeholder="Type something to search on the GitHub"
 | 
				
			||||||
 | 
					                       name="query"
 | 
				
			||||||
 | 
					                       value="{{ query if query }}">
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="col">
 | 
				
			||||||
 | 
					                <label for="search_limit" class="col-form-label">
 | 
				
			||||||
 | 
					                    Limit:
 | 
				
			||||||
 | 
					                </label>
 | 
				
			||||||
 | 
					                <select class="form-control" id="search_limit" name="limit">
 | 
				
			||||||
 | 
					                    {% for value in [5, 10, 20] %}
 | 
				
			||||||
 | 
					                    <option {% if value == limit %}selected{% endif %}>
 | 
				
			||||||
 | 
					                        {{ value }}
 | 
				
			||||||
 | 
					                    </option>
 | 
				
			||||||
 | 
					                    {% endfor %}
 | 
				
			||||||
 | 
					                </select>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <p><small>Results found: {{ repositories|length }}</small></p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <table class="table table-striped">
 | 
				
			||||||
 | 
					        <thead>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <th>#</th>
 | 
				
			||||||
 | 
					                <th>Repository</th>
 | 
				
			||||||
 | 
					                <th class="text-nowrap">Repository owner</th>
 | 
				
			||||||
 | 
					                <th class="text-nowrap">Last commit</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </thead>
 | 
				
			||||||
 | 
					        <tbody>
 | 
				
			||||||
 | 
					        {% for repository in repositories %} {{n}}
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <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>
 | 
				
			||||||
 | 
					              </td>
 | 
				
			||||||
 | 
					              <td><a href="{{ repository.latest_commit.url }}">
 | 
				
			||||||
 | 
					                  {{ repository.latest_commit.sha }}</a>
 | 
				
			||||||
 | 
					                  {{ repository.latest_commit.message }}
 | 
				
			||||||
 | 
					                  {{ repository.latest_commit.author_name }}
 | 
				
			||||||
 | 
					              </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        {% endfor %}
 | 
				
			||||||
 | 
					        </tbody>
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
							
								
								
									
										71
									
								
								examples/miniapps/flask-blueprints/githubnavigator/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								examples/miniapps/flask-blueprints/githubnavigator/tests.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					"""Tests module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from unittest import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from github import Github
 | 
				
			||||||
 | 
					from flask import url_for
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .application import create_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def app():
 | 
				
			||||||
 | 
					    app = create_app()
 | 
				
			||||||
 | 
					    yield app
 | 
				
			||||||
 | 
					    app.container.unwire()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_index(client, app):
 | 
				
			||||||
 | 
					    github_client_mock = mock.Mock(spec=Github)
 | 
				
			||||||
 | 
					    github_client_mock.search_repositories.return_value = [
 | 
				
			||||||
 | 
					        mock.Mock(
 | 
				
			||||||
 | 
					            html_url='repo1-url',
 | 
				
			||||||
 | 
					            name='repo1-name',
 | 
				
			||||||
 | 
					            owner=mock.Mock(
 | 
				
			||||||
 | 
					                login='owner1-login',
 | 
				
			||||||
 | 
					                html_url='owner1-url',
 | 
				
			||||||
 | 
					                avatar_url='owner1-avatar-url',
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            get_commits=mock.Mock(return_value=[mock.Mock()]),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        mock.Mock(
 | 
				
			||||||
 | 
					            html_url='repo2-url',
 | 
				
			||||||
 | 
					            name='repo2-name',
 | 
				
			||||||
 | 
					            owner=mock.Mock(
 | 
				
			||||||
 | 
					                login='owner2-login',
 | 
				
			||||||
 | 
					                html_url='owner2-url',
 | 
				
			||||||
 | 
					                avatar_url='owner2-avatar-url',
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            get_commits=mock.Mock(return_value=[mock.Mock()]),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with app.container.github_client.override(github_client_mock):
 | 
				
			||||||
 | 
					        response = client.get(url_for('example.index'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 200
 | 
				
			||||||
 | 
					    assert b'Results found: 2' in response.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert b'repo1-url' in response.data
 | 
				
			||||||
 | 
					    assert b'repo1-name' in response.data
 | 
				
			||||||
 | 
					    assert b'owner1-login' in response.data
 | 
				
			||||||
 | 
					    assert b'owner1-url' in response.data
 | 
				
			||||||
 | 
					    assert b'owner1-avatar-url' in response.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert b'repo2-url' in response.data
 | 
				
			||||||
 | 
					    assert b'repo2-name' in response.data
 | 
				
			||||||
 | 
					    assert b'owner2-login' in response.data
 | 
				
			||||||
 | 
					    assert b'owner2-url' in response.data
 | 
				
			||||||
 | 
					    assert b'owner2-avatar-url' in response.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_index_no_results(client, app):
 | 
				
			||||||
 | 
					    github_client_mock = mock.Mock(spec=Github)
 | 
				
			||||||
 | 
					    github_client_mock.search_repositories.return_value = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with app.container.github_client.override(github_client_mock):
 | 
				
			||||||
 | 
					        response = client.get(url_for('example.index'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 200
 | 
				
			||||||
 | 
					    assert b'Results found: 0' in response.data
 | 
				
			||||||
							
								
								
									
										7
									
								
								examples/miniapps/flask-blueprints/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/miniapps/flask-blueprints/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					dependency-injector
 | 
				
			||||||
 | 
					flask
 | 
				
			||||||
 | 
					bootstrap-flask
 | 
				
			||||||
 | 
					pygithub
 | 
				
			||||||
 | 
					pyyaml
 | 
				
			||||||
 | 
					pytest-flask
 | 
				
			||||||
 | 
					pytest-cov
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								examples/miniapps/flask-blueprints/screenshot.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								examples/miniapps/flask-blueprints/screenshot.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 647 KiB  | 
| 
						 | 
					@ -95,6 +95,6 @@ The output should be something like:
 | 
				
			||||||
   githubnavigator/containers.py        7      0   100%
 | 
					   githubnavigator/containers.py        7      0   100%
 | 
				
			||||||
   githubnavigator/services.py         14      0   100%
 | 
					   githubnavigator/services.py         14      0   100%
 | 
				
			||||||
   githubnavigator/tests.py            34      0   100%
 | 
					   githubnavigator/tests.py            34      0   100%
 | 
				
			||||||
   githubnavigator/views.py             9      0   100%
 | 
					   githubnavigator/views.py            10      0   100%
 | 
				
			||||||
   ----------------------------------------------------
 | 
					   ----------------------------------------------------
 | 
				
			||||||
   TOTAL                               79      0   100%
 | 
					   TOTAL                               80      0   100%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,13 @@
 | 
				
			||||||
"""Views module."""
 | 
					"""Views module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import request, render_template
 | 
					from flask import request, render_template
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .services import SearchService
 | 
					from .services import SearchService
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def index(
 | 
					def index(
 | 
				
			||||||
        search_service: SearchService = Provide[Container.search_service],
 | 
					        search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
        default_query: str = Provide[Container.config.default.query],
 | 
					        default_query: str = Provide[Container.config.default.query],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,11 +68,11 @@ The output should be something like:
 | 
				
			||||||
   Name                   Stmts   Miss  Cover
 | 
					   Name                   Stmts   Miss  Cover
 | 
				
			||||||
   ------------------------------------------
 | 
					   ------------------------------------------
 | 
				
			||||||
   movies/__init__.py         0      0   100%
 | 
					   movies/__init__.py         0      0   100%
 | 
				
			||||||
   movies/__main__.py        17     17     0%
 | 
					   movies/__main__.py        18     18     0%
 | 
				
			||||||
   movies/containers.py       9      0   100%
 | 
					   movies/containers.py       9      0   100%
 | 
				
			||||||
   movies/entities.py         7      1    86%
 | 
					   movies/entities.py         7      1    86%
 | 
				
			||||||
   movies/finders.py         26     13    50%
 | 
					   movies/finders.py         26     13    50%
 | 
				
			||||||
   movies/listers.py          8      0   100%
 | 
					   movies/listers.py          8      0   100%
 | 
				
			||||||
   movies/tests.py           24      0   100%
 | 
					   movies/tests.py           24      0   100%
 | 
				
			||||||
   ------------------------------------------
 | 
					   ------------------------------------------
 | 
				
			||||||
   TOTAL                     91     31    66%
 | 
					   TOTAL                     92     32    65%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .listers import MovieLister
 | 
					from .listers import MovieLister
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
					def main(lister: MovieLister = Provide[Container.lister]) -> None:
 | 
				
			||||||
    print('Francis Lawrence movies:')
 | 
					    print('Francis Lawrence movies:')
 | 
				
			||||||
    for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
					    for movie in lister.movies_directed_by('Francis Lawrence'):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,8 +112,8 @@ The output should be something like:
 | 
				
			||||||
   giphynavigator/application.py      12      0   100%
 | 
					   giphynavigator/application.py      12      0   100%
 | 
				
			||||||
   giphynavigator/containers.py        6      0   100%
 | 
					   giphynavigator/containers.py        6      0   100%
 | 
				
			||||||
   giphynavigator/giphy.py            14      9    36%
 | 
					   giphynavigator/giphy.py            14      9    36%
 | 
				
			||||||
   giphynavigator/handlers.py         10      0   100%
 | 
					   giphynavigator/handlers.py         11      0   100%
 | 
				
			||||||
   giphynavigator/services.py          9      1    89%
 | 
					   giphynavigator/services.py          9      1    89%
 | 
				
			||||||
   giphynavigator/tests.py            34      0   100%
 | 
					   giphynavigator/tests.py            34      0   100%
 | 
				
			||||||
   ---------------------------------------------------
 | 
					   ---------------------------------------------------
 | 
				
			||||||
   TOTAL                              89     14    84%
 | 
					   TOTAL                              90     14    84%
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,13 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from sanic.request import Request
 | 
					from sanic.request import Request
 | 
				
			||||||
from sanic.response import HTTPResponse, json
 | 
					from sanic.response import HTTPResponse, json
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .services import SearchService
 | 
					from .services import SearchService
 | 
				
			||||||
from .containers import Container
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
async def index(
 | 
					async def index(
 | 
				
			||||||
        request: Request,
 | 
					        request: Request,
 | 
				
			||||||
        search_service: SearchService = Provide[Container.search_service],
 | 
					        search_service: SearchService = Provide[Container.search_service],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import containers, providers
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Service:
 | 
					class Service:
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@ class Container(containers.DeclarativeContainer):
 | 
				
			||||||
    service = providers.Factory(Service)
 | 
					    service = providers.Factory(Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def main(service: Service = Provide[Container.service]) -> None:
 | 
					def main(service: Service = Provide[Container.service]) -> None:
 | 
				
			||||||
    ...
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import containers, providers
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
from flask import Flask, json
 | 
					from flask import Flask, json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,6 +16,7 @@ class Container(containers.DeclarativeContainer):
 | 
				
			||||||
    service = providers.Factory(Service)
 | 
					    service = providers.Factory(Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def index_view(service: Service = Provide[Container.service]) -> str:
 | 
					def index_view(service: Service = Provide[Container.service]) -> str:
 | 
				
			||||||
    return json.dumps({'service_id': id(service)})
 | 
					    return json.dumps({'service_id': id(service)})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import containers, providers
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
from dependency_injector.wiring import Provide, Closing
 | 
					from dependency_injector.wiring import inject, Provide, Closing
 | 
				
			||||||
from flask import Flask, current_app
 | 
					from flask import Flask, current_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,7 @@ class Container(containers.DeclarativeContainer):
 | 
				
			||||||
    service = providers.Resource(init_service)
 | 
					    service = providers.Resource(init_service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def index_view(service: Service = Closing[Provide[Container.service]]):
 | 
					def index_view(service: Service = Closing[Provide[Container.service]]):
 | 
				
			||||||
    assert service is current_app.container.service()
 | 
					    assert service is current_app.container.service()
 | 
				
			||||||
    return 'Hello  World!'
 | 
					    return 'Hello  World!'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
"""Top-level package."""
 | 
					"""Top-level package."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__version__ = '4.3.9'
 | 
					__version__ = '4.4.0'
 | 
				
			||||||
"""Version number.
 | 
					"""Version number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:type: str
 | 
					:type: str
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,19 @@ import importlib
 | 
				
			||||||
import pkgutil
 | 
					import pkgutil
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
from types import ModuleType
 | 
					from types import ModuleType
 | 
				
			||||||
from typing import Optional, Iterable, Callable, Any, Tuple, Dict, Generic, TypeVar, Type, cast
 | 
					from typing import (
 | 
				
			||||||
 | 
					    Optional,
 | 
				
			||||||
 | 
					    Iterable,
 | 
				
			||||||
 | 
					    Iterator,
 | 
				
			||||||
 | 
					    Callable,
 | 
				
			||||||
 | 
					    Any,
 | 
				
			||||||
 | 
					    Tuple,
 | 
				
			||||||
 | 
					    Dict,
 | 
				
			||||||
 | 
					    Generic,
 | 
				
			||||||
 | 
					    TypeVar,
 | 
				
			||||||
 | 
					    Type,
 | 
				
			||||||
 | 
					    cast,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if sys.version_info < (3, 7):
 | 
					if sys.version_info < (3, 7):
 | 
				
			||||||
    from typing import GenericMeta
 | 
					    from typing import GenericMeta
 | 
				
			||||||
| 
						 | 
					@ -21,15 +33,35 @@ from . import providers
 | 
				
			||||||
__all__ = (
 | 
					__all__ = (
 | 
				
			||||||
    'wire',
 | 
					    'wire',
 | 
				
			||||||
    'unwire',
 | 
					    'unwire',
 | 
				
			||||||
 | 
					    'inject',
 | 
				
			||||||
    'Provide',
 | 
					    'Provide',
 | 
				
			||||||
    'Provider',
 | 
					    'Provider',
 | 
				
			||||||
    'Closing',
 | 
					    'Closing',
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
T = TypeVar('T')
 | 
					T = TypeVar('T')
 | 
				
			||||||
 | 
					F = TypeVar('F', bound=Callable[..., Any])
 | 
				
			||||||
Container = Any
 | 
					Container = Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Registry:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self._storage = set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add(self, patched: Callable[..., Any]) -> None:
 | 
				
			||||||
 | 
					        self._storage.add(patched)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_from_module(self, module: ModuleType) -> Iterator[Callable[..., Any]]:
 | 
				
			||||||
 | 
					        for patched in self._storage:
 | 
				
			||||||
 | 
					            if patched.__module__ != module.__name__:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            yield patched
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_patched_registry = Registry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProvidersMap:
 | 
					class ProvidersMap:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, container):
 | 
					    def __init__(self, container):
 | 
				
			||||||
| 
						 | 
					@ -152,7 +184,7 @@ class ProvidersMap:
 | 
				
			||||||
        return providers_map
 | 
					        return providers_map
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def wire(
 | 
					def wire(  # noqa: C901
 | 
				
			||||||
        container: Container,
 | 
					        container: Container,
 | 
				
			||||||
        *,
 | 
					        *,
 | 
				
			||||||
        modules: Optional[Iterable[ModuleType]] = None,
 | 
					        modules: Optional[Iterable[ModuleType]] = None,
 | 
				
			||||||
| 
						 | 
					@ -179,6 +211,9 @@ def wire(
 | 
				
			||||||
                for method_name, method in inspect.getmembers(member, _is_method):
 | 
					                for method_name, method in inspect.getmembers(member, _is_method):
 | 
				
			||||||
                    _patch_method(member, method_name, method, providers_map)
 | 
					                    _patch_method(member, method_name, method, providers_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for patched in _patched_registry.get_from_module(module):
 | 
				
			||||||
 | 
					            _bind_injections(patched, providers_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def unwire(
 | 
					def unwire(
 | 
				
			||||||
        *,
 | 
					        *,
 | 
				
			||||||
| 
						 | 
					@ -201,6 +236,17 @@ def unwire(
 | 
				
			||||||
                for method_name, method in inspect.getmembers(member, inspect.isfunction):
 | 
					                for method_name, method in inspect.getmembers(member, inspect.isfunction):
 | 
				
			||||||
                    _unpatch(member, method_name, method)
 | 
					                    _unpatch(member, method_name, method)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for patched in _patched_registry.get_from_module(module):
 | 
				
			||||||
 | 
					            _unbind_injections(patched)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def inject(fn: F) -> F:
 | 
				
			||||||
 | 
					    """Decorate callable with injecting decorator."""
 | 
				
			||||||
 | 
					    reference_injections, reference_closing = _fetch_reference_injections(fn)
 | 
				
			||||||
 | 
					    patched = _get_patched(fn, reference_injections, reference_closing)
 | 
				
			||||||
 | 
					    _patched_registry.add(patched)
 | 
				
			||||||
 | 
					    return cast(F, patched)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _patch_fn(
 | 
					def _patch_fn(
 | 
				
			||||||
        module: ModuleType,
 | 
					        module: ModuleType,
 | 
				
			||||||
| 
						 | 
					@ -208,11 +254,16 @@ def _patch_fn(
 | 
				
			||||||
        fn: Callable[..., Any],
 | 
					        fn: Callable[..., Any],
 | 
				
			||||||
        providers_map: ProvidersMap,
 | 
					        providers_map: ProvidersMap,
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
    injections, closing = _resolve_injections(fn, providers_map)
 | 
					    if not _is_patched(fn):
 | 
				
			||||||
    if not injections:
 | 
					        reference_injections, reference_closing = _fetch_reference_injections(fn)
 | 
				
			||||||
        return
 | 
					        if not reference_injections:
 | 
				
			||||||
    patched = _patch_with_injections(fn, injections, closing)
 | 
					            return
 | 
				
			||||||
    setattr(module, name, _wrap_patched(patched, fn, injections, closing))
 | 
					        fn = _get_patched(fn, reference_injections, reference_closing)
 | 
				
			||||||
 | 
					        _patched_registry.add(fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _bind_injections(fn, providers_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setattr(module, name, fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _patch_method(
 | 
					def _patch_method(
 | 
				
			||||||
| 
						 | 
					@ -221,28 +272,27 @@ def _patch_method(
 | 
				
			||||||
        method: Callable[..., Any],
 | 
					        method: Callable[..., Any],
 | 
				
			||||||
        providers_map: ProvidersMap,
 | 
					        providers_map: ProvidersMap,
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
    injections, closing = _resolve_injections(method, providers_map)
 | 
					 | 
				
			||||||
    if not injections:
 | 
					 | 
				
			||||||
        return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if hasattr(cls, '__dict__') \
 | 
					    if hasattr(cls, '__dict__') \
 | 
				
			||||||
            and name in cls.__dict__ \
 | 
					            and name in cls.__dict__ \
 | 
				
			||||||
            and isinstance(cls.__dict__[name], (classmethod, staticmethod)):
 | 
					            and isinstance(cls.__dict__[name], (classmethod, staticmethod)):
 | 
				
			||||||
        method = cls.__dict__[name]
 | 
					        method = cls.__dict__[name]
 | 
				
			||||||
        patched = _patch_with_injections(method.__func__, injections, closing)
 | 
					        fn = method.__func__
 | 
				
			||||||
        patched = type(method)(patched)
 | 
					 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        patched = _patch_with_injections(method, injections, closing)
 | 
					        fn = method
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setattr(cls, name, _wrap_patched(patched, method, injections, closing))
 | 
					    if not _is_patched(fn):
 | 
				
			||||||
 | 
					        reference_injections, reference_closing = _fetch_reference_injections(fn)
 | 
				
			||||||
 | 
					        if not reference_injections:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        fn = _get_patched(fn, reference_injections, reference_closing)
 | 
				
			||||||
 | 
					        _patched_registry.add(fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _bind_injections(fn, providers_map)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _wrap_patched(patched: Callable[..., Any], original, injections, closing):
 | 
					    if isinstance(method, (classmethod, staticmethod)):
 | 
				
			||||||
    patched.__wired__ = True
 | 
					        fn = type(method)(fn)
 | 
				
			||||||
    patched.__original__ = original
 | 
					
 | 
				
			||||||
    patched.__injections__ = injections
 | 
					    setattr(cls, name, fn)
 | 
				
			||||||
    patched.__closing__ = closing
 | 
					 | 
				
			||||||
    return patched
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _unpatch(
 | 
					def _unpatch(
 | 
				
			||||||
| 
						 | 
					@ -250,14 +300,20 @@ def _unpatch(
 | 
				
			||||||
        name: str,
 | 
					        name: str,
 | 
				
			||||||
        fn: Callable[..., Any],
 | 
					        fn: Callable[..., Any],
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
 | 
					    if hasattr(module, '__dict__') \
 | 
				
			||||||
 | 
					            and name in module.__dict__ \
 | 
				
			||||||
 | 
					            and isinstance(module.__dict__[name], (classmethod, staticmethod)):
 | 
				
			||||||
 | 
					        method = module.__dict__[name]
 | 
				
			||||||
 | 
					        fn = method.__func__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if not _is_patched(fn):
 | 
					    if not _is_patched(fn):
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
    setattr(module, name, _get_original_from_patched(fn))
 | 
					
 | 
				
			||||||
 | 
					    _unbind_injections(fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _resolve_injections(
 | 
					def _fetch_reference_injections(
 | 
				
			||||||
        fn: Callable[..., Any],
 | 
					        fn: Callable[..., Any],
 | 
				
			||||||
        providers_map: ProvidersMap,
 | 
					 | 
				
			||||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
 | 
					) -> Tuple[Dict[str, Any], Dict[str, Any]]:
 | 
				
			||||||
    signature = inspect.signature(fn)
 | 
					    signature = inspect.signature(fn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -268,24 +324,33 @@ def _resolve_injections(
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
        marker = parameter.default
 | 
					        marker = parameter.default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        closing_modifier = False
 | 
					 | 
				
			||||||
        if isinstance(marker, Closing):
 | 
					        if isinstance(marker, Closing):
 | 
				
			||||||
            closing_modifier = True
 | 
					 | 
				
			||||||
            marker = marker.provider
 | 
					            marker = marker.provider
 | 
				
			||||||
 | 
					            closing[parameter_name] = marker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        injections[parameter_name] = marker
 | 
				
			||||||
 | 
					    return injections, closing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> None:
 | 
				
			||||||
 | 
					    for injection, marker in fn.__reference_injections__.items():
 | 
				
			||||||
        provider = providers_map.resolve_provider(marker.provider)
 | 
					        provider = providers_map.resolve_provider(marker.provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if provider is None:
 | 
					        if provider is None:
 | 
				
			||||||
            continue
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if closing_modifier:
 | 
					 | 
				
			||||||
            closing[parameter_name] = provider
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if isinstance(marker, Provide):
 | 
					        if isinstance(marker, Provide):
 | 
				
			||||||
            injections[parameter_name] = provider
 | 
					            fn.__injections__[injection] = provider
 | 
				
			||||||
        elif isinstance(marker, Provider):
 | 
					        elif isinstance(marker, Provider):
 | 
				
			||||||
            injections[parameter_name] = provider.provider
 | 
					            fn.__injections__[injection] = provider.provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return injections, closing
 | 
					        if injection in fn.__reference_closing__:
 | 
				
			||||||
 | 
					            fn.__closing__[injection] = provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _unbind_injections(fn: Callable[..., Any]) -> None:
 | 
				
			||||||
 | 
					    fn.__injections__ = {}
 | 
				
			||||||
 | 
					    fn.__closing__ = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _fetch_modules(package):
 | 
					def _fetch_modules(package):
 | 
				
			||||||
| 
						 | 
					@ -303,26 +368,34 @@ def _is_method(member):
 | 
				
			||||||
    return inspect.ismethod(member) or inspect.isfunction(member)
 | 
					    return inspect.ismethod(member) or inspect.isfunction(member)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _patch_with_injections(fn, injections, closing):
 | 
					def _get_patched(fn, reference_injections, reference_closing):
 | 
				
			||||||
    if inspect.iscoroutinefunction(fn):
 | 
					    if inspect.iscoroutinefunction(fn):
 | 
				
			||||||
        _patched = _get_async_patched(fn, injections, closing)
 | 
					        patched = _get_async_patched(fn)
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        _patched = _get_patched(fn, injections, closing)
 | 
					        patched = _get_sync_patched(fn)
 | 
				
			||||||
    return _patched
 | 
					
 | 
				
			||||||
 | 
					    patched.__wired__ = True
 | 
				
			||||||
 | 
					    patched.__original__ = fn
 | 
				
			||||||
 | 
					    patched.__injections__ = {}
 | 
				
			||||||
 | 
					    patched.__reference_injections__ = reference_injections
 | 
				
			||||||
 | 
					    patched.__closing__ = {}
 | 
				
			||||||
 | 
					    patched.__reference_closing__ = reference_closing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return patched
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_patched(fn, injections, closing):
 | 
					def _get_sync_patched(fn):
 | 
				
			||||||
    @functools.wraps(fn)
 | 
					    @functools.wraps(fn)
 | 
				
			||||||
    def _patched(*args, **kwargs):
 | 
					    def _patched(*args, **kwargs):
 | 
				
			||||||
        to_inject = kwargs.copy()
 | 
					        to_inject = kwargs.copy()
 | 
				
			||||||
        for injection, provider in injections.items():
 | 
					        for injection, provider in _patched.__injections__.items():
 | 
				
			||||||
            if injection not in kwargs \
 | 
					            if injection not in kwargs \
 | 
				
			||||||
                    or _is_fastapi_default_arg_injection(injection, kwargs):
 | 
					                    or _is_fastapi_default_arg_injection(injection, kwargs):
 | 
				
			||||||
                to_inject[injection] = provider()
 | 
					                to_inject[injection] = provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = fn(*args, **to_inject)
 | 
					        result = fn(*args, **to_inject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for injection, provider in closing.items():
 | 
					        for injection, provider in _patched.__closing__.items():
 | 
				
			||||||
            if injection in kwargs \
 | 
					            if injection in kwargs \
 | 
				
			||||||
                    and not _is_fastapi_default_arg_injection(injection, kwargs):
 | 
					                    and not _is_fastapi_default_arg_injection(injection, kwargs):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
| 
						 | 
					@ -334,18 +407,18 @@ def _get_patched(fn, injections, closing):
 | 
				
			||||||
    return _patched
 | 
					    return _patched
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_async_patched(fn, injections, closing):
 | 
					def _get_async_patched(fn):
 | 
				
			||||||
    @functools.wraps(fn)
 | 
					    @functools.wraps(fn)
 | 
				
			||||||
    async def _patched(*args, **kwargs):
 | 
					    async def _patched(*args, **kwargs):
 | 
				
			||||||
        to_inject = kwargs.copy()
 | 
					        to_inject = kwargs.copy()
 | 
				
			||||||
        for injection, provider in injections.items():
 | 
					        for injection, provider in _patched.__injections__.items():
 | 
				
			||||||
            if injection not in kwargs \
 | 
					            if injection not in kwargs \
 | 
				
			||||||
                    or _is_fastapi_default_arg_injection(injection, kwargs):
 | 
					                    or _is_fastapi_default_arg_injection(injection, kwargs):
 | 
				
			||||||
                to_inject[injection] = provider()
 | 
					                to_inject[injection] = provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = await fn(*args, **to_inject)
 | 
					        result = await fn(*args, **to_inject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for injection, provider in closing.items():
 | 
					        for injection, provider in _patched.__closing__.items():
 | 
				
			||||||
            if injection in kwargs \
 | 
					            if injection in kwargs \
 | 
				
			||||||
                    and not _is_fastapi_default_arg_injection(injection, kwargs):
 | 
					                    and not _is_fastapi_default_arg_injection(injection, kwargs):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
| 
						 | 
					@ -366,10 +439,6 @@ def _is_patched(fn):
 | 
				
			||||||
    return getattr(fn, '__wired__', False) is True
 | 
					    return getattr(fn, '__wired__', False) is True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _get_original_from_patched(fn):
 | 
					 | 
				
			||||||
    return getattr(fn, '__original__')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def _is_declarative_container_instance(instance: Any) -> bool:
 | 
					def _is_declarative_container_instance(instance: Any) -> bool:
 | 
				
			||||||
    return (not isinstance(instance, type)
 | 
					    return (not isinstance(instance, type)
 | 
				
			||||||
            and getattr(instance, '__IS_CONTAINER__', False) is True
 | 
					            and getattr(instance, '__IS_CONTAINER__', False) is True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@
 | 
				
			||||||
from decimal import Decimal
 | 
					from decimal import Decimal
 | 
				
			||||||
from typing import Callable
 | 
					from typing import Callable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector.wiring import Provide, Provider
 | 
					from dependency_injector.wiring import inject, Provide, Provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .container import Container, SubContainer
 | 
					from .container import Container, SubContainer
 | 
				
			||||||
from .service import Service
 | 
					from .service import Service
 | 
				
			||||||
| 
						 | 
					@ -11,30 +11,37 @@ from .service import Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestClass:
 | 
					class TestClass:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @inject
 | 
				
			||||||
    def __init__(self, service: Service = Provide[Container.service]):
 | 
					    def __init__(self, service: Service = Provide[Container.service]):
 | 
				
			||||||
        self.service = service
 | 
					        self.service = service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @inject
 | 
				
			||||||
    def method(self, service: Service = Provide[Container.service]):
 | 
					    def method(self, service: Service = Provide[Container.service]):
 | 
				
			||||||
        return service
 | 
					        return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    @inject
 | 
				
			||||||
    def class_method(cls, service: Service = Provide[Container.service]):
 | 
					    def class_method(cls, service: Service = Provide[Container.service]):
 | 
				
			||||||
        return service
 | 
					        return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    @inject
 | 
				
			||||||
    def static_method(service: Service = Provide[Container.service]):
 | 
					    def static_method(service: Service = Provide[Container.service]):
 | 
				
			||||||
        return service
 | 
					        return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_function(service: Service = Provide[Container.service]):
 | 
					def test_function(service: Service = Provide[Container.service]):
 | 
				
			||||||
    return service
 | 
					    return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_function_provider(service_provider: Callable[..., Service] = Provider[Container.service]):
 | 
					def test_function_provider(service_provider: Callable[..., Service] = Provider[Container.service]):
 | 
				
			||||||
    service = service_provider()
 | 
					    service = service_provider()
 | 
				
			||||||
    return service
 | 
					    return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_config_value(
 | 
					def test_config_value(
 | 
				
			||||||
        some_value_int: int = Provide[Container.config.a.b.c.as_int()],
 | 
					        some_value_int: int = Provide[Container.config.a.b.c.as_int()],
 | 
				
			||||||
        some_value_str: str = Provide[Container.config.a.b.c.as_(str)],
 | 
					        some_value_str: str = Provide[Container.config.a.b.c.as_(str)],
 | 
				
			||||||
| 
						 | 
					@ -43,25 +50,44 @@ def test_config_value(
 | 
				
			||||||
    return some_value_int, some_value_str, some_value_decimal
 | 
					    return some_value_int, some_value_str, some_value_decimal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_provide_provider(service_provider: Callable[..., Service] = Provider[Container.service.provider]):
 | 
					def test_provide_provider(service_provider: Callable[..., Service] = Provider[Container.service.provider]):
 | 
				
			||||||
    service = service_provider()
 | 
					    service = service_provider()
 | 
				
			||||||
    return service
 | 
					    return service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_provided_instance(some_value: int = Provide[Container.service.provided.foo['bar'].call()]):
 | 
					def test_provided_instance(some_value: int = Provide[Container.service.provided.foo['bar'].call()]):
 | 
				
			||||||
    return some_value
 | 
					    return some_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_subcontainer_provider(some_value: int = Provide[Container.sub.int_object]):
 | 
					def test_subcontainer_provider(some_value: int = Provide[Container.sub.int_object]):
 | 
				
			||||||
    return some_value
 | 
					    return some_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_config_invariant(some_value: int = Provide[Container.config.option[Container.config.switch]]):
 | 
					def test_config_invariant(some_value: int = Provide[Container.config.option[Container.config.switch]]):
 | 
				
			||||||
    return some_value
 | 
					    return some_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_provide_from_different_containers(
 | 
					def test_provide_from_different_containers(
 | 
				
			||||||
        service: Service = Provide[Container.service],
 | 
					        service: Service = Provide[Container.service],
 | 
				
			||||||
        some_value: int = Provide[SubContainer.int_object],
 | 
					        some_value: int = Provide[SubContainer.int_object],
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    return service, some_value
 | 
					    return service, some_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClassDecorator:
 | 
				
			||||||
 | 
					    def __init__(self, fn):
 | 
				
			||||||
 | 
					        self._fn = fn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __call__(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return self._fn(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@ClassDecorator
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
 | 
					def test_class_decorator(service: Service = Provide[Container.service]):
 | 
				
			||||||
 | 
					    return service
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
from dependency_injector.wiring import Provide
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ...container import Container
 | 
					from ...container import Container
 | 
				
			||||||
from ...service import Service
 | 
					from ...service import Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_function(service: Service = Provide[Container.service]):
 | 
					def test_function(service: Service = Provide[Container.service]):
 | 
				
			||||||
    return service
 | 
					    return service
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
from dependency_injector import containers, providers
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
from dependency_injector.wiring import Provide, Closing
 | 
					from dependency_injector.wiring import inject, Provide, Closing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Service:
 | 
					class Service:
 | 
				
			||||||
| 
						 | 
					@ -32,5 +32,6 @@ class Container(containers.DeclarativeContainer):
 | 
				
			||||||
    service = providers.Resource(init_service)
 | 
					    service = providers.Resource(init_service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
def test_function(service: Service = Closing[Provide[Container.service]]):
 | 
					def test_function(service: Service = Closing[Provide[Container.service]]):
 | 
				
			||||||
    return service
 | 
					    return service
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -226,6 +226,10 @@ class WiringTest(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(result_2.init_counter, 0)
 | 
					        self.assertEqual(result_2.init_counter, 0)
 | 
				
			||||||
        self.assertEqual(result_2.shutdown_counter, 0)
 | 
					        self.assertEqual(result_2.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_class_decorator(self):
 | 
				
			||||||
 | 
					        service = module.test_class_decorator()
 | 
				
			||||||
 | 
					        self.assertIsInstance(service, Service)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WiringAndFastAPITest(unittest.TestCase):
 | 
					class WiringAndFastAPITest(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user