mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-10-31 16:07:51 +03:00 
			
		
		
		
	Wiring reengineering (#324)
* Bump version to 4.3.9: FastAPI example * Reengineer wiring * Add @inject decorator * Add .workspace dir to gitignore * Add generic typing for @inject * Add type cast for @inject * Update movie lister example * Update cli application tutorial * Update demo example * Update wiring docs and examples * Update aiohttp example and tutorial * Update multiple containers example * Update single container example * Update decoupled packages example * Update django example * Update asyncio daemon example and tutorial * Update FastAPI example * Update flask example and tutorial * Update sanic example * Add wiring registry * Add new line to .gitignore * Add @inject to the test samples * Fix flake8 errors
This commit is contained in:
		
							parent
							
								
									bece33fc21
								
							
						
					
					
						commit
						ae3024588c
					
				
							
								
								
									
										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/ | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ Key features of the ``Dependency Injector``: | ||||||
|   or process pool, etc. Can be used for per-function execution scope in tandem with wiring. |   or process pool, etc. Can be used for per-function execution scope in tandem with wiring. | ||||||
|   See `Resource provider <https://python-dependency-injector.ets-labs.org/providers/resource.html>`_. |   See `Resource provider <https://python-dependency-injector.ets-labs.org/providers/resource.html>`_. | ||||||
| - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | ||||||
|   other frameworks: Django, Flask, Aiohttp, etc. |   other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. | ||||||
|   See `Wiring <https://python-dependency-injector.ets-labs.org/wiring.html>`_. |   See `Wiring <https://python-dependency-injector.ets-labs.org/wiring.html>`_. | ||||||
| - **Typing**. Provides typing stubs, ``mypy``-friendly. | - **Typing**. Provides typing stubs, ``mypy``-friendly. | ||||||
|   See `Typing and mypy <https://python-dependency-injector.ets-labs.org/providers/typing_mypy.html>`_. |   See `Typing and mypy <https://python-dependency-injector.ets-labs.org/providers/typing_mypy.html>`_. | ||||||
|  | @ -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]): | ||||||
|        ... |        ... | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										79
									
								
								docs/examples/fastapi.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								docs/examples/fastapi.rst
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | ||||||
|  | .. _fastapi-example: | ||||||
|  | 
 | ||||||
|  | FastAPI example | ||||||
|  | =============== | ||||||
|  | 
 | ||||||
|  | .. meta:: | ||||||
|  |    :keywords: Python,Dependency Injection,FastAPI,Example | ||||||
|  |    :description: This example demonstrates a usage of the FastAPI and Dependency Injector. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | This example shows how to use ``Dependency Injector`` with `FastAPI <https://fastapi.tiangolo.com/>`_. | ||||||
|  | 
 | ||||||
|  | The example application is a REST API that searches for funny GIFs on the `Giphy <https://giphy.com/>`_. | ||||||
|  | 
 | ||||||
|  | The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi>`_. | ||||||
|  | 
 | ||||||
|  | Application structure | ||||||
|  | --------------------- | ||||||
|  | 
 | ||||||
|  | Application has next structure: | ||||||
|  | 
 | ||||||
|  | .. code-block:: bash | ||||||
|  | 
 | ||||||
|  |    ./ | ||||||
|  |    ├── giphynavigator/ | ||||||
|  |    │   ├── __init__.py | ||||||
|  |    │   ├── application.py | ||||||
|  |    │   ├── containers.py | ||||||
|  |    │   ├── endpoints.py | ||||||
|  |    │   ├── giphy.py | ||||||
|  |    │   ├── services.py | ||||||
|  |    │   └── tests.py | ||||||
|  |    ├── config.yml | ||||||
|  |    └── requirements.txt | ||||||
|  | 
 | ||||||
|  | Container | ||||||
|  | --------- | ||||||
|  | 
 | ||||||
|  | Declarative container is defined in ``giphynavigator/containers.py``: | ||||||
|  | 
 | ||||||
|  | .. literalinclude:: ../../examples/miniapps/fastapi/giphynavigator/containers.py | ||||||
|  |    :language: python | ||||||
|  | 
 | ||||||
|  | Endpoints | ||||||
|  | --------- | ||||||
|  | 
 | ||||||
|  | Endpoint has a dependency on search service. There are also some config options that are used as default values. | ||||||
|  | The dependencies are injected using :ref:`wiring` feature. | ||||||
|  | 
 | ||||||
|  | Listing of ``giphynavigator/endpoints.py``: | ||||||
|  | 
 | ||||||
|  | .. literalinclude:: ../../examples/miniapps/fastapi/giphynavigator/endpoints.py | ||||||
|  |    :language: python | ||||||
|  | 
 | ||||||
|  | Application factory | ||||||
|  | ------------------- | ||||||
|  | Application factory creates container, wires it with the ``endpoints`` module, creates | ||||||
|  | ``FastAPI`` app, and setup routes. | ||||||
|  | 
 | ||||||
|  | Listing of ``giphynavigator/application.py``: | ||||||
|  | 
 | ||||||
|  | .. literalinclude:: ../../examples/miniapps/fastapi/giphynavigator/application.py | ||||||
|  |    :language: python | ||||||
|  | 
 | ||||||
|  | Tests | ||||||
|  | ----- | ||||||
|  | 
 | ||||||
|  | Tests use :ref:`provider-overriding` feature to replace giphy client with a mock ``giphynavigator/tests.py``: | ||||||
|  | 
 | ||||||
|  | .. literalinclude:: ../../examples/miniapps/fastapi/giphynavigator/tests.py | ||||||
|  |    :language: python | ||||||
|  |    :emphasize-lines: 29,57,72 | ||||||
|  | 
 | ||||||
|  | Sources | ||||||
|  | ------- | ||||||
|  | 
 | ||||||
|  | Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi>`_. | ||||||
|  | 
 | ||||||
