mirror of
				https://github.com/ets-labs/python-dependency-injector.git
				synced 2025-11-04 01:47:36 +03:00 
			
		
		
		
	Merge branch 'release/4.6.0' into master
This commit is contained in:
		
						commit
						9cd201a493
					
				| 
						 | 
					@ -78,6 +78,15 @@ jobs:
 | 
				
			||||||
      after_success:
 | 
					      after_success:
 | 
				
			||||||
        - python3 -m pip install --upgrade --upgrade-strategy eager twine
 | 
					        - python3 -m pip install --upgrade --upgrade-strategy eager twine
 | 
				
			||||||
        - python3 -m twine upload wheelhouse/*.whl
 | 
					        - python3 -m twine upload wheelhouse/*.whl
 | 
				
			||||||
 | 
					    - services: docker
 | 
				
			||||||
 | 
					      arch: arm64
 | 
				
			||||||
 | 
					      if: tag IS present
 | 
				
			||||||
 | 
					      env: TWINE_USERNAME=__token__
 | 
				
			||||||
 | 
					      install: python3 -m pip install cibuildwheel==1.6.3
 | 
				
			||||||
 | 
					      script: python3 -m cibuildwheel --output-dir wheelhouse
 | 
				
			||||||
 | 
					      after_success:
 | 
				
			||||||
 | 
					        - python3 -m pip install --upgrade --upgrade-strategy eager twine
 | 
				
			||||||
 | 
					        - python3 -m twine upload wheelhouse/*.whl
 | 
				
			||||||
    - os: osx
 | 
					    - os: osx
 | 
				
			||||||
      if: tag IS present
 | 
					      if: tag IS present
 | 
				
			||||||
      language: shell
 | 
					      language: shell
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,3 +14,4 @@ Dependency Injector Contributors
 | 
				
			||||||
+ RobinsonMa (RobinsonMa)
 | 
					+ RobinsonMa (RobinsonMa)
 | 
				
			||||||
+ Rüdiger Busche (JarnoRFB)
 | 
					+ Rüdiger Busche (JarnoRFB)
 | 
				
			||||||
+ Dmitry Rassoshenko (rda-dev)
 | 
					+ Dmitry Rassoshenko (rda-dev)
 | 
				
			||||||
 | 
					+ Fotis Koutoupas (kootoopas)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
Copyright (c) 2020, ETS Labs
 | 
					Copyright (c) 2021, ETS Labs
 | 
				
			||||||
All rights reserved.
 | 
					All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Redistribution and use in source and binary forms, with or without
 | 
					Redistribution and use in source and binary forms, with or without
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,8 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
- **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, Sanic, FastAPI, 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>`_.
 | 
				
			||||||
 | 
					- **Asynchronous**. Supports asynchronous injections.
 | 
				
			||||||
 | 
					  See `Asynchronous injections <https://python-dependency-injector.ets-labs.org/providers/async.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>`_.
 | 
				
			||||||
- **Performance**. Fast. Written in ``Cython``.
 | 
					- **Performance**. Fast. Written in ``Cython``.
 | 
				
			||||||
| 
						 | 
					@ -157,6 +159,8 @@ Choose one of the following:
 | 
				
			||||||
- `Flask example <https://python-dependency-injector.ets-labs.org/examples/flask.html>`_
 | 
					- `Flask example <https://python-dependency-injector.ets-labs.org/examples/flask.html>`_
 | 
				
			||||||
- `Aiohttp example <https://python-dependency-injector.ets-labs.org/examples/aiohttp.html>`_
 | 
					- `Aiohttp example <https://python-dependency-injector.ets-labs.org/examples/aiohttp.html>`_
 | 
				
			||||||
- `Sanic example <https://python-dependency-injector.ets-labs.org/examples/sanic.html>`_
 | 
					- `Sanic example <https://python-dependency-injector.ets-labs.org/examples/sanic.html>`_
 | 
				
			||||||
 | 
					- `FastAPI example <https://python-dependency-injector.ets-labs.org/examples/fastapi.html>`_
 | 
				
			||||||
 | 
					- `FastAPI + Redis example <https://python-dependency-injector.ets-labs.org/examples/fastapi-redis.html>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Tutorials
 | 
					Tutorials
 | 
				
			||||||
---------
 | 
					---------
 | 
				
			||||||
| 
						 | 
					@ -223,4 +227,3 @@ Want to contribute?
 | 
				
			||||||
.. |tell| unicode:: U+1F4AC .. tell sign
 | 
					.. |tell| unicode:: U+1F4AC .. tell sign
 | 
				
			||||||
.. |fork| unicode:: U+1F500 .. fork sign
 | 
					.. |fork| unicode:: U+1F500 .. fork sign
 | 
				
			||||||
.. |pull| unicode:: U+2B05 U+FE0F .. pull sign
 | 
					.. |pull| unicode:: U+2B05 U+FE0F .. pull sign
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,7 @@ master_doc = 'index'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# General information about the project.
 | 
					# General information about the project.
 | 
				
			||||||
project = u'Dependency Injector'
 | 
					project = u'Dependency Injector'
 | 
				
			||||||
copyright = u'2020, ETS Labs'
 | 
					copyright = u'2021, ETS Labs'
 | 
				
			||||||
author = u'ETS Labs'
 | 
					author = u'ETS Labs'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The version info for the project you're documenting, acts as replacement for
 | 
					# The version info for the project you're documenting, acts as replacement for
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										98
									
								
								docs/examples/fastapi-redis.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								docs/examples/fastapi-redis.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,98 @@
 | 
				
			||||||
 | 
					.. _fastapi-redis-example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FastAPI + Redis example
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. meta::
 | 
				
			||||||
 | 
					   :keywords: Python,Dependency Injection,FastAPI,Redis,Example
 | 
				
			||||||
 | 
					   :description: This example demonstrates a usage of the FastAPI, Redis, and Dependency Injector.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This example shows how to use ``Dependency Injector`` with `FastAPI <https://fastapi.tiangolo.com/>`_ and
 | 
				
			||||||
 | 
					`Redis <https://redis.io/>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi-redis>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Provider :ref:`async-injections`
 | 
				
			||||||
 | 
					- Resource provider :ref:`resource-async-initializers`
 | 
				
			||||||
 | 
					- Wiring :ref:`async-injections-wiring`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application structure
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application has next structure:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ./
 | 
				
			||||||
 | 
					   ├── fastapiredis/
 | 
				
			||||||
 | 
					   │   ├── __init__.py
 | 
				
			||||||
 | 
					   │   ├── application.py
 | 
				
			||||||
 | 
					   │   ├── containers.py
 | 
				
			||||||
 | 
					   │   ├── redis.py
 | 
				
			||||||
 | 
					   │   ├── services.py
 | 
				
			||||||
 | 
					   │   └── tests.py
 | 
				
			||||||
 | 
					   ├── docker-compose.yml
 | 
				
			||||||
 | 
					   ├── Dockerfile
 | 
				
			||||||
 | 
					   └── requirements.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Redis
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Module ``redis`` defines Redis connection pool initialization and shutdown. See ``fastapiredis/redis.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/fastapi-redis/fastapiredis/redis.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Service
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Module ``services`` contains example service. Service has a dependency on Redis connection pool.
 | 
				
			||||||
 | 
					It uses it for getting and setting a key asynchronously. Real life service will do something more meaningful.
 | 
				
			||||||
 | 
					See ``fastapiredis/services.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/fastapi-redis/fastapiredis/services.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Container
 | 
				
			||||||
 | 
					---------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Declarative container wires example service with Redis connection pool. See ``fastapiredis/containers.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/fastapi-redis/fastapiredis/containers.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Application
 | 
				
			||||||
 | 
					-----------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Module ``application`` creates ``FastAPI`` app, setup endpoint, and init container.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Endpoint ``index`` has a dependency on example service. The dependency is injected using :ref:`wiring` feature.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Listing of ``fastapiredis/application.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/fastapi-redis/fastapiredis/application.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tests
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tests use :ref:`provider-overriding` feature to replace example service with a mock. See ``fastapiredis/tests.py``:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/miniapps/fastapi-redis/fastapiredis/tests.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					   :emphasize-lines: 24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sources
 | 
				
			||||||
 | 
					-------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi-redis>`_.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Provider :ref:`async-injections`
 | 
				
			||||||
 | 
					- Resource provider :ref:`resource-async-initializers`
 | 
				
			||||||
 | 
					- Wiring :ref:`async-injections-wiring`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. disqus::
 | 
				
			||||||
| 
						 | 
					@ -19,5 +19,6 @@ Explore the examples to see the ``Dependency Injector`` in action.
 | 
				
			||||||
    aiohttp
 | 
					    aiohttp
 | 
				
			||||||
    sanic
 | 
					    sanic
 | 
				
			||||||
    fastapi
 | 
					    fastapi
 | 
				
			||||||
 | 
					    fastapi-redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. disqus::
 | 
					.. disqus::
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
- **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, Sanic, FastAPI, etc. See :ref:`wiring`.
 | 
					  other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See :ref:`wiring`.
 | 
				
			||||||
 | 
					- **Asynchronous**. Supports asynchronous injections. See :ref:`async-injections`.
 | 
				
			||||||
- **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.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -287,6 +287,7 @@ Choose one of the following as a next step:
 | 
				
			||||||
    - :ref:`aiohttp-example`
 | 
					    - :ref:`aiohttp-example`
 | 
				
			||||||
    - :ref:`sanic-example`
 | 
					    - :ref:`sanic-example`
 | 
				
			||||||
    - :ref:`fastapi-example`
 | 
					    - :ref:`fastapi-example`
 | 
				
			||||||
 | 
					    - :ref:`fastapi-redis-example`
 | 
				
			||||||
- Pass the tutorials:
 | 
					- Pass the tutorials:
 | 
				
			||||||
    - :ref:`flask-tutorial`
 | 
					    - :ref:`flask-tutorial`
 | 
				
			||||||
    - :ref:`aiohttp-tutorial`
 | 
					    - :ref:`aiohttp-tutorial`
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@ Key features of the ``Dependency Injector``:
 | 
				
			||||||
- **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, Sanic, FastAPI, etc. See :ref:`wiring`.
 | 
					  other frameworks: Django, Flask, Aiohttp, Sanic, FastAPI, etc. See :ref:`wiring`.
 | 
				
			||||||
 | 
					- **Asynchronous**. Supports asynchronous injections. See :ref:`async-injections`.
 | 
				
			||||||
- **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,19 @@ 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.6.0
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					- Add support of async injections for providers.
 | 
				
			||||||
 | 
					- Add support of async injections for wiring.
 | 
				
			||||||
 | 
					- Add support of async initializers for ``Resource`` provider.
 | 
				
			||||||
 | 
					- Add ``FastAPI`` + ``Redis`` example.
 | 
				
			||||||
 | 
					- Add ARM wheel builds.
 | 
				
			||||||
 | 
					  See issue `#342 <https://github.com/ets-labs/python-dependency-injector/issues/342>`_ for details.
 | 
				
			||||||
 | 
					- Fix a typo in `ext.flask` deprecation warning.
 | 
				
			||||||
 | 
					  See PR `#345 <https://github.com/ets-labs/python-dependency-injector/pull/345>`_ for details.
 | 
				
			||||||
 | 
					  Thanks to `Fotis Koutoupas <https://github.com/kootoopas>`_ for the fix.
 | 
				
			||||||
 | 
					- Update copyright year.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4.5.4
 | 
					4.5.4
 | 
				
			||||||
-----
 | 
					-----
 | 
				
			||||||
- Fix manylinux wheels uploading issue.
 | 
					- Fix manylinux wheels uploading issue.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										108
									
								
								docs/providers/async.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								docs/providers/async.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,108 @@
 | 
				
			||||||
 | 
					.. _async-injections:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronous injections
 | 
				
			||||||
 | 
					=======================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. meta::
 | 
				
			||||||
 | 
					   :keywords: Python,DI,Dependency injection,IoC,Inversion of Control,Providers,Async,Injections,Asynchronous,Await,
 | 
				
			||||||
 | 
					              Asyncio
 | 
				
			||||||
 | 
					   :description: Dependency Injector providers support asynchronous injections. This page
 | 
				
			||||||
 | 
					                 demonstrates how make asynchronous dependency injections in Python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Providers support asynchronous injections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/providers/async.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					   :emphasize-lines: 26-29
 | 
				
			||||||
 | 
					   :lines: 3-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If provider has any awaitable injections it switches into async mode. In async mode provider always returns awaitable.
 | 
				
			||||||
 | 
					This causes a cascade effect:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   provider1()              <── Async mode enabled <──┐
 | 
				
			||||||
 | 
					   │                                                  │
 | 
				
			||||||
 | 
					   ├──> provider2()                                   │
 | 
				
			||||||
 | 
					   │                                                  │
 | 
				
			||||||
 | 
					   ├──> provider3()         <── Async mode enabled <──┤
 | 
				
			||||||
 | 
					   │    │                                             │
 | 
				
			||||||
 | 
					   │    └──> provider4()    <── Async provider ───────┘
 | 
				
			||||||
 | 
					   │
 | 
				
			||||||
 | 
					   └──> provider5()
 | 
				
			||||||
 | 
					        │
 | 
				
			||||||
 | 
					        └──> provider6()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In async mode provider prepares injections asynchronously.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If provider has multiple awaitable dependencies, it will run them concurrently. Provider will wait until all
 | 
				
			||||||
 | 
					dependencies are ready and inject them afterwards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   provider1()
 | 
				
			||||||
 | 
					   │
 | 
				
			||||||
 | 
					   ├──> provider2()         <── Async mode enabled
 | 
				
			||||||
 | 
					   │
 | 
				
			||||||
 | 
					   ├──> provider3()         <── Async mode enabled
 | 
				
			||||||
 | 
					   │
 | 
				
			||||||
 | 
					   └──> provider4()         <── Async mode enabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is what provider will do for the previous example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   injections = await asyncio.gather(
 | 
				
			||||||
 | 
					       provider2(),
 | 
				
			||||||
 | 
					       provider3(),
 | 
				
			||||||
 | 
					       provider4(),
 | 
				
			||||||
 | 
					   )
 | 
				
			||||||
 | 
					   await provider1(*injections)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Overriding behaviour
 | 
				
			||||||
 | 
					--------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In async mode provider always returns awaitable. It applies to the overriding too. If provider in async mode is
 | 
				
			||||||
 | 
					overridden by a provider that doesn't return awaitable result, the result will be wrapped into awaitable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. literalinclude:: ../../examples/providers/async_overriding.py
 | 
				
			||||||
 | 
					   :language: python
 | 
				
			||||||
 | 
					   :emphasize-lines: 19-24
 | 
				
			||||||
 | 
					   :lines: 3-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Async mode mechanics and API
 | 
				
			||||||
 | 
					----------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By default provider's async mode is undefined.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When provider async mode is undefined, provider will automatically select the mode during the next call.
 | 
				
			||||||
 | 
					If the result is awaitable, provider will enable async mode, if not - disable it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If provider async mode is enabled, provider always returns awaitable. If the result is not awaitable,
 | 
				
			||||||
 | 
					provider wraps it into awaitable explicitly. You can safely ``await`` provider in async mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If provider async mode is disabled, provider behaves the regular way. It doesn't do async injections
 | 
				
			||||||
 | 
					preparation or non-awaitables to awaitables conversion.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once provider async mode is enabled or disabled, provider will stay in this state. No automatic switching
 | 
				
			||||||
 | 
					will be done.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. image:: images/async_mode.png
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also use following methods to change provider's async mode manually:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ``Provider.enable_async_mode()``
 | 
				
			||||||
 | 
					- ``Provider.disable_async_mode()``
 | 
				
			||||||
 | 
					- ``Provider.reset_async_mode()``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To check the state of provider's async mode use:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- ``Provider.is_async_mode_enabled()``
 | 
				
			||||||
 | 
					- ``Provider.is_async_mode_disabled()``
 | 
				
			||||||
 | 
					- ``Provider.is_async_mode_undefined()``
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Wiring :ref:`async-injections-wiring`
 | 
				
			||||||
 | 
					- Resource provider :ref:`resource-async-initializers`
 | 
				
			||||||
 | 
					- :ref:`fastapi-redis-example`
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docs/providers/images/async_mode.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/providers/images/async_mode.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 12 KiB  | 
| 
						 | 
					@ -51,4 +51,5 @@ Providers module API docs - :py:mod:`dependency_injector.providers`
 | 
				
			||||||
    overriding
 | 
					    overriding
 | 
				
			||||||
    provided_instance
 | 
					    provided_instance
 | 
				
			||||||
    custom
 | 
					    custom
 | 
				
			||||||
 | 
					    async
 | 
				
			||||||
    typing_mypy
 | 
					    typing_mypy
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@ Resource provider
 | 
				
			||||||
Resource providers help to initialize and configure logging, event loop, thread or process pool, etc.
 | 
					Resource providers help to initialize and configure logging, event loop, thread or process pool, etc.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Resource provider is similar to ``Singleton``. Resource initialization happens only once.
 | 
					Resource provider is similar to ``Singleton``. Resource initialization happens only once.
 | 
				
			||||||
You can do injections and use provided instance the same way like you do with any other provider.
 | 
					You can make injections and use provided instance the same way like you do with any other provider.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
   :emphasize-lines: 12
 | 
					   :emphasize-lines: 12
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ You can do injections and use provided instance the same way like you do with an
 | 
				
			||||||
           executor=thread_pool,
 | 
					           executor=thread_pool,
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Container has an interface to initialize and shutdown all resources:
 | 
					Container has an interface to initialize and shutdown all resources at once:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,7 @@ Container has an interface to initialize and shutdown all resources:
 | 
				
			||||||
   container.init_resources()
 | 
					   container.init_resources()
 | 
				
			||||||
   container.shutdown_resources()
 | 
					   container.shutdown_resources()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You also can initialize and shutdown resources one-by-one using ``init()`` and
 | 
					You can also initialize and shutdown resources one-by-one using ``init()`` and
 | 
				
			||||||
``shutdown()`` methods of the provider:
 | 
					``shutdown()`` methods of the provider:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. code-block:: python
 | 
					.. code-block:: python
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,10 @@ You also can initialize and shutdown resources one-by-one using ``init()`` and
 | 
				
			||||||
   container.thread_pool.init()
 | 
					   container.thread_pool.init()
 | 
				
			||||||
   container.thread_pool.shutdown()
 | 
					   container.thread_pool.shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you call ``.shutdown()`` method on a resource provider, it will remove the reference to the initialized resource,
 | 
				
			||||||
 | 
					if any, and switch to uninitialized state. Some of resource initializer types support specifying custom
 | 
				
			||||||
 | 
					resource shutdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Resource provider supports 3 types of initializers:
 | 
					Resource provider supports 3 types of initializers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Function
 | 
					- Function
 | 
				
			||||||
| 
						 | 
					@ -97,7 +101,7 @@ you configure global resource:
 | 
				
			||||||
           fname='logging.ini',
 | 
					           fname='logging.ini',
 | 
				
			||||||
       )
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Function initializer does not support shutdown.
 | 
					Function initializer does not provide a way to specify custom resource shutdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Generator initializer
 | 
					Generator initializer
 | 
				
			||||||
---------------------
 | 
					---------------------
 | 
				
			||||||
| 
						 | 
					@ -235,4 +239,124 @@ The example above produces next output:
 | 
				
			||||||
   Shutdown service
 | 
					   Shutdown service
 | 
				
			||||||
   127.0.0.1 - - [29/Oct/2020 22:39:41] "GET / HTTP/1.1" 200 -
 | 
					   127.0.0.1 - - [29/Oct/2020 22:39:41] "GET / HTTP/1.1" 200 -
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. _resource-async-initializers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronous initializers
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you write an asynchronous application, you might need to initialize resources asynchronously. Resource
 | 
				
			||||||
 | 
					provider supports asynchronous initialization and shutdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronous function initializer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   async def init_async_resource(argument1=..., argument2=...):
 | 
				
			||||||
 | 
					       return await connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       resource = providers.Resource(
 | 
				
			||||||
 | 
					           init_resource,
 | 
				
			||||||
 | 
					           argument1=...,
 | 
				
			||||||
 | 
					           argument2=...,
 | 
				
			||||||
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronous generator initializer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   async def init_async_resource(argument1=..., argument2=...):
 | 
				
			||||||
 | 
					       connection = await connect()
 | 
				
			||||||
 | 
					       yield connection
 | 
				
			||||||
 | 
					       await connection.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       resource = providers.Resource(
 | 
				
			||||||
 | 
					           init_async_resource,
 | 
				
			||||||
 | 
					           argument1=...,
 | 
				
			||||||
 | 
					           argument2=...,
 | 
				
			||||||
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Asynchronous subclass initializer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   from dependency_injector import resources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class AsyncConnection(resources.AsyncResource):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       async def init(self, argument1=..., argument2=...):
 | 
				
			||||||
 | 
					           yield await connect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       async def shutdown(self, connection):
 | 
				
			||||||
 | 
					           await connection.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       resource = providers.Resource(
 | 
				
			||||||
 | 
					           AsyncConnection,
 | 
				
			||||||
 | 
					           argument1=...,
 | 
				
			||||||
 | 
					           argument2=...,
 | 
				
			||||||
 | 
					       )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you use resource provider with asynchronous initializer you need to call its ``__call__()``,
 | 
				
			||||||
 | 
					``init()``, and ``shutdown()`` methods asynchronously:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       connection = providers.Resource(init_async_connection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   async def main():
 | 
				
			||||||
 | 
					       container = Container()
 | 
				
			||||||
 | 
					       connection = await container.connection()
 | 
				
			||||||
 | 
					       connection = await container.connection.init()
 | 
				
			||||||
 | 
					       connection = await container.connection.shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if __name__ == '__main__':
 | 
				
			||||||
 | 
					       asyncio.run(main())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Container ``init_resources()`` and ``shutdown_resources()`` methods should be used asynchronously if there is
 | 
				
			||||||
 | 
					at least one asynchronous resource provider:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       connection1 = providers.Resource(init_async_connection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       connection2 = providers.Resource(init_sync_connection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   async def main():
 | 
				
			||||||
 | 
					       container = Container()
 | 
				
			||||||
 | 
					       await container.init_resources()
 | 
				
			||||||
 | 
					       await container.shutdown_resources()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   if __name__ == '__main__':
 | 
				
			||||||
 | 
					       asyncio.run(main())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Provider :ref:`async-injections`
 | 
				
			||||||
 | 
					- Wiring :ref:`async-injections-wiring`
 | 
				
			||||||
 | 
					- :ref:`fastapi-redis-example`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. disqus::
 | 
					.. disqus::
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -167,21 +167,105 @@ You can use that in testing to re-create and re-wire a container before each tes
 | 
				
			||||||
   avoid re-wiring between tests.
 | 
					   avoid re-wiring between tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. note::
 | 
					.. note::
 | 
				
			||||||
   Python has a limitation on patching already imported individual members. To protect from errors
 | 
					   Python has a limitation on patching individually imported functions. To protect from errors
 | 
				
			||||||
   prefer an import of modules instead of individual members or make sure that imports happen
 | 
					   prefer importing modules to importing individual functions or make sure imports happen
 | 
				
			||||||
   after the wiring:
 | 
					   after the wiring:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   .. code-block:: python
 | 
					   .. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Potential error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      from .module import fn
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      fn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Instead use next:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   .. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Always works:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      from . import module
 | 
					      from . import module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      module.fn()
 | 
					      module.fn()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      # instead of
 | 
					.. _async-injections-wiring:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      from .module import fn
 | 
					Asynchronous injections
 | 
				
			||||||
 | 
					-----------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      fn()
 | 
					Wiring feature supports asynchronous injections:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       db = providers.Resource(init_async_db_client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       cache = providers.Resource(init_async_cache_client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
 | 
					   async def main(
 | 
				
			||||||
 | 
					       db: Database = Provide[Container.db],
 | 
				
			||||||
 | 
					       cache: Cache = Provide[Container.cache],
 | 
				
			||||||
 | 
					   ):
 | 
				
			||||||
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you call asynchronous function wiring prepares injections asynchronously.
 | 
				
			||||||
 | 
					Here is what it does for previous example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db, cache = await asyncio.gather(
 | 
				
			||||||
 | 
					        container.db(),
 | 
				
			||||||
 | 
					        container.cache(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await main(db=db, cache=cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also use ``Closing`` marker with the asynchronous ``Resource`` providers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   @inject
 | 
				
			||||||
 | 
					   async def main(
 | 
				
			||||||
 | 
					       db: Database = Closing[Provide[Container.db]],
 | 
				
			||||||
 | 
					       cache: Cache = Closing[Provide[Container.cache]],
 | 
				
			||||||
 | 
					   ):
 | 
				
			||||||
 | 
					       ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Wiring does closing asynchronously:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    db, cache = await asyncio.gather(
 | 
				
			||||||
 | 
					        container.db(),
 | 
				
			||||||
 | 
					        container.cache(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await main(db=db, cache=cache)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await asyncio.gather(
 | 
				
			||||||
 | 
					        container.db.shutdown(),
 | 
				
			||||||
 | 
					        container.cache.shutdown(),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See :ref:`Resources, wiring and per-function execution scope <resource-provider-wiring-closing>` for
 | 
				
			||||||
 | 
					details on ``Closing`` marker.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. note::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Wiring does not not convert asynchronous injections to synchronous.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   It handles asynchronous injections only for ``async def`` functions. Asynchronous injections into
 | 
				
			||||||
 | 
					   synchronous ``def`` function still work, but you need to take care of awaitables by your own.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See also:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Provider :ref:`async-injections`
 | 
				
			||||||
 | 
					- Resource provider :ref:`resource-async-initializers`
 | 
				
			||||||
 | 
					- :ref:`fastapi-redis-example`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Integration with other frameworks
 | 
					Integration with other frameworks
 | 
				
			||||||
---------------------------------
 | 
					---------------------------------
 | 
				
			||||||
| 
						 | 
					@ -211,5 +295,6 @@ Take a look at other application examples:
 | 
				
			||||||
- :ref:`aiohttp-example`
 | 
					- :ref:`aiohttp-example`
 | 
				
			||||||
- :ref:`sanic-example`
 | 
					- :ref:`sanic-example`
 | 
				
			||||||
- :ref:`fastapi-example`
 | 
					- :ref:`fastapi-example`
 | 
				
			||||||
 | 
					- :ref:`fastapi-redis-example`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.. disqus::
 | 
					.. disqus::
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								examples/miniapps/fastapi-redis/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								examples/miniapps/fastapi-redis/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					FROM python:3.8-buster
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENV PYTHONUNBUFFERED=1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WORKDIR /code
 | 
				
			||||||
 | 
					COPY . /code/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RUN pip install -r requirements.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CMD ["uvicorn", "fastapiredis.application:app", "--host", "0.0.0.0"]
 | 
				
			||||||
							
								
								
									
										89
									
								
								examples/miniapps/fastapi-redis/README.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								examples/miniapps/fastapi-redis/README.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					FastAPI + Redis + Dependency Injector Example
 | 
				
			||||||
 | 
					=============================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a `FastAPI <https://docs.python.org/3/library/asyncio.html>`_
 | 
				
			||||||
 | 
					+ `Redis <https://redis.io/>`_
 | 
				
			||||||
 | 
					+ `Dependency Injector <https://python-dependency-injector.ets-labs.org/>`_ example application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run
 | 
				
			||||||
 | 
					---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Build the Docker image:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   docker-compose build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run the docker-compose environment:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    docker-compose up
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The output should be something like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:14.115 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:14.115 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=1, just started
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:14.115 # Configuration loaded
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.116 * Running mode=standalone, port=6379.
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.116 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.116 # Server initialized
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.117 * Loading RDB produced by version 6.0.9
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.117 * RDB age 1 seconds
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.117 * RDB memory usage when created 0.77 Mb
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.117 * DB loaded from disk: 0.000 seconds
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:14.117 * Ready to accept connections
 | 
				
			||||||
 | 
					   redis_1    | 1:signal-handler (1609728137) Received SIGTERM scheduling shutdown...
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:17.984 # User requested shutdown...
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:17.984 # Redis is now ready to exit, bye bye...
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:22.035 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:22.035 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=1, just started
 | 
				
			||||||
 | 
					   redis_1    | 1:C 04 Jan 2021 02:42:22.035 # Configuration loaded
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * Running mode=standalone, port=6379.
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 # Server initialized
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * Loading RDB produced by version 6.0.9
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * RDB age 9 seconds
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * RDB memory usage when created 0.77 Mb
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * DB loaded from disk: 0.000 seconds
 | 
				
			||||||
 | 
					   redis_1    | 1:M 04 Jan 2021 02:42:22.037 * Ready to accept connections
 | 
				
			||||||
 | 
					   example_1  | INFO:     Started server process [1]
 | 
				
			||||||
 | 
					   example_1  | INFO:     Waiting for application startup.
 | 
				
			||||||
 | 
					   example_1  | INFO:     Application startup complete.
 | 
				
			||||||
 | 
					   example_1  | INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Test
 | 
				
			||||||
 | 
					----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This application comes with the unit tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To run the tests do:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block:: bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   docker-compose run --rm example py.test fastapiredis/tests.py --cov=fastapiredis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The output should be something like:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.. code-block::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   platform linux -- Python 3.8.6, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
 | 
				
			||||||
 | 
					   rootdir: /code
 | 
				
			||||||
 | 
					   plugins: cov-2.10.1, asyncio-0.14.0
 | 
				
			||||||
 | 
					   collected 1 item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   fastapiredis/tests.py .                                         [100%]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   ----------- coverage: platform linux, python 3.8.6-final-0 -----------
 | 
				
			||||||
 | 
					   Name                          Stmts   Miss  Cover
 | 
				
			||||||
 | 
					   -------------------------------------------------
 | 
				
			||||||
 | 
					   fastapiredis/__init__.py          0      0   100%
 | 
				
			||||||
 | 
					   fastapiredis/application.py      15      0   100%
 | 
				
			||||||
 | 
					   fastapiredis/containers.py        6      0   100%
 | 
				
			||||||
 | 
					   fastapiredis/redis.py             7      4    43%
 | 
				
			||||||
 | 
					   fastapiredis/services.py          7      3    57%
 | 
				
			||||||
 | 
					   fastapiredis/tests.py            18      0   100%
 | 
				
			||||||
 | 
					   -------------------------------------------------
 | 
				
			||||||
 | 
					   TOTAL                            53      7    87%
 | 
				
			||||||
							
								
								
									
										21
									
								
								examples/miniapps/fastapi-redis/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								examples/miniapps/fastapi-redis/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					version: "3.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					services:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  example:
 | 
				
			||||||
 | 
					    build: .
 | 
				
			||||||
 | 
					    environment:
 | 
				
			||||||
 | 
					      REDIS_HOST: "redis"
 | 
				
			||||||
 | 
					      REDIS_PASSWORD: "password"
 | 
				
			||||||
 | 
					    ports:
 | 
				
			||||||
 | 
					      - "8000:8000"
 | 
				
			||||||
 | 
					    volumes:
 | 
				
			||||||
 | 
					      - "./:/code"
 | 
				
			||||||
 | 
					    depends_on:
 | 
				
			||||||
 | 
					      - "redis"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  redis:
 | 
				
			||||||
 | 
					    image: redis
 | 
				
			||||||
 | 
					    command: ["redis-server",  "--requirepass", "password"]
 | 
				
			||||||
 | 
					    ports:
 | 
				
			||||||
 | 
					      - "6379:6379"
 | 
				
			||||||
							
								
								
									
										1
									
								
								examples/miniapps/fastapi-redis/fastapiredis/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								examples/miniapps/fastapi-redis/fastapiredis/__init__.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					"""Top-level package."""
 | 
				
			||||||
							
								
								
									
										25
									
								
								examples/miniapps/fastapi-redis/fastapiredis/application.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								examples/miniapps/fastapi-redis/fastapiredis/application.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,25 @@
 | 
				
			||||||
 | 
					"""Application module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from fastapi import FastAPI, Depends
 | 
				
			||||||
 | 
					from dependency_injector.wiring import inject, Provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .containers import Container
 | 
				
			||||||
 | 
					from .services import Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app = FastAPI()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.api_route('/')
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
 | 
					async def index(service: Service = Depends(Provide[Container.service])):
 | 
				
			||||||
 | 
					    value = await service.process()
 | 
				
			||||||
 | 
					    return {'result': value}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					container = Container()
 | 
				
			||||||
 | 
					container.config.redis_host.from_env('REDIS_HOST', 'localhost')
 | 
				
			||||||
 | 
					container.config.redis_password.from_env('REDIS_PASSWORD', 'password')
 | 
				
			||||||
 | 
					container.wire(modules=[sys.modules[__name__]])
 | 
				
			||||||
							
								
								
									
										21
									
								
								examples/miniapps/fastapi-redis/fastapiredis/containers.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								examples/miniapps/fastapi-redis/fastapiredis/containers.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,21 @@
 | 
				
			||||||
 | 
					"""Containers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from . import redis, services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    config = providers.Configuration()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    redis_pool = providers.Resource(
 | 
				
			||||||
 | 
					        redis.init_redis_pool,
 | 
				
			||||||
 | 
					        host=config.redis_host,
 | 
				
			||||||
 | 
					        password=config.redis_password,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    service = providers.Factory(
 | 
				
			||||||
 | 
					        services.Service,
 | 
				
			||||||
 | 
					        redis=redis_pool,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
							
								
								
									
										12
									
								
								examples/miniapps/fastapi-redis/fastapiredis/redis.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								examples/miniapps/fastapi-redis/fastapiredis/redis.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					"""Redis client module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from typing import AsyncIterator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aioredis import create_redis_pool, Redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def init_redis_pool(host: str, password: str) -> AsyncIterator[Redis]:
 | 
				
			||||||
 | 
					    pool = await create_redis_pool(f'redis://{host}', password=password)
 | 
				
			||||||
 | 
					    yield pool
 | 
				
			||||||
 | 
					    pool.close()
 | 
				
			||||||
 | 
					    await pool.wait_closed()
 | 
				
			||||||
							
								
								
									
										12
									
								
								examples/miniapps/fastapi-redis/fastapiredis/services.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								examples/miniapps/fastapi-redis/fastapiredis/services.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					"""Services module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from aioredis import Redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Service:
 | 
				
			||||||
 | 
					    def __init__(self, redis: Redis) -> None:
 | 
				
			||||||
 | 
					        self._redis = redis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def process(self) -> str:
 | 
				
			||||||
 | 
					        await self._redis.set('my-key', 'value')
 | 
				
			||||||
 | 
					        return await self._redis.get('my-key', encoding='utf-8')
 | 
				
			||||||
							
								
								
									
										28
									
								
								examples/miniapps/fastapi-redis/fastapiredis/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								examples/miniapps/fastapi-redis/fastapiredis/tests.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,28 @@
 | 
				
			||||||
 | 
					"""Tests module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from unittest import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import pytest
 | 
				
			||||||
 | 
					from httpx import AsyncClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .application import app, container
 | 
				
			||||||
 | 
					from .services import Service
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.fixture
 | 
				
			||||||
 | 
					def client(event_loop):
 | 
				
			||||||
 | 
					    client = AsyncClient(app=app, base_url='http://test')
 | 
				
			||||||
 | 
					    yield client
 | 
				
			||||||
 | 
					    event_loop.run_until_complete(client.aclose())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.asyncio
 | 
				
			||||||
 | 
					async def test_index(client):
 | 
				
			||||||
 | 
					    service_mock = mock.AsyncMock(spec=Service)
 | 
				
			||||||
 | 
					    service_mock.process.return_value = 'Foo'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with container.service.override(service_mock):
 | 
				
			||||||
 | 
					        response = await client.get('/')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert response.status_code == 200
 | 
				
			||||||
 | 
					    assert response.json() == {'result': 'Foo'}
 | 
				
			||||||
							
								
								
									
										10
									
								
								examples/miniapps/fastapi-redis/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								examples/miniapps/fastapi-redis/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					dependency-injector
 | 
				
			||||||
 | 
					fastapi
 | 
				
			||||||
 | 
					uvicorn
 | 
				
			||||||
 | 
					aioredis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# For testing:
 | 
				
			||||||
 | 
					pytest
 | 
				
			||||||
 | 
					pytest-asyncio
 | 
				
			||||||
 | 
					pytest-cov
 | 
				
			||||||
 | 
					httpx
 | 
				
			||||||
							
								
								
									
										37
									
								
								examples/providers/async.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								examples/providers/async.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,37 @@
 | 
				
			||||||
 | 
					"""Asynchronous injections example."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def init_async_resource():
 | 
				
			||||||
 | 
					    await asyncio.sleep(0.1)
 | 
				
			||||||
 | 
					    yield 'Initialized'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Service:
 | 
				
			||||||
 | 
					    def __init__(self, resource):
 | 
				
			||||||
 | 
					        self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resource = providers.Resource(init_async_resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    service = providers.Factory(
 | 
				
			||||||
 | 
					        Service,
 | 
				
			||||||
 | 
					        resource=resource,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def main(container: Container):
 | 
				
			||||||
 | 
					    resource = await container.resource()
 | 
				
			||||||
 | 
					    service = await container.service()
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    asyncio.run(main(container))
 | 
				
			||||||
							
								
								
									
										32
									
								
								examples/providers/async_overriding.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								examples/providers/async_overriding.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					"""Provider overriding in async mode example."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def init_async_resource():
 | 
				
			||||||
 | 
					    return ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def init_resource_mock():
 | 
				
			||||||
 | 
					    return ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resource = providers.Resource(init_async_resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def main(container: Container):
 | 
				
			||||||
 | 
					    resource1 = await container.resource()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    container.resource.override(providers.Callable(init_resource_mock))
 | 
				
			||||||
 | 
					    resource2 = await container.resource()
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    asyncio.run(main(container))
 | 
				
			||||||
| 
						 | 
					@ -7,5 +7,8 @@ pydocstyle
 | 
				
			||||||
sphinx_autobuild
 | 
					sphinx_autobuild
 | 
				
			||||||
pip
 | 
					pip
 | 
				
			||||||
mypy
 | 
					mypy
 | 
				
			||||||
 | 
					pyyaml
 | 
				
			||||||
 | 
					httpx
 | 
				
			||||||
 | 
					fastapi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-r requirements-ext.txt
 | 
					-r requirements-ext.txt
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,8 @@ max_complexity = 10
 | 
				
			||||||
exclude = types.py
 | 
					exclude = types.py
 | 
				
			||||||
per-file-ignores =
 | 
					per-file-ignores =
 | 
				
			||||||
    examples/demo/*: F841
 | 
					    examples/demo/*: F841
 | 
				
			||||||
 | 
					    examples/providers/async.py: F841
 | 
				
			||||||
 | 
					    examples/providers/async_overriding.py: F841
 | 
				
			||||||
    examples/wiring/*: F841
 | 
					    examples/wiring/*: F841
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[pydocstyle]
 | 
					[pydocstyle]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
"""Top-level package."""
 | 
					"""Top-level package."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__version__ = '4.5.4'
 | 
					__version__ = '4.6.0'
 | 
				
			||||||
"""Version number.
 | 
					"""Version number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:type: str
 | 
					:type: str
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -11,3 +11,6 @@ cpdef bint is_container(object instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cpdef object _check_provider_type(object container, object provider)
 | 
					cpdef object _check_provider_type(object container, object provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cpdef bint _isawaitable(object instance)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,17 @@
 | 
				
			||||||
from types import ModuleType
 | 
					from types import ModuleType
 | 
				
			||||||
from typing import Type, Dict, Tuple, Optional, Any, Union, ClassVar, Callable as _Callable, Iterable, TypeVar
 | 
					from typing import (
 | 
				
			||||||
 | 
					    Type,
 | 
				
			||||||
 | 
					    Dict,
 | 
				
			||||||
 | 
					    Tuple,
 | 
				
			||||||
 | 
					    Optional,
 | 
				
			||||||
 | 
					    Any,
 | 
				
			||||||
 | 
					    Union,
 | 
				
			||||||
 | 
					    ClassVar,
 | 
				
			||||||
 | 
					    Callable as _Callable,
 | 
				
			||||||
 | 
					    Iterable,
 | 
				
			||||||
 | 
					    TypeVar,
 | 
				
			||||||
 | 
					    Awaitable,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .providers import Provider
 | 
					from .providers import Provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,8 +37,8 @@ class Container:
 | 
				
			||||||
    def resolve_provider_name(self, provider_to_resolve: Provider) -> Optional[str]: ...
 | 
					    def resolve_provider_name(self, provider_to_resolve: Provider) -> Optional[str]: ...
 | 
				
			||||||
    def wire(self, modules: Optional[Iterable[ModuleType]] = None, packages: Optional[Iterable[ModuleType]] = None) -> None: ...
 | 
					    def wire(self, modules: Optional[Iterable[ModuleType]] = None, packages: Optional[Iterable[ModuleType]] = None) -> None: ...
 | 
				
			||||||
    def unwire(self) -> None: ...
 | 
					    def unwire(self) -> None: ...
 | 
				
			||||||
    def init_resources(self) -> None: ...
 | 
					    def init_resources(self) -> Optional[Awaitable]: ...
 | 
				
			||||||
    def shutdown_resources(self) -> None: ...
 | 
					    def shutdown_resources(self) -> Optional[Awaitable]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DynamicContainer(Container): ...
 | 
					class DynamicContainer(Container): ...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,13 @@
 | 
				
			||||||
"""Containers module."""
 | 
					"""Containers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import inspect
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    import asyncio
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    asyncio = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import six
 | 
					import six
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .errors import Error
 | 
					from .errors import Error
 | 
				
			||||||
| 
						 | 
					@ -216,17 +222,33 @@ class DynamicContainer(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def init_resources(self):
 | 
					    def init_resources(self):
 | 
				
			||||||
        """Initialize all container resources."""
 | 
					        """Initialize all container resources."""
 | 
				
			||||||
 | 
					        futures = []
 | 
				
			||||||
        for provider in self.providers.values():
 | 
					        for provider in self.providers.values():
 | 
				
			||||||
            if not isinstance(provider, Resource):
 | 
					            if not isinstance(provider, Resource):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            provider.init()
 | 
					
 | 
				
			||||||
 | 
					            resource = provider.init()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if _isawaitable(resource):
 | 
				
			||||||
 | 
					                futures.append(resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if futures:
 | 
				
			||||||
 | 
					            return asyncio.gather(*futures)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def shutdown_resources(self):
 | 
					    def shutdown_resources(self):
 | 
				
			||||||
        """Shutdown all container resources."""
 | 
					        """Shutdown all container resources."""
 | 
				
			||||||
 | 
					        futures = []
 | 
				
			||||||
        for provider in self.providers.values():
 | 
					        for provider in self.providers.values():
 | 
				
			||||||
            if not isinstance(provider, Resource):
 | 
					            if not isinstance(provider, Resource):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            provider.shutdown()
 | 
					
 | 
				
			||||||
 | 
					            shutdown = provider.shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if _isawaitable(shutdown):
 | 
				
			||||||
 | 
					                futures.append(shutdown)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if futures:
 | 
				
			||||||
 | 
					            return asyncio.gather(*futures)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DeclarativeContainerMetaClass(type):
 | 
					class DeclarativeContainerMetaClass(type):
 | 
				
			||||||
| 
						 | 
					@ -494,3 +516,10 @@ cpdef object _check_provider_type(object container, object provider):
 | 
				
			||||||
    if not isinstance(provider, container.provider_type):
 | 
					    if not isinstance(provider, container.provider_type):
 | 
				
			||||||
        raise Error('{0} can contain only {1} '
 | 
					        raise Error('{0} can contain only {1} '
 | 
				
			||||||
                    'instances'.format(container, container.provider_type))
 | 
					                    'instances'.format(container, container.provider_type))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cpdef bint _isawaitable(object instance):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return <bint> inspect.isawaitable(instance)
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        return <bint> False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@ from dependency_injector import providers, errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
warnings.warn(
 | 
					warnings.warn(
 | 
				
			||||||
    'Module "dependency_injector.ext.aiohttp" is deprecated since '
 | 
					    'Module "dependency_injector.ext.flask" is deprecated since '
 | 
				
			||||||
    'version 4.0.0. Use "dependency_injector.wiring" module instead.',
 | 
					    'version 4.0.0. Use "dependency_injector.wiring" module instead.',
 | 
				
			||||||
    category=DeprecationWarning,
 | 
					    category=DeprecationWarning,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
					@ -1,5 +1,12 @@
 | 
				
			||||||
"""Providers module."""
 | 
					"""Providers module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    import asyncio
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    asyncio = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import inspect
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cimport cython
 | 
					cimport cython
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +14,7 @@ cimport cython
 | 
				
			||||||
cdef class Provider(object):
 | 
					cdef class Provider(object):
 | 
				
			||||||
    cdef tuple __overridden
 | 
					    cdef tuple __overridden
 | 
				
			||||||
    cdef Provider __last_overriding
 | 
					    cdef Provider __last_overriding
 | 
				
			||||||
 | 
					    cdef int __async_mode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs)
 | 
					    cpdef object _provide(self, tuple args, dict kwargs)
 | 
				
			||||||
    cpdef void _copy_overridings(self, Provider copied, dict memo)
 | 
					    cpdef void _copy_overridings(self, Provider copied, dict memo)
 | 
				
			||||||
| 
						 | 
					@ -134,10 +142,10 @@ cdef class FactoryAggregate(Provider):
 | 
				
			||||||
# Singleton providers
 | 
					# Singleton providers
 | 
				
			||||||
cdef class BaseSingleton(Provider):
 | 
					cdef class BaseSingleton(Provider):
 | 
				
			||||||
    cdef Factory __instantiator
 | 
					    cdef Factory __instantiator
 | 
				
			||||||
 | 
					    cdef object __storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Singleton(BaseSingleton):
 | 
					cdef class Singleton(BaseSingleton):
 | 
				
			||||||
    cdef object __storage
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs)
 | 
					    cpdef object _provide(self, tuple args, dict kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,7 +155,6 @@ cdef class DelegatedSingleton(Singleton):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class ThreadSafeSingleton(BaseSingleton):
 | 
					cdef class ThreadSafeSingleton(BaseSingleton):
 | 
				
			||||||
    cdef object __storage
 | 
					 | 
				
			||||||
    cdef object __storage_lock
 | 
					    cdef object __storage_lock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs)
 | 
					    cpdef object _provide(self, tuple args, dict kwargs)
 | 
				
			||||||
| 
						 | 
					@ -158,7 +165,6 @@ cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class ThreadLocalSingleton(BaseSingleton):
 | 
					cdef class ThreadLocalSingleton(BaseSingleton):
 | 
				
			||||||
    cdef object __storage
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs)
 | 
					    cpdef object _provide(self, tuple args, dict kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,30 +337,38 @@ cdef inline tuple __separate_prefixed_kwargs(dict kwargs):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cython.boundscheck(False)
 | 
					@cython.boundscheck(False)
 | 
				
			||||||
@cython.wraparound(False)
 | 
					@cython.wraparound(False)
 | 
				
			||||||
cdef inline tuple __provide_positional_args(
 | 
					cdef inline object __provide_positional_args(
 | 
				
			||||||
        tuple args,
 | 
					        tuple args,
 | 
				
			||||||
        tuple inj_args,
 | 
					        tuple inj_args,
 | 
				
			||||||
        int inj_args_len,
 | 
					        int inj_args_len,
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    cdef int index
 | 
					    cdef int index
 | 
				
			||||||
    cdef list positional_args
 | 
					    cdef list positional_args = []
 | 
				
			||||||
 | 
					    cdef list awaitables = []
 | 
				
			||||||
    cdef PositionalInjection injection
 | 
					    cdef PositionalInjection injection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if inj_args_len == 0:
 | 
					    if inj_args_len == 0:
 | 
				
			||||||
        return args
 | 
					        return args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    positional_args = list()
 | 
					 | 
				
			||||||
    for index in range(inj_args_len):
 | 
					    for index in range(inj_args_len):
 | 
				
			||||||
        injection = <PositionalInjection>inj_args[index]
 | 
					        injection = <PositionalInjection>inj_args[index]
 | 
				
			||||||
        positional_args.append(__get_value(injection))
 | 
					        value = __get_value(injection)
 | 
				
			||||||
 | 
					        positional_args.append(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if __isawaitable(value):
 | 
				
			||||||
 | 
					            awaitables.append((index, value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    positional_args.extend(args)
 | 
					    positional_args.extend(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return tuple(positional_args)
 | 
					    if awaitables:
 | 
				
			||||||
 | 
					        return __awaitable_args_kwargs_future(positional_args, awaitables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return positional_args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cython.boundscheck(False)
 | 
					@cython.boundscheck(False)
 | 
				
			||||||
@cython.wraparound(False)
 | 
					@cython.wraparound(False)
 | 
				
			||||||
cdef inline dict __provide_keyword_args(
 | 
					cdef inline object __provide_keyword_args(
 | 
				
			||||||
        dict kwargs,
 | 
					        dict kwargs,
 | 
				
			||||||
        tuple inj_kwargs,
 | 
					        tuple inj_kwargs,
 | 
				
			||||||
        int inj_kwargs_len,
 | 
					        int inj_kwargs_len,
 | 
				
			||||||
| 
						 | 
					@ -362,14 +376,18 @@ cdef inline dict __provide_keyword_args(
 | 
				
			||||||
    cdef int index
 | 
					    cdef int index
 | 
				
			||||||
    cdef object name
 | 
					    cdef object name
 | 
				
			||||||
    cdef object value
 | 
					    cdef object value
 | 
				
			||||||
    cdef dict prefixed
 | 
					    cdef dict prefixed = {}
 | 
				
			||||||
 | 
					    cdef list awaitables = []
 | 
				
			||||||
    cdef NamedInjection kw_injection
 | 
					    cdef NamedInjection kw_injection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if len(kwargs) == 0:
 | 
					    if len(kwargs) == 0:
 | 
				
			||||||
        for index in range(inj_kwargs_len):
 | 
					        for index in range(inj_kwargs_len):
 | 
				
			||||||
            kw_injection = <NamedInjection>inj_kwargs[index]
 | 
					            kw_injection = <NamedInjection>inj_kwargs[index]
 | 
				
			||||||
            name = __get_name(kw_injection)
 | 
					            name = __get_name(kw_injection)
 | 
				
			||||||
            kwargs[name] = __get_value(kw_injection)
 | 
					            value = __get_value(kw_injection)
 | 
				
			||||||
 | 
					            kwargs[name] = value
 | 
				
			||||||
 | 
					            if __isawaitable(value):
 | 
				
			||||||
 | 
					                awaitables.append((name, value))
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        kwargs, prefixed = __separate_prefixed_kwargs(kwargs)
 | 
					        kwargs, prefixed = __separate_prefixed_kwargs(kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -387,23 +405,77 @@ cdef inline dict __provide_keyword_args(
 | 
				
			||||||
                value = __get_value(kw_injection)
 | 
					                value = __get_value(kw_injection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            kwargs[name] = value
 | 
					            kwargs[name] = value
 | 
				
			||||||
 | 
					            if __isawaitable(value):
 | 
				
			||||||
 | 
					                awaitables.append((name, value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if awaitables:
 | 
				
			||||||
 | 
					        return __awaitable_args_kwargs_future(kwargs, awaitables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return kwargs
 | 
					    return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline object __awaitable_args_kwargs_future(object args, list awaitables):
 | 
				
			||||||
 | 
					    future_result = asyncio.Future()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    args_future = asyncio.Future()
 | 
				
			||||||
 | 
					    args_future.set_result((future_result, args, awaitables))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    args_ready = asyncio.gather(args_future, *[value for _, value in awaitables])
 | 
				
			||||||
 | 
					    args_ready.add_done_callback(__async_prepare_args_kwargs_callback)
 | 
				
			||||||
 | 
					    asyncio.ensure_future(args_ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline void __async_prepare_args_kwargs_callback(object future):
 | 
				
			||||||
 | 
					    (future_result, args, awaitables), *awaited = future.result()
 | 
				
			||||||
 | 
					    for value, (key, _) in zip(awaited, awaitables):
 | 
				
			||||||
 | 
					        args[key] = value
 | 
				
			||||||
 | 
					    future_result.set_result(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@cython.boundscheck(False)
 | 
					@cython.boundscheck(False)
 | 
				
			||||||
@cython.wraparound(False)
 | 
					@cython.wraparound(False)
 | 
				
			||||||
cdef inline object __inject_attributes(
 | 
					cdef inline object __provide_attributes(tuple attributes, int attributes_len):
 | 
				
			||||||
        object instance,
 | 
					 | 
				
			||||||
        tuple attributes,
 | 
					 | 
				
			||||||
        int attributes_len,
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    cdef NamedInjection attr_injection
 | 
					    cdef NamedInjection attr_injection
 | 
				
			||||||
 | 
					    cdef dict attribute_injections = {}
 | 
				
			||||||
 | 
					    cdef list awaitables = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for index in range(attributes_len):
 | 
					    for index in range(attributes_len):
 | 
				
			||||||
        attr_injection = <NamedInjection>attributes[index]
 | 
					        attr_injection = <NamedInjection>attributes[index]
 | 
				
			||||||
        setattr(instance,
 | 
					        name = __get_name(attr_injection)
 | 
				
			||||||
                __get_name(attr_injection),
 | 
					        value = __get_value(attr_injection)
 | 
				
			||||||
                __get_value(attr_injection))
 | 
					        attribute_injections[name] = value
 | 
				
			||||||
 | 
					        if __isawaitable(value):
 | 
				
			||||||
 | 
					            awaitables.append((name, value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if awaitables:
 | 
				
			||||||
 | 
					        return __awaitable_args_kwargs_future(attribute_injections, awaitables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return attribute_injections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline object __async_inject_attributes(future_instance, future_attributes):
 | 
				
			||||||
 | 
					    future_result = asyncio.Future()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    future = asyncio.Future()
 | 
				
			||||||
 | 
					    future.set_result(future_result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    attributes_ready = asyncio.gather(future, future_instance, future_attributes)
 | 
				
			||||||
 | 
					    attributes_ready.add_done_callback(__async_inject_attributes_callback)
 | 
				
			||||||
 | 
					    asyncio.ensure_future(attributes_ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline void __async_inject_attributes_callback(future):
 | 
				
			||||||
 | 
					    future_result, instance, attributes = future.result()
 | 
				
			||||||
 | 
					    __inject_attributes(instance, attributes)
 | 
				
			||||||
 | 
					    future_result.set_result(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline void __inject_attributes(object instance, dict attributes):
 | 
				
			||||||
 | 
					    for name, value in attributes.items():
 | 
				
			||||||
 | 
					        setattr(instance, name, value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef inline object __call(
 | 
					cdef inline object __call(
 | 
				
			||||||
| 
						 | 
					@ -411,25 +483,53 @@ cdef inline object __call(
 | 
				
			||||||
        tuple context_args,
 | 
					        tuple context_args,
 | 
				
			||||||
        tuple injection_args,
 | 
					        tuple injection_args,
 | 
				
			||||||
        int injection_args_len,
 | 
					        int injection_args_len,
 | 
				
			||||||
        dict kwargs,
 | 
					        dict context_kwargs,
 | 
				
			||||||
        tuple injection_kwargs,
 | 
					        tuple injection_kwargs,
 | 
				
			||||||
        int injection_kwargs_len,
 | 
					        int injection_kwargs_len,
 | 
				
			||||||
):
 | 
					):
 | 
				
			||||||
    cdef tuple positional_args
 | 
					    args = __provide_positional_args(
 | 
				
			||||||
    cdef dict keyword_args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    positional_args = __provide_positional_args(
 | 
					 | 
				
			||||||
        context_args,
 | 
					        context_args,
 | 
				
			||||||
        injection_args,
 | 
					        injection_args,
 | 
				
			||||||
        injection_args_len,
 | 
					        injection_args_len,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    keyword_args = __provide_keyword_args(
 | 
					    kwargs = __provide_keyword_args(
 | 
				
			||||||
        kwargs,
 | 
					        context_kwargs,
 | 
				
			||||||
        injection_kwargs,
 | 
					        injection_kwargs,
 | 
				
			||||||
        injection_kwargs_len,
 | 
					        injection_kwargs_len,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return call(*positional_args, **keyword_args)
 | 
					    args_awaitable = __isawaitable(args)
 | 
				
			||||||
 | 
					    kwargs_awaitable = __isawaitable(kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if args_awaitable or kwargs_awaitable:
 | 
				
			||||||
 | 
					        if not args_awaitable:
 | 
				
			||||||
 | 
					            future = asyncio.Future()
 | 
				
			||||||
 | 
					            future.set_result(args)
 | 
				
			||||||
 | 
					            args = future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not kwargs_awaitable:
 | 
				
			||||||
 | 
					            future = asyncio.Future()
 | 
				
			||||||
 | 
					            future.set_result(kwargs)
 | 
				
			||||||
 | 
					            kwargs = future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future_result = asyncio.Future()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future = asyncio.Future()
 | 
				
			||||||
 | 
					        future.set_result((future_result, call))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        args_kwargs_ready = asyncio.gather(future, args, kwargs)
 | 
				
			||||||
 | 
					        args_kwargs_ready.add_done_callback(__async_call_callback)
 | 
				
			||||||
 | 
					        asyncio.ensure_future(args_kwargs_ready)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return call(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline void __async_call_callback(object future):
 | 
				
			||||||
 | 
					    (future_result, call), args, kwargs = future.result()
 | 
				
			||||||
 | 
					    result = call(*args, **kwargs)
 | 
				
			||||||
 | 
					    future_result.set_result(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
 | 
					cdef inline object __callable_call(Callable self, tuple args, dict kwargs):
 | 
				
			||||||
| 
						 | 
					@ -450,8 +550,40 @@ cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
 | 
				
			||||||
    instance = __callable_call(self.__instantiator, args, kwargs)
 | 
					    instance = __callable_call(self.__instantiator, args, kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if self.__attributes_len > 0:
 | 
					    if self.__attributes_len > 0:
 | 
				
			||||||
        __inject_attributes(instance,
 | 
					        attributes = __provide_attributes(self.__attributes, self.__attributes_len)
 | 
				
			||||||
                            self.__attributes,
 | 
					
 | 
				
			||||||
                            self.__attributes_len)
 | 
					        instance_awaitable = __isawaitable(instance)
 | 
				
			||||||
 | 
					        attributes_awaitable = __isawaitable(attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if instance_awaitable or attributes_awaitable:
 | 
				
			||||||
 | 
					            if not instance_awaitable:
 | 
				
			||||||
 | 
					                future = asyncio.Future()
 | 
				
			||||||
 | 
					                future.set_result(instance)
 | 
				
			||||||
 | 
					                instance = future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if not attributes_awaitable:
 | 
				
			||||||
 | 
					                future = asyncio.Future()
 | 
				
			||||||
 | 
					                future.set_result(attributes)
 | 
				
			||||||
 | 
					                attributes = future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return __async_inject_attributes(instance, attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        __inject_attributes(instance, attributes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return instance
 | 
					    return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef bint __has_isawaitable = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef inline bint __isawaitable(object instance):
 | 
				
			||||||
 | 
					    global __has_isawaitable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if __has_isawaitable is True:
 | 
				
			||||||
 | 
					        return inspect.isawaitable(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if hasattr(inspect, 'isawaitable'):
 | 
				
			||||||
 | 
					        __has_isawaitable = True
 | 
				
			||||||
 | 
					        return inspect.isawaitable(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@ from __future__ import annotations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
from typing import (
 | 
					from typing import (
 | 
				
			||||||
 | 
					    Awaitable,
 | 
				
			||||||
    TypeVar,
 | 
					    TypeVar,
 | 
				
			||||||
    Generic,
 | 
					    Generic,
 | 
				
			||||||
    Type,
 | 
					    Type,
 | 
				
			||||||
| 
						 | 
					@ -14,6 +15,7 @@ from typing import (
 | 
				
			||||||
    Union,
 | 
					    Union,
 | 
				
			||||||
    Coroutine as _Coroutine,
 | 
					    Coroutine as _Coroutine,
 | 
				
			||||||
    Iterator as _Iterator,
 | 
					    Iterator as _Iterator,
 | 
				
			||||||
 | 
					    AsyncIterator as _AsyncIterator,
 | 
				
			||||||
    Generator as _Generator,
 | 
					    Generator as _Generator,
 | 
				
			||||||
    overload,
 | 
					    overload,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -33,7 +35,13 @@ class OverridingContext:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Provider(Generic[T]):
 | 
					class Provider(Generic[T]):
 | 
				
			||||||
    def __init__(self) -> None: ...
 | 
					    def __init__(self) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __call__(self, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
 | 
				
			||||||
 | 
					    def async_(self, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __deepcopy__(self, memo: Optional[_Dict[Any, Any]]) -> Provider: ...
 | 
					    def __deepcopy__(self, memo: Optional[_Dict[Any, Any]]) -> Provider: ...
 | 
				
			||||||
    def __str__(self) -> str: ...
 | 
					    def __str__(self) -> str: ...
 | 
				
			||||||
    def __repr__(self) -> str: ...
 | 
					    def __repr__(self) -> str: ...
 | 
				
			||||||
| 
						 | 
					@ -49,30 +57,33 @@ class Provider(Generic[T]):
 | 
				
			||||||
    def provider(self) -> Provider: ...
 | 
					    def provider(self) -> Provider: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def provided(self) -> ProvidedInstance: ...
 | 
					    def provided(self) -> ProvidedInstance: ...
 | 
				
			||||||
 | 
					    def enable_async_mode(self) -> None: ...
 | 
				
			||||||
 | 
					    def disable_async_mode(self) -> None: ...
 | 
				
			||||||
 | 
					    def reset_async_mode(self) -> None: ...
 | 
				
			||||||
 | 
					    def is_async_mode_enabled(self) -> bool: ...
 | 
				
			||||||
 | 
					    def is_async_mode_disabled(self) -> bool: ...
 | 
				
			||||||
 | 
					    def is_async_mode_undefined(self) -> bool: ...
 | 
				
			||||||
    def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ...
 | 
					    def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Object(Provider, Generic[T]):
 | 
					class Object(Provider[T]):
 | 
				
			||||||
    def __init__(self, provides: T) -> None: ...
 | 
					    def __init__(self, provides: T) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Delegate(Provider):
 | 
					class Delegate(Provider[Provider]):
 | 
				
			||||||
    def __init__(self, provides: Provider) -> None: ...
 | 
					    def __init__(self, provides: Provider) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> Provider: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def provides(self) -> Provider: ...
 | 
					    def provides(self) -> Provider: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Dependency(Provider, Generic[T]):
 | 
					class Dependency(Provider[T]):
 | 
				
			||||||
    def __init__(self, instance_of: Type[T] = object) -> None: ...
 | 
					    def __init__(self, instance_of: Type[T] = object) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def instance_of(self) -> Type[T]: ...
 | 
					    def instance_of(self) -> Type[T]: ...
 | 
				
			||||||
    def provided_by(self, provider: Provider) -> OverridingContext: ...
 | 
					    def provided_by(self, provider: Provider) -> OverridingContext: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ExternalDependency(Dependency): ...
 | 
					class ExternalDependency(Dependency[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DependenciesContainer(Object):
 | 
					class DependenciesContainer(Object):
 | 
				
			||||||
| 
						 | 
					@ -82,9 +93,8 @@ class DependenciesContainer(Object):
 | 
				
			||||||
    def providers(self) -> _Dict[str, Provider]: ...
 | 
					    def providers(self) -> _Dict[str, Provider]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Callable(Provider, Generic[T]):
 | 
					class Callable(Provider[T]):
 | 
				
			||||||
    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def provides(self) -> T: ...
 | 
					    def provides(self) -> T: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
| 
						 | 
					@ -93,16 +103,16 @@ class Callable(Provider, Generic[T]):
 | 
				
			||||||
    def set_args(self, *args: Injection) -> Callable[T]: ...
 | 
					    def set_args(self, *args: Injection) -> Callable[T]: ...
 | 
				
			||||||
    def clear_args(self) -> Callable[T]: ...
 | 
					    def clear_args(self) -> Callable[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self) -> _Dict[str, Injection]: ...
 | 
					    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
 | 
					    def add_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
 | 
				
			||||||
    def set_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
 | 
					    def set_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
 | 
				
			||||||
    def clear_kwargs(self) -> Callable[T]: ...
 | 
					    def clear_kwargs(self) -> Callable[T]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedCallable(Callable): ...
 | 
					class DelegatedCallable(Callable[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractCallable(Callable):
 | 
					class AbstractCallable(Callable[T]):
 | 
				
			||||||
    def override(self, provider: Callable) -> OverridingContext: ...
 | 
					    def override(self, provider: Callable) -> OverridingContext: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,13 +120,13 @@ class CallableDelegate(Delegate):
 | 
				
			||||||
    def __init__(self, callable: Callable) -> None: ...
 | 
					    def __init__(self, callable: Callable) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Coroutine(Callable): ...
 | 
					class Coroutine(Callable[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedCoroutine(Coroutine): ...
 | 
					class DelegatedCoroutine(Coroutine[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractCoroutine(Coroutine):
 | 
					class AbstractCoroutine(Coroutine[T]):
 | 
				
			||||||
    def override(self, provider: Coroutine) -> OverridingContext: ...
 | 
					    def override(self, provider: Coroutine) -> OverridingContext: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,10 +134,9 @@ class CoroutineDelegate(Delegate):
 | 
				
			||||||
    def __init__(self, coroutine: Coroutine) -> None: ...
 | 
					    def __init__(self, coroutine: Coroutine) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConfigurationOption(Provider):
 | 
					class ConfigurationOption(Provider[Any]):
 | 
				
			||||||
    UNDEFINED: object
 | 
					    UNDEFINED: object
 | 
				
			||||||
    def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
 | 
					    def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> Any: ...
 | 
					 | 
				
			||||||
    def __getattr__(self, item: str) -> ConfigurationOption: ...
 | 
					    def __getattr__(self, item: str) -> ConfigurationOption: ...
 | 
				
			||||||
    def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
 | 
					    def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
| 
						 | 
					@ -149,7 +158,7 @@ class TypedConfigurationOption(Callable[T]):
 | 
				
			||||||
    def option(self) -> ConfigurationOption: ...
 | 
					    def option(self) -> ConfigurationOption: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Configuration(Object):
 | 
					class Configuration(Object[Any]):
 | 
				
			||||||
    DEFAULT_NAME: str = 'config'
 | 
					    DEFAULT_NAME: str = 'config'
 | 
				
			||||||
    def __init__(self, name: str = DEFAULT_NAME, default: Optional[Any] = None) -> None: ...
 | 
					    def __init__(self, name: str = DEFAULT_NAME, default: Optional[Any] = None) -> None: ...
 | 
				
			||||||
    def __getattr__(self, item: str) -> ConfigurationOption: ...
 | 
					    def __getattr__(self, item: str) -> ConfigurationOption: ...
 | 
				
			||||||
| 
						 | 
					@ -165,10 +174,9 @@ class Configuration(Object):
 | 
				
			||||||
    def from_env(self, name: str, default: Optional[Any] = None) -> None: ...
 | 
					    def from_env(self, name: str, default: Optional[Any] = None) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Factory(Provider, Generic[T]):
 | 
					class Factory(Provider[T]):
 | 
				
			||||||
    provided_type: Optional[Type]
 | 
					    provided_type: Optional[Type]
 | 
				
			||||||
    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def cls(self) -> T: ...
 | 
					    def cls(self) -> T: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
| 
						 | 
					@ -179,21 +187,21 @@ class Factory(Provider, Generic[T]):
 | 
				
			||||||
    def set_args(self, *args: Injection) -> Factory[T]: ...
 | 
					    def set_args(self, *args: Injection) -> Factory[T]: ...
 | 
				
			||||||
    def clear_args(self) -> Factory[T]: ...
 | 
					    def clear_args(self) -> Factory[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self) -> _Dict[str, Injection]: ...
 | 
					    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def add_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
				
			||||||
    def set_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def set_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
				
			||||||
    def clear_kwargs(self) -> Factory[T]: ...
 | 
					    def clear_kwargs(self) -> Factory[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def attributes(self) -> _Dict[str, Injection]: ...
 | 
					    def attributes(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def add_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
				
			||||||
    def set_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def set_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
				
			||||||
    def clear_attributes(self) -> Factory[T]: ...
 | 
					    def clear_attributes(self) -> Factory[T]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedFactory(Factory): ...
 | 
					class DelegatedFactory(Factory[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractFactory(Factory):
 | 
					class AbstractFactory(Factory[T]):
 | 
				
			||||||
    def override(self, provider: Factory) -> OverridingContext: ...
 | 
					    def override(self, provider: Factory) -> OverridingContext: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -203,55 +211,60 @@ class FactoryDelegate(Delegate):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FactoryAggregate(Provider):
 | 
					class FactoryAggregate(Provider):
 | 
				
			||||||
    def __init__(self, **factories: Factory): ...
 | 
					    def __init__(self, **factories: Factory): ...
 | 
				
			||||||
    def __call__(self, factory_name: str, *args: Injection, **kwargs: Injection) -> Any: ...
 | 
					 | 
				
			||||||
    def __getattr__(self, factory_name: str) -> Factory: ...
 | 
					    def __getattr__(self, factory_name: str) -> Factory: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __call__(self, factory_name: str, *args: Injection, **kwargs: Injection) -> Any: ...
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __call__(self, factory_name: str, *args: Injection, **kwargs: Injection) -> Awaitable[Any]: ...
 | 
				
			||||||
 | 
					    def async_(self, factory_name: str, *args: Injection, **kwargs: Injection) -> Awaitable[Any]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def factories(self) -> _Dict[str, Factory]: ...
 | 
					    def factories(self) -> _Dict[str, Factory]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BaseSingleton(Provider, Generic[T]):
 | 
					class BaseSingleton(Provider[T]):
 | 
				
			||||||
    provided_type = Optional[Type]
 | 
					    provided_type = Optional[Type]
 | 
				
			||||||
    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, provides: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def cls(self) -> T: ...
 | 
					    def cls(self) -> T: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def args(self) -> Tuple[Injection]: ...
 | 
					    def args(self) -> Tuple[Injection]: ...
 | 
				
			||||||
    def add_args(self, *args: Injection) -> Factory[T]: ...
 | 
					    def add_args(self, *args: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def set_args(self, *args: Injection) -> Factory[T]: ...
 | 
					    def set_args(self, *args: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def clear_args(self) -> Factory[T]: ...
 | 
					    def clear_args(self) -> BaseSingleton[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self) -> _Dict[str, Injection]: ...
 | 
					    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def add_kwargs(self, **kwargs: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def set_kwargs(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def set_kwargs(self, **kwargs: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def clear_kwargs(self) -> Factory[T]: ...
 | 
					    def clear_kwargs(self) -> BaseSingleton[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def attributes(self) -> _Dict[str, Injection]: ...
 | 
					    def attributes(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def add_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def set_attributes(self, **kwargs: Injection) -> Factory[T]: ...
 | 
					    def set_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def clear_attributes(self) -> Factory[T]: ...
 | 
					    def clear_attributes(self) -> BaseSingleton[T]: ...
 | 
				
			||||||
    def reset(self) -> None: ...
 | 
					    def reset(self) -> None: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Singleton(BaseSingleton): ...
 | 
					class Singleton(BaseSingleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedSingleton(Singleton): ...
 | 
					class DelegatedSingleton(Singleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ThreadSafeSingleton(Singleton): ...
 | 
					class ThreadSafeSingleton(Singleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedThreadSafeSingleton(ThreadSafeSingleton): ...
 | 
					class DelegatedThreadSafeSingleton(ThreadSafeSingleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ThreadLocalSingleton(BaseSingleton): ...
 | 
					class ThreadLocalSingleton(BaseSingleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DelegatedThreadLocalSingleton(ThreadLocalSingleton): ...
 | 
					class DelegatedThreadLocalSingleton(ThreadLocalSingleton[T]): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbstractSingleton(BaseSingleton):
 | 
					class AbstractSingleton(BaseSingleton[T]):
 | 
				
			||||||
    def override(self, provider: BaseSingleton) -> OverridingContext: ...
 | 
					    def override(self, provider: BaseSingleton) -> OverridingContext: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,19 +272,17 @@ class SingletonDelegate(Delegate):
 | 
				
			||||||
    def __init__(self, factory: BaseSingleton): ...
 | 
					    def __init__(self, factory: BaseSingleton): ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class List(Provider):
 | 
					class List(Provider[_List]):
 | 
				
			||||||
    def __init__(self, *args: Injection): ...
 | 
					    def __init__(self, *args: Injection): ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> _List[Any]: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def args(self) -> Tuple[Injection]: ...
 | 
					    def args(self) -> Tuple[Injection]: ...
 | 
				
			||||||
    def add_args(self, *args: Injection) -> List: ...
 | 
					    def add_args(self, *args: Injection) -> List[T]: ...
 | 
				
			||||||
    def set_args(self, *args: Injection) -> List: ...
 | 
					    def set_args(self, *args: Injection) -> List[T]: ...
 | 
				
			||||||
    def clear_args(self) -> List: ...
 | 
					    def clear_args(self) -> List[T]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Dict(Provider):
 | 
					class Dict(Provider[_Dict]):
 | 
				
			||||||
    def __init__(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection): ...
 | 
					    def __init__(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection): ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> _Dict[Any, Any]: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
					    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
 | 
					    def add_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
 | 
				
			||||||
| 
						 | 
					@ -279,42 +290,44 @@ class Dict(Provider):
 | 
				
			||||||
    def clear_kwargs(self) -> Dict: ...
 | 
					    def clear_kwargs(self) -> Dict: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Resource(Provider, Generic[T]):
 | 
					class Resource(Provider[T]):
 | 
				
			||||||
    @overload
 | 
					    @overload
 | 
				
			||||||
    def __init__(self, initializer: _Callable[..., resources.Resource[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, initializer: Type[resources.Resource[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __init__(self, initializer: Type[resources.AsyncResource[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    @overload
 | 
					    @overload
 | 
				
			||||||
    def __init__(self, initializer: _Callable[..., _Iterator[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, initializer: _Callable[..., _Iterator[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    @overload
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __init__(self, initializer: _Callable[..., _AsyncIterator[T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
 | 
					    def __init__(self, initializer: _Callable[..., _Coroutine[Injection, Injection, T]], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
 | 
					    @overload
 | 
				
			||||||
    def __init__(self, initializer: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
					    def __init__(self, initializer: _Callable[..., T], *args: Injection, **kwargs: Injection) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def args(self) -> Tuple[Injection]: ...
 | 
					    def args(self) -> Tuple[Injection]: ...
 | 
				
			||||||
    def add_args(self, *args: Injection) -> Resource: ...
 | 
					    def add_args(self, *args: Injection) -> Resource[T]: ...
 | 
				
			||||||
    def set_args(self, *args: Injection) -> Resource: ...
 | 
					    def set_args(self, *args: Injection) -> Resource[T]: ...
 | 
				
			||||||
    def clear_args(self) -> Resource: ...
 | 
					    def clear_args(self) -> Resource[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
					    def kwargs(self) -> _Dict[Any, Injection]: ...
 | 
				
			||||||
    def add_kwargs(self, **kwargs: Injection) -> Resource: ...
 | 
					    def add_kwargs(self, **kwargs: Injection) -> Resource[T]: ...
 | 
				
			||||||
    def set_kwargs(self, **kwargs: Injection) -> Resource: ...
 | 
					    def set_kwargs(self, **kwargs: Injection) -> Resource[T]: ...
 | 
				
			||||||
    def clear_kwargs(self) -> Resource: ...
 | 
					    def clear_kwargs(self) -> Resource[T]: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def initialized(self) -> bool: ...
 | 
					    def initialized(self) -> bool: ...
 | 
				
			||||||
    def init(self) -> T: ...
 | 
					    def init(self) -> Optional[Awaitable[T]]: ...
 | 
				
			||||||
    def shutdown(self) -> None: ...
 | 
					    def shutdown(self) -> Optional[Awaitable]: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Container(Provider):
 | 
					class Container(Provider[T]):
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ...
 | 
					    def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Provider) -> None: ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
 | 
					 | 
				
			||||||
    def __getattr__(self, name: str) -> Provider: ...
 | 
					    def __getattr__(self, name: str) -> Provider: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def container(self) -> T: ...
 | 
					    def container(self) -> T: ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Selector(Provider):
 | 
					class Selector(Provider[Any]):
 | 
				
			||||||
    def __init__(self, selector: _Callable[..., Any], **providers: Provider): ...
 | 
					    def __init__(self, selector: _Callable[..., Any], **providers: Provider): ...
 | 
				
			||||||
    def __call__(self, *args: Injection, **kwargs: Injection) -> Any: ...
 | 
					 | 
				
			||||||
    def __getattr__(self, name: str) -> Provider: ...
 | 
					    def __getattr__(self, name: str) -> Provider: ...
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def providers(self) -> _Dict[str, Provider]: ...
 | 
					    def providers(self) -> _Dict[str, Provider]: ...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
from __future__ import absolute_import
 | 
					from __future__ import absolute_import
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import copy
 | 
					import copy
 | 
				
			||||||
 | 
					import functools
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import re
 | 
					import re
 | 
				
			||||||
| 
						 | 
					@ -88,6 +89,11 @@ else:
 | 
				
			||||||
            return parser
 | 
					            return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cdef int ASYNC_MODE_UNDEFINED = 0
 | 
				
			||||||
 | 
					cdef int ASYNC_MODE_ENABLED = 1
 | 
				
			||||||
 | 
					cdef int ASYNC_MODE_DISABLED = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Provider(object):
 | 
					cdef class Provider(object):
 | 
				
			||||||
    """Base provider class.
 | 
					    """Base provider class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,6 +154,7 @@ cdef class Provider(object):
 | 
				
			||||||
        """Initializer."""
 | 
					        """Initializer."""
 | 
				
			||||||
        self.__overridden = tuple()
 | 
					        self.__overridden = tuple()
 | 
				
			||||||
        self.__last_overriding = None
 | 
					        self.__last_overriding = None
 | 
				
			||||||
 | 
					        self.__async_mode = ASYNC_MODE_UNDEFINED
 | 
				
			||||||
        super(Provider, self).__init__()
 | 
					        super(Provider, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __call__(self, *args, **kwargs):
 | 
					    def __call__(self, *args, **kwargs):
 | 
				
			||||||
| 
						 | 
					@ -156,8 +163,24 @@ cdef class Provider(object):
 | 
				
			||||||
        Callable interface implementation.
 | 
					        Callable interface implementation.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self.__last_overriding is not None:
 | 
					        if self.__last_overriding is not None:
 | 
				
			||||||
            return self.__last_overriding(*args, **kwargs)
 | 
					            result = self.__last_overriding(*args, **kwargs)
 | 
				
			||||||
        return self._provide(args, kwargs)
 | 
					        else:
 | 
				
			||||||
 | 
					            result = self._provide(args, kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.is_async_mode_disabled():
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					        elif self.is_async_mode_enabled():
 | 
				
			||||||
 | 
					            if not __isawaitable(result):
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                future_result.set_result(result)
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					        elif self.is_async_mode_undefined():
 | 
				
			||||||
 | 
					            if __isawaitable(result):
 | 
				
			||||||
 | 
					                self.enable_async_mode()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.disable_async_mode()
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __deepcopy__(self, memo):
 | 
					    def __deepcopy__(self, memo):
 | 
				
			||||||
        """Create and return full copy of provider."""
 | 
					        """Create and return full copy of provider."""
 | 
				
			||||||
| 
						 | 
					@ -254,6 +277,23 @@ cdef class Provider(object):
 | 
				
			||||||
            self.__overridden = tuple()
 | 
					            self.__overridden = tuple()
 | 
				
			||||||
            self.__last_overriding = None
 | 
					            self.__last_overriding = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def async_(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        """Return provided object asynchronously.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This method is a synonym of __call__().
 | 
				
			||||||
 | 
					        It provides typing stubs for correct type checking with
 | 
				
			||||||
 | 
					        `await` expression:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        .. code-block:: python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            database_provider: Provider[DatabaseConnection] = Resource(init_db_async)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            async def main():
 | 
				
			||||||
 | 
					                db: DatabaseConnection = await database_provider.async_()
 | 
				
			||||||
 | 
					                ...
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__call__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def delegate(self):
 | 
					    def delegate(self):
 | 
				
			||||||
        """Return provider's delegate.
 | 
					        """Return provider's delegate.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -279,6 +319,33 @@ cdef class Provider(object):
 | 
				
			||||||
        """Return :py:class:`ProvidedInstance` provider."""
 | 
					        """Return :py:class:`ProvidedInstance` provider."""
 | 
				
			||||||
        return ProvidedInstance(self)
 | 
					        return ProvidedInstance(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def enable_async_mode(self):
 | 
				
			||||||
 | 
					        """Enable async mode."""
 | 
				
			||||||
 | 
					        self.__async_mode = ASYNC_MODE_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def disable_async_mode(self):
 | 
				
			||||||
 | 
					        """Disable async mode."""
 | 
				
			||||||
 | 
					        self.__async_mode = ASYNC_MODE_DISABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_async_mode(self):
 | 
				
			||||||
 | 
					        """Reset async mode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Provider will automatically set the mode on the next call.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__async_mode = ASYNC_MODE_UNDEFINED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_async_mode_enabled(self):
 | 
				
			||||||
 | 
					        """Check if async mode is enabled."""
 | 
				
			||||||
 | 
					        return self.__async_mode == ASYNC_MODE_ENABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_async_mode_disabled(self):
 | 
				
			||||||
 | 
					        """Check if async mode is disabled."""
 | 
				
			||||||
 | 
					        return self.__async_mode == ASYNC_MODE_DISABLED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_async_mode_undefined(self):
 | 
				
			||||||
 | 
					        """Check if async mode is undefined."""
 | 
				
			||||||
 | 
					        return self.__async_mode == ASYNC_MODE_UNDEFINED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        """Providing strategy implementation.
 | 
					        """Providing strategy implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -472,18 +539,38 @@ cdef class Dependency(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :rtype: object
 | 
					        :rtype: object
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        cdef object instance
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if self.__last_overriding is None:
 | 
					        if self.__last_overriding is None:
 | 
				
			||||||
            raise Error('Dependency is not defined')
 | 
					            raise Error('Dependency is not defined')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        instance = self.__last_overriding(*args, **kwargs)
 | 
					        result = self.__last_overriding(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not isinstance(instance, self.instance_of):
 | 
					 | 
				
			||||||
            raise Error('{0} is not an '.format(instance) +
 | 
					 | 
				
			||||||
                        'instance of {0}'.format(self.instance_of))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return instance
 | 
					        if self.is_async_mode_disabled():
 | 
				
			||||||
 | 
					            self._check_instance_type(result)
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					        elif self.is_async_mode_enabled():
 | 
				
			||||||
 | 
					            if __isawaitable(result):
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                result = asyncio.ensure_future(result)
 | 
				
			||||||
 | 
					                result.add_done_callback(functools.partial(self._async_provide, future_result))
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self._check_instance_type(result)
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                future_result.set_result(result)
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					        elif self.is_async_mode_undefined():
 | 
				
			||||||
 | 
					            if __isawaitable(result):
 | 
				
			||||||
 | 
					                self.enable_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                result = asyncio.ensure_future(result)
 | 
				
			||||||
 | 
					                result.add_done_callback(functools.partial(self._async_provide, future_result))
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.disable_async_mode()
 | 
				
			||||||
 | 
					                self._check_instance_type(result)
 | 
				
			||||||
 | 
					                return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __str__(self):
 | 
					    def __str__(self):
 | 
				
			||||||
        """Return string representation of provider.
 | 
					        """Return string representation of provider.
 | 
				
			||||||
| 
						 | 
					@ -514,6 +601,19 @@ cdef class Dependency(Provider):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        return self.override(provider)
 | 
					        return self.override(provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_provide(self, future_result, future):
 | 
				
			||||||
 | 
					        instance = future.result()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self._check_instance_type(instance)
 | 
				
			||||||
 | 
					        except Error as exception:
 | 
				
			||||||
 | 
					            future_result.set_exception(exception)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            future_result.set_result(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _check_instance_type(self, instance):
 | 
				
			||||||
 | 
					        if not isinstance(instance, self.instance_of):
 | 
				
			||||||
 | 
					            raise Error('{0} is not an instance of {1}'.format(instance, self.instance_of))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class ExternalDependency(Dependency):
 | 
					cdef class ExternalDependency(Dependency):
 | 
				
			||||||
    """:py:class:`ExternalDependency` provider describes dependency interface.
 | 
					    """:py:class:`ExternalDependency` provider describes dependency interface.
 | 
				
			||||||
| 
						 | 
					@ -904,7 +1004,7 @@ cdef class AbstractCallable(Callable):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self.__last_overriding is None:
 | 
					        if self.__last_overriding is None:
 | 
				
			||||||
            raise Error('{0} must be overridden before calling'.format(self))
 | 
					            raise Error('{0} must be overridden before calling'.format(self))
 | 
				
			||||||
        return self.__last_overriding(*args, **kwargs)
 | 
					        return super().__call__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def override(self, provider):
 | 
					    def override(self, provider):
 | 
				
			||||||
        """Override provider with another provider.
 | 
					        """Override provider with another provider.
 | 
				
			||||||
| 
						 | 
					@ -1020,7 +1120,7 @@ cdef class AbstractCoroutine(Coroutine):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self.__last_overriding is None:
 | 
					        if self.__last_overriding is None:
 | 
				
			||||||
            raise Error('{0} must be overridden before calling'.format(self))
 | 
					            raise Error('{0} must be overridden before calling'.format(self))
 | 
				
			||||||
        return self.__last_overriding(*args, **kwargs)
 | 
					        return super().__call__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def override(self, provider):
 | 
					    def override(self, provider):
 | 
				
			||||||
        """Override provider with another provider.
 | 
					        """Override provider with another provider.
 | 
				
			||||||
| 
						 | 
					@ -1790,7 +1890,7 @@ cdef class AbstractFactory(Factory):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self.__last_overriding is None:
 | 
					        if self.__last_overriding is None:
 | 
				
			||||||
            raise Error('{0} must be overridden before calling'.format(self))
 | 
					            raise Error('{0} must be overridden before calling'.format(self))
 | 
				
			||||||
        return self.__last_overriding(*args, **kwargs)
 | 
					        return super().__call__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def override(self, provider):
 | 
					    def override(self, provider):
 | 
				
			||||||
        """Override provider with another provider.
 | 
					        """Override provider with another provider.
 | 
				
			||||||
| 
						 | 
					@ -1881,13 +1981,6 @@ cdef class FactoryAggregate(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return copied
 | 
					        return copied
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __call__(self, factory_name, *args, **kwargs):
 | 
					 | 
				
			||||||
        """Create new object using factory with provided name.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Callable interface implementation.
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        return self.__get_factory(factory_name)(*args, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __getattr__(self, factory_name):
 | 
					    def __getattr__(self, factory_name):
 | 
				
			||||||
        """Return aggregated factory."""
 | 
					        """Return aggregated factory."""
 | 
				
			||||||
        return self.__get_factory(factory_name)
 | 
					        return self.__get_factory(factory_name)
 | 
				
			||||||
| 
						 | 
					@ -1915,6 +2008,19 @@ cdef class FactoryAggregate(Provider):
 | 
				
			||||||
        raise Error(
 | 
					        raise Error(
 | 
				
			||||||
            '{0} providers could not be overridden'.format(self.__class__))
 | 
					            '{0} providers could not be overridden'.format(self.__class__))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            factory_name = args[0]
 | 
				
			||||||
 | 
					        except IndexError:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                factory_name = kwargs.pop('factory_name')
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                raise TypeError('Factory missing 1 required positional argument: \'factory_name\'')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            args = args[1:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.__get_factory(factory_name)(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cdef Factory __get_factory(self, str factory_name):
 | 
					    cdef Factory __get_factory(self, str factory_name):
 | 
				
			||||||
        if factory_name not in self.__factories:
 | 
					        if factory_name not in self.__factories:
 | 
				
			||||||
            raise NoSuchProviderError(
 | 
					            raise NoSuchProviderError(
 | 
				
			||||||
| 
						 | 
					@ -2075,6 +2181,16 @@ cdef class BaseSingleton(Provider):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        raise NotImplementedError()
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_init_instance(self, future_result, result):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            instance = result.result()
 | 
				
			||||||
 | 
					        except Exception as exception:
 | 
				
			||||||
 | 
					            self.__storage = None
 | 
				
			||||||
 | 
					            future_result.set_exception(exception)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__storage = instance
 | 
				
			||||||
 | 
					            future_result.set_result(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Singleton(BaseSingleton):
 | 
					cdef class Singleton(BaseSingleton):
 | 
				
			||||||
    """Singleton provider returns same instance on every call.
 | 
					    """Singleton provider returns same instance on every call.
 | 
				
			||||||
| 
						 | 
					@ -2122,13 +2238,24 @@ cdef class Singleton(BaseSingleton):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :rtype: None
 | 
					        :rtype: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        if __isawaitable(self.__storage):
 | 
				
			||||||
 | 
					            asyncio.ensure_future(self.__storage).cancel()
 | 
				
			||||||
        self.__storage = None
 | 
					        self.__storage = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        """Return single instance."""
 | 
					        """Return single instance."""
 | 
				
			||||||
        if self.__storage is None:
 | 
					        if self.__storage is None:
 | 
				
			||||||
            self.__storage = __factory_call(self.__instantiator,
 | 
					            instance = __factory_call(self.__instantiator, args, kwargs)
 | 
				
			||||||
                                            args, kwargs)
 | 
					
 | 
				
			||||||
 | 
					            if __isawaitable(instance):
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                instance = asyncio.ensure_future(instance)
 | 
				
			||||||
 | 
					                instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
 | 
				
			||||||
 | 
					                self.__storage = future_result
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.__storage = instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.__storage
 | 
					        return self.__storage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2179,18 +2306,30 @@ cdef class ThreadSafeSingleton(BaseSingleton):
 | 
				
			||||||
        :rtype: None
 | 
					        :rtype: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        with self.__storage_lock:
 | 
					        with self.__storage_lock:
 | 
				
			||||||
 | 
					            if __isawaitable(self.__storage):
 | 
				
			||||||
 | 
					                asyncio.ensure_future(self.__storage).cancel()
 | 
				
			||||||
            self.__storage = None
 | 
					            self.__storage = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        """Return single instance."""
 | 
					        """Return single instance."""
 | 
				
			||||||
        storage = self.__storage
 | 
					        instance = self.__storage
 | 
				
			||||||
        if storage is None:
 | 
					
 | 
				
			||||||
 | 
					        if instance is None:
 | 
				
			||||||
            with self.__storage_lock:
 | 
					            with self.__storage_lock:
 | 
				
			||||||
                if self.__storage is None:
 | 
					                if self.__storage is None:
 | 
				
			||||||
                    self.__storage = __factory_call(self.__instantiator,
 | 
					                    instance = __factory_call(self.__instantiator, args, kwargs)
 | 
				
			||||||
                                                    args, kwargs)
 | 
					
 | 
				
			||||||
                storage = self.__storage
 | 
					                    if __isawaitable(instance):
 | 
				
			||||||
        return storage
 | 
					                        future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                        instance = asyncio.ensure_future(instance)
 | 
				
			||||||
 | 
					                        instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
 | 
				
			||||||
 | 
					                        self.__storage = future_result
 | 
				
			||||||
 | 
					                        return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    self.__storage = instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
 | 
					cdef class DelegatedThreadSafeSingleton(ThreadSafeSingleton):
 | 
				
			||||||
| 
						 | 
					@ -2248,6 +2387,8 @@ cdef class ThreadLocalSingleton(BaseSingleton):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        :rtype: None
 | 
					        :rtype: None
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        if __isawaitable(self.__storage.instance):
 | 
				
			||||||
 | 
					            asyncio.ensure_future(self.__storage.instance).cancel()
 | 
				
			||||||
        del self.__storage.instance
 | 
					        del self.__storage.instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
| 
						 | 
					@ -2258,10 +2399,28 @@ cdef class ThreadLocalSingleton(BaseSingleton):
 | 
				
			||||||
            instance = self.__storage.instance
 | 
					            instance = self.__storage.instance
 | 
				
			||||||
        except AttributeError:
 | 
					        except AttributeError:
 | 
				
			||||||
            instance = __factory_call(self.__instantiator, args, kwargs)
 | 
					            instance = __factory_call(self.__instantiator, args, kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if __isawaitable(instance):
 | 
				
			||||||
 | 
					                future_result = asyncio.Future()
 | 
				
			||||||
 | 
					                instance = asyncio.ensure_future(instance)
 | 
				
			||||||
 | 
					                instance.add_done_callback(functools.partial(self._async_init_instance, future_result))
 | 
				
			||||||
 | 
					                self.__storage.instance = future_result
 | 
				
			||||||
 | 
					                return future_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.__storage.instance = instance
 | 
					            self.__storage.instance = instance
 | 
				
			||||||
        finally:
 | 
					        finally:
 | 
				
			||||||
            return instance
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_init_instance(self, future_result, result):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            instance = result.result()
 | 
				
			||||||
 | 
					        except Exception as exception:
 | 
				
			||||||
 | 
					            del self.__storage.instance
 | 
				
			||||||
 | 
					            future_result.set_exception(exception)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__storage.instance = instance
 | 
				
			||||||
 | 
					            future_result.set_result(instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
 | 
					cdef class DelegatedThreadLocalSingleton(ThreadLocalSingleton):
 | 
				
			||||||
    """Delegated thread-local singleton is injected "as is".
 | 
					    """Delegated thread-local singleton is injected "as is".
 | 
				
			||||||
| 
						 | 
					@ -2302,7 +2461,7 @@ cdef class AbstractSingleton(BaseSingleton):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if self.__last_overriding is None:
 | 
					        if self.__last_overriding is None:
 | 
				
			||||||
            raise Error('{0} must be overridden before calling'.format(self))
 | 
					            raise Error('{0} must be overridden before calling'.format(self))
 | 
				
			||||||
        return self.__last_overriding(*args, **kwargs)
 | 
					        return super().__call__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def override(self, provider):
 | 
					    def override(self, provider):
 | 
				
			||||||
        """Override provider with another provider.
 | 
					        """Override provider with another provider.
 | 
				
			||||||
| 
						 | 
					@ -2705,18 +2864,30 @@ cdef class Resource(Provider):
 | 
				
			||||||
    def shutdown(self):
 | 
					    def shutdown(self):
 | 
				
			||||||
        """Shutdown resource."""
 | 
					        """Shutdown resource."""
 | 
				
			||||||
        if not self.__initialized:
 | 
					        if not self.__initialized:
 | 
				
			||||||
 | 
					            if self.is_async_mode_enabled():
 | 
				
			||||||
 | 
					                result = asyncio.Future()
 | 
				
			||||||
 | 
					                result.set_result(None)
 | 
				
			||||||
 | 
					                return result
 | 
				
			||||||
            return
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.__shutdowner:
 | 
					        if self.__shutdowner:
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                self.__shutdowner(self.__resource)
 | 
					                shutdown = self.__shutdowner(self.__resource)
 | 
				
			||||||
            except StopIteration:
 | 
					            except StopIteration:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if inspect.isawaitable(shutdown):
 | 
				
			||||||
 | 
					                    return self._create_shutdown_future(shutdown)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.__resource = None
 | 
					        self.__resource = None
 | 
				
			||||||
        self.__initialized = False
 | 
					        self.__initialized = False
 | 
				
			||||||
        self.__shutdowner = None
 | 
					        self.__shutdowner = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.is_async_mode_enabled():
 | 
				
			||||||
 | 
					            result = asyncio.Future()
 | 
				
			||||||
 | 
					            result.set_result(None)
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        if self.__initialized:
 | 
					        if self.__initialized:
 | 
				
			||||||
            return self.__resource
 | 
					            return self.__resource
 | 
				
			||||||
| 
						 | 
					@ -2733,6 +2904,19 @@ cdef class Resource(Provider):
 | 
				
			||||||
                self.__kwargs_len,
 | 
					                self.__kwargs_len,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            self.__shutdowner = initializer.shutdown
 | 
					            self.__shutdowner = initializer.shutdown
 | 
				
			||||||
 | 
					        elif self._is_async_resource_subclass(self.__initializer):
 | 
				
			||||||
 | 
					            initializer = self.__initializer()
 | 
				
			||||||
 | 
					            async_init = __call(
 | 
				
			||||||
 | 
					                initializer.init,
 | 
				
			||||||
 | 
					                args,
 | 
				
			||||||
 | 
					                self.__args,
 | 
				
			||||||
 | 
					                self.__args_len,
 | 
				
			||||||
 | 
					                kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs_len,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.__initialized = True
 | 
				
			||||||
 | 
					            return self._create_init_future(async_init, initializer.shutdown)
 | 
				
			||||||
        elif inspect.isgeneratorfunction(self.__initializer):
 | 
					        elif inspect.isgeneratorfunction(self.__initializer):
 | 
				
			||||||
            initializer = __call(
 | 
					            initializer = __call(
 | 
				
			||||||
                self.__initializer,
 | 
					                self.__initializer,
 | 
				
			||||||
| 
						 | 
					@ -2745,6 +2929,30 @@ cdef class Resource(Provider):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            self.__resource = next(initializer)
 | 
					            self.__resource = next(initializer)
 | 
				
			||||||
            self.__shutdowner = initializer.send
 | 
					            self.__shutdowner = initializer.send
 | 
				
			||||||
 | 
					        elif iscoroutinefunction(self.__initializer):
 | 
				
			||||||
 | 
					            initializer = __call(
 | 
				
			||||||
 | 
					                self.__initializer,
 | 
				
			||||||
 | 
					                args,
 | 
				
			||||||
 | 
					                self.__args,
 | 
				
			||||||
 | 
					                self.__args_len,
 | 
				
			||||||
 | 
					                kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs_len,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.__initialized = True
 | 
				
			||||||
 | 
					            return self._create_init_future(initializer)
 | 
				
			||||||
 | 
					        elif isasyncgenfunction(self.__initializer):
 | 
				
			||||||
 | 
					            initializer = __call(
 | 
				
			||||||
 | 
					                self.__initializer,
 | 
				
			||||||
 | 
					                args,
 | 
				
			||||||
 | 
					                self.__args,
 | 
				
			||||||
 | 
					                self.__args_len,
 | 
				
			||||||
 | 
					                kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs,
 | 
				
			||||||
 | 
					                self.__kwargs_len,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.__initialized = True
 | 
				
			||||||
 | 
					            return self._create_init_future(initializer.__anext__(), initializer.asend)
 | 
				
			||||||
        elif callable(self.__initializer):
 | 
					        elif callable(self.__initializer):
 | 
				
			||||||
            self.__resource = __call(
 | 
					            self.__resource = __call(
 | 
				
			||||||
                self.__initializer,
 | 
					                self.__initializer,
 | 
				
			||||||
| 
						 | 
					@ -2761,6 +2969,45 @@ cdef class Resource(Provider):
 | 
				
			||||||
        self.__initialized = True
 | 
					        self.__initialized = True
 | 
				
			||||||
        return self.__resource
 | 
					        return self.__resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_init_future(self, future, shutdowner=None):
 | 
				
			||||||
 | 
					        callback = self._async_init_callback
 | 
				
			||||||
 | 
					        if shutdowner:
 | 
				
			||||||
 | 
					            callback = functools.partial(callback, shutdowner=shutdowner)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future = asyncio.ensure_future(future)
 | 
				
			||||||
 | 
					        future.add_done_callback(callback)
 | 
				
			||||||
 | 
					        self.__resource = future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_init_callback(self, initializer, shutdowner=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            resource = initializer.result()
 | 
				
			||||||
 | 
					        except Exception:
 | 
				
			||||||
 | 
					            self.__initialized = False
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__resource = resource
 | 
				
			||||||
 | 
					            self.__shutdowner = shutdowner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _create_shutdown_future(self, shutdown_future):
 | 
				
			||||||
 | 
					        future = asyncio.Future()
 | 
				
			||||||
 | 
					        shutdown_future = asyncio.ensure_future(shutdown_future)
 | 
				
			||||||
 | 
					        shutdown_future.add_done_callback(functools.partial(self._async_shutdown_callback, future))
 | 
				
			||||||
 | 
					        return future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_shutdown_callback(self, future_result, shutdowner):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            shutdowner.result()
 | 
				
			||||||
 | 
					        except StopAsyncIteration:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__resource = None
 | 
				
			||||||
 | 
					        self.__initialized = False
 | 
				
			||||||
 | 
					        self.__shutdowner = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future_result.set_result(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def _is_resource_subclass(instance):
 | 
					    def _is_resource_subclass(instance):
 | 
				
			||||||
        if  sys.version_info < (3, 5):
 | 
					        if  sys.version_info < (3, 5):
 | 
				
			||||||
| 
						 | 
					@ -2770,6 +3017,15 @@ cdef class Resource(Provider):
 | 
				
			||||||
        from . import resources
 | 
					        from . import resources
 | 
				
			||||||
        return issubclass(instance, resources.Resource)
 | 
					        return issubclass(instance, resources.Resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def _is_async_resource_subclass(instance):
 | 
				
			||||||
 | 
					        if  sys.version_info < (3, 5):
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					        if not isinstance(instance, CLASS_TYPES):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        from . import resources
 | 
				
			||||||
 | 
					        return issubclass(instance, resources.AsyncResource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Container(Provider):
 | 
					cdef class Container(Provider):
 | 
				
			||||||
    """Container provider provides an instance of declarative container.
 | 
					    """Container provider provides an instance of declarative container.
 | 
				
			||||||
| 
						 | 
					@ -3037,8 +3293,18 @@ cdef class AttributeGetter(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        provided = self.__provider(*args, **kwargs)
 | 
					        provided = self.__provider(*args, **kwargs)
 | 
				
			||||||
 | 
					        if __isawaitable(provided):
 | 
				
			||||||
 | 
					            future_result = asyncio.Future()
 | 
				
			||||||
 | 
					            provided = asyncio.ensure_future(provided)
 | 
				
			||||||
 | 
					            provided.add_done_callback(functools.partial(self._async_provide, future_result))
 | 
				
			||||||
 | 
					            return future_result
 | 
				
			||||||
        return getattr(provided, self.__attribute)
 | 
					        return getattr(provided, self.__attribute)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_provide(self, future_result, future):
 | 
				
			||||||
 | 
					        provided = future.result()
 | 
				
			||||||
 | 
					        result = getattr(provided, self.__attribute)
 | 
				
			||||||
 | 
					        future_result.set_result(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class ItemGetter(Provider):
 | 
					cdef class ItemGetter(Provider):
 | 
				
			||||||
    """Provider that returns the item of the injected instance.
 | 
					    """Provider that returns the item of the injected instance.
 | 
				
			||||||
| 
						 | 
					@ -3087,8 +3353,18 @@ cdef class ItemGetter(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        provided = self.__provider(*args, **kwargs)
 | 
					        provided = self.__provider(*args, **kwargs)
 | 
				
			||||||
 | 
					        if __isawaitable(provided):
 | 
				
			||||||
 | 
					            future_result = asyncio.Future()
 | 
				
			||||||
 | 
					            provided = asyncio.ensure_future(provided)
 | 
				
			||||||
 | 
					            provided.add_done_callback(functools.partial(self._async_provide, future_result))
 | 
				
			||||||
 | 
					            return future_result
 | 
				
			||||||
        return provided[self.__item]
 | 
					        return provided[self.__item]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_provide(self, future_result, future):
 | 
				
			||||||
 | 
					        provided = future.result()
 | 
				
			||||||
 | 
					        result = provided[self.__item]
 | 
				
			||||||
 | 
					        future_result.set_result(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class MethodCaller(Provider):
 | 
					cdef class MethodCaller(Provider):
 | 
				
			||||||
    """Provider that calls the method of the injected instance.
 | 
					    """Provider that calls the method of the injected instance.
 | 
				
			||||||
| 
						 | 
					@ -3169,6 +3445,11 @@ cdef class MethodCaller(Provider):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cpdef object _provide(self, tuple args, dict kwargs):
 | 
					    cpdef object _provide(self, tuple args, dict kwargs):
 | 
				
			||||||
        call = self.__provider()
 | 
					        call = self.__provider()
 | 
				
			||||||
 | 
					        if __isawaitable(call):
 | 
				
			||||||
 | 
					            future_result = asyncio.Future()
 | 
				
			||||||
 | 
					            call = asyncio.ensure_future(call)
 | 
				
			||||||
 | 
					            call.add_done_callback(functools.partial(self._async_provide, future_result, args, kwargs))
 | 
				
			||||||
 | 
					            return future_result
 | 
				
			||||||
        return __call(
 | 
					        return __call(
 | 
				
			||||||
            call,
 | 
					            call,
 | 
				
			||||||
            args,
 | 
					            args,
 | 
				
			||||||
| 
						 | 
					@ -3179,6 +3460,19 @@ cdef class MethodCaller(Provider):
 | 
				
			||||||
            self.__kwargs_len,
 | 
					            self.__kwargs_len,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _async_provide(self, future_result, args, kwargs, future):
 | 
				
			||||||
 | 
					        call = future.result()
 | 
				
			||||||
 | 
					        result = __call(
 | 
				
			||||||
 | 
					            call,
 | 
				
			||||||
 | 
					            args,
 | 
				
			||||||
 | 
					            self.__args,
 | 
				
			||||||
 | 
					            self.__args_len,
 | 
				
			||||||
 | 
					            kwargs,
 | 
				
			||||||
 | 
					            self.__kwargs,
 | 
				
			||||||
 | 
					            self.__kwargs_len,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        future_result.set_result(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cdef class Injection(object):
 | 
					cdef class Injection(object):
 | 
				
			||||||
    """Abstract injection class."""
 | 
					    """Abstract injection class."""
 | 
				
			||||||
| 
						 | 
					@ -3381,3 +3675,36 @@ def merge_dicts(dict1, dict2):
 | 
				
			||||||
    result = dict1.copy()
 | 
					    result = dict1.copy()
 | 
				
			||||||
    result.update(dict2)
 | 
					    result.update(dict2)
 | 
				
			||||||
    return result
 | 
					    return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def isawaitable(obj):
 | 
				
			||||||
 | 
					    """Check if object is a coroutine function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Return False for any object in Python 3.4 or below.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return inspect.isawaitable(obj)
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def iscoroutinefunction(obj):
 | 
				
			||||||
 | 
					    """Check if object is a coroutine function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Return False for any object in Python 3.4 or below.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return inspect.iscoroutinefunction(obj)
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def isasyncgenfunction(obj):
 | 
				
			||||||
 | 
					    """Check if object is an asynchronous generator function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Return False for any object in Python 3.4 or below.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return inspect.isasyncgenfunction(obj)
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,3 +29,14 @@ class Resource(Generic[T], metaclass=ResourceMeta):
 | 
				
			||||||
    @abc.abstractmethod
 | 
					    @abc.abstractmethod
 | 
				
			||||||
    def shutdown(self, resource: T) -> None:
 | 
					    def shutdown(self, resource: T) -> None:
 | 
				
			||||||
        ...
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncResource(Generic[T], metaclass=ResourceMeta):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractmethod
 | 
				
			||||||
 | 
					    async def init(self, *args, **kwargs) -> T:
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @abc.abstractmethod
 | 
				
			||||||
 | 
					    async def shutdown(self, resource: T) -> None:
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
"""Wiring module."""
 | 
					"""Wiring module."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
import functools
 | 
					import functools
 | 
				
			||||||
import inspect
 | 
					import inspect
 | 
				
			||||||
import importlib
 | 
					import importlib
 | 
				
			||||||
| 
						 | 
					@ -426,10 +427,20 @@ 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()
 | 
				
			||||||
 | 
					        to_inject_await = []
 | 
				
			||||||
 | 
					        to_close_await = []
 | 
				
			||||||
        for injection, provider in _patched.__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()
 | 
					                provide = provider()
 | 
				
			||||||
 | 
					                if inspect.isawaitable(provide):
 | 
				
			||||||
 | 
					                    to_inject_await.append((injection, provide))
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    to_inject[injection] = provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async_to_inject = await asyncio.gather(*[provide for _, provide in to_inject_await])
 | 
				
			||||||
 | 
					        for provide, (injection, _) in zip(async_to_inject, to_inject_await):
 | 
				
			||||||
 | 
					            to_inject[injection] = provide
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = await fn(*args, **to_inject)
 | 
					        result = await fn(*args, **to_inject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -439,7 +450,11 @@ def _get_async_patched(fn):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            if not isinstance(provider, providers.Resource):
 | 
					            if not isinstance(provider, providers.Resource):
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            provider.shutdown()
 | 
					            shutdown = provider.shutdown()
 | 
				
			||||||
 | 
					            if inspect.isawaitable(shutdown):
 | 
				
			||||||
 | 
					                to_close_await.append(shutdown)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await asyncio.gather(*to_close_await)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return result
 | 
					        return result
 | 
				
			||||||
    return _patched
 | 
					    return _patched
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,3 +50,9 @@ animal7: Animal = provider7(1, 2, 3, b='1', c=2, e=0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test 8: to check the CallableDelegate __init__
 | 
					# Test 8: to check the CallableDelegate __init__
 | 
				
			||||||
provider8 = providers.CallableDelegate(providers.Callable(lambda: None))
 | 
					provider8 = providers.CallableDelegate(providers.Callable(lambda: None))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 9: to check the return type with await
 | 
				
			||||||
 | 
					provider9 = providers.Callable(Cat)
 | 
				
			||||||
 | 
					async def _async9() -> None:
 | 
				
			||||||
 | 
					    animal1: Animal = await provider9(1, 2, 3, b='1', c=2, e=0.0)  # type: ignore
 | 
				
			||||||
 | 
					    animal2: Animal = await provider9.async_(1, 2, 3, b='1', c=2, e=0.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,3 +4,9 @@ from dependency_injector import providers
 | 
				
			||||||
# Test 1: to check the return type
 | 
					# Test 1: to check the return type
 | 
				
			||||||
provider1 = providers.Delegate(providers.Provider())
 | 
					provider1 = providers.Delegate(providers.Provider())
 | 
				
			||||||
var1: providers.Provider = provider1()
 | 
					var1: providers.Provider = provider1()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 2: to check the return type with await
 | 
				
			||||||
 | 
					provider2 = providers.Delegate(providers.Provider())
 | 
				
			||||||
 | 
					async def _async2() -> None:
 | 
				
			||||||
 | 
					    var1: providers.Provider = await provider2()  # type: ignore
 | 
				
			||||||
 | 
					    var2: providers.Provider = await provider2.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,3 +20,9 @@ var1: Animal = provider1()
 | 
				
			||||||
# Test 2: to check the return type
 | 
					# Test 2: to check the return type
 | 
				
			||||||
provider2 = providers.Dependency(instance_of=Animal)
 | 
					provider2 = providers.Dependency(instance_of=Animal)
 | 
				
			||||||
var2: Type[Animal] = provider2.instance_of
 | 
					var2: Type[Animal] = provider2.instance_of
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 3: to check the return type with await
 | 
				
			||||||
 | 
					provider3 = providers.Dependency(instance_of=Animal)
 | 
				
			||||||
 | 
					async def _async3() -> None:
 | 
				
			||||||
 | 
					    var1: Animal = await provider3()  # type: ignore
 | 
				
			||||||
 | 
					    var2: Animal = await provider3.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,3 +35,13 @@ provider5 = providers.Dict(
 | 
				
			||||||
    a2=providers.Factory(object),
 | 
					    a2=providers.Factory(object),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
provided5: providers.ProvidedInstance = provider5.provided
 | 
					provided5: providers.ProvidedInstance = provider5.provided
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 6: to check the return type with await
 | 
				
			||||||
 | 
					provider6 = providers.Dict(
 | 
				
			||||||
 | 
					    a1=providers.Factory(object),
 | 
				
			||||||
 | 
					    a2=providers.Factory(object),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					async def _async3() -> None:
 | 
				
			||||||
 | 
					    var1: Dict[Any, Any] = await provider6()  # type: ignore
 | 
				
			||||||
 | 
					    var2: Dict[Any, Any] = await provider6.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,3 +66,9 @@ val9: Any = provider9('a')
 | 
				
			||||||
# Test 10: to check the explicit typing
 | 
					# Test 10: to check the explicit typing
 | 
				
			||||||
factory10: providers.Provider[Animal] = providers.Factory(Cat)
 | 
					factory10: providers.Provider[Animal] = providers.Factory(Cat)
 | 
				
			||||||
animal10: Animal = factory10()
 | 
					animal10: Animal = factory10()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 11: to check the return type with await
 | 
				
			||||||
 | 
					provider11 = providers.Factory(Cat)
 | 
				
			||||||
 | 
					async def _async11() -> None:
 | 
				
			||||||
 | 
					    animal1: Animal = await provider11(1, 2, 3, b='1', c=2, e=0.0)  # type: ignore
 | 
				
			||||||
 | 
					    animal2: Animal = await provider11.async_(1, 2, 3, b='1', c=2, e=0.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,3 +27,12 @@ provided3: providers.ProvidedInstance = provider3.provided
 | 
				
			||||||
attr_getter3: providers.AttributeGetter = provider3.provided.attr
 | 
					attr_getter3: providers.AttributeGetter = provider3.provided.attr
 | 
				
			||||||
item_getter3: providers.ItemGetter = provider3.provided['item']
 | 
					item_getter3: providers.ItemGetter = provider3.provided['item']
 | 
				
			||||||
method_caller3: providers.MethodCaller = provider3.provided.method.call(123, arg=324)
 | 
					method_caller3: providers.MethodCaller = provider3.provided.method.call(123, arg=324)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 4: to check the return type with await
 | 
				
			||||||
 | 
					provider4 = providers.List(
 | 
				
			||||||
 | 
					    providers.Factory(object),
 | 
				
			||||||
 | 
					    providers.Factory(object),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					async def _async4() -> None:
 | 
				
			||||||
 | 
					    var1: List[Any] = await provider4()  # type: ignore
 | 
				
			||||||
 | 
					    var2: List[Any] = await provider4.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,3 +11,9 @@ provided2: providers.ProvidedInstance = provider2.provided
 | 
				
			||||||
attr_getter2: providers.AttributeGetter = provider2.provided.attr
 | 
					attr_getter2: providers.AttributeGetter = provider2.provided.attr
 | 
				
			||||||
item_getter2: providers.ItemGetter = provider2.provided['item']
 | 
					item_getter2: providers.ItemGetter = provider2.provided['item']
 | 
				
			||||||
method_caller2: providers.MethodCaller = provider2.provided.method.call(123, arg=324)
 | 
					method_caller2: providers.MethodCaller = provider2.provided.method.call(123, arg=324)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 3: to check the return type with await
 | 
				
			||||||
 | 
					provider3 = providers.Object(int(3))
 | 
				
			||||||
 | 
					async def _async3() -> None:
 | 
				
			||||||
 | 
					    var1: int = await provider3()  # type: ignore
 | 
				
			||||||
 | 
					    var2: int = await provider3.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,3 +4,12 @@ from dependency_injector import providers
 | 
				
			||||||
# Test 1: to check .provided attribute
 | 
					# Test 1: to check .provided attribute
 | 
				
			||||||
provider1: providers.Provider[int] = providers.Object(1)
 | 
					provider1: providers.Provider[int] = providers.Object(1)
 | 
				
			||||||
provided: providers.ProvidedInstance = provider1.provided
 | 
					provided: providers.ProvidedInstance = provider1.provided
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 2: to check async mode API
 | 
				
			||||||
 | 
					provider2: providers.Provider = providers.Provider()
 | 
				
			||||||
 | 
					provider2.enable_async_mode()
 | 
				
			||||||
 | 
					provider2.disable_async_mode()
 | 
				
			||||||
 | 
					provider2.reset_async_mode()
 | 
				
			||||||
 | 
					r1: bool = provider2.is_async_mode_enabled()
 | 
				
			||||||
 | 
					r2: bool = provider2.is_async_mode_disabled()
 | 
				
			||||||
 | 
					r3: bool = provider2.is_async_mode_undefined()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
from typing import List, Iterator, Generator
 | 
					from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import providers, resources
 | 
					from dependency_injector import providers, resources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,3 +41,59 @@ class MyResource4(resources.Resource[List[int]]):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
provider4 = providers.Resource(MyResource4)
 | 
					provider4 = providers.Resource(MyResource4)
 | 
				
			||||||
var4: List[int] = provider4()
 | 
					var4: List[int] = provider4()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 5: to check the return type with async function
 | 
				
			||||||
 | 
					async def init5() -> List[int]:
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					provider5 = providers.Resource(init5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def _provide5() -> None:
 | 
				
			||||||
 | 
					    var1: List[int] = await provider5()  # type: ignore
 | 
				
			||||||
 | 
					    var2: List[int] = await provider5.async_()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 6: to check the return type with async iterator
 | 
				
			||||||
 | 
					async def init6() -> AsyncIterator[List[int]]:
 | 
				
			||||||
 | 
					    yield []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					provider6 = providers.Resource(init6)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def _provide6() -> None:
 | 
				
			||||||
 | 
					    var1: List[int] = await provider6()  # type: ignore
 | 
				
			||||||
 | 
					    var2: List[int] = await provider6.async_()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 7: to check the return type with async generator
 | 
				
			||||||
 | 
					async def init7() -> AsyncGenerator[List[int], None]:
 | 
				
			||||||
 | 
					    yield []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					provider7 = providers.Resource(init7)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def _provide7() -> None:
 | 
				
			||||||
 | 
					    var1: List[int] = await provider7()  # type: ignore
 | 
				
			||||||
 | 
					    var2: List[int] = await provider7.async_()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 8: to check the return type with async resource subclass
 | 
				
			||||||
 | 
					class MyResource8(resources.AsyncResource[List[int]]):
 | 
				
			||||||
 | 
					    async def init(self, *args, **kwargs) -> List[int]:
 | 
				
			||||||
 | 
					        return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def shutdown(self, resource: List[int]) -> None:
 | 
				
			||||||
 | 
					        ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					provider8 = providers.Resource(MyResource8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def _provide8() -> None:
 | 
				
			||||||
 | 
					    var1: List[int] = await provider8()  # type: ignore
 | 
				
			||||||
 | 
					    var2: List[int] = await provider8.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					from typing import Any
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import providers
 | 
					from dependency_injector import providers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +9,7 @@ provider1 = providers.Selector(
 | 
				
			||||||
    a=providers.Factory(object),
 | 
					    a=providers.Factory(object),
 | 
				
			||||||
    b=providers.Factory(object),
 | 
					    b=providers.Factory(object),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
var1: int = provider1()
 | 
					var1: Any = provider1()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test 2: to check the provided instance interface
 | 
					# Test 2: to check the provided instance interface
 | 
				
			||||||
provider2 = providers.Selector(
 | 
					provider2 = providers.Selector(
 | 
				
			||||||
| 
						 | 
					@ -27,3 +29,13 @@ provider3 = providers.Selector(
 | 
				
			||||||
    b=providers.Factory(object),
 | 
					    b=providers.Factory(object),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
attr3: providers.Provider = provider3.a
 | 
					attr3: providers.Provider = provider3.a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 4: to check the return type with await
 | 
				
			||||||
 | 
					provider4 = providers.Selector(
 | 
				
			||||||
 | 
					    lambda: 'a',
 | 
				
			||||||
 | 
					    a=providers.Factory(object),
 | 
				
			||||||
 | 
					    b=providers.Factory(object),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					async def _async4() -> None:
 | 
				
			||||||
 | 
					    var1: Any = await provider4()  # type: ignore
 | 
				
			||||||
 | 
					    var2: Any = await provider4.async_()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,3 +69,9 @@ animal11: Animal = provider11(1, 2, 3, b='1', c=2, e=0.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Test 12: to check the SingletonDelegate __init__
 | 
					# Test 12: to check the SingletonDelegate __init__
 | 
				
			||||||
provider12 = providers.SingletonDelegate(providers.Singleton(object))
 | 
					provider12 = providers.SingletonDelegate(providers.Singleton(object))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test 13: to check the return type with await
 | 
				
			||||||
 | 
					provider13 = providers.Singleton(Cat)
 | 
				
			||||||
 | 
					async def _async13() -> None:
 | 
				
			||||||
 | 
					    animal1: Animal = await provider13(1, 2, 3, b='1', c=2, e=0.0)  # type: ignore
 | 
				
			||||||
 | 
					    animal2: Animal = await provider13.async_(1, 2, 3, b='1', c=2, e=0.0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										57
									
								
								tests/unit/asyncutils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								tests/unit/asyncutils.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					"""Test utils."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					import contextlib
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import gc
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run(main):
 | 
				
			||||||
 | 
					    loop = asyncio.get_event_loop()
 | 
				
			||||||
 | 
					    return loop.run_until_complete(main)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def setup_test_loop(
 | 
				
			||||||
 | 
					        loop_factory=asyncio.new_event_loop
 | 
				
			||||||
 | 
					) -> asyncio.AbstractEventLoop:
 | 
				
			||||||
 | 
					    loop = loop_factory()
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        module = loop.__class__.__module__
 | 
				
			||||||
 | 
					        skip_watcher = 'uvloop' in module
 | 
				
			||||||
 | 
					    except AttributeError:  # pragma: no cover
 | 
				
			||||||
 | 
					        # Just in case
 | 
				
			||||||
 | 
					        skip_watcher = True
 | 
				
			||||||
 | 
					    asyncio.set_event_loop(loop)
 | 
				
			||||||
 | 
					    if sys.platform != 'win32' and not skip_watcher:
 | 
				
			||||||
 | 
					        policy = asyncio.get_event_loop_policy()
 | 
				
			||||||
 | 
					        watcher = asyncio.SafeChildWatcher()  # type: ignore
 | 
				
			||||||
 | 
					        watcher.attach_loop(loop)
 | 
				
			||||||
 | 
					        with contextlib.suppress(NotImplementedError):
 | 
				
			||||||
 | 
					            policy.set_child_watcher(watcher)
 | 
				
			||||||
 | 
					    return loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def teardown_test_loop(loop: asyncio.AbstractEventLoop, fast: bool = False) -> None:
 | 
				
			||||||
 | 
					    closed = loop.is_closed()
 | 
				
			||||||
 | 
					    if not closed:
 | 
				
			||||||
 | 
					        loop.call_soon(loop.stop)
 | 
				
			||||||
 | 
					        loop.run_forever()
 | 
				
			||||||
 | 
					        loop.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not fast:
 | 
				
			||||||
 | 
					        gc.collect()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    asyncio.set_event_loop(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncTestCase(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self.loop = setup_test_loop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tearDown(self):
 | 
				
			||||||
 | 
					        teardown_test_loop(self.loop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _run(self, f):
 | 
				
			||||||
 | 
					        return self.loop.run_until_complete(f)
 | 
				
			||||||
							
								
								
									
										71
									
								
								tests/unit/containers/test_dynamic_async_resources_py36.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								tests/unit/containers/test_dynamic_async_resources_py36.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					"""Dependency injector dynamic container unit tests for async resources."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import unittest2 as unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Runtime import to get asyncutils module
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import (
 | 
				
			||||||
 | 
					    containers,
 | 
				
			||||||
 | 
					    providers,
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncResourcesTest(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @unittest.skipIf(sys.version_info[:2] <= (3, 5), 'Async test')
 | 
				
			||||||
 | 
					    def test_async_init_resources(self):
 | 
				
			||||||
 | 
					        async def _init1():
 | 
				
			||||||
 | 
					            _init1.init_counter += 1
 | 
				
			||||||
 | 
					            yield
 | 
				
			||||||
 | 
					            _init1.shutdown_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _init1.init_counter = 0
 | 
				
			||||||
 | 
					        _init1.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _init2():
 | 
				
			||||||
 | 
					            _init2.init_counter += 1
 | 
				
			||||||
 | 
					            yield
 | 
				
			||||||
 | 
					            _init2.shutdown_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _init2.init_counter = 0
 | 
				
			||||||
 | 
					        _init2.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource1 = providers.Resource(_init1)
 | 
				
			||||||
 | 
					            resource2 = providers.Resource(_init2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.init_counter, 0)
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.shutdown_counter, 0)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.init_counter, 0)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(container.init_resources())
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.shutdown_counter, 0)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(container.shutdown_resources())
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.shutdown_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(container.init_resources())
 | 
				
			||||||
 | 
					        self._run(container.shutdown_resources())
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init1.shutdown_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init2.shutdown_counter, 2)
 | 
				
			||||||
| 
						 | 
					@ -231,7 +231,3 @@ class DeclarativeContainerInstanceTests(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(_init1.shutdown_counter, 2)
 | 
					        self.assertEqual(_init1.shutdown_counter, 2)
 | 
				
			||||||
        self.assertEqual(_init2.init_counter, 2)
 | 
					        self.assertEqual(_init2.init_counter, 2)
 | 
				
			||||||
        self.assertEqual(_init2.shutdown_counter, 2)
 | 
					        self.assertEqual(_init2.shutdown_counter, 2)
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    unittest.main()
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										818
									
								
								tests/unit/providers/test_async_py36.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										818
									
								
								tests/unit/providers/test_async_py36.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,818 @@
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers, errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Runtime import to get asyncutils module
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RESOURCE1 = object()
 | 
				
			||||||
 | 
					RESOURCE2 = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def init_resource(resource):
 | 
				
			||||||
 | 
					    await asyncio.sleep(random.randint(1, 10) / 1000)
 | 
				
			||||||
 | 
					    yield resource
 | 
				
			||||||
 | 
					    await asyncio.sleep(random.randint(1, 10) / 1000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Client:
 | 
				
			||||||
 | 
					    def __init__(self, resource1: object, resource2: object) -> None:
 | 
				
			||||||
 | 
					        self.resource1 = resource1
 | 
				
			||||||
 | 
					        self.resource2 = resource2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Service:
 | 
				
			||||||
 | 
					    def __init__(self, client: Client) -> None:
 | 
				
			||||||
 | 
					        self.client = client
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					    resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					    resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    client = providers.Factory(
 | 
				
			||||||
 | 
					        Client,
 | 
				
			||||||
 | 
					        resource1=resource1,
 | 
				
			||||||
 | 
					        resource2=resource2,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    service = providers.Factory(
 | 
				
			||||||
 | 
					        Service,
 | 
				
			||||||
 | 
					        client=client,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FactoryTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_args_injection(self):
 | 
				
			||||||
 | 
					        class ContainerWithArgs(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                Client,
 | 
				
			||||||
 | 
					                resource1,
 | 
				
			||||||
 | 
					                resource2,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            service = providers.Factory(
 | 
				
			||||||
 | 
					                Service,
 | 
				
			||||||
 | 
					                client,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = ContainerWithArgs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_kwargs_injection(self):
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_context_kwargs_injection(self):
 | 
				
			||||||
 | 
					        resource2_extra = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client(resource2=resource2_extra))
 | 
				
			||||||
 | 
					        client2 = self._run(container.client(resource2=resource2_extra))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, resource2_extra)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, resource2_extra)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_args_kwargs_injection(self):
 | 
				
			||||||
 | 
					        class ContainerWithArgsAndKwArgs(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                Client,
 | 
				
			||||||
 | 
					                resource1,
 | 
				
			||||||
 | 
					                resource2=resource2,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            service = providers.Factory(
 | 
				
			||||||
 | 
					                Service,
 | 
				
			||||||
 | 
					                client=client,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = ContainerWithArgsAndKwArgs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_attributes_injection(self):
 | 
				
			||||||
 | 
					        class ContainerWithAttributes(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Factory(
 | 
				
			||||||
 | 
					                Client,
 | 
				
			||||||
 | 
					                resource1,
 | 
				
			||||||
 | 
					                resource2=None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            client.add_attributes(resource2=resource2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            service = providers.Factory(
 | 
				
			||||||
 | 
					                Service,
 | 
				
			||||||
 | 
					                client=None,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            service.add_attributes(client=client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = ContainerWithAttributes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FactoryAggregateTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        object1 = object()
 | 
				
			||||||
 | 
					        object2 = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_object1():
 | 
				
			||||||
 | 
					            return object1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_object2():
 | 
				
			||||||
 | 
					            return object2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.FactoryAggregate(
 | 
				
			||||||
 | 
					            object1=providers.Factory(_get_object1),
 | 
				
			||||||
 | 
					            object2=providers.Factory(_get_object2),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        created_object1 = self._run(provider('object1'))
 | 
				
			||||||
 | 
					        self.assertIs(created_object1, object1)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        created_object2 = self._run(provider('object2'))
 | 
				
			||||||
 | 
					        self.assertIs(created_object2, object2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_injections(self):
 | 
				
			||||||
 | 
					        class ContainerWithSingletons(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource1 = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            resource2 = providers.Resource(init_resource, providers.Object(RESOURCE2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            client = providers.Singleton(
 | 
				
			||||||
 | 
					                Client,
 | 
				
			||||||
 | 
					                resource1=resource1,
 | 
				
			||||||
 | 
					                resource2=resource2,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            service = providers.Singleton(
 | 
				
			||||||
 | 
					                Service,
 | 
				
			||||||
 | 
					                client=client,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = ContainerWithSingletons()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(service1, service2)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client, service2.client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client, client1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(service2.client, client2)
 | 
				
			||||||
 | 
					        self.assertIs(client1, client2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Singleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_init_with_error(self):
 | 
				
			||||||
 | 
					        # Disable default exception handling to prevent output
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(lambda loop, context: ...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            create_instance.counter += 1
 | 
				
			||||||
 | 
					            raise RuntimeError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        create_instance.counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Singleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future = provider()
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(RuntimeError):
 | 
				
			||||||
 | 
					            self._run(future)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(create_instance.counter, 1)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(RuntimeError):
 | 
				
			||||||
 | 
					            self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(create_instance.counter, 2)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Restore default exception handling
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DelegatedSingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.DelegatedSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ThreadSafeSingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.ThreadSafeSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DelegatedThreadSafeSingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.DelegatedThreadSafeSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ThreadLocalSingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.ThreadLocalSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_init_with_error(self):
 | 
				
			||||||
 | 
					        # Disable default exception handling to prevent output
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(lambda loop, context: ...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            create_instance.counter += 1
 | 
				
			||||||
 | 
					            raise RuntimeError()
 | 
				
			||||||
 | 
					        create_instance.counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.ThreadLocalSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future = provider()
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(RuntimeError):
 | 
				
			||||||
 | 
					            self._run(future)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(create_instance.counter, 1)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(RuntimeError):
 | 
				
			||||||
 | 
					            self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(create_instance.counter, 2)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Restore default exception handling
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DelegatedThreadLocalSingletonTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        instance = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def create_instance():
 | 
				
			||||||
 | 
					            return instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.DelegatedThreadLocalSingleton(create_instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1 = self._run(provider())
 | 
				
			||||||
 | 
					        instance2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1, instance2)
 | 
				
			||||||
 | 
					        self.assertIs(instance, instance)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProvidedInstanceTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_provided_attribute(self):
 | 
				
			||||||
 | 
					        class TestClient:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestService:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestContainer(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            client = providers.Factory(TestClient, resource=resource)
 | 
				
			||||||
 | 
					            service = providers.Factory(TestService, resource=client.provided.resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = TestContainer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1, instance2 = self._run(
 | 
				
			||||||
 | 
					            asyncio.gather(
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance2.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, instance2.resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_provided_item(self):
 | 
				
			||||||
 | 
					        class TestClient:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            def __getitem__(self, item):
 | 
				
			||||||
 | 
					                return getattr(self, item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestService:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestContainer(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            client = providers.Factory(TestClient, resource=resource)
 | 
				
			||||||
 | 
					            service = providers.Factory(TestService, resource=client.provided['resource'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = TestContainer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1, instance2 = self._run(
 | 
				
			||||||
 | 
					            asyncio.gather(
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance2.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, instance2.resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_provided_method_call(self):
 | 
				
			||||||
 | 
					        class TestClient:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            def get_resource(self):
 | 
				
			||||||
 | 
					                return self.resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestService:
 | 
				
			||||||
 | 
					            def __init__(self, resource):
 | 
				
			||||||
 | 
					                self.resource = resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestContainer(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					            resource = providers.Resource(init_resource, providers.Object(RESOURCE1))
 | 
				
			||||||
 | 
					            client = providers.Factory(TestClient, resource=resource)
 | 
				
			||||||
 | 
					            service = providers.Factory(TestService, resource=client.provided.get_resource.call())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = TestContainer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        instance1, instance2 = self._run(
 | 
				
			||||||
 | 
					            asyncio.gather(
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					                container.service(),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance2.resource, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(instance1.resource, instance2.resource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DependencyTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_isinstance(self):
 | 
				
			||||||
 | 
					        dependency = 1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def get_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Dependency(instance_of=float)
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(get_async))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency1 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertEqual(dependency1, dependency)
 | 
				
			||||||
 | 
					        self.assertEqual(dependency2, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_isinstance_invalid(self):
 | 
				
			||||||
 | 
					        async def get_async():
 | 
				
			||||||
 | 
					            return {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Dependency(instance_of=float)
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(get_async))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(errors.Error):
 | 
				
			||||||
 | 
					            self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode(self):
 | 
				
			||||||
 | 
					        dependency = 123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def get_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def get_sync():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Dependency(instance_of=int)
 | 
				
			||||||
 | 
					        provider.override(providers.Factory(get_async))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency1 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency2 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertEqual(dependency1, dependency)
 | 
				
			||||||
 | 
					        self.assertEqual(dependency2, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider.override(providers.Factory(get_sync))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency3 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dependency4 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertEqual(dependency3, dependency)
 | 
				
			||||||
 | 
					        self.assertEqual(dependency4, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OverrideTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_provider(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_dependency_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_dependency_sync():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency_async))
 | 
				
			||||||
 | 
					        dependency1 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency_sync))
 | 
				
			||||||
 | 
					        dependency2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(dependency1, dependency)
 | 
				
			||||||
 | 
					        self.assertIs(dependency2, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_callable(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_dependency_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_dependency_sync():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Callable(_get_dependency_async)
 | 
				
			||||||
 | 
					        dependency1 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency_sync))
 | 
				
			||||||
 | 
					        dependency2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(dependency1, dependency)
 | 
				
			||||||
 | 
					        self.assertIs(dependency2, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_factory(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_dependency_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_dependency_sync():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Factory(_get_dependency_async)
 | 
				
			||||||
 | 
					        dependency1 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency_sync))
 | 
				
			||||||
 | 
					        dependency2 = self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(dependency1, dependency)
 | 
				
			||||||
 | 
					        self.assertIs(dependency2, dependency)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode_enabling(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_dependency_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Callable(_get_dependency_async)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode_disabling(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_dependency():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Callable(_get_dependency)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode_enabling_on_overriding(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _get_dependency_async():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Provider()
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency_async))
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_mode_disabling_on_overriding(self):
 | 
				
			||||||
 | 
					        dependency = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def _get_dependency():
 | 
				
			||||||
 | 
					            return dependency
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Provider()
 | 
				
			||||||
 | 
					        provider.override(providers.Callable(_get_dependency))
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestAsyncModeApi(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setUp(self):
 | 
				
			||||||
 | 
					        self.provider = providers.Provider()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_default_mode(self):
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					        self.assertTrue(self.provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_enable(self):
 | 
				
			||||||
 | 
					        self.provider.enable_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(self.provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_disable(self):
 | 
				
			||||||
 | 
					        self.provider.disable_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					        self.assertTrue(self.provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_reset(self):
 | 
				
			||||||
 | 
					        self.provider.enable_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertTrue(self.provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.provider.reset_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					        self.assertFalse(self.provider.is_async_mode_disabled())
 | 
				
			||||||
 | 
					        self.assertTrue(self.provider.is_async_mode_undefined())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncTypingStubTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_(self):
 | 
				
			||||||
 | 
					        container = Container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        client1 = self._run(container.client.async_())
 | 
				
			||||||
 | 
					        client2 = self._run(container.client.async_())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client1, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client1.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(client2, Client)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(client2.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service1 = self._run(container.service.async_())
 | 
				
			||||||
 | 
					        service2 = self._run(container.service.async_())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service1.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service1.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2, Service)
 | 
				
			||||||
 | 
					        self.assertIsInstance(service2.client, Client)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource1, RESOURCE1)
 | 
				
			||||||
 | 
					        self.assertIs(service2.client.resource2, RESOURCE2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIsNot(service1.client, service2.client)
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,6 @@
 | 
				
			||||||
"""Dependency injector coroutine providers unit tests."""
 | 
					"""Dependency injector coroutine providers unit tests."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import asyncio
 | 
					import asyncio
 | 
				
			||||||
import contextlib
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import gc
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import unittest2 as unittest
 | 
					import unittest2 as unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +9,19 @@ from dependency_injector import (
 | 
				
			||||||
    errors,
 | 
					    errors,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Runtime import to get asyncutils module
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async def _example(arg1, arg2, arg3, arg4):
 | 
					async def _example(arg1, arg2, arg3, arg4):
 | 
				
			||||||
    future = asyncio.Future()
 | 
					    future = asyncio.Future()
 | 
				
			||||||
| 
						 | 
					@ -25,52 +35,6 @@ def run(main):
 | 
				
			||||||
    return loop.run_until_complete(main)
 | 
					    return loop.run_until_complete(main)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def setup_test_loop(
 | 
					 | 
				
			||||||
        loop_factory=asyncio.new_event_loop
 | 
					 | 
				
			||||||
) -> asyncio.AbstractEventLoop:
 | 
					 | 
				
			||||||
    loop = loop_factory()
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        module = loop.__class__.__module__
 | 
					 | 
				
			||||||
        skip_watcher = 'uvloop' in module
 | 
					 | 
				
			||||||
    except AttributeError:  # pragma: no cover
 | 
					 | 
				
			||||||
        # Just in case
 | 
					 | 
				
			||||||
        skip_watcher = True
 | 
					 | 
				
			||||||
    asyncio.set_event_loop(loop)
 | 
					 | 
				
			||||||
    if sys.platform != "win32" and not skip_watcher:
 | 
					 | 
				
			||||||
        policy = asyncio.get_event_loop_policy()
 | 
					 | 
				
			||||||
        watcher = asyncio.SafeChildWatcher()  # type: ignore
 | 
					 | 
				
			||||||
        watcher.attach_loop(loop)
 | 
					 | 
				
			||||||
        with contextlib.suppress(NotImplementedError):
 | 
					 | 
				
			||||||
            policy.set_child_watcher(watcher)
 | 
					 | 
				
			||||||
    return loop
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def teardown_test_loop(loop: asyncio.AbstractEventLoop,
 | 
					 | 
				
			||||||
                       fast: bool=False) -> None:
 | 
					 | 
				
			||||||
    closed = loop.is_closed()
 | 
					 | 
				
			||||||
    if not closed:
 | 
					 | 
				
			||||||
        loop.call_soon(loop.stop)
 | 
					 | 
				
			||||||
        loop.run_forever()
 | 
					 | 
				
			||||||
        loop.close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not fast:
 | 
					 | 
				
			||||||
        gc.collect()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    asyncio.set_event_loop(None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AsyncTestCase(unittest.TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        self.loop = setup_test_loop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def tearDown(self):
 | 
					 | 
				
			||||||
        teardown_test_loop(self.loop)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _run(self, f):
 | 
					 | 
				
			||||||
        return self.loop.run_until_complete(f)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CoroutineTests(AsyncTestCase):
 | 
					class CoroutineTests(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_init_with_coroutine(self):
 | 
					    def test_init_with_coroutine(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -520,6 +520,24 @@ class FactoryAggregateTests(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(object_b.init_arg3, 33)
 | 
					        self.assertEqual(object_b.init_arg3, 33)
 | 
				
			||||||
        self.assertEqual(object_b.init_arg4, 44)
 | 
					        self.assertEqual(object_b.init_arg4, 44)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_call_factory_name_as_kwarg(self):
 | 
				
			||||||
 | 
					        object_a = self.factory_aggregate(
 | 
				
			||||||
 | 
					            factory_name='example_a',
 | 
				
			||||||
 | 
					            init_arg1=1,
 | 
				
			||||||
 | 
					            init_arg2=2,
 | 
				
			||||||
 | 
					            init_arg3=3,
 | 
				
			||||||
 | 
					            init_arg4=4,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        self.assertIsInstance(object_a, self.ExampleA)
 | 
				
			||||||
 | 
					        self.assertEqual(object_a.init_arg1, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(object_a.init_arg2, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(object_a.init_arg3, 3)
 | 
				
			||||||
 | 
					        self.assertEqual(object_a.init_arg4, 4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_call_no_factory_name(self):
 | 
				
			||||||
 | 
					        with self.assertRaises(TypeError):
 | 
				
			||||||
 | 
					            self.factory_aggregate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_call_no_such_provider(self):
 | 
					    def test_call_no_such_provider(self):
 | 
				
			||||||
        with self.assertRaises(errors.NoSuchProviderError):
 | 
					        with self.assertRaises(errors.NoSuchProviderError):
 | 
				
			||||||
            self.factory_aggregate('unknown')
 | 
					            self.factory_aggregate('unknown')
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,24 @@
 | 
				
			||||||
"""Dependency injector resource provider unit tests."""
 | 
					"""Dependency injector resource provider unit tests."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import unittest2 as unittest
 | 
					import unittest2 as unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dependency_injector import containers, providers, resources, errors
 | 
					from dependency_injector import containers, providers, resources, errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Runtime import to get asyncutils module
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def init_fn(*args, **kwargs):
 | 
					def init_fn(*args, **kwargs):
 | 
				
			||||||
    return args, kwargs
 | 
					    return args, kwargs
 | 
				
			||||||
| 
						 | 
					@ -156,6 +169,15 @@ class ResourceTests(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(_init.init_counter, 2)
 | 
					        self.assertEqual(_init.init_counter, 2)
 | 
				
			||||||
        self.assertEqual(_init.shutdown_counter, 2)
 | 
					        self.assertEqual(_init.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_shutdown_of_not_initialized(self):
 | 
				
			||||||
 | 
					        def _init():
 | 
				
			||||||
 | 
					            yield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = provider.shutdown()
 | 
				
			||||||
 | 
					        self.assertIsNone(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_initialized(self):
 | 
					    def test_initialized(self):
 | 
				
			||||||
        provider = providers.Resource(init_fn)
 | 
					        provider = providers.Resource(init_fn)
 | 
				
			||||||
        self.assertFalse(provider.initialized)
 | 
					        self.assertFalse(provider.initialized)
 | 
				
			||||||
| 
						 | 
					@ -320,3 +342,186 @@ class ResourceTests(unittest.TestCase):
 | 
				
			||||||
                provider.initialized,
 | 
					                provider.initialized,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AsyncResourceTest(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_init_async_function(self):
 | 
				
			||||||
 | 
					        resource = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.counter += 1
 | 
				
			||||||
 | 
					            return resource
 | 
				
			||||||
 | 
					        _init.counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result1 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result1, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result2 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result2, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_init_async_generator(self):
 | 
				
			||||||
 | 
					        resource = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.init_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yield resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.shutdown_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _init.init_counter = 0
 | 
				
			||||||
 | 
					        _init.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result1 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result1, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result2 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result2, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_init_async_class(self):
 | 
				
			||||||
 | 
					        resource = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        class TestResource(resources.AsyncResource):
 | 
				
			||||||
 | 
					            init_counter = 0
 | 
				
			||||||
 | 
					            shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            async def init(self):
 | 
				
			||||||
 | 
					                await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					                self.__class__.init_counter += 1
 | 
				
			||||||
 | 
					                return resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            async def shutdown(self, resource_):
 | 
				
			||||||
 | 
					                await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					                self.__class__.shutdown_counter += 1
 | 
				
			||||||
 | 
					                assert resource_ is resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(TestResource)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result1 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result1, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result2 = self._run(provider())
 | 
				
			||||||
 | 
					        self.assertIs(result2, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(TestResource.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_init_with_error(self):
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            raise RuntimeError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        future = provider()
 | 
				
			||||||
 | 
					        self.assertTrue(provider.initialized)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Disable default exception handling to prevent output
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(lambda loop, context: ...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.assertRaises(RuntimeError):
 | 
				
			||||||
 | 
					            self._run(future)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Restore default exception handling
 | 
				
			||||||
 | 
					        asyncio.get_event_loop().set_exception_handler(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertFalse(provider.initialized)
 | 
				
			||||||
 | 
					        self.assertTrue(provider.is_async_mode_enabled())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_init_and_shutdown_methods(self):
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.init_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            yield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.shutdown_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _init.init_counter = 0
 | 
				
			||||||
 | 
					        _init.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.init())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.init())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertEqual(_init.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_shutdown_of_not_initialized(self):
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            yield
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					        provider.enable_async_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = self._run(provider.shutdown())
 | 
				
			||||||
 | 
					        self.assertIsNone(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_concurrent_init(self):
 | 
				
			||||||
 | 
					        resource = object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        async def _init():
 | 
				
			||||||
 | 
					            await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					            _init.counter += 1
 | 
				
			||||||
 | 
					            return resource
 | 
				
			||||||
 | 
					        _init.counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        provider = providers.Resource(_init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result1, result2 = self._run(
 | 
				
			||||||
 | 
					            asyncio.gather(
 | 
				
			||||||
 | 
					                provider(),
 | 
				
			||||||
 | 
					                provider()
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(result1, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(result2, resource)
 | 
				
			||||||
 | 
					        self.assertEqual(_init.counter, 1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										50
									
								
								tests/unit/samples/wiringsamples/asyncinjections.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tests/unit/samples/wiringsamples/asyncinjections.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,50 @@
 | 
				
			||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from dependency_injector import containers, providers
 | 
				
			||||||
 | 
					from dependency_injector.wiring import inject, Provide, Closing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestResource:
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.init_counter = 0
 | 
				
			||||||
 | 
					        self.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_counters(self):
 | 
				
			||||||
 | 
					        self.init_counter = 0
 | 
				
			||||||
 | 
					        self.shutdown_counter = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					resource1 = TestResource()
 | 
				
			||||||
 | 
					resource2 = TestResource()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def async_resource(resource):
 | 
				
			||||||
 | 
					    await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					    resource.init_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    yield resource
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await asyncio.sleep(0.001)
 | 
				
			||||||
 | 
					    resource.shutdown_counter += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Container(containers.DeclarativeContainer):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resource1 = providers.Resource(async_resource, providers.Object(resource1))
 | 
				
			||||||
 | 
					    resource2 = providers.Resource(async_resource, providers.Object(resource2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
 | 
					async def async_injection(
 | 
				
			||||||
 | 
					        resource1: object = Provide[Container.resource1],
 | 
				
			||||||
 | 
					        resource2: object = Provide[Container.resource2],
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    return resource1, resource2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@inject
 | 
				
			||||||
 | 
					async def async_injection_with_closing(
 | 
				
			||||||
 | 
					        resource1: object = Closing[Provide[Container.resource1]],
 | 
				
			||||||
 | 
					        resource2: object = Closing[Provide[Container.resource2]],
 | 
				
			||||||
 | 
					):
 | 
				
			||||||
 | 
					    return resource1, resource2
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,12 @@ from dependency_injector.wiring import wire, Provide, Closing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Runtime import to avoid syntax errors in samples on Python < 3.5
 | 
					# Runtime import to avoid syntax errors in samples on Python < 3.5
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
_SAMPLES_DIR = os.path.abspath(
 | 
					_SAMPLES_DIR = os.path.abspath(
 | 
				
			||||||
    os.path.sep.join((
 | 
					    os.path.sep.join((
 | 
				
			||||||
        os.path.dirname(__file__),
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
| 
						 | 
					@ -12,8 +18,11 @@ _SAMPLES_DIR = os.path.abspath(
 | 
				
			||||||
    )),
 | 
					    )),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
sys.path.append(_SAMPLES_DIR)
 | 
					sys.path.append(_SAMPLES_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from wiringsamples import module, package
 | 
					from wiringsamples import module, package
 | 
				
			||||||
from wiringsamples.service import Service
 | 
					from wiringsamples.service import Service
 | 
				
			||||||
from wiringsamples.container import Container, SubContainer
 | 
					from wiringsamples.container import Container, SubContainer
 | 
				
			||||||
| 
						 | 
					@ -267,3 +276,56 @@ class WiringAndFastAPITest(unittest.TestCase):
 | 
				
			||||||
        self.assertEqual(result_2.shutdown_counter, 2)
 | 
					        self.assertEqual(result_2.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertIsNot(result_1, result_2)
 | 
					        self.assertIsNot(result_1, result_2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WiringAsyncInjectionsTest(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_injections(self):
 | 
				
			||||||
 | 
					        from wiringsamples import asyncinjections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = asyncinjections.Container()
 | 
				
			||||||
 | 
					        container.wire(modules=[asyncinjections])
 | 
				
			||||||
 | 
					        self.addCleanup(container.unwire)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asyncinjections.resource1.reset_counters()
 | 
				
			||||||
 | 
					        asyncinjections.resource2.reset_counters()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resource1, resource2 = self._run(asyncinjections.async_injection())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource1, asyncinjections.resource1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource2, asyncinjections.resource2)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.shutdown_counter, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_async_injections_with_closing(self):
 | 
				
			||||||
 | 
					        from wiringsamples import asyncinjections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        container = asyncinjections.Container()
 | 
				
			||||||
 | 
					        container.wire(modules=[asyncinjections])
 | 
				
			||||||
 | 
					        self.addCleanup(container.unwire)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asyncinjections.resource1.reset_counters()
 | 
				
			||||||
 | 
					        asyncinjections.resource2.reset_counters()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resource1, resource2 = self._run(asyncinjections.async_injection_with_closing())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource1, asyncinjections.resource1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource2, asyncinjections.resource2)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.init_counter, 1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.shutdown_counter, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        resource1, resource2 = self._run(asyncinjections.async_injection_with_closing())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource1, asyncinjections.resource1)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource1.shutdown_counter, 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assertIs(resource2, asyncinjections.resource2)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.init_counter, 2)
 | 
				
			||||||
 | 
					        self.assertEqual(asyncinjections.resource2.shutdown_counter, 2)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
import asyncio
 | 
					 | 
				
			||||||
import contextlib
 | 
					 | 
				
			||||||
import gc
 | 
					 | 
				
			||||||
import unittest
 | 
					 | 
				
			||||||
from unittest import mock
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from httpx import AsyncClient
 | 
					from httpx import AsyncClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Runtime import to avoid syntax errors in samples on Python < 3.5
 | 
					# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					_TOP_DIR = os.path.abspath(
 | 
				
			||||||
 | 
					    os.path.sep.join((
 | 
				
			||||||
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
 | 
					        '../',
 | 
				
			||||||
 | 
					    )),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
_SAMPLES_DIR = os.path.abspath(
 | 
					_SAMPLES_DIR = os.path.abspath(
 | 
				
			||||||
    os.path.sep.join((
 | 
					    os.path.sep.join((
 | 
				
			||||||
        os.path.dirname(__file__),
 | 
					        os.path.dirname(__file__),
 | 
				
			||||||
| 
						 | 
					@ -15,58 +15,14 @@ _SAMPLES_DIR = os.path.abspath(
 | 
				
			||||||
    )),
 | 
					    )),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					sys.path.append(_TOP_DIR)
 | 
				
			||||||
sys.path.append(_SAMPLES_DIR)
 | 
					sys.path.append(_SAMPLES_DIR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from asyncutils import AsyncTestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from wiringfastapi import web
 | 
					from wiringfastapi import web
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO: Refactor to use common async test case
 | 
					 | 
				
			||||||
def setup_test_loop(
 | 
					 | 
				
			||||||
        loop_factory=asyncio.new_event_loop
 | 
					 | 
				
			||||||
) -> asyncio.AbstractEventLoop:
 | 
					 | 
				
			||||||
    loop = loop_factory()
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        module = loop.__class__.__module__
 | 
					 | 
				
			||||||
        skip_watcher = 'uvloop' in module
 | 
					 | 
				
			||||||
    except AttributeError:  # pragma: no cover
 | 
					 | 
				
			||||||
        # Just in case
 | 
					 | 
				
			||||||
        skip_watcher = True
 | 
					 | 
				
			||||||
    asyncio.set_event_loop(loop)
 | 
					 | 
				
			||||||
    if sys.platform != "win32" and not skip_watcher:
 | 
					 | 
				
			||||||
        policy = asyncio.get_event_loop_policy()
 | 
					 | 
				
			||||||
        watcher = asyncio.SafeChildWatcher()  # type: ignore
 | 
					 | 
				
			||||||
        watcher.attach_loop(loop)
 | 
					 | 
				
			||||||
        with contextlib.suppress(NotImplementedError):
 | 
					 | 
				
			||||||
            policy.set_child_watcher(watcher)
 | 
					 | 
				
			||||||
    return loop
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def teardown_test_loop(loop: asyncio.AbstractEventLoop,
 | 
					 | 
				
			||||||
                       fast: bool=False) -> None:
 | 
					 | 
				
			||||||
    closed = loop.is_closed()
 | 
					 | 
				
			||||||
    if not closed:
 | 
					 | 
				
			||||||
        loop.call_soon(loop.stop)
 | 
					 | 
				
			||||||
        loop.run_forever()
 | 
					 | 
				
			||||||
        loop.close()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not fast:
 | 
					 | 
				
			||||||
        gc.collect()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    asyncio.set_event_loop(None)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AsyncTestCase(unittest.TestCase):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def setUp(self):
 | 
					 | 
				
			||||||
        self.loop = setup_test_loop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def tearDown(self):
 | 
					 | 
				
			||||||
        teardown_test_loop(self.loop)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _run(self, f):
 | 
					 | 
				
			||||||
        return self.loop.run_until_complete(f)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class WiringFastAPITest(AsyncTestCase):
 | 
					class WiringFastAPITest(AsyncTestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    client: AsyncClient
 | 
					    client: AsyncClient
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user