|  | .. disqus:: | ||||||
|  | @ -17,5 +17,6 @@ Explore the examples to see the ``Dependency Injector`` in action. | ||||||
|     flask |     flask | ||||||
|     aiohttp |     aiohttp | ||||||
|     sanic |     sanic | ||||||
|  |     fastapi | ||||||
| 
 | 
 | ||||||
| .. disqus:: | .. disqus:: | ||||||
|  |  | ||||||
|  | @ -77,7 +77,7 @@ Key features of the ``Dependency Injector``: | ||||||
|   See :ref:`resource-provider`. |   See :ref:`resource-provider`. | ||||||
| - **Containers**. Provides declarative and dynamic containers. See :ref:`containers`. | - **Containers**. Provides declarative and dynamic containers. See :ref:`containers`. | ||||||
| - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | ||||||
|   other frameworks: Django, Flask, Aiohttp, etc. See :ref:`wiring`. |   other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See :ref:`wiring`. | ||||||
| - **Typing**. Provides typing stubs, ``mypy``-friendly. See :ref:`provider-typing`. | - **Typing**. Provides typing stubs, ``mypy``-friendly. See :ref:`provider-typing`. | ||||||
| - **Performance**. Fast. Written in ``Cython``. | - **Performance**. Fast. Written in ``Cython``. | ||||||
| - **Maturity**. Mature and production-ready. Well-tested, documented and supported. | - **Maturity**. Mature and production-ready. Well-tested, documented and supported. | ||||||
|  | @ -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]): | ||||||
|        ... |        ... | ||||||
| 
 | 
 | ||||||
|  | @ -284,6 +285,7 @@ Choose one of the following as a next step: | ||||||
|     - :ref:`flask-example` |     - :ref:`flask-example` | ||||||
|     - :ref:`aiohttp-example` |     - :ref:`aiohttp-example` | ||||||
|     - :ref:`sanic-example` |     - :ref:`sanic-example` | ||||||
|  |     - :ref:`fastapi-example` | ||||||
| - Pass the tutorials: | - Pass the tutorials: | ||||||
|     - :ref:`flask-tutorial` |     - :ref:`flask-tutorial` | ||||||
|     - :ref:`aiohttp-tutorial` |     - :ref:`aiohttp-tutorial` | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ Key features of the ``Dependency Injector``: | ||||||
|   See :ref:`resource-provider`. |   See :ref:`resource-provider`. | ||||||
| - **Containers**. Provides declarative and dynamic containers. See :ref:`containers`. | - **Containers**. Provides declarative and dynamic containers. See :ref:`containers`. | ||||||
| - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | - **Wiring**. Injects dependencies into functions and methods. Helps integrating with | ||||||
|   other frameworks: Django, Flask, Aiohttp, etc. See :ref:`wiring`. |   other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See :ref:`wiring`. | ||||||
| - **Typing**. Provides typing stubs, ``mypy``-friendly. See :ref:`provider-typing`. | - **Typing**. Provides typing stubs, ``mypy``-friendly. See :ref:`provider-typing`. | ||||||
| - **Performance**. Fast. Written in ``Cython``. | - **Performance**. Fast. Written in ``Cython``. | ||||||
| - **Maturity**. Mature and production-ready. Well-tested, documented and supported. | - **Maturity**. Mature and production-ready. Well-tested, documented and supported. | ||||||
|  |  | ||||||
|  | @ -7,6 +7,10 @@ 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.3.9 | ||||||
|  | ----- | ||||||
|  | - Add ``FastAPI`` example. | ||||||
|  | 
 | ||||||
| 4.3.8 | 4.3.8 | ||||||
| ----- | ----- | ||||||
| - Add a hotfix to support wiring for ``FastAPI`` endpoints. | - Add a hotfix to support wiring for ``FastAPI`` endpoints. | ||||||
|  |  | ||||||
|  | @ -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]): | ||||||
|        ... |        ... | ||||||
| 
 | 
 | ||||||
|  | @ -201,5 +209,6 @@ Take a look at other application examples: | ||||||
| - :ref:`flask-example` | - :ref:`flask-example` | ||||||
| - :ref:`aiohttp-example` | - :ref:`aiohttp-example` | ||||||
| - :ref:`sanic-example` | - :ref:`sanic-example` | ||||||
|  | - :ref:`fastapi-example` | ||||||
| 
 | 
 | ||||||
| .. disqus:: | .. disqus:: | ||||||
|  |  | ||||||
|  | @ -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()], | ||||||
|  |  | ||||||
|  | @ -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.8' | __version__ = '4.3.9' | ||||||
| """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