mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-07-14 18:12:21 +03:00
Compare commits
No commits in common. "master" and "4.45.0" have entirely different histories.
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
description: Code in Python and Cython
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- Follow PEP 8 rules
|
||||
- When you write imports, split system, 3rd-party, and local imports with a new line
|
||||
- Have two empty lines between the import block and the rest of the code
|
||||
- Have an empty line (\n) at the end of every file
|
||||
- If a file is supposed to be run, always add ``if __name__ == 'main'``
|
||||
- Always follow a consistent pattern of using double or single quotes
|
||||
- When there is a class without a docblock, leave one blank line before its members, e.g.:
|
||||
```python
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(Service)
|
||||
```
|
||||
|
||||
- Avoid shortcuts in names unless absolutely necessary, exceptions:
|
||||
```
|
||||
arg
|
||||
args
|
||||
kwarg
|
||||
kwargs
|
||||
obj
|
||||
cls
|
||||
```
|
||||
|
||||
- Avoid inline comments unless absolutely necessary
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
description: Build and run tests
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- Use Makefile commands to build, test, lint and other similar operations when they are available.
|
||||
- Activate virtualenv before running any commands by ``. venv/bin/actvate``
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
description: Run examples
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- When you run an example from the ``examples/`` folder, switch to the example folder and run it from there.
|
||||
- If there are instructions on running the examples or its tests in readme, follow them
|
||||
- Activate virtualenv before running any commands by ``. venv/bin/actvate``
|
|
@ -1,9 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{py,pyi,pxd,pyx}]
|
||||
ij_visual_guides = 80,88
|
74
.github/workflows/publishing.yml
vendored
74
.github/workflows/publishing.yml
vendored
|
@ -10,7 +10,7 @@ jobs:
|
|||
|
||||
tests:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
@ -23,7 +23,7 @@ jobs:
|
|||
|
||||
linters:
|
||||
name: Run linters
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
toxenv: [flake8, pydocstyle, mypy, pylint]
|
||||
|
@ -40,7 +40,7 @@ jobs:
|
|||
build-sdist:
|
||||
name: Build source tarball
|
||||
needs: [tests, linters]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
@ -49,9 +49,8 @@ jobs:
|
|||
- run: |
|
||||
python -m pip install --upgrade build
|
||||
python -m build --sdist
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cibw-sdist
|
||||
path: ./dist/*
|
||||
|
||||
build-wheels:
|
||||
|
@ -60,58 +59,57 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2022, macos-14]
|
||||
os: [ubuntu-22.04, windows-2019, macos-14]
|
||||
env:
|
||||
CIBW_ENABLE: pypy
|
||||
CIBW_ENVIRONMENT: >-
|
||||
PIP_CONFIG_SETTINGS="build_ext=-j4"
|
||||
DEPENDENCY_INJECTOR_LIMITED_API="1"
|
||||
CFLAGS="-g0"
|
||||
CIBW_SKIP: cp27-*
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v3.0.0
|
||||
- uses: actions/upload-artifact@v4
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
test-publish:
|
||||
name: Upload release to TestPyPI
|
||||
needs: [build-sdist, build-wheels]
|
||||
runs-on: ubuntu-latest
|
||||
environment: test-pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
build-wheels-linux-aarch64:
|
||||
name: Build wheels (ubuntu-22.04-aarch64)
|
||||
needs: [tests, linters]
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
CIBW_SKIP: cp27-*
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v2.20.0
|
||||
env:
|
||||
CIBW_ARCHS_LINUX: aarch64
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
pattern: cibw-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
publish:
|
||||
name: Upload release to PyPI
|
||||
needs: [build-sdist, build-wheels, test-publish]
|
||||
runs-on: ubuntu-latest
|
||||
environment: pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
name: Publish on PyPI
|
||||
needs: [build-sdist, build-wheels, build-wheels-linux-aarch64]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v3
|
||||
with:
|
||||
pattern: cibw-*
|
||||
name: artifact
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
user: __token__
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
# For publishing to Test PyPI, uncomment next two lines:
|
||||
# password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
# repository_url: https://test.pypi.org/legacy/
|
||||
|
||||
publish-docs:
|
||||
name: Publish docs
|
||||
needs: [publish]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
|
27
.github/workflows/tests-and-linters.yml
vendored
27
.github/workflows/tests-and-linters.yml
vendored
|
@ -4,12 +4,28 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
|
||||
test-on-different-versions:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
tests-on-legacy-versions:
|
||||
name: Run tests on legacy versions
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
python-version: [3.7]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
TOXENV: ${{ matrix.python-version }}
|
||||
|
||||
test-on-different-versions:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
@ -18,7 +34,6 @@ jobs:
|
|||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
DEPENDENCY_INJECTOR_LIMITED_API: 1
|
||||
TOXENV: ${{ matrix.python-version }}
|
||||
|
||||
test-different-pydantic-versions:
|
||||
|
@ -45,7 +60,7 @@ jobs:
|
|||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.12
|
||||
- run: pip install tox
|
||||
- run: pip install tox 'cython>=3,<4'
|
||||
- run: tox -vv
|
||||
env:
|
||||
TOXENV: coveralls
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,7 +15,6 @@ lib64/
|
|||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheelhouse/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
recursive-include src/dependency_injector *.py* *.c py.typed
|
||||
recursive-include src/dependency_injector *.py* *.c
|
||||
recursive-include tests *.py
|
||||
include README.rst
|
||||
include CONTRIBUTORS.rst
|
||||
include LICENSE.rst
|
||||
include requirements.txt
|
||||
include setup.py
|
||||
include tox.ini
|
||||
include py.typed
|
||||
|
|
2
Makefile
2
Makefile
|
@ -36,7 +36,7 @@ uninstall:
|
|||
test:
|
||||
# Unit tests with coverage report
|
||||
coverage erase
|
||||
coverage run -m pytest
|
||||
coverage run -m pytest -c tests/.configs/pytest.ini
|
||||
coverage report
|
||||
coverage html
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
dependency_injector.ext.starlette
|
||||
=================================
|
||||
|
||||
.. automodule:: dependency_injector.ext.starlette
|
||||
:members:
|
||||
:inherited-members:
|
||||
:show-inheritance:
|
||||
|
||||
.. disqus::
|
|
@ -2,11 +2,10 @@ API Documentation
|
|||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 2
|
||||
|
||||
top-level
|
||||
providers
|
||||
containers
|
||||
wiring
|
||||
errors
|
||||
asgi-lifespan
|
||||
|
|
|
@ -72,7 +72,7 @@ release = version
|
|||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = "en"
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
|
|
|
@ -78,7 +78,7 @@ Container is wired to the ``views`` module in the app config ``web/apps.py``:
|
|||
|
||||
.. literalinclude:: ../../examples/miniapps/django/web/apps.py
|
||||
:language: python
|
||||
:emphasize-lines: 12
|
||||
:emphasize-lines: 13
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
.. _fastdepends-example:
|
||||
|
||||
FastDepends example
|
||||
===================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,Dependency Injection,FastDepends,Example
|
||||
:description: This example demonstrates a usage of the FastDepends and Dependency Injector.
|
||||
|
||||
|
||||
This example demonstrates how to use ``Dependency Injector`` with `FastDepends <https://github.com/Lancetnik/FastDepends>`_, a lightweight dependency injection framework inspired by FastAPI's dependency system, but without the web framework components.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
The integration between FastDepends and Dependency Injector is straightforward. Simply use Dependency Injector's ``Provide`` marker within FastDepends' ``Depends`` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sys
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from fast_depends import Depends
|
||||
|
||||
|
||||
class CoefficientService:
|
||||
@staticmethod
|
||||
def get_coefficient() -> float:
|
||||
return 1.2
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
service = providers.Factory(CoefficientService)
|
||||
|
||||
|
||||
@inject
|
||||
def apply_coefficient(
|
||||
a: int,
|
||||
coefficient_provider: CoefficientService = Depends(Provide[Container.service]),
|
||||
) -> float:
|
||||
return a * coefficient_provider.get_coefficient()
|
||||
|
||||
|
||||
container = Container()
|
||||
container.wire(modules=[sys.modules[__name__]])
|
||||
|
||||
apply_coefficient(100) == 120.0
|
|
@ -22,6 +22,5 @@ Explore the examples to see the ``Dependency Injector`` in action.
|
|||
fastapi
|
||||
fastapi-redis
|
||||
fastapi-sqlalchemy
|
||||
fastdepends
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -31,7 +31,7 @@ Key features of the ``Dependency Injector``:
|
|||
|
||||
The framework stands on the `PEP20 (The Zen of Python) <https://www.python.org/dev/peps/pep-0020/>`_ principle:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Explicit is better than implicit
|
||||
|
||||
|
|
|
@ -7,61 +7,6 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
4.48.1
|
||||
------
|
||||
|
||||
* Improve performance of ``dependency_injector._cwiring.DependencyResolver``
|
||||
* Add ``typing-extensions`` as a dependency for older Python versions (<3.11)
|
||||
* Produce warning on ``@inject``s without ``Provide[...]`` marks
|
||||
* Add support for `resource_type` in ``Lifespan``s
|
||||
|
||||
4.48.0
|
||||
------
|
||||
|
||||
- Improve performance of wiring (`#897 <https://github.com/ets-labs/python-dependency-injector/pull/897>`_)
|
||||
- Add Context Manager support to Resource provider (`#899 <https://github.com/ets-labs/python-dependency-injector/pull/899>`_)
|
||||
- Add support for async generator injections (`#900 <https://github.com/ets-labs/python-dependency-injector/pull/900>`_)
|
||||
- Fix unintended dependency on ``typing_extensions`` (`#902 <https://github.com/ets-labs/python-dependency-injector/pull/902>`_)
|
||||
- Add support for Fast Depends (`#898 <https://github.com/ets-labs/python-dependency-injector/pull/898>`_)
|
||||
- Add ``resource_type`` parameter to init and shutdown resources using specialized providers (`#858 <https://github.com/ets-labs/python-dependency-injector/pull/858>`_)
|
||||
|
||||
4.47.1
|
||||
------
|
||||
|
||||
- Fix typing for wiring marker (`#892 <https://github.com/ets-labs/python-dependency-injector/pull/896>`_)
|
||||
- Strip debug symbols in wheels
|
||||
|
||||
4.47.0
|
||||
------
|
||||
|
||||
- Add support for ``Annotated`` type for module and class attribute injection in wiring,
|
||||
with updated documentation and examples.
|
||||
See discussion:
|
||||
https://github.com/ets-labs/python-dependency-injector/pull/721#issuecomment-2025263718
|
||||
- Fix ``root`` property shadowing in ``ConfigurationOption`` (`#875 <https://github.com/ets-labs/python-dependency-injector/pull/875>`_)
|
||||
- Fix incorrect monkeypatching during ``wire()`` that could violate MRO in some classes (`#886 <https://github.com/ets-labs/python-dependency-injector/pull/886>`_)
|
||||
- ABI3 wheels are now published for CPython.
|
||||
- Drop support of Python 3.7.
|
||||
|
||||
4.46.0
|
||||
------
|
||||
|
||||
- Add option to disable env var interpolation in configs (`#861 <https://github.com/ets-labs/python-dependency-injector/pull/861>`_)
|
||||
- Fix ``Closing`` dependency resolution (`#852 <https://github.com/ets-labs/python-dependency-injector/pull/852>`_)
|
||||
- Add support for ``inspect.iscoroutinefunction()`` in ``Coroutine`` provider (`#830 <https://github.com/ets-labs/python-dependency-injector/pull/830>`_)
|
||||
- Fix broken wiring of sync inject-decorated methods (`#673 <https://github.com/ets-labs/python-dependency-injector/pull/673>`_)
|
||||
- Add support for ``typing.Annotated`` (`#721 <https://github.com/ets-labs/python-dependency-injector/pull/721>`_, `#853 <https://github.com/ets-labs/python-dependency-injector/pull/853>`_)
|
||||
- Documentation updates for movie-lister example (`#747 <https://github.com/ets-labs/python-dependency-injector/pull/747>`_)
|
||||
- Fix type propagation in ``Provider.provider`` (`#744 <https://github.com/ets-labs/python-dependency-injector/pull/744>`_)
|
||||
|
||||
Many thanks for the contributions to:
|
||||
- `ZipFile <https://github.com/ZipFile>`_
|
||||
- `Yegor Statkevich <https://github.com/jazzthief>`_
|
||||
- `Federico Tomasi <https://github.com/federinik>`_
|
||||
- `Martin Lafrance <https://github.com/martlaf>`_
|
||||
- `Philip Bjorge <https://github.com/philipbjorge>`_
|
||||
- `Ilya Kazakov <https://github.com/mrKazzila>`_
|
||||
|
||||
4.45.0
|
||||
--------
|
||||
- Add Starlette lifespan handler implementation (`#683 <https://github.com/ets-labs/python-dependency-injector/pull/683>`_).
|
||||
|
@ -395,8 +340,8 @@ Many thanks to `ZipFile <https://github.com/ZipFile>`_ for both contributions.
|
|||
- Make refactoring of wiring module and tests.
|
||||
See PR # `#406 <https://github.com/ets-labs/python-dependency-injector/issues/406>`_.
|
||||
Thanks to `@withshubh <https://github.com/withshubh>`_ for the contribution:
|
||||
- Remove unused imports in tests.
|
||||
- Use literal syntax to create data structure in tests.
|
||||
- Remove unused imports in tests.
|
||||
- Use literal syntax to create data structure in tests.
|
||||
- Add integration with a static analysis tool `DeepSource <https://deepsource.io/>`_.
|
||||
|
||||
4.26.0
|
||||
|
|
|
@ -366,19 +366,6 @@ See also: :ref:`configuration-strict-mode`.
|
|||
|
||||
assert container.config.section.option() is None
|
||||
|
||||
If you want to disable environment variables interpolation, pass ``envs_required=None``:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: templates.yml
|
||||
|
||||
template_string: 'Hello, ${name}!'
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> container.config.from_yaml("templates.yml", envs_required=None)
|
||||
>>> container.config.template_string()
|
||||
'Hello, ${name}!'
|
||||
|
||||
Mandatory and optional sources
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -61,12 +61,11 @@ When you call ``.shutdown()`` method on a resource provider, it will remove the
|
|||
if any, and switch to uninitialized state. Some of resource initializer types support specifying custom
|
||||
resource shutdown.
|
||||
|
||||
Resource provider supports 4 types of initializers:
|
||||
Resource provider supports 3 types of initializers:
|
||||
|
||||
- Function
|
||||
- Context Manager
|
||||
- Generator (legacy)
|
||||
- Subclass of ``resources.Resource`` (legacy)
|
||||
- Generator
|
||||
- Subclass of ``resources.Resource``
|
||||
|
||||
Function initializer
|
||||
--------------------
|
||||
|
@ -104,44 +103,8 @@ you configure global resource:
|
|||
|
||||
Function initializer does not provide a way to specify custom resource shutdown.
|
||||
|
||||
Context Manager initializer
|
||||
---------------------------
|
||||
|
||||
This is an extension to the Function initializer. Resource provider automatically detects if the initializer returns a
|
||||
context manager and uses it to manage the resource lifecycle.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
class DatabaseConnection:
|
||||
def __init__(self, host, port, user, password):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.user = user
|
||||
self.password = password
|
||||
|
||||
def __enter__(self):
|
||||
print(f"Connecting to {self.host}:{self.port} as {self.user}")
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
print("Closing connection")
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
db = providers.Resource(
|
||||
DatabaseConnection,
|
||||
host=config.db.host,
|
||||
port=config.db.port,
|
||||
user=config.db.user,
|
||||
password=config.db.password,
|
||||
)
|
||||
|
||||
Generator initializer (legacy)
|
||||
------------------------------
|
||||
Generator initializer
|
||||
---------------------
|
||||
|
||||
Resource provider can use 2-step generators:
|
||||
|
||||
|
@ -191,13 +154,8 @@ object is not mandatory. You can leave ``yield`` statement empty:
|
|||
argument2=...,
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
Generator initializers are automatically wrapped with ``contextmanager`` or ``asynccontextmanager`` decorator when
|
||||
provided to a ``Resource`` provider.
|
||||
|
||||
Subclass initializer (legacy)
|
||||
-----------------------------
|
||||
Subclass initializer
|
||||
--------------------
|
||||
|
||||
You can create resource initializer by implementing a subclass of the ``resources.Resource``:
|
||||
|
||||
|
@ -252,72 +210,6 @@ first argument.
|
|||
|
||||
.. _resource-provider-wiring-closing:
|
||||
|
||||
Scoping Resources using specialized subclasses
|
||||
----------------------------------------------
|
||||
|
||||
You can use specialized subclasses of ``Resource`` provider to initialize and shutdown resources by type.
|
||||
Allowing for example to only initialize a subgroup of resources.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ScopedResource(resources.Resource):
|
||||
pass
|
||||
|
||||
def init_service(name) -> Service:
|
||||
print(f"Init {name}")
|
||||
yield Service()
|
||||
print(f"Shutdown {name}")
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
scoped = ScopedResource(
|
||||
init_service,
|
||||
"scoped",
|
||||
)
|
||||
|
||||
generic = providers.Resource(
|
||||
init_service,
|
||||
"generic",
|
||||
)
|
||||
|
||||
|
||||
To initialize resources by type you can use ``init_resources(resource_type)`` and ``shutdown_resources(resource_type)``
|
||||
methods adding the resource type as an argument:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def main():
|
||||
container = Container()
|
||||
container.init_resources(ScopedResource)
|
||||
# Generates:
|
||||
# >>> Init scoped
|
||||
|
||||
container.shutdown_resources(ScopedResource)
|
||||
# Generates:
|
||||
# >>> Shutdown scoped
|
||||
|
||||
|
||||
And to initialize all resources you can use ``init_resources()`` and ``shutdown_resources()`` without arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def main():
|
||||
container = Container()
|
||||
container.init_resources()
|
||||
# Generates:
|
||||
# >>> Init scoped
|
||||
# >>> Init generic
|
||||
|
||||
container.shutdown_resources()
|
||||
# Generates:
|
||||
# >>> Shutdown scoped
|
||||
# >>> Shutdown generic
|
||||
|
||||
|
||||
It works using the ``traverse()`` method to find all resources of the specified type, selecting all resources
|
||||
which are instances of the specified type.
|
||||
|
||||
|
||||
Resources, wiring, and per-function execution scope
|
||||
---------------------------------------------------
|
||||
|
||||
|
@ -371,11 +263,10 @@ Asynchronous function initializer:
|
|||
argument2=...,
|
||||
)
|
||||
|
||||
Asynchronous Context Manager initializer:
|
||||
Asynchronous generator initializer:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@asynccontextmanager
|
||||
async def init_async_resource(argument1=..., argument2=...):
|
||||
connection = await connect()
|
||||
yield connection
|
||||
|
@ -467,54 +358,5 @@ See also:
|
|||
- Wiring :ref:`async-injections-wiring`
|
||||
- :ref:`fastapi-redis-example`
|
||||
|
||||
ASGI Lifespan Protocol Support
|
||||
------------------------------
|
||||
|
||||
The :mod:`dependency_injector.ext.starlette` module provides a :class:`~dependency_injector.ext.starlette.Lifespan`
|
||||
class that integrates resource providers with ASGI applications using the `Lifespan Protocol`_. This allows resources to
|
||||
be automatically initialized at application startup and properly shut down when the application stops.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.ext.starlette import Lifespan
|
||||
from fastapi import FastAPI, Request, Depends, APIRouter
|
||||
|
||||
class Connection: ...
|
||||
|
||||
@asynccontextmanager
|
||||
async def init_database():
|
||||
print("opening database connection")
|
||||
yield Connection()
|
||||
print("closing database connection")
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/")
|
||||
@inject
|
||||
async def index(request: Request, db: Connection = Depends(Provide["db"])):
|
||||
# use the database connection here
|
||||
return "OK!"
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
__self__ = providers.Self()
|
||||
db = providers.Resource(init_database)
|
||||
lifespan = providers.Singleton(Lifespan, __self__)
|
||||
app = providers.Singleton(FastAPI, lifespan=lifespan)
|
||||
_include_router = providers.Resource(
|
||||
app.provided.include_router.call(),
|
||||
router,
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
container = Container()
|
||||
app = container.app()
|
||||
uvicorn.run(app, host="localhost", port=8000)
|
||||
|
||||
.. _Lifespan Protocol: https://asgi.readthedocs.io/en/latest/specs/lifespan.html
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -257,7 +257,7 @@ Let's check that it works. Open another terminal session and use ``httpie``:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: http
|
||||
.. code-block:: json
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 844
|
||||
|
@ -596,7 +596,7 @@ and make a request to the API in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: http
|
||||
.. code-block:: json
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 492
|
||||
|
|
|
@ -84,7 +84,7 @@ Create next structure in the project root directory. All files are empty. That's
|
|||
|
||||
Initial project layout:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
./
|
||||
├── movies/
|
||||
|
@ -109,7 +109,7 @@ Now it's time to install the project requirements. We will use next packages:
|
|||
|
||||
Put next lines into the ``requirements.txt`` file:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
dependency-injector
|
||||
pyyaml
|
||||
|
@ -134,7 +134,7 @@ We will create a script that creates database files.
|
|||
First add the folder ``data/`` in the root of the project and then add the file
|
||||
``fixtures.py`` inside of it:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 2-3
|
||||
|
||||
./
|
||||
|
@ -205,13 +205,13 @@ Now run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
OK
|
||||
|
||||
Check that files ``movies.csv`` and ``movies.db`` have appeared in the ``data/`` folder:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 4-5
|
||||
|
||||
./
|
||||
|
@ -289,7 +289,7 @@ After each step we will add the provider to the container.
|
|||
|
||||
Create the ``entities.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 10
|
||||
|
||||
./
|
||||
|
@ -356,7 +356,7 @@ Let's move on to the finders.
|
|||
|
||||
Create the ``finders.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 11
|
||||
|
||||
./
|
||||
|
@ -465,7 +465,7 @@ The configuration file is ready. Move on to the lister.
|
|||
|
||||
Create the ``listers.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 12
|
||||
|
||||
./
|
||||
|
@ -613,7 +613,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -752,7 +752,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -868,7 +868,7 @@ Run in the terminal line by line:
|
|||
|
||||
The output should be similar for each command:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -888,7 +888,7 @@ We will use `pytest <https://docs.pytest.org/en/stable/>`_ and
|
|||
|
||||
Create ``tests.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 13
|
||||
|
||||
./
|
||||
|
@ -911,7 +911,7 @@ Create ``tests.py`` in the ``movies`` package:
|
|||
and put next into it:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 41,50
|
||||
:emphasize-lines: 36,51
|
||||
|
||||
"""Tests module."""
|
||||
|
||||
|
@ -941,18 +941,13 @@ and put next into it:
|
|||
return container
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def finder_mock(container):
|
||||
def test_movies_directed_by(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
return finder_mock
|
||||
|
||||
|
||||
def test_movies_directed_by(container, finder_mock):
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_directed_by("Jon Favreau")
|
||||
|
@ -961,7 +956,13 @@ and put next into it:
|
|||
assert movies[0].title == "The Jungle Book"
|
||||
|
||||
|
||||
def test_movies_released_in(container, finder_mock):
|
||||
def test_movies_released_in(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_released_in(2015)
|
||||
|
@ -977,7 +978,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block::
|
||||
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: cov-3.0.0
|
||||
|
@ -994,9 +995,9 @@ You should see:
|
|||
movies/entities.py 7 1 86%
|
||||
movies/finders.py 26 13 50%
|
||||
movies/listers.py 8 0 100%
|
||||
movies/tests.py 24 0 100%
|
||||
movies/tests.py 23 0 100%
|
||||
------------------------------------------
|
||||
TOTAL 90 30 67%
|
||||
TOTAL 89 30 66%
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ Now let's fill in the layout.
|
|||
|
||||
Put next into the ``base.html``:
|
||||
|
||||
.. code-block:: jinja
|
||||
.. code-block:: html
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
@ -313,7 +313,7 @@ And put something to the index page.
|
|||
|
||||
Put next into the ``index.html``:
|
||||
|
||||
.. code-block:: jinja
|
||||
.. code-block:: html
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ FastAPI example:
|
|||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(service: Annotated[Service, Depends(Provide[Container.service])]):
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
value = await service.process()
|
||||
return {"result": value}
|
||||
|
||||
|
@ -127,7 +127,6 @@ To inject the provider itself use ``Provide[foo.provider]``:
|
|||
def foo(bar_provider: Factory[Bar] = Provide[Container.bar.provider]):
|
||||
bar = bar_provider(argument="baz")
|
||||
...
|
||||
|
||||
You can also use ``Provider[foo]`` for injecting the provider itself:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -255,43 +254,13 @@ To inject a container use special identifier ``<container>``:
|
|||
Making injections into modules and class attributes
|
||||
---------------------------------------------------
|
||||
|
||||
You can use wiring to make injections into modules and class attributes. Both the classic marker
|
||||
syntax and the ``Annotated`` form are supported.
|
||||
|
||||
Classic marker syntax:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
service: Service = Provide[Container.service]
|
||||
|
||||
class Main:
|
||||
service: Service = Provide[Container.service]
|
||||
|
||||
Full example of the classic marker syntax:
|
||||
You can use wiring to make injections into modules and class attributes.
|
||||
|
||||
.. literalinclude:: ../examples/wiring/example_attribute.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 14,19
|
||||
|
||||
Annotated form (Python 3.9+):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
class Main:
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
Full example of the annotated form:
|
||||
|
||||
.. literalinclude:: ../examples/wiring/example_attribute_annotated.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 16,21
|
||||
|
||||
You could also use string identifiers to avoid a dependency on a container:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -632,36 +601,6 @@ or with a single container ``register_loader_containers(container)`` multiple ti
|
|||
To unregister a container use ``unregister_loader_containers(container)``.
|
||||
Wiring module will uninstall the import hook when unregister last container.
|
||||
|
||||
Few notes on performance
|
||||
------------------------
|
||||
|
||||
``.wire()`` utilize caching to speed up the wiring process. At the end it clears the cache to avoid memory leaks.
|
||||
But this may not always be desirable, when you want to keep the cache for the next wiring
|
||||
(e.g. due to usage of multiple containers or during unit tests).
|
||||
|
||||
To keep the cache after wiring, you can set flag ``keep_cache=True`` (works with ``WiringConfiguration`` too):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
container1.wire(
|
||||
modules=["yourapp.module1", "yourapp.module2"],
|
||||
keep_cache=True,
|
||||
)
|
||||
container2.wire(
|
||||
modules=["yourapp.module2", "yourapp.module3"],
|
||||
keep_cache=True,
|
||||
)
|
||||
...
|
||||
|
||||
and then clear it manually when you need it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from dependency_injector.wiring import clear_cache
|
||||
|
||||
clear_cache()
|
||||
|
||||
|
||||
Integration with other frameworks
|
||||
---------------------------------
|
||||
|
||||
|
@ -693,6 +632,5 @@ Take a look at other application examples:
|
|||
- :ref:`fastapi-example`
|
||||
- :ref:`fastapi-redis-example`
|
||||
- :ref:`fastapi-sqlalchemy-example`
|
||||
- :ref:`fastdepends-example`
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
"""Application module."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from fastapi import FastAPI, Depends
|
||||
|
||||
from .containers import Container
|
||||
from .services import Service
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(
|
||||
service: Annotated[Service, Depends(Provide[Container.service])]
|
||||
) -> dict[str, str]:
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
value = await service.process()
|
||||
return {"result": value}
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
from fastapi import FastAPI, Depends
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
|
@ -21,9 +18,7 @@ app = FastAPI()
|
|||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(
|
||||
service: Annotated[Service, Depends(Provide[Container.service])]
|
||||
) -> dict[str, str]:
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
result = await service.process()
|
||||
return {"result": result}
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
"""Endpoints module."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, Response, status
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
||||
from .containers import Container
|
||||
from .repositories import NotFoundError
|
||||
from .services import UserService
|
||||
from .repositories import NotFoundError
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
@ -16,7 +13,7 @@ router = APIRouter()
|
|||
@router.get("/users")
|
||||
@inject
|
||||
def get_list(
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
return user_service.get_users()
|
||||
|
||||
|
@ -24,8 +21,8 @@ def get_list(
|
|||
@router.get("/users/{user_id}")
|
||||
@inject
|
||||
def get_by_id(
|
||||
user_id: int,
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_id: int,
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
try:
|
||||
return user_service.get_user_by_id(user_id)
|
||||
|
@ -36,7 +33,7 @@ def get_by_id(
|
|||
@router.post("/users", status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
def add(
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
return user_service.create_user()
|
||||
|
||||
|
@ -44,9 +41,9 @@ def add(
|
|||
@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
def remove(
|
||||
user_id: int,
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
) -> Response:
|
||||
user_id: int,
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
try:
|
||||
user_service.delete_user_by_id(user_id)
|
||||
except NotFoundError:
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
"""Endpoints module."""
|
||||
|
||||
from typing import Annotated, List
|
||||
from typing import Optional, List
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
from .containers import Container
|
||||
from .services import SearchService
|
||||
from .containers import Container
|
||||
|
||||
|
||||
class Gif(BaseModel):
|
||||
|
@ -27,15 +26,11 @@ router = APIRouter()
|
|||
@router.get("/", response_model=Response)
|
||||
@inject
|
||||
async def index(
|
||||
default_query: Annotated[str, Depends(Provide[Container.config.default.query])],
|
||||
default_limit: Annotated[
|
||||
int, Depends(Provide[Container.config.default.limit.as_int()])
|
||||
],
|
||||
search_service: Annotated[
|
||||
SearchService, Depends(Provide[Container.search_service])
|
||||
],
|
||||
query: str | None = None,
|
||||
limit: int | None = None,
|
||||
query: Optional[str] = None,
|
||||
limit: Optional[str] = None,
|
||||
default_query: str = Depends(Provide[Container.config.default.query]),
|
||||
default_limit: int = Depends(Provide[Container.config.default.limit.as_int()]),
|
||||
search_service: SearchService = Depends(Provide[Container.search_service]),
|
||||
):
|
||||
query = query or default_query
|
||||
limit = limit or default_limit
|
||||
|
|
|
@ -18,9 +18,10 @@ SQLITE_FILE = DIR / "movies.db"
|
|||
|
||||
|
||||
def create_csv(movies_data, path):
|
||||
with open(path, "w", newline="") as opened_file:
|
||||
with open(path, "w") as opened_file:
|
||||
writer = csv.writer(opened_file)
|
||||
writer.writerows(movies_data)
|
||||
for row in movies_data:
|
||||
writer.writerow(row)
|
||||
|
||||
|
||||
def create_sqlite(movies_data, path):
|
||||
|
|
|
@ -29,7 +29,7 @@ class CsvMovieFinder(MovieFinder):
|
|||
super().__init__(movie_factory)
|
||||
|
||||
def find_all(self) -> List[Movie]:
|
||||
with open(self._csv_file_path, newline="") as csv_file:
|
||||
with open(self._csv_file_path) as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=self._delimiter)
|
||||
return [self._movie_factory(*row) for row in csv_reader]
|
||||
|
||||
|
|
|
@ -26,18 +26,13 @@ def container():
|
|||
return container
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def finder_mock(container):
|
||||
def test_movies_directed_by(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
return finder_mock
|
||||
|
||||
|
||||
def test_movies_directed_by(container, finder_mock):
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_directed_by("Jon Favreau")
|
||||
|
@ -46,7 +41,13 @@ def test_movies_directed_by(container, finder_mock):
|
|||
assert movies[0].title == "The Jungle Book"
|
||||
|
||||
|
||||
def test_movies_released_in(container, finder_mock):
|
||||
def test_movies_released_in(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_released_in(2015)
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
import sys
|
||||
import logging
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from contextlib import contextmanager
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
@contextmanager
|
||||
def init_thread_pool(max_workers: int):
|
||||
thread_pool = ThreadPoolExecutor(max_workers=max_workers)
|
||||
yield thread_pool
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from typing import Annotated
|
||||
|
||||
|
||||
class Service: ...
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
@ -13,16 +13,9 @@ class Container(containers.DeclarativeContainer):
|
|||
service = providers.Factory(Service)
|
||||
|
||||
|
||||
# You can place marker on parameter default value
|
||||
@inject
|
||||
def main(service: Service = Provide[Container.service]) -> None: ...
|
||||
|
||||
|
||||
# Also, you can place marker with typing.Annotated
|
||||
@inject
|
||||
def main_with_annotated(
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
) -> None: ...
|
||||
def main(service: Service = Provide[Container.service]) -> None:
|
||||
...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
"""Wiring attribute example with Annotated."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide
|
||||
|
||||
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(Service)
|
||||
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
|
||||
class Main:
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
container = Container()
|
||||
container.wire(modules=[__name__])
|
||||
|
||||
assert isinstance(service, Service)
|
||||
assert isinstance(Main.service, Service)
|
|
@ -1,5 +1,5 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "Cython>=3.1.1"]
|
||||
requires = ["setuptools", "Cython"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
|
@ -13,7 +13,7 @@ maintainers = [
|
|||
description = "Dependency injection framework for Python"
|
||||
readme = {file = "README.rst", content-type = "text/x-rst"}
|
||||
license = {file = "LICENSE.rst", content-type = "text/x-rst"}
|
||||
requires-python = ">=3.8"
|
||||
requires-python = ">=3.7"
|
||||
keywords = [
|
||||
"Dependency injection",
|
||||
"DI",
|
||||
|
@ -31,6 +31,7 @@ classifiers = [
|
|||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
|
@ -52,11 +53,6 @@ classifiers = [
|
|||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
]
|
||||
dynamic = ["version"]
|
||||
dependencies = [
|
||||
# typing.Annotated since v3.9
|
||||
# typing.Self since v3.11
|
||||
"typing-extensions; python_version<'3.11'",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
yaml = ["pyyaml"]
|
||||
|
@ -96,7 +92,6 @@ show_missing = true
|
|||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
combine_as_imports = true
|
||||
|
||||
[tool.pylint.main]
|
||||
ignore = ["tests"]
|
||||
|
@ -104,19 +99,3 @@ ignore = ["tests"]
|
|||
[tool.pylint.design]
|
||||
min-public-methods = 0
|
||||
max-public-methods = 30
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests/unit/"]
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
markers = [
|
||||
"pydantic: Tests with Pydantic as a dependency",
|
||||
]
|
||||
filterwarnings = [
|
||||
"ignore::dependency_injector.wiring.DIWiringWarning",
|
||||
"ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
|
||||
"ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
|
||||
"ignore:Please use \\`.*?\\` from the \\`scipy.*?\\`(.*?)namespace is deprecated\\.:DeprecationWarning",
|
||||
"ignore:Please import \\`.*?\\` from the \\`scipy(.*?)\\` namespace(.*):DeprecationWarning",
|
||||
"ignore:\\`scipy(.*?)\\` is deprecated(.*):DeprecationWarning",
|
||||
]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
cython==3.1.1
|
||||
cython==3.0.11
|
||||
setuptools
|
||||
pytest
|
||||
pytest-asyncio
|
||||
|
@ -13,13 +13,10 @@ mypy
|
|||
pyyaml
|
||||
httpx
|
||||
fastapi
|
||||
pydantic
|
||||
pydantic-settings
|
||||
pydantic==1.10.17
|
||||
numpy
|
||||
scipy
|
||||
boto3
|
||||
mypy_boto3_s3
|
||||
typing_extensions
|
||||
fast-depends
|
||||
|
||||
-r requirements-ext.txt
|
||||
|
|
|
@ -2,13 +2,12 @@
|
|||
max_line_length = 120
|
||||
max_complexity = 10
|
||||
exclude = types.py
|
||||
extend-ignore = E203,E701
|
||||
per-file-ignores =
|
||||
examples/demo/*: F841
|
||||
examples/containers/traverse.py: E501
|
||||
examples/providers/async.py: F841
|
||||
examples/providers/async_overriding.py: F841
|
||||
examples/wiring/*: F821,F841
|
||||
examples/wiring/*: F841
|
||||
|
||||
[pydocstyle]
|
||||
ignore = D100,D101,D102,D105,D106,D107,D203,D213
|
||||
|
|
13
setup.py
13
setup.py
|
@ -1,19 +1,13 @@
|
|||
"""`Dependency injector` setup script."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Compiler import Options
|
||||
from setuptools import Extension, setup
|
||||
|
||||
debug = os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1"
|
||||
limited_api = (
|
||||
os.environ.get("DEPENDENCY_INJECTOR_LIMITED_API") == "1"
|
||||
and sys.implementation.name == "cpython"
|
||||
)
|
||||
defined_macros = []
|
||||
options = {}
|
||||
compiler_directives = {
|
||||
"language_level": 3,
|
||||
"profile": debug,
|
||||
|
@ -23,7 +17,6 @@ Options.annotate = debug
|
|||
|
||||
# Adding debug options:
|
||||
if debug:
|
||||
limited_api = False # line tracing is not part of the Limited API
|
||||
defined_macros.extend(
|
||||
[
|
||||
("CYTHON_TRACE", "1"),
|
||||
|
@ -32,20 +25,14 @@ if debug:
|
|||
]
|
||||
)
|
||||
|
||||
if limited_api:
|
||||
options.setdefault("bdist_wheel", {})
|
||||
options["bdist_wheel"]["py_limited_api"] = "cp38"
|
||||
defined_macros.append(("Py_LIMITED_API", "0x03080000"))
|
||||
|
||||
setup(
|
||||
options=options,
|
||||
ext_modules=cythonize(
|
||||
[
|
||||
Extension(
|
||||
"*",
|
||||
["src/**/*.pyx"],
|
||||
define_macros=defined_macros,
|
||||
py_limited_api=limited_api,
|
||||
),
|
||||
],
|
||||
annotate=debug,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Top-level package."""
|
||||
|
||||
__version__ = "4.48.1"
|
||||
__version__ = "4.45.0"
|
||||
"""Version number.
|
||||
|
||||
:type: str
|
||||
|
|
0
src/dependency_injector/__init__.pyi
Normal file
0
src/dependency_injector/__init__.pyi
Normal file
|
@ -1,18 +0,0 @@
|
|||
from typing import Any, Dict
|
||||
|
||||
from .providers import Provider
|
||||
|
||||
class DependencyResolver:
|
||||
def __init__(
|
||||
self,
|
||||
kwargs: Dict[str, Any],
|
||||
injections: Dict[str, Provider[Any]],
|
||||
closings: Dict[str, Provider[Any]],
|
||||
/,
|
||||
) -> None: ...
|
||||
def __enter__(self) -> Dict[str, Any]: ...
|
||||
def __exit__(self, *exc_info: Any) -> None: ...
|
||||
async def __aenter__(self) -> Dict[str, Any]: ...
|
||||
async def __aexit__(self, *exc_info: Any) -> None: ...
|
||||
|
||||
def _isawaitable(instance: Any) -> bool: ...
|
|
@ -1,93 +1,88 @@
|
|||
"""Wiring optimizations module."""
|
||||
|
||||
from asyncio import gather
|
||||
from collections.abc import Awaitable
|
||||
from inspect import CO_ITERABLE_COROUTINE
|
||||
from types import CoroutineType, GeneratorType
|
||||
import asyncio
|
||||
import collections.abc
|
||||
import functools
|
||||
import inspect
|
||||
import types
|
||||
|
||||
from .providers cimport Provider, Resource
|
||||
from .wiring import _Marker
|
||||
from . import providers
|
||||
from .wiring import _Marker, PatchedCallable
|
||||
|
||||
from .providers cimport Provider
|
||||
|
||||
|
||||
cdef inline bint _is_injectable(dict kwargs, object name):
|
||||
return name not in kwargs or isinstance(kwargs[name], _Marker)
|
||||
|
||||
|
||||
cdef class DependencyResolver:
|
||||
cdef dict kwargs
|
||||
cdef dict to_inject
|
||||
cdef dict injections
|
||||
cdef dict closings
|
||||
|
||||
def __init__(self, dict kwargs, dict injections, dict closings, /):
|
||||
self.kwargs = kwargs
|
||||
self.to_inject = kwargs.copy()
|
||||
self.injections = injections
|
||||
self.closings = closings
|
||||
|
||||
async def _await_injection(self, name: str, value: object, /) -> None:
|
||||
self.to_inject[name] = await value
|
||||
|
||||
cdef void _handle_injections_sync(self):
|
||||
def _get_sync_patched(fn, patched: PatchedCallable):
|
||||
@functools.wraps(fn)
|
||||
def _patched(*args, **kwargs):
|
||||
cdef object result
|
||||
cdef dict to_inject
|
||||
cdef object arg_key
|
||||
cdef Provider provider
|
||||
|
||||
for name, provider in self.injections.items():
|
||||
if _is_injectable(self.kwargs, name):
|
||||
self.to_inject[name] = provider()
|
||||
to_inject = kwargs.copy()
|
||||
for arg_key, provider in patched.injections.items():
|
||||
if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker):
|
||||
to_inject[arg_key] = provider()
|
||||
|
||||
cdef list _handle_injections_async(self):
|
||||
cdef list to_await = []
|
||||
cdef Provider provider
|
||||
result = fn(*args, **to_inject)
|
||||
|
||||
for name, provider in self.injections.items():
|
||||
if _is_injectable(self.kwargs, name):
|
||||
provide = provider()
|
||||
|
||||
if provider.is_async_mode_enabled() or _isawaitable(provide):
|
||||
to_await.append(self._await_injection(name, provide))
|
||||
else:
|
||||
self.to_inject[name] = provide
|
||||
|
||||
return to_await
|
||||
|
||||
cdef void _handle_closings_sync(self):
|
||||
cdef Provider provider
|
||||
|
||||
for name, provider in self.closings.items():
|
||||
if _is_injectable(self.kwargs, name) and isinstance(provider, Resource):
|
||||
if patched.closing:
|
||||
for arg_key, provider in patched.closing.items():
|
||||
if arg_key in kwargs and not isinstance(kwargs[arg_key], _Marker):
|
||||
continue
|
||||
if not isinstance(provider, providers.Resource):
|
||||
continue
|
||||
provider.shutdown()
|
||||
|
||||
cdef list _handle_closings_async(self):
|
||||
cdef list to_await = []
|
||||
cdef Provider provider
|
||||
return result
|
||||
return _patched
|
||||
|
||||
for name, provider in self.closings.items():
|
||||
if _is_injectable(self.kwargs, name) and isinstance(provider, Resource):
|
||||
if _isawaitable(shutdown := provider.shutdown()):
|
||||
to_await.append(shutdown)
|
||||
|
||||
return to_await
|
||||
async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dict closings):
|
||||
cdef object result
|
||||
cdef dict to_inject
|
||||
cdef list to_inject_await = []
|
||||
cdef list to_close_await = []
|
||||
cdef object arg_key
|
||||
cdef Provider provider
|
||||
|
||||
def __enter__(self):
|
||||
self._handle_injections_sync()
|
||||
return self.to_inject
|
||||
to_inject = kwargs.copy()
|
||||
for arg_key, provider in injections.items():
|
||||
if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker):
|
||||
provide = provider()
|
||||
if provider.is_async_mode_enabled():
|
||||
to_inject_await.append((arg_key, provide))
|
||||
elif _isawaitable(provide):
|
||||
to_inject_await.append((arg_key, provide))
|
||||
else:
|
||||
to_inject[arg_key] = provide
|
||||
|
||||
def __exit__(self, *_):
|
||||
self._handle_closings_sync()
|
||||
if to_inject_await:
|
||||
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
|
||||
|
||||
async def __aenter__(self):
|
||||
if to_await := self._handle_injections_async():
|
||||
await gather(*to_await)
|
||||
return self.to_inject
|
||||
result = await fn(*args, **to_inject)
|
||||
|
||||
async def __aexit__(self, *_):
|
||||
if to_await := self._handle_closings_async():
|
||||
await gather(*to_await)
|
||||
if closings:
|
||||
for arg_key, provider in closings.items():
|
||||
if arg_key in kwargs and isinstance(kwargs[arg_key], _Marker):
|
||||
continue
|
||||
if not isinstance(provider, providers.Resource):
|
||||
continue
|
||||
shutdown = provider.shutdown()
|
||||
if _isawaitable(shutdown):
|
||||
to_close_await.append(shutdown)
|
||||
|
||||
await asyncio.gather(*to_close_await)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
cdef bint _isawaitable(object instance):
|
||||
"""Return true if object can be passed to an ``await`` expression."""
|
||||
return (isinstance(instance, CoroutineType) or
|
||||
isinstance(instance, GeneratorType) and
|
||||
bool(instance.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
|
||||
isinstance(instance, Awaitable))
|
||||
return (isinstance(instance, types.CoroutineType) or
|
||||
isinstance(instance, types.GeneratorType) and
|
||||
bool(instance.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE) or
|
||||
isinstance(instance, collections.abc.Awaitable))
|
||||
|
|
|
@ -1,28 +1,24 @@
|
|||
from pathlib import Path
|
||||
from typing import (
|
||||
Any,
|
||||
Awaitable,
|
||||
Callable as _Callable,
|
||||
ClassVar,
|
||||
Dict,
|
||||
Generic,
|
||||
Type,
|
||||
Dict,
|
||||
List,
|
||||
Tuple,
|
||||
Optional,
|
||||
Any,
|
||||
Union,
|
||||
ClassVar,
|
||||
Callable as _Callable,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
Awaitable,
|
||||
overload,
|
||||
)
|
||||
|
||||
try:
|
||||
from typing import Self as _Self
|
||||
except ImportError:
|
||||
from typing_extensions import Self as _Self
|
||||
from .providers import Provider, Self, ProviderParent
|
||||
|
||||
from .providers import Provider, Resource, Self, ProviderParent
|
||||
|
||||
C_Base = TypeVar("C_Base", bound="Container")
|
||||
C = TypeVar("C", bound="DeclarativeContainer")
|
||||
|
@ -30,66 +26,51 @@ C_Overriding = TypeVar("C_Overriding", bound="DeclarativeContainer")
|
|||
T = TypeVar("T")
|
||||
TT = TypeVar("TT")
|
||||
|
||||
|
||||
class WiringConfiguration:
|
||||
modules: List[Any]
|
||||
packages: List[Any]
|
||||
from_package: Optional[str]
|
||||
auto_wire: bool
|
||||
keep_cache: bool
|
||||
def __init__(
|
||||
self,
|
||||
modules: Optional[Iterable[Any]] = None,
|
||||
packages: Optional[Iterable[Any]] = None,
|
||||
from_package: Optional[str] = None,
|
||||
auto_wire: bool = True,
|
||||
keep_cache: bool = False,
|
||||
) -> None: ...
|
||||
def __init__(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None, auto_wire: bool = True) -> None: ...
|
||||
|
||||
|
||||
class Container:
|
||||
provider_type: Type[Provider[Any]] = Provider
|
||||
providers: Dict[str, Provider[Any]]
|
||||
dependencies: Dict[str, Provider[Any]]
|
||||
overridden: Tuple[Provider[Any], ...]
|
||||
provider_type: Type[Provider] = Provider
|
||||
providers: Dict[str, Provider]
|
||||
dependencies: Dict[str, Provider]
|
||||
overridden: Tuple[Provider]
|
||||
wiring_config: WiringConfiguration
|
||||
auto_load_config: bool = True
|
||||
__self__: Self
|
||||
def __init__(self) -> None: ...
|
||||
def __deepcopy__(self, memo: Optional[Dict[str, Any]]) -> _Self: ...
|
||||
def __setattr__(self, name: str, value: Union[Provider[Any], Any]) -> None: ...
|
||||
def __getattr__(self, name: str) -> Provider[Any]: ...
|
||||
def __deepcopy__(self, memo: Optional[Dict[str, Any]]) -> Provider: ...
|
||||
def __setattr__(self, name: str, value: Union[Provider, Any]) -> None: ...
|
||||
def __getattr__(self, name: str) -> Provider: ...
|
||||
def __delattr__(self, name: str) -> None: ...
|
||||
def set_providers(self, **providers: Provider[Any]) -> None: ...
|
||||
def set_provider(self, name: str, provider: Provider[Any]) -> None: ...
|
||||
def set_providers(self, **providers: Provider): ...
|
||||
def set_provider(self, name: str, provider: Provider) -> None: ...
|
||||
def override(self, overriding: Union[Container, Type[Container]]) -> None: ...
|
||||
def override_providers(
|
||||
self, **overriding_providers: Union[Provider[Any], Any]
|
||||
) -> ProvidersOverridingContext[C_Base]: ...
|
||||
def override_providers(self, **overriding_providers: Union[Provider, Any]) -> ProvidersOverridingContext[C_Base]: ...
|
||||
def reset_last_overriding(self) -> None: ...
|
||||
def reset_override(self) -> None: ...
|
||||
def is_auto_wiring_enabled(self) -> bool: ...
|
||||
def wire(
|
||||
self,
|
||||
modules: Optional[Iterable[Any]] = None,
|
||||
packages: Optional[Iterable[Any]] = None,
|
||||
from_package: Optional[str] = None,
|
||||
) -> None: ...
|
||||
def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None) -> None: ...
|
||||
def unwire(self) -> None: ...
|
||||
def init_resources(self, resource_type: Type[Resource[Any]] = Resource) -> Optional[Awaitable[None]]: ...
|
||||
def shutdown_resources(self, resource_type: Type[Resource[Any]] = Resource) -> Optional[Awaitable[None]]: ...
|
||||
def init_resources(self) -> Optional[Awaitable]: ...
|
||||
def shutdown_resources(self) -> Optional[Awaitable]: ...
|
||||
def load_config(self) -> None: ...
|
||||
def apply_container_providers_overridings(self) -> None: ...
|
||||
def reset_singletons(self) -> SingletonResetContext[C_Base]: ...
|
||||
def check_dependencies(self) -> None: ...
|
||||
def from_schema(self, schema: Dict[Any, Any]) -> None: ...
|
||||
def from_yaml_schema(
|
||||
self, filepath: Union[Path, str], loader: Optional[Any] = None
|
||||
) -> None: ...
|
||||
def from_yaml_schema(self, filepath: Union[Path, str], loader: Optional[Any]=None) -> None: ...
|
||||
def from_json_schema(self, filepath: Union[Path, str]) -> None: ...
|
||||
@overload
|
||||
def resolve_provider_name(self, provider: Provider[Any]) -> str: ...
|
||||
def resolve_provider_name(self, provider: Provider) -> str: ...
|
||||
@classmethod
|
||||
@overload
|
||||
def resolve_provider_name(cls, provider: Provider[Any]) -> str: ...
|
||||
def resolve_provider_name(cls, provider: Provider) -> str: ...
|
||||
@property
|
||||
def parent(self) -> Optional[ProviderParent]: ...
|
||||
@property
|
||||
|
@ -101,37 +82,40 @@ class Container:
|
|||
@overload
|
||||
def traverse(cls, types: Optional[Iterable[Type[TT]]] = None) -> Iterator[TT]: ...
|
||||
|
||||
|
||||
class DynamicContainer(Container): ...
|
||||
|
||||
|
||||
class DeclarativeContainer(Container):
|
||||
cls_providers: ClassVar[Dict[str, Provider[Any]]]
|
||||
inherited_providers: ClassVar[Dict[str, Provider[Any]]]
|
||||
def __init__(self, **overriding_providers: Union[Provider[Any], Any]) -> None: ...
|
||||
cls_providers: ClassVar[Dict[str, Provider]]
|
||||
inherited_providers: ClassVar[Dict[str, Provider]]
|
||||
def __init__(self, **overriding_providers: Union[Provider, Any]) -> None: ...
|
||||
@classmethod
|
||||
def override(cls, overriding: Union[Container, Type[Container]]) -> None: ...
|
||||
@classmethod
|
||||
def override_providers(
|
||||
cls, **overriding_providers: Union[Provider[Any], Any]
|
||||
) -> ProvidersOverridingContext[C_Base]: ...
|
||||
def override_providers(cls, **overriding_providers: Union[Provider, Any]) -> ProvidersOverridingContext[C_Base]: ...
|
||||
@classmethod
|
||||
def reset_last_overriding(cls) -> None: ...
|
||||
@classmethod
|
||||
def reset_override(cls) -> None: ...
|
||||
|
||||
|
||||
class ProvidersOverridingContext(Generic[T]):
|
||||
def __init__(
|
||||
self, container: T, overridden_providers: Iterable[Union[Provider[Any], Any]]
|
||||
) -> None: ...
|
||||
def __init__(self, container: T, overridden_providers: Iterable[Union[Provider, Any]]) -> None: ...
|
||||
def __enter__(self) -> T: ...
|
||||
def __exit__(self, *_: Any) -> None: ...
|
||||
|
||||
|
||||
class SingletonResetContext(Generic[T]):
|
||||
def __init__(self, container: T): ...
|
||||
def __enter__(self) -> T: ...
|
||||
def __exit__(self, *_: Any) -> None: ...
|
||||
|
||||
def override(
|
||||
container: Type[C],
|
||||
) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
|
||||
|
||||
def override(container: Type[C]) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
|
||||
|
||||
|
||||
def copy(container: Type[C]) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
|
||||
|
||||
|
||||
def is_container(instance: Any) -> bool: ...
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
"""Containers module."""
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import copy as copy_module
|
||||
import json
|
||||
import sys
|
||||
import importlib
|
||||
import inspect
|
||||
import warnings
|
||||
|
||||
try:
|
||||
import asyncio
|
||||
except ImportError:
|
||||
asyncio = None
|
||||
|
||||
try:
|
||||
import yaml
|
||||
|
@ -14,24 +20,40 @@ except ImportError:
|
|||
|
||||
from . import providers, errors
|
||||
from .providers cimport __is_future_or_coroutine
|
||||
from .wiring import wire, unwire
|
||||
|
||||
|
||||
if sys.version_info[:2] >= (3, 6):
|
||||
from .wiring import wire, unwire
|
||||
else:
|
||||
def wire(*args, **kwargs):
|
||||
raise NotImplementedError("Wiring requires Python 3.6 or above")
|
||||
|
||||
def unwire(*args, **kwargs):
|
||||
raise NotImplementedError("Wiring requires Python 3.6 or above")
|
||||
|
||||
if sys.version_info[:2] == (3, 5):
|
||||
warnings.warn(
|
||||
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
|
||||
"This does not mean that there will be any immediate breaking changes, "
|
||||
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
|
||||
|
||||
class WiringConfiguration:
|
||||
"""Container wiring configuration."""
|
||||
|
||||
def __init__(self, modules=None, packages=None, from_package=None, auto_wire=True, keep_cache=False):
|
||||
def __init__(self, modules=None, packages=None, from_package=None, auto_wire=True):
|
||||
self.modules = [*modules] if modules else []
|
||||
self.packages = [*packages] if packages else []
|
||||
self.from_package = from_package
|
||||
self.auto_wire = auto_wire
|
||||
self.keep_cache = keep_cache
|
||||
|
||||
def __deepcopy__(self, memo=None):
|
||||
return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire, self.keep_cache)
|
||||
return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire)
|
||||
|
||||
|
||||
class Container:
|
||||
class Container(object):
|
||||
"""Abstract container."""
|
||||
|
||||
|
||||
|
@ -259,7 +281,7 @@ class DynamicContainer(Container):
|
|||
"""Check if auto wiring is needed."""
|
||||
return self.wiring_config.auto_wire is True
|
||||
|
||||
def wire(self, modules=None, packages=None, from_package=None, keep_cache=None):
|
||||
def wire(self, modules=None, packages=None, from_package=None):
|
||||
"""Wire container providers with provided packages and modules.
|
||||
|
||||
:rtype: None
|
||||
|
@ -290,14 +312,10 @@ class DynamicContainer(Container):
|
|||
if not modules and not packages:
|
||||
return
|
||||
|
||||
if keep_cache is None:
|
||||
keep_cache = self.wiring_config.keep_cache
|
||||
|
||||
wire(
|
||||
container=self,
|
||||
modules=modules,
|
||||
packages=packages,
|
||||
keep_cache=keep_cache,
|
||||
)
|
||||
|
||||
if modules:
|
||||
|
@ -315,15 +333,11 @@ class DynamicContainer(Container):
|
|||
self.wired_to_modules.clear()
|
||||
self.wired_to_packages.clear()
|
||||
|
||||
def init_resources(self, resource_type=providers.Resource):
|
||||
def init_resources(self):
|
||||
"""Initialize all container resources."""
|
||||
|
||||
if not issubclass(resource_type, providers.Resource):
|
||||
raise TypeError("resource_type must be a subclass of Resource provider")
|
||||
|
||||
futures = []
|
||||
|
||||
for provider in self.traverse(types=[resource_type]):
|
||||
for provider in self.traverse(types=[providers.Resource]):
|
||||
resource = provider.init()
|
||||
|
||||
if __is_future_or_coroutine(resource):
|
||||
|
@ -332,12 +346,8 @@ class DynamicContainer(Container):
|
|||
if futures:
|
||||
return asyncio.gather(*futures)
|
||||
|
||||
def shutdown_resources(self, resource_type=providers.Resource):
|
||||
def shutdown_resources(self):
|
||||
"""Shutdown all container resources."""
|
||||
|
||||
if not issubclass(resource_type, providers.Resource):
|
||||
raise TypeError("resource_type must be a subclass of Resource provider")
|
||||
|
||||
def _independent_resources(resources):
|
||||
for resource in resources:
|
||||
for other_resource in resources:
|
||||
|
@ -368,7 +378,7 @@ class DynamicContainer(Container):
|
|||
for resource in resources_to_shutdown:
|
||||
resource.shutdown()
|
||||
|
||||
resources = list(self.traverse(types=[resource_type]))
|
||||
resources = list(self.traverse(types=[providers.Resource]))
|
||||
if any(resource.is_async_mode_enabled() for resource in resources):
|
||||
return _async_ordered_shutdown(resources)
|
||||
else:
|
||||
|
|
|
@ -7,6 +7,7 @@ import warnings
|
|||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
warnings.warn(
|
||||
'Module "dependency_injector.ext.aiohttp" is deprecated since '
|
||||
'version 4.0.0. Use "dependency_injector.wiring" module instead.',
|
||||
|
@ -37,11 +38,9 @@ class View(providers.Callable):
|
|||
|
||||
def as_view(self):
|
||||
"""Return aiohttp view function."""
|
||||
|
||||
@functools.wraps(self.provides)
|
||||
async def _view(request, *args, **kwargs):
|
||||
return await self.__call__(request, *args, **kwargs)
|
||||
|
||||
return _view
|
||||
|
||||
|
||||
|
@ -50,8 +49,6 @@ class ClassBasedView(providers.Factory):
|
|||
|
||||
def as_view(self):
|
||||
"""Return aiohttp view function."""
|
||||
|
||||
async def _view(request, *args, **kwargs):
|
||||
return await self.__call__(request, *args, **kwargs)
|
||||
|
||||
return _view
|
||||
|
|
|
@ -1,16 +1,23 @@
|
|||
from typing import Any, Awaitable as _Awaitable, TypeVar
|
||||
from typing import Awaitable as _Awaitable
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
class Application(providers.Singleton[T]): ...
|
||||
class Extension(providers.Singleton[T]): ...
|
||||
class Middleware(providers.DelegatedCallable[T]): ...
|
||||
class MiddlewareFactory(providers.Factory[T]): ...
|
||||
class Application(providers.Singleton): ...
|
||||
|
||||
class View(providers.Callable[T]):
|
||||
def as_view(self) -> _Awaitable[T]: ...
|
||||
|
||||
class ClassBasedView(providers.Factory[T]):
|
||||
def as_view(self) -> _Awaitable[T]: ...
|
||||
class Extension(providers.Singleton): ...
|
||||
|
||||
|
||||
class Middleware(providers.DelegatedCallable): ...
|
||||
|
||||
|
||||
class MiddlewareFactory(providers.Factory): ...
|
||||
|
||||
|
||||
class View(providers.Callable):
|
||||
def as_view(self) -> _Awaitable: ...
|
||||
|
||||
|
||||
class ClassBasedView(providers.Factory):
|
||||
def as_view(self) -> _Awaitable: ...
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
"""Flask extension module."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from flask import request as flask_request
|
||||
|
||||
from dependency_injector import errors, providers
|
||||
from dependency_injector import providers, errors
|
||||
|
||||
|
||||
warnings.warn(
|
||||
'Module "dependency_injector.ext.flask" is deprecated since '
|
||||
|
@ -45,7 +45,6 @@ class ClassBasedView(providers.Factory):
|
|||
def as_view(provider, name=None):
|
||||
"""Transform class-based view provider to view function."""
|
||||
if isinstance(provider, providers.Factory):
|
||||
|
||||
def view(*args, **kwargs):
|
||||
self = provider()
|
||||
return self.dispatch_request(*args, **kwargs)
|
||||
|
@ -53,13 +52,12 @@ def as_view(provider, name=None):
|
|||
assert name, 'Argument "endpoint" is required for class-based views'
|
||||
view.__name__ = name
|
||||
elif isinstance(provider, providers.Callable):
|
||||
|
||||
def view(*args, **kwargs):
|
||||
return provider(*args, **kwargs)
|
||||
|
||||
view.__name__ = provider.provides.__name__
|
||||
else:
|
||||
raise errors.Error("Undefined provider type")
|
||||
raise errors.Error('Undefined provider type')
|
||||
|
||||
view.__doc__ = provider.provides.__doc__
|
||||
view.__module__ = provider.provides.__module__
|
||||
|
@ -67,14 +65,14 @@ def as_view(provider, name=None):
|
|||
if isinstance(provider.provides, type):
|
||||
view.view_class = provider.provides
|
||||
|
||||
if hasattr(provider.provides, "decorators"):
|
||||
if hasattr(provider.provides, 'decorators'):
|
||||
for decorator in provider.provides.decorators:
|
||||
view = decorator(view)
|
||||
|
||||
if hasattr(provider.provides, "methods"):
|
||||
if hasattr(provider.provides, 'methods'):
|
||||
view.methods = provider.provides.methods
|
||||
|
||||
if hasattr(provider.provides, "provide_automatic_options"):
|
||||
if hasattr(provider.provides, 'provide_automatic_options'):
|
||||
view.provide_automatic_options = provider.provides.provide_automatic_options
|
||||
|
||||
return view
|
||||
|
|
|
@ -1,21 +1,24 @@
|
|||
from typing import Any, Callable as _Callable, Optional, TypeVar, Union
|
||||
|
||||
from flask.wrappers import Request
|
||||
from typing import Union, Optional, Callable as _Callable, Any
|
||||
|
||||
from flask import request as flask_request
|
||||
from dependency_injector import providers
|
||||
|
||||
request: providers.Object[Request]
|
||||
T = TypeVar("T")
|
||||
|
||||
class Application(providers.Singleton[T]): ...
|
||||
class Extension(providers.Singleton[T]): ...
|
||||
request: providers.Object[flask_request]
|
||||
|
||||
class View(providers.Callable[T]):
|
||||
def as_view(self) -> _Callable[..., T]: ...
|
||||
|
||||
class ClassBasedView(providers.Factory[T]):
|
||||
def as_view(self, name: str) -> _Callable[..., T]: ...
|
||||
class Application(providers.Singleton): ...
|
||||
|
||||
def as_view(
|
||||
provider: Union[View[T], ClassBasedView[T]], name: Optional[str] = None
|
||||
) -> _Callable[..., T]: ...
|
||||
|
||||
class Extension(providers.Singleton): ...
|
||||
|
||||
|
||||
class View(providers.Callable):
|
||||
def as_view(self) -> _Callable[..., Any]: ...
|
||||
|
||||
|
||||
class ClassBasedView(providers.Factory):
|
||||
def as_view(self, name: str) -> _Callable[..., Any]: ...
|
||||
|
||||
|
||||
def as_view(provider: Union[View, ClassBasedView], name: Optional[str] = None) -> _Callable[..., Any]: ...
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import sys
|
||||
from typing import Any, Type
|
||||
from typing import Any
|
||||
|
||||
if sys.version_info >= (3, 11): # pragma: no cover
|
||||
from typing import Self
|
||||
|
@ -7,7 +7,6 @@ else: # pragma: no cover
|
|||
from typing_extensions import Self
|
||||
|
||||
from dependency_injector.containers import Container
|
||||
from dependency_injector.providers import Resource
|
||||
|
||||
|
||||
class Lifespan:
|
||||
|
@ -30,32 +29,24 @@ class Lifespan:
|
|||
app = Factory(Starlette, lifespan=lifespan)
|
||||
|
||||
:param container: container instance
|
||||
:param resource_type: A :py:class:`~dependency_injector.resources.Resource`
|
||||
subclass. Limits the resources to be initialized and shutdown.
|
||||
"""
|
||||
|
||||
container: Container
|
||||
resource_type: Type[Resource[Any]]
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
container: Container,
|
||||
resource_type: Type[Resource[Any]] = Resource,
|
||||
) -> None:
|
||||
def __init__(self, container: Container) -> None:
|
||||
self.container = container
|
||||
self.resource_type = resource_type
|
||||
|
||||
def __call__(self, app: Any) -> Self:
|
||||
return self
|
||||
|
||||
async def __aenter__(self) -> None:
|
||||
result = self.container.init_resources(self.resource_type)
|
||||
result = self.container.init_resources()
|
||||
|
||||
if result is not None:
|
||||
await result
|
||||
|
||||
async def __aexit__(self, *exc_info: Any) -> None:
|
||||
result = self.container.shutdown_resources(self.resource_type)
|
||||
result = self.container.shutdown_resources()
|
||||
|
||||
if result is not None:
|
||||
await result
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
"""Providers module."""
|
||||
|
||||
import asyncio
|
||||
try:
|
||||
import asyncio
|
||||
except ImportError:
|
||||
asyncio = None
|
||||
|
||||
import functools
|
||||
|
||||
cimport cython
|
||||
|
@ -15,7 +19,7 @@ cdef tuple __COROUTINE_TYPES
|
|||
|
||||
|
||||
# Base providers
|
||||
cdef class Provider:
|
||||
cdef class Provider(object):
|
||||
cdef tuple _overridden
|
||||
cdef Provider _last_overriding
|
||||
cdef tuple _overrides
|
||||
|
@ -287,7 +291,7 @@ cdef class MethodCaller(Provider):
|
|||
|
||||
|
||||
# Injections
|
||||
cdef class Injection:
|
||||
cdef class Injection(object):
|
||||
cdef object _value
|
||||
cdef int _is_provider
|
||||
cdef int _is_delegated
|
||||
|
@ -309,12 +313,12 @@ cpdef tuple parse_named_injections(dict kwargs)
|
|||
|
||||
|
||||
# Utils
|
||||
cdef class OverridingContext:
|
||||
cdef class OverridingContext(object):
|
||||
cdef Provider _overridden
|
||||
cdef Provider _overriding
|
||||
|
||||
|
||||
cdef class BaseSingletonResetContext:
|
||||
cdef class BaseSingletonResetContext(object):
|
||||
cdef object _singleton
|
||||
|
||||
|
||||
|
@ -697,10 +701,3 @@ cdef inline object __future_result(object instance):
|
|||
future_result = asyncio.Future()
|
||||
future_result.set_result(instance)
|
||||
return future_result
|
||||
|
||||
|
||||
cdef class NullAwaitable:
|
||||
pass
|
||||
|
||||
|
||||
cdef NullAwaitable NULL_AWAITABLE
|
||||
|
|
|
@ -33,6 +33,7 @@ except ImportError:
|
|||
|
||||
from . import resources
|
||||
|
||||
|
||||
Injection = Any
|
||||
ProviderParent = Union["Provider", Any]
|
||||
T = TypeVar("T")
|
||||
|
@ -40,13 +41,16 @@ TT = TypeVar("TT")
|
|||
P = TypeVar("P", bound="Provider")
|
||||
BS = TypeVar("BS", bound="BaseSingleton")
|
||||
|
||||
|
||||
class Provider(Generic[T]):
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
@overload
|
||||
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 __str__(self) -> str: ...
|
||||
def __repr__(self) -> str: ...
|
||||
|
@ -63,9 +67,9 @@ class Provider(Generic[T]):
|
|||
def unregister_overrides(self, provider: Union[Provider, Any]) -> None: ...
|
||||
def delegate(self) -> Provider: ...
|
||||
@property
|
||||
def provider(self) -> Provider[T]: ...
|
||||
def provider(self) -> Provider: ...
|
||||
@property
|
||||
def provided(self) -> ProvidedInstance[T]: ...
|
||||
def provided(self) -> ProvidedInstance: ...
|
||||
def enable_async_mode(self) -> None: ...
|
||||
def disable_async_mode(self) -> None: ...
|
||||
def reset_async_mode(self) -> None: ...
|
||||
|
@ -74,12 +78,9 @@ class Provider(Generic[T]):
|
|||
def is_async_mode_undefined(self) -> bool: ...
|
||||
@property
|
||||
def related(self) -> _Iterator[Provider]: ...
|
||||
def traverse(
|
||||
self, types: Optional[_Iterable[Type[TT]]] = None
|
||||
) -> _Iterator[TT]: ...
|
||||
def _copy_overridings(
|
||||
self, copied: Provider, memo: Optional[_Dict[Any, Any]]
|
||||
) -> None: ...
|
||||
def traverse(self, types: Optional[_Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
|
||||
def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ...
|
||||
|
||||
|
||||
class Object(Provider[T]):
|
||||
def __init__(self, provides: Optional[T] = None) -> None: ...
|
||||
|
@ -87,6 +88,7 @@ class Object(Provider[T]):
|
|||
def provides(self) -> Optional[T]: ...
|
||||
def set_provides(self, provides: Optional[T]) -> Object: ...
|
||||
|
||||
|
||||
class Self(Provider[T]):
|
||||
def __init__(self, container: Optional[T] = None) -> None: ...
|
||||
def set_container(self, container: T) -> None: ...
|
||||
|
@ -94,51 +96,41 @@ class Self(Provider[T]):
|
|||
@property
|
||||
def alt_names(self) -> Tuple[Any]: ...
|
||||
|
||||
|
||||
class Delegate(Provider[Provider]):
|
||||
def __init__(self, provides: Optional[Provider] = None) -> None: ...
|
||||
@property
|
||||
def provides(self) -> Optional[Provider]: ...
|
||||
def set_provides(self, provides: Optional[Provider]) -> Delegate: ...
|
||||
|
||||
|
||||
class Aggregate(Provider[T]):
|
||||
def __init__(
|
||||
self,
|
||||
provider_dict: Optional[_Dict[Any, Provider[T]]] = None,
|
||||
**provider_kwargs: Provider[T],
|
||||
): ...
|
||||
def __init__(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]): ...
|
||||
def __getattr__(self, provider_name: Any) -> Provider[T]: ...
|
||||
|
||||
@overload
|
||||
def __call__(
|
||||
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
|
||||
) -> T: ...
|
||||
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> T: ...
|
||||
@overload
|
||||
def __call__(
|
||||
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
|
||||
) -> Awaitable[T]: ...
|
||||
def async_(
|
||||
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
|
||||
) -> Awaitable[T]: ...
|
||||
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||
def async_(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
|
||||
|
||||
@property
|
||||
def providers(self) -> _Dict[Any, Provider[T]]: ...
|
||||
def set_providers(
|
||||
self,
|
||||
provider_dict: Optional[_Dict[Any, Provider[T]]] = None,
|
||||
**provider_kwargs: Provider[T],
|
||||
) -> Aggregate[T]: ...
|
||||
def set_providers(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]) -> Aggregate[T]: ...
|
||||
|
||||
|
||||
class Dependency(Provider[T]):
|
||||
def __init__(
|
||||
self,
|
||||
instance_of: Type[T] = object,
|
||||
default: Optional[Union[Provider, Any]] = None,
|
||||
) -> None: ...
|
||||
def __init__(self, instance_of: Type[T] = object, default: Optional[Union[Provider, Any]] = None) -> None: ...
|
||||
def __getattr__(self, name: str) -> Any: ...
|
||||
|
||||
@property
|
||||
def instance_of(self) -> Type[T]: ...
|
||||
def set_instance_of(self, instance_of: Type[T]) -> Dependency[T]: ...
|
||||
|
||||
@property
|
||||
def default(self) -> Provider[T]: ...
|
||||
def set_default(self, default: Optional[Union[Provider, Any]]) -> Dependency[T]: ...
|
||||
|
||||
@property
|
||||
def is_defined(self) -> bool: ...
|
||||
def provided_by(self, provider: Provider) -> OverridingContext[P]: ...
|
||||
|
@ -148,8 +140,10 @@ class Dependency(Provider[T]):
|
|||
def parent_name(self) -> Optional[str]: ...
|
||||
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||
|
||||
|
||||
class ExternalDependency(Dependency[T]): ...
|
||||
|
||||
|
||||
class DependenciesContainer(Object):
|
||||
def __init__(self, **dependencies: Provider) -> None: ...
|
||||
def __getattr__(self, name: str) -> Provider: ...
|
||||
|
@ -162,18 +156,12 @@ class DependenciesContainer(Object):
|
|||
def parent_name(self) -> Optional[str]: ...
|
||||
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||
|
||||
|
||||
class Callable(Provider[T]):
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Union[_Callable[..., T], str]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@property
|
||||
def provides(self) -> Optional[_Callable[..., T]]: ...
|
||||
def set_provides(
|
||||
self, provides: Optional[Union[_Callable[..., T], str]]
|
||||
) -> Callable[T]: ...
|
||||
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> Callable[T]: ...
|
||||
@property
|
||||
def args(self) -> Tuple[Injection]: ...
|
||||
def add_args(self, *args: Injection) -> Callable[T]: ...
|
||||
|
@ -185,23 +173,32 @@ class Callable(Provider[T]):
|
|||
def set_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
|
||||
def clear_kwargs(self) -> Callable[T]: ...
|
||||
|
||||
|
||||
class DelegatedCallable(Callable[T]): ...
|
||||
|
||||
|
||||
class AbstractCallable(Callable[T]):
|
||||
def override(self, provider: Callable) -> OverridingContext[P]: ...
|
||||
|
||||
|
||||
class CallableDelegate(Delegate):
|
||||
def __init__(self, callable: Callable) -> None: ...
|
||||
|
||||
|
||||
class Coroutine(Callable[T]): ...
|
||||
|
||||
|
||||
class DelegatedCoroutine(Coroutine[T]): ...
|
||||
|
||||
|
||||
class AbstractCoroutine(Coroutine[T]):
|
||||
def override(self, provider: Coroutine) -> OverridingContext[P]: ...
|
||||
|
||||
|
||||
class CoroutineDelegate(Delegate):
|
||||
def __init__(self, coroutine: Coroutine) -> None: ...
|
||||
|
||||
|
||||
class ConfigurationOption(Provider[Any]):
|
||||
UNDEFINED: object
|
||||
def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
|
||||
|
@ -215,137 +212,89 @@ class ConfigurationOption(Provider[Any]):
|
|||
def get_name_segments(self) -> Tuple[Union[str, Provider]]: ...
|
||||
def as_int(self) -> TypedConfigurationOption[int]: ...
|
||||
def as_float(self) -> TypedConfigurationOption[float]: ...
|
||||
def as_(
|
||||
self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection
|
||||
) -> TypedConfigurationOption[T]: ...
|
||||
def as_(self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection) -> TypedConfigurationOption[T]: ...
|
||||
def required(self) -> ConfigurationOption: ...
|
||||
def is_required(self) -> bool: ...
|
||||
def update(self, value: Any) -> None: ...
|
||||
def from_ini(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
envs_required: Optional[bool] = False,
|
||||
) -> None: ...
|
||||
def from_yaml(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
loader: Optional[Any] = None,
|
||||
envs_required: Optional[bool] = False,
|
||||
) -> None: ...
|
||||
def from_json(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
envs_required: Optional[bool] = False,
|
||||
) -> None: ...
|
||||
def from_pydantic(
|
||||
self, settings: PydanticSettings, required: bool = False, **kwargs: Any
|
||||
) -> None: ...
|
||||
def from_ini(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
|
||||
def from_yaml(self, filepath: Union[Path, str], required: bool = False, loader: Optional[Any] = None, envs_required: bool = False) -> None: ...
|
||||
def from_json(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
|
||||
def from_pydantic(self, settings: PydanticSettings, required: bool = False, **kwargs: Any) -> None: ...
|
||||
def from_dict(self, options: _Dict[str, Any], required: bool = False) -> None: ...
|
||||
def from_env(
|
||||
self,
|
||||
name: str,
|
||||
default: Optional[Any] = None,
|
||||
required: bool = False,
|
||||
as_: Optional[_Callable[..., Any]] = None,
|
||||
) -> None: ...
|
||||
def from_env(self, name: str, default: Optional[Any] = None, required: bool = False, as_: Optional[_Callable[..., Any]] = None) -> None: ...
|
||||
def from_value(self, value: Any) -> None: ...
|
||||
|
||||
|
||||
class TypedConfigurationOption(Callable[T]):
|
||||
@property
|
||||
def option(self) -> ConfigurationOption: ...
|
||||
|
||||
|
||||
class Configuration(Object[Any]):
|
||||
DEFAULT_NAME: str = "config"
|
||||
def __init__(
|
||||
self,
|
||||
name: str = DEFAULT_NAME,
|
||||
default: Optional[Any] = None,
|
||||
*,
|
||||
strict: bool = False,
|
||||
ini_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
json_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
|
||||
self,
|
||||
name: str = DEFAULT_NAME,
|
||||
default: Optional[Any] = None,
|
||||
*,
|
||||
strict: bool = False,
|
||||
ini_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
json_files: Optional[_Iterable[Union[Path, str]]] = None,
|
||||
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
|
||||
) -> None: ...
|
||||
def __enter__(self) -> Configuration: ...
|
||||
def __enter__(self) -> Configuration : ...
|
||||
def __exit__(self, *exc_info: Any) -> None: ...
|
||||
def __getattr__(self, item: str) -> ConfigurationOption: ...
|
||||
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
|
||||
|
||||
def get_name(self) -> str: ...
|
||||
def set_name(self, name: str) -> Configuration: ...
|
||||
|
||||
def get_default(self) -> _Dict[Any, Any]: ...
|
||||
def set_default(self, default: _Dict[Any, Any]): ...
|
||||
|
||||
def get_strict(self) -> bool: ...
|
||||
def set_strict(self, strict: bool) -> Configuration: ...
|
||||
|
||||
def get_children(self) -> _Dict[str, ConfigurationOption]: ...
|
||||
def set_children(
|
||||
self, children: _Dict[str, ConfigurationOption]
|
||||
) -> Configuration: ...
|
||||
def set_children(self, children: _Dict[str, ConfigurationOption]) -> Configuration: ...
|
||||
|
||||
def get_ini_files(self) -> _List[Union[Path, str]]: ...
|
||||
def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
|
||||
|
||||
def get_yaml_files(self) -> _List[Union[Path, str]]: ...
|
||||
def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
|
||||
|
||||
def get_json_files(self) -> _List[Union[Path, str]]: ...
|
||||
def set_json_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
|
||||
|
||||
def get_pydantic_settings(self) -> _List[PydanticSettings]: ...
|
||||
def set_pydantic_settings(
|
||||
self, settings: _Iterable[PydanticSettings]
|
||||
) -> Configuration: ...
|
||||
def set_pydantic_settings(self, settings: _Iterable[PydanticSettings]) -> Configuration: ...
|
||||
|
||||
def load(self, required: bool = False, envs_required: bool = False) -> None: ...
|
||||
|
||||
def get(self, selector: str) -> Any: ...
|
||||
def set(self, selector: str, value: Any) -> OverridingContext[P]: ...
|
||||
def reset_cache(self) -> None: ...
|
||||
def update(self, value: Any) -> None: ...
|
||||
def from_ini(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
envs_required: bool = False,
|
||||
) -> None: ...
|
||||
def from_yaml(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
loader: Optional[Any] = None,
|
||||
envs_required: bool = False,
|
||||
) -> None: ...
|
||||
def from_json(
|
||||
self,
|
||||
filepath: Union[Path, str],
|
||||
required: bool = False,
|
||||
envs_required: bool = False,
|
||||
) -> None: ...
|
||||
def from_pydantic(
|
||||
self, settings: PydanticSettings, required: bool = False, **kwargs: Any
|
||||
) -> None: ...
|
||||
def from_ini(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
|
||||
def from_yaml(self, filepath: Union[Path, str], required: bool = False, loader: Optional[Any] = None, envs_required: bool = False) -> None: ...
|
||||
def from_json(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
|
||||
def from_pydantic(self, settings: PydanticSettings, required: bool = False, **kwargs: Any) -> None: ...
|
||||
def from_dict(self, options: _Dict[str, Any], required: bool = False) -> None: ...
|
||||
def from_env(
|
||||
self,
|
||||
name: str,
|
||||
default: Optional[Any] = None,
|
||||
required: bool = False,
|
||||
as_: Optional[_Callable[..., Any]] = None,
|
||||
) -> None: ...
|
||||
def from_env(self, name: str, default: Optional[Any] = None, required: bool = False, as_: Optional[_Callable[..., Any]] = None) -> None: ...
|
||||
def from_value(self, value: Any) -> None: ...
|
||||
|
||||
|
||||
class Factory(Provider[T]):
|
||||
provided_type: Optional[Type]
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Union[_Callable[..., T], str]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@property
|
||||
def cls(self) -> Type[T]: ...
|
||||
@property
|
||||
def provides(self) -> Optional[_Callable[..., T]]: ...
|
||||
def set_provides(
|
||||
self, provides: Optional[Union[_Callable[..., T], str]]
|
||||
) -> Factory[T]: ...
|
||||
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> Factory[T]: ...
|
||||
@property
|
||||
def args(self) -> Tuple[Injection]: ...
|
||||
def add_args(self, *args: Injection) -> Factory[T]: ...
|
||||
|
@ -362,39 +311,33 @@ class Factory(Provider[T]):
|
|||
def set_attributes(self, **kwargs: Injection) -> Factory[T]: ...
|
||||
def clear_attributes(self) -> Factory[T]: ...
|
||||
|
||||
|
||||
class DelegatedFactory(Factory[T]): ...
|
||||
|
||||
|
||||
class AbstractFactory(Factory[T]):
|
||||
def override(self, provider: Factory) -> OverridingContext[P]: ...
|
||||
|
||||
|
||||
class FactoryDelegate(Delegate):
|
||||
def __init__(self, factory: Factory): ...
|
||||
|
||||
|
||||
class FactoryAggregate(Aggregate[T]):
|
||||
def __getattr__(self, provider_name: Any) -> Factory[T]: ...
|
||||
@property
|
||||
def factories(self) -> _Dict[Any, Factory[T]]: ...
|
||||
def set_factories(
|
||||
self,
|
||||
provider_dict: Optional[_Dict[Any, Factory[T]]] = None,
|
||||
**provider_kwargs: Factory[T],
|
||||
) -> FactoryAggregate[T]: ...
|
||||
def set_factories(self, provider_dict: Optional[_Dict[Any, Factory[T]]] = None, **provider_kwargs: Factory[T]) -> FactoryAggregate[T]: ...
|
||||
|
||||
|
||||
class BaseSingleton(Provider[T]):
|
||||
provided_type = Optional[Type]
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Union[_Callable[..., T], str]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@property
|
||||
def cls(self) -> Type[T]: ...
|
||||
@property
|
||||
def provides(self) -> Optional[_Callable[..., T]]: ...
|
||||
def set_provides(
|
||||
self, provides: Optional[Union[_Callable[..., T], str]]
|
||||
) -> BaseSingleton[T]: ...
|
||||
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> BaseSingleton[T]: ...
|
||||
@property
|
||||
def args(self) -> Tuple[Injection]: ...
|
||||
def add_args(self, *args: Injection) -> BaseSingleton[T]: ...
|
||||
|
@ -413,20 +356,36 @@ class BaseSingleton(Provider[T]):
|
|||
def reset(self) -> SingletonResetContext[BS]: ...
|
||||
def full_reset(self) -> SingletonFullResetContext[BS]: ...
|
||||
|
||||
|
||||
class Singleton(BaseSingleton[T]): ...
|
||||
|
||||
|
||||
class DelegatedSingleton(Singleton[T]): ...
|
||||
|
||||
|
||||
class ThreadSafeSingleton(Singleton[T]): ...
|
||||
|
||||
|
||||
class DelegatedThreadSafeSingleton(ThreadSafeSingleton[T]): ...
|
||||
|
||||
|
||||
class ThreadLocalSingleton(BaseSingleton[T]): ...
|
||||
|
||||
|
||||
class ContextLocalSingleton(BaseSingleton[T]): ...
|
||||
|
||||
|
||||
class DelegatedThreadLocalSingleton(ThreadLocalSingleton[T]): ...
|
||||
|
||||
|
||||
class AbstractSingleton(BaseSingleton[T]):
|
||||
def override(self, provider: BaseSingleton) -> OverridingContext[P]: ...
|
||||
|
||||
|
||||
class SingletonDelegate(Delegate):
|
||||
def __init__(self, singleton: BaseSingleton): ...
|
||||
|
||||
|
||||
class List(Provider[_List]):
|
||||
def __init__(self, *args: Injection): ...
|
||||
@property
|
||||
|
@ -435,63 +394,29 @@ class List(Provider[_List]):
|
|||
def set_args(self, *args: Injection) -> List[T]: ...
|
||||
def clear_args(self) -> List[T]: ...
|
||||
|
||||
|
||||
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): ...
|
||||
@property
|
||||
def kwargs(self) -> _Dict[Any, Injection]: ...
|
||||
def add_kwargs(
|
||||
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection
|
||||
) -> Dict: ...
|
||||
def set_kwargs(
|
||||
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection
|
||||
) -> Dict: ...
|
||||
def add_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
|
||||
def set_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
|
||||
def clear_kwargs(self) -> Dict: ...
|
||||
|
||||
|
||||
class Resource(Provider[T]):
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Type[resources.Resource[T]]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Type[resources.Resource[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Type[resources.AsyncResource[T]]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Type[resources.AsyncResource[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[_Callable[..., _Iterator[T]]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[_Callable[..., _Iterator[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[_Callable[..., _AsyncIterator[T]]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[_Callable[..., _AsyncIterator[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[_Callable[..., _Coroutine[Injection, Injection, T]]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[_Callable[..., _Coroutine[Injection, Injection, T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@overload
|
||||
def __init__(
|
||||
self,
|
||||
provides: Optional[Union[_Callable[..., T], str]] = None,
|
||||
*args: Injection,
|
||||
**kwargs: Injection,
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
@property
|
||||
def provides(self) -> Optional[_Callable[..., Any]]: ...
|
||||
def set_provides(self, provides: Optional[Any]) -> Resource[T]: ...
|
||||
|
@ -510,13 +435,9 @@ class Resource(Provider[T]):
|
|||
def init(self) -> Optional[Awaitable[T]]: ...
|
||||
def shutdown(self) -> Optional[Awaitable]: ...
|
||||
|
||||
|
||||
class Container(Provider[T]):
|
||||
def __init__(
|
||||
self,
|
||||
container_cls: Type[T],
|
||||
container: Optional[T] = None,
|
||||
**overriding_providers: Union[Provider, Any],
|
||||
) -> None: ...
|
||||
def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Union[Provider, Any]) -> None: ...
|
||||
def __getattr__(self, name: str) -> Provider: ...
|
||||
@property
|
||||
def container(self) -> T: ...
|
||||
|
@ -527,51 +448,50 @@ class Container(Provider[T]):
|
|||
def parent_name(self) -> Optional[str]: ...
|
||||
def assign_parent(self, parent: ProviderParent) -> None: ...
|
||||
|
||||
|
||||
class Selector(Provider[Any]):
|
||||
def __init__(
|
||||
self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider
|
||||
): ...
|
||||
def __init__(self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider): ...
|
||||
def __getattr__(self, name: str) -> Provider: ...
|
||||
|
||||
@property
|
||||
def selector(self) -> Optional[_Callable[..., Any]]: ...
|
||||
def set_selector(self, selector: Optional[_Callable[..., Any]]) -> Selector: ...
|
||||
|
||||
@property
|
||||
def providers(self) -> _Dict[str, Provider]: ...
|
||||
def set_providers(self, **providers: Provider) -> Selector: ...
|
||||
|
||||
|
||||
class ProvidedInstanceFluentInterface:
|
||||
def __getattr__(self, item: Any) -> AttributeGetter: ...
|
||||
def __getitem__(self, item: Any) -> ItemGetter: ...
|
||||
def call(self, *args: Injection, **kwargs: Injection) -> MethodCaller: ...
|
||||
@property
|
||||
def provides(self) -> Optional[Provider]: ...
|
||||
def set_provides(
|
||||
self, provides: Optional[Provider]
|
||||
) -> ProvidedInstanceFluentInterface: ...
|
||||
def set_provides(self, provides: Optional[Provider]) -> ProvidedInstanceFluentInterface: ...
|
||||
|
||||
|
||||
class ProvidedInstance(Provider, ProvidedInstanceFluentInterface):
|
||||
def __init__(self, provides: Optional[Provider] = None) -> None: ...
|
||||
|
||||
|
||||
class AttributeGetter(Provider, ProvidedInstanceFluentInterface):
|
||||
def __init__(
|
||||
self, provides: Optional[Provider] = None, name: Optional[str] = None
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Provider] = None, name: Optional[str] = None) -> None: ...
|
||||
@property
|
||||
def name(self) -> Optional[str]: ...
|
||||
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ...
|
||||
|
||||
|
||||
class ItemGetter(Provider, ProvidedInstanceFluentInterface):
|
||||
def __init__(
|
||||
self, provides: Optional[Provider] = None, name: Optional[str] = None
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Provider] = None, name: Optional[str] = None) -> None: ...
|
||||
@property
|
||||
def name(self) -> Optional[str]: ...
|
||||
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ...
|
||||
|
||||
|
||||
class MethodCaller(Provider, ProvidedInstanceFluentInterface):
|
||||
def __init__(
|
||||
self, provides: Optional[Provider] = None, *args: Injection, **kwargs: Injection
|
||||
) -> None: ...
|
||||
def __init__(self, provides: Optional[Provider] = None, *args: Injection, **kwargs: Injection) -> None: ...
|
||||
|
||||
|
||||
class OverridingContext(Generic[T]):
|
||||
def __init__(self, overridden: Provider, overriding: Provider): ...
|
||||
|
@ -580,39 +500,61 @@ class OverridingContext(Generic[T]):
|
|||
pass
|
||||
...
|
||||
|
||||
|
||||
class BaseSingletonResetContext(Generic[T]):
|
||||
def __init__(self, provider: T): ...
|
||||
def __enter__(self) -> T: ...
|
||||
def __exit__(self, *_: Any) -> None: ...
|
||||
|
||||
class SingletonResetContext(BaseSingletonResetContext): ...
|
||||
class SingletonFullResetContext(BaseSingletonResetContext): ...
|
||||
|
||||
class SingletonResetContext(BaseSingletonResetContext):
|
||||
...
|
||||
|
||||
|
||||
class SingletonFullResetContext(BaseSingletonResetContext):
|
||||
...
|
||||
|
||||
|
||||
CHILD_PROVIDERS: Tuple[Provider]
|
||||
|
||||
|
||||
def is_provider(instance: Any) -> bool: ...
|
||||
|
||||
|
||||
def ensure_is_provider(instance: Any) -> Provider: ...
|
||||
|
||||
|
||||
def is_delegated(instance: Any) -> bool: ...
|
||||
|
||||
|
||||
def represent_provider(provider: Provider, provides: Any) -> str: ...
|
||||
|
||||
|
||||
def deepcopy(instance: Any, memo: Optional[_Dict[Any, Any]] = None) -> Any: ...
|
||||
|
||||
|
||||
def deepcopy_args(
|
||||
provider: Provider[Any],
|
||||
args: Tuple[Any, ...],
|
||||
memo: Optional[_Dict[int, Any]] = None,
|
||||
) -> Tuple[Any, ...]: ...
|
||||
|
||||
|
||||
def deepcopy_kwargs(
|
||||
provider: Provider[Any],
|
||||
kwargs: _Dict[str, Any],
|
||||
memo: Optional[_Dict[int, Any]] = None,
|
||||
) -> Dict[str, Any]: ...
|
||||
|
||||
|
||||
def merge_dicts(dict1: _Dict[Any, Any], dict2: _Dict[Any, Any]) -> _Dict[Any, Any]: ...
|
||||
def traverse(
|
||||
*providers: Provider, types: Optional[_Iterable[Type]] = None
|
||||
) -> _Iterator[Provider]: ...
|
||||
|
||||
|
||||
def traverse(*providers: Provider, types: Optional[_Iterable[Type]]=None) -> _Iterator[Provider]: ...
|
||||
|
||||
|
||||
if yaml:
|
||||
class YamlLoader(yaml.SafeLoader): ...
|
||||
|
||||
else:
|
||||
class YamlLoader: ...
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import asyncio
|
||||
import builtins
|
||||
import copy
|
||||
import errno
|
||||
import functools
|
||||
|
@ -14,26 +12,36 @@ import os
|
|||
import re
|
||||
import sys
|
||||
import threading
|
||||
import types
|
||||
import warnings
|
||||
from asyncio import ensure_future
|
||||
from configparser import ConfigParser as IniConfigParser
|
||||
from contextlib import asynccontextmanager, contextmanager
|
||||
from contextvars import ContextVar
|
||||
from inspect import isasyncgenfunction, isgeneratorfunction
|
||||
|
||||
try:
|
||||
from inspect import _is_coroutine_mark as _is_coroutine_marker
|
||||
import contextvars
|
||||
except ImportError:
|
||||
try:
|
||||
# Python >=3.12.0,<3.12.5
|
||||
from inspect import _is_coroutine_marker
|
||||
except ImportError:
|
||||
contextvars = None
|
||||
|
||||
try:
|
||||
import builtins
|
||||
except ImportError:
|
||||
# Python 2.7
|
||||
import __builtin__ as builtins
|
||||
|
||||
try:
|
||||
import asyncio
|
||||
except ImportError:
|
||||
asyncio = None
|
||||
_is_coroutine_marker = None
|
||||
else:
|
||||
if sys.version_info >= (3, 5, 3):
|
||||
import asyncio.coroutines
|
||||
_is_coroutine_marker = asyncio.coroutines._is_coroutine
|
||||
else:
|
||||
_is_coroutine_marker = True
|
||||
|
||||
try:
|
||||
from asyncio.coroutines import _is_coroutine
|
||||
import ConfigParser as iniconfigparser
|
||||
except ImportError:
|
||||
_is_coroutine = True
|
||||
import configparser as iniconfigparser
|
||||
|
||||
try:
|
||||
import yaml
|
||||
|
@ -69,11 +77,29 @@ from .errors import (
|
|||
cimport cython
|
||||
|
||||
|
||||
if sys.version_info[0] == 3: # pragma: no cover
|
||||
CLASS_TYPES = (type,)
|
||||
else: # pragma: no cover
|
||||
CLASS_TYPES = (type, types.ClassType)
|
||||
|
||||
copy._deepcopy_dispatch[types.MethodType] = \
|
||||
lambda obj, memo: type(obj)(obj.im_func,
|
||||
copy.deepcopy(obj.im_self, memo),
|
||||
obj.im_class)
|
||||
|
||||
if sys.version_info[:2] == (3, 5):
|
||||
warnings.warn(
|
||||
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
|
||||
"This does not mean that there will be any immediate breaking changes, "
|
||||
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
|
||||
config_env_marker_pattern = re.compile(
|
||||
r"\${(?P<name>[^}^{:]+)(?P<separator>:?)(?P<default>.*?)}",
|
||||
)
|
||||
|
||||
cdef str _resolve_config_env_markers(config_content: str, envs_required: bool):
|
||||
def _resolve_config_env_markers(config_content, envs_required=False):
|
||||
"""Replace environment variable markers with their values."""
|
||||
findings = list(config_env_marker_pattern.finditer(config_content))
|
||||
|
||||
|
@ -92,19 +118,28 @@ cdef str _resolve_config_env_markers(config_content: str, envs_required: bool):
|
|||
return config_content
|
||||
|
||||
|
||||
cdef object _parse_ini_file(filepath, envs_required: bool | None):
|
||||
parser = IniConfigParser()
|
||||
|
||||
with open(filepath) as config_file:
|
||||
config_string = config_file.read()
|
||||
|
||||
if envs_required is not None:
|
||||
if sys.version_info[0] == 3:
|
||||
def _parse_ini_file(filepath, envs_required=False):
|
||||
parser = iniconfigparser.ConfigParser()
|
||||
with open(filepath) as config_file:
|
||||
config_string = _resolve_config_env_markers(
|
||||
config_string,
|
||||
config_file.read(),
|
||||
envs_required=envs_required,
|
||||
)
|
||||
parser.read_string(config_string)
|
||||
return parser
|
||||
parser.read_string(config_string)
|
||||
return parser
|
||||
else:
|
||||
import StringIO
|
||||
|
||||
def _parse_ini_file(filepath, envs_required=False):
|
||||
parser = iniconfigparser.ConfigParser()
|
||||
with open(filepath) as config_file:
|
||||
config_string = _resolve_config_env_markers(
|
||||
config_file.read(),
|
||||
envs_required=envs_required,
|
||||
)
|
||||
parser.readfp(StringIO.StringIO(config_string))
|
||||
return parser
|
||||
|
||||
|
||||
if yaml:
|
||||
|
@ -128,7 +163,7 @@ cdef int ASYNC_MODE_ENABLED = 1
|
|||
cdef int ASYNC_MODE_DISABLED = 2
|
||||
|
||||
cdef set __iscoroutine_typecache = set()
|
||||
cdef tuple __COROUTINE_TYPES = asyncio.coroutines._COROUTINE_TYPES
|
||||
cdef tuple __COROUTINE_TYPES = asyncio.coroutines._COROUTINE_TYPES if asyncio else tuple()
|
||||
|
||||
cdef dict pydantic_settings_to_dict(settings, dict kwargs):
|
||||
if not has_pydantic_settings:
|
||||
|
@ -138,7 +173,7 @@ cdef dict pydantic_settings_to_dict(settings, dict kwargs):
|
|||
f"\"pip install dependency-injector[{pydantic_extra}]\""
|
||||
)
|
||||
|
||||
if isinstance(settings, type) and issubclass(settings, PydanticSettings):
|
||||
if isinstance(settings, CLASS_TYPES) and issubclass(settings, PydanticSettings):
|
||||
raise Error(
|
||||
"Got settings class, but expect instance: "
|
||||
"instead \"{0}\" use \"{0}()\"".format(settings.__name__)
|
||||
|
@ -156,7 +191,7 @@ cdef dict pydantic_settings_to_dict(settings, dict kwargs):
|
|||
return settings.model_dump(mode="python", **kwargs)
|
||||
|
||||
|
||||
cdef class Provider:
|
||||
cdef class Provider(object):
|
||||
"""Base provider class.
|
||||
|
||||
:py:class:`Provider` is callable (implements ``__call__`` method). Every
|
||||
|
@ -878,9 +913,12 @@ cdef class Dependency(Provider):
|
|||
|
||||
def set_instance_of(self, instance_of):
|
||||
"""Set type."""
|
||||
if not isinstance(instance_of, type):
|
||||
if not isinstance(instance_of, CLASS_TYPES):
|
||||
raise TypeError(
|
||||
f"\"instance_of\" is not a class (got {instance_of!r}))",
|
||||
"\"instance_of\" has incorrect type (expected {0}, got {1}))".format(
|
||||
CLASS_TYPES,
|
||||
instance_of,
|
||||
),
|
||||
)
|
||||
self._instance_of = instance_of
|
||||
return self
|
||||
|
@ -1437,11 +1475,12 @@ cdef class Coroutine(Callable):
|
|||
some_coroutine.add_kwargs(keyword_argument1=3, keyword_argument=4)
|
||||
"""
|
||||
|
||||
_is_coroutine_marker = _is_coroutine_marker # Python >=3.12
|
||||
_is_coroutine = _is_coroutine # Python <3.16
|
||||
_is_coroutine = _is_coroutine_marker
|
||||
|
||||
def set_provides(self, provides):
|
||||
"""Set provider provides."""
|
||||
if not asyncio:
|
||||
raise Error("Package asyncio is not available")
|
||||
provides = _resolve_string_import(provides)
|
||||
if provides and not asyncio.iscoroutinefunction(provides):
|
||||
raise Error(f"Provider {_class_qualname(self)} expected to get coroutine function, "
|
||||
|
@ -1595,7 +1634,8 @@ cdef class ConfigurationOption(Provider):
|
|||
segment() if is_provider(segment) else segment for segment in self._name
|
||||
)
|
||||
|
||||
def _get_root(self):
|
||||
@property
|
||||
def root(self):
|
||||
return self._root
|
||||
|
||||
def get_name(self):
|
||||
|
@ -1673,7 +1713,7 @@ cdef class ConfigurationOption(Provider):
|
|||
try:
|
||||
parser = _parse_ini_file(
|
||||
filepath,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
except IOError as exception:
|
||||
if required is not False \
|
||||
|
@ -1732,11 +1772,10 @@ cdef class ConfigurationOption(Provider):
|
|||
raise
|
||||
return
|
||||
|
||||
if envs_required is not None:
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config = yaml.load(config_content, loader)
|
||||
|
||||
current_config = self.__call__()
|
||||
|
@ -1771,11 +1810,10 @@ cdef class ConfigurationOption(Provider):
|
|||
raise
|
||||
return
|
||||
|
||||
if envs_required is not None:
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config = json.loads(config_content)
|
||||
|
||||
current_config = self.__call__()
|
||||
|
@ -2228,7 +2266,7 @@ cdef class Configuration(Object):
|
|||
try:
|
||||
parser = _parse_ini_file(
|
||||
filepath,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
except IOError as exception:
|
||||
if required is not False \
|
||||
|
@ -2287,11 +2325,10 @@ cdef class Configuration(Object):
|
|||
raise
|
||||
return
|
||||
|
||||
if envs_required is not None:
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config = yaml.load(config_content, loader)
|
||||
|
||||
current_config = self.__call__()
|
||||
|
@ -2326,11 +2363,10 @@ cdef class Configuration(Object):
|
|||
raise
|
||||
return
|
||||
|
||||
if envs_required is not None:
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config_content = _resolve_config_env_markers(
|
||||
config_content,
|
||||
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
|
||||
)
|
||||
config = json.loads(config_content)
|
||||
|
||||
current_config = self.__call__()
|
||||
|
@ -3226,10 +3262,15 @@ cdef class ContextLocalSingleton(BaseSingleton):
|
|||
:param provides: Provided type.
|
||||
:type provides: type
|
||||
"""
|
||||
|
||||
if not contextvars:
|
||||
raise RuntimeError(
|
||||
"Contextvars library not found. This provider "
|
||||
"requires Python 3.7 or a backport of contextvars. "
|
||||
"To install a backport run \"pip install contextvars\"."
|
||||
)
|
||||
|
||||
super(ContextLocalSingleton, self).__init__(provides, *args, **kwargs)
|
||||
self._storage = ContextVar("_storage", default=self._none)
|
||||
self._storage = contextvars.ContextVar("_storage", default=self._none)
|
||||
|
||||
def reset(self):
|
||||
"""Reset cached instance, if any.
|
||||
|
@ -3601,17 +3642,6 @@ cdef class Dict(Provider):
|
|||
return __provide_keyword_args(kwargs, self._kwargs, self._kwargs_len, self._async_mode)
|
||||
|
||||
|
||||
@cython.no_gc
|
||||
cdef class NullAwaitable:
|
||||
def __next__(self):
|
||||
raise StopIteration from None
|
||||
|
||||
def __await__(self):
|
||||
return self
|
||||
|
||||
|
||||
cdef NullAwaitable NULL_AWAITABLE = NullAwaitable()
|
||||
|
||||
|
||||
cdef class Resource(Provider):
|
||||
"""Resource provider provides a component with initialization and shutdown."""
|
||||
|
@ -3667,12 +3697,6 @@ cdef class Resource(Provider):
|
|||
def set_provides(self, provides):
|
||||
"""Set provider provides."""
|
||||
provides = _resolve_string_import(provides)
|
||||
|
||||
if isasyncgenfunction(provides):
|
||||
provides = asynccontextmanager(provides)
|
||||
elif isgeneratorfunction(provides):
|
||||
provides = contextmanager(provides)
|
||||
|
||||
self._provides = provides
|
||||
return self
|
||||
|
||||
|
@ -3773,21 +3797,28 @@ cdef class Resource(Provider):
|
|||
"""Shutdown resource."""
|
||||
if not self._initialized:
|
||||
if self._async_mode == ASYNC_MODE_ENABLED:
|
||||
return NULL_AWAITABLE
|
||||
result = asyncio.Future()
|
||||
result.set_result(None)
|
||||
return result
|
||||
return
|
||||
|
||||
if self._shutdowner:
|
||||
future = self._shutdowner(None, None, None)
|
||||
|
||||
if __is_future_or_coroutine(future):
|
||||
return ensure_future(self._shutdown_async(future))
|
||||
try:
|
||||
shutdown = self._shutdowner(self._resource)
|
||||
except StopIteration:
|
||||
pass
|
||||
else:
|
||||
if inspect.isawaitable(shutdown):
|
||||
return self._create_shutdown_future(shutdown)
|
||||
|
||||
self._resource = None
|
||||
self._initialized = False
|
||||
self._shutdowner = None
|
||||
|
||||
if self._async_mode == ASYNC_MODE_ENABLED:
|
||||
return NULL_AWAITABLE
|
||||
result = asyncio.Future()
|
||||
result.set_result(None)
|
||||
return result
|
||||
|
||||
@property
|
||||
def related(self):
|
||||
|
@ -3797,75 +3828,169 @@ cdef class Resource(Provider):
|
|||
yield from filter(is_provider, self.kwargs.values())
|
||||
yield from super().related
|
||||
|
||||
async def _shutdown_async(self, future) -> None:
|
||||
try:
|
||||
await future
|
||||
finally:
|
||||
self._resource = None
|
||||
self._initialized = False
|
||||
self._shutdowner = None
|
||||
|
||||
async def _handle_async_cm(self, obj) -> None:
|
||||
try:
|
||||
self._resource = resource = await obj.__aenter__()
|
||||
self._shutdowner = obj.__aexit__
|
||||
return resource
|
||||
except:
|
||||
self._initialized = False
|
||||
raise
|
||||
|
||||
async def _provide_async(self, future) -> None:
|
||||
try:
|
||||
obj = await future
|
||||
|
||||
if hasattr(obj, '__aenter__') and hasattr(obj, '__aexit__'):
|
||||
self._resource = await obj.__aenter__()
|
||||
self._shutdowner = obj.__aexit__
|
||||
elif hasattr(obj, '__enter__') and hasattr(obj, '__exit__'):
|
||||
self._resource = obj.__enter__()
|
||||
self._shutdowner = obj.__exit__
|
||||
else:
|
||||
self._resource = obj
|
||||
self._shutdowner = None
|
||||
|
||||
return self._resource
|
||||
except:
|
||||
self._initialized = False
|
||||
raise
|
||||
|
||||
cpdef object _provide(self, tuple args, dict kwargs):
|
||||
if self._initialized:
|
||||
return self._resource
|
||||
|
||||
obj = __call(
|
||||
self._provides,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
|
||||
if __is_future_or_coroutine(obj):
|
||||
if self._is_resource_subclass(self._provides):
|
||||
initializer = self._provides()
|
||||
self._resource = __call(
|
||||
initializer.init,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
self._shutdowner = initializer.shutdown
|
||||
elif self._is_async_resource_subclass(self._provides):
|
||||
initializer = self._provides()
|
||||
async_init = __call(
|
||||
initializer.init,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
self._initialized = True
|
||||
self._resource = resource = ensure_future(self._provide_async(obj))
|
||||
return resource
|
||||
elif hasattr(obj, '__enter__') and hasattr(obj, '__exit__'):
|
||||
self._resource = obj.__enter__()
|
||||
self._shutdowner = obj.__exit__
|
||||
elif hasattr(obj, '__aenter__') and hasattr(obj, '__aexit__'):
|
||||
return self._create_init_future(async_init, initializer.shutdown)
|
||||
elif inspect.isgeneratorfunction(self._provides):
|
||||
initializer = __call(
|
||||
self._provides,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
self._resource = next(initializer)
|
||||
self._shutdowner = initializer.send
|
||||
elif iscoroutinefunction(self._provides):
|
||||
initializer = __call(
|
||||
self._provides,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
self._initialized = True
|
||||
self._resource = resource = ensure_future(self._handle_async_cm(obj))
|
||||
return resource
|
||||
return self._create_init_future(initializer)
|
||||
elif isasyncgenfunction(self._provides):
|
||||
initializer = __call(
|
||||
self._provides,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
self._initialized = True
|
||||
return self._create_async_gen_init_future(initializer)
|
||||
elif callable(self._provides):
|
||||
self._resource = __call(
|
||||
self._provides,
|
||||
args,
|
||||
self._args,
|
||||
self._args_len,
|
||||
kwargs,
|
||||
self._kwargs,
|
||||
self._kwargs_len,
|
||||
self._async_mode,
|
||||
)
|
||||
else:
|
||||
self._resource = obj
|
||||
self._shutdowner = None
|
||||
raise Error("Unknown type of resource initializer")
|
||||
|
||||
self._initialized = True
|
||||
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 _create_async_gen_init_future(self, initializer):
|
||||
if inspect.isasyncgen(initializer):
|
||||
return self._create_init_future(initializer.__anext__(), initializer.asend)
|
||||
|
||||
future = asyncio.Future()
|
||||
|
||||
create_initializer = asyncio.ensure_future(initializer)
|
||||
create_initializer.add_done_callback(functools.partial(self._async_create_gen_callback, future))
|
||||
self._resource = future
|
||||
|
||||
return future
|
||||
|
||||
def _async_init_callback(self, initializer, shutdowner=None):
|
||||
try:
|
||||
resource = initializer.result()
|
||||
except Exception:
|
||||
self._initialized = False
|
||||
else:
|
||||
self._resource = resource
|
||||
self._shutdowner = shutdowner
|
||||
|
||||
def _async_create_gen_callback(self, future, initializer_future):
|
||||
initializer = initializer_future.result()
|
||||
init_future = self._create_init_future(initializer.__anext__(), initializer.asend)
|
||||
init_future.add_done_callback(functools.partial(self._async_trigger_result, future))
|
||||
|
||||
def _async_trigger_result(self, future, future_result):
|
||||
future.set_result(future_result.result())
|
||||
|
||||
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
|
||||
def _is_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.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):
|
||||
"""Container provider provides an instance of declarative container.
|
||||
|
@ -4519,7 +4644,7 @@ cdef class MethodCaller(Provider):
|
|||
future_result.set_result(result)
|
||||
|
||||
|
||||
cdef class Injection:
|
||||
cdef class Injection(object):
|
||||
"""Abstract injection class."""
|
||||
|
||||
|
||||
|
@ -4646,7 +4771,7 @@ cpdef tuple parse_named_injections(dict kwargs):
|
|||
return tuple(injections)
|
||||
|
||||
|
||||
cdef class OverridingContext:
|
||||
cdef class OverridingContext(object):
|
||||
"""Provider overriding context.
|
||||
|
||||
:py:class:`OverridingContext` is used by :py:meth:`Provider.override` for
|
||||
|
@ -4682,7 +4807,7 @@ cdef class OverridingContext:
|
|||
self._overridden.reset_last_overriding()
|
||||
|
||||
|
||||
cdef class BaseSingletonResetContext:
|
||||
cdef class BaseSingletonResetContext(object):
|
||||
|
||||
def __init__(self, Provider provider):
|
||||
self._singleton = provider
|
||||
|
@ -4718,7 +4843,7 @@ cpdef bint is_provider(object instance):
|
|||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, type) and
|
||||
return (not isinstance(instance, CLASS_TYPES) and
|
||||
getattr(instance, "__IS_PROVIDER__", False) is True)
|
||||
|
||||
|
||||
|
@ -4746,7 +4871,7 @@ cpdef bint is_delegated(object instance):
|
|||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, type) and
|
||||
return (not isinstance(instance, CLASS_TYPES) and
|
||||
getattr(instance, "__IS_DELEGATED__", False) is True)
|
||||
|
||||
|
||||
|
@ -4777,7 +4902,7 @@ cpdef bint is_container_instance(object instance):
|
|||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (not isinstance(instance, type) and
|
||||
return (not isinstance(instance, CLASS_TYPES) and
|
||||
getattr(instance, "__IS_CONTAINER__", False) is True)
|
||||
|
||||
|
||||
|
@ -4789,7 +4914,7 @@ cpdef bint is_container_class(object instance):
|
|||
|
||||
:rtype: bool
|
||||
"""
|
||||
return (isinstance(instance, type) and
|
||||
return (isinstance(instance, CLASS_TYPES) and
|
||||
getattr(instance, "__IS_CONTAINER__", False) is True)
|
||||
|
||||
|
||||
|
@ -4916,6 +5041,14 @@ def iscoroutinefunction(obj):
|
|||
return False
|
||||
|
||||
|
||||
def isasyncgenfunction(obj):
|
||||
"""Check if object is an asynchronous generator function."""
|
||||
try:
|
||||
return inspect.isasyncgenfunction(obj)
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
def _resolve_string_import(provides):
|
||||
if provides is None:
|
||||
return provides
|
||||
|
|
|
@ -1,54 +1,27 @@
|
|||
"""Resources module."""
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from typing import Any, ClassVar, Generic, Optional, Tuple, TypeVar
|
||||
import abc
|
||||
from typing import TypeVar, Generic, Optional
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class Resource(Generic[T], metaclass=ABCMeta):
|
||||
__slots__: ClassVar[Tuple[str, ...]] = ("args", "kwargs", "obj")
|
||||
class Resource(Generic[T], metaclass=abc.ABCMeta):
|
||||
|
||||
obj: Optional[T]
|
||||
@abc.abstractmethod
|
||||
def init(self, *args, **kwargs) -> Optional[T]:
|
||||
...
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.obj = None
|
||||
|
||||
@abstractmethod
|
||||
def init(self, *args: Any, **kwargs: Any) -> Optional[T]: ...
|
||||
|
||||
def shutdown(self, resource: Optional[T]) -> None: ...
|
||||
|
||||
def __enter__(self) -> Optional[T]:
|
||||
self.obj = obj = self.init(*self.args, **self.kwargs)
|
||||
return obj
|
||||
|
||||
def __exit__(self, *exc_info: Any) -> None:
|
||||
self.shutdown(self.obj)
|
||||
self.obj = None
|
||||
def shutdown(self, resource: Optional[T]) -> None:
|
||||
...
|
||||
|
||||
|
||||
class AsyncResource(Generic[T], metaclass=ABCMeta):
|
||||
__slots__: ClassVar[Tuple[str, ...]] = ("args", "kwargs", "obj")
|
||||
class AsyncResource(Generic[T], metaclass=abc.ABCMeta):
|
||||
|
||||
obj: Optional[T]
|
||||
@abc.abstractmethod
|
||||
async def init(self, *args, **kwargs) -> Optional[T]:
|
||||
...
|
||||
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
self.obj = None
|
||||
|
||||
@abstractmethod
|
||||
async def init(self, *args: Any, **kwargs: Any) -> Optional[T]: ...
|
||||
|
||||
async def shutdown(self, resource: Optional[T]) -> None: ...
|
||||
|
||||
async def __aenter__(self) -> Optional[T]:
|
||||
self.obj = obj = await self.init(*self.args, **self.kwargs)
|
||||
return obj
|
||||
|
||||
async def __aexit__(self, *exc_info: Any) -> None:
|
||||
await self.shutdown(self.obj)
|
||||
self.obj = None
|
||||
async def shutdown(self, resource: Optional[T]) -> None:
|
||||
...
|
||||
|
|
|
@ -27,9 +27,9 @@ class SchemaProcessorV1:
|
|||
return self._container.providers
|
||||
|
||||
def _create_providers(
|
||||
self,
|
||||
provider_schema: ProviderSchema,
|
||||
container: Optional[containers.Container] = None,
|
||||
self,
|
||||
provider_schema: ProviderSchema,
|
||||
container: Optional[containers.Container] = None,
|
||||
) -> None:
|
||||
if container is None:
|
||||
container = self._container
|
||||
|
@ -57,9 +57,9 @@ class SchemaProcessorV1:
|
|||
self._create_providers(provider_schema=data, container=provider)
|
||||
|
||||
def _setup_injections( # noqa: C901
|
||||
self,
|
||||
provider_schema: ProviderSchema,
|
||||
container: Optional[containers.Container] = None,
|
||||
self,
|
||||
provider_schema: ProviderSchema,
|
||||
container: Optional[containers.Container] = None,
|
||||
) -> None:
|
||||
if container is None:
|
||||
container = self._container
|
||||
|
@ -72,7 +72,7 @@ class SchemaProcessorV1:
|
|||
provides = data.get("provides")
|
||||
if provides:
|
||||
if isinstance(provides, str) and provides.startswith("container."):
|
||||
provides = self._resolve_provider(provides[len("container.") :])
|
||||
provides = self._resolve_provider(provides[len("container."):])
|
||||
else:
|
||||
provides = _import_string(provides)
|
||||
provider.set_provides(provides)
|
||||
|
@ -83,7 +83,7 @@ class SchemaProcessorV1:
|
|||
injection = None
|
||||
|
||||
if isinstance(arg, str) and arg.startswith("container."):
|
||||
injection = self._resolve_provider(arg[len("container.") :])
|
||||
injection = self._resolve_provider(arg[len("container."):])
|
||||
|
||||
# TODO: refactoring
|
||||
if isinstance(arg, dict):
|
||||
|
@ -91,23 +91,16 @@ class SchemaProcessorV1:
|
|||
provider_type = _get_provider_cls(arg.get("provider"))
|
||||
provides = arg.get("provides")
|
||||
if provides:
|
||||
if isinstance(provides, str) and provides.startswith(
|
||||
"container."
|
||||
):
|
||||
provides = self._resolve_provider(
|
||||
provides[len("container.") :]
|
||||
)
|
||||
if isinstance(provides, str) and provides.startswith("container."):
|
||||
provides = self._resolve_provider(provides[len("container."):])
|
||||
else:
|
||||
provides = _import_string(provides)
|
||||
provider_args.append(provides)
|
||||
for provider_arg in arg.get("args", []):
|
||||
if isinstance(
|
||||
provider_arg, str
|
||||
) and provider_arg.startswith("container."):
|
||||
if isinstance(provider_arg, str) \
|
||||
and provider_arg.startswith("container."):
|
||||
provider_args.append(
|
||||
self._resolve_provider(
|
||||
provider_arg[len("container.") :]
|
||||
),
|
||||
self._resolve_provider(provider_arg[len("container."):]),
|
||||
)
|
||||
injection = provider_type(*provider_args)
|
||||
|
||||
|
@ -124,7 +117,7 @@ class SchemaProcessorV1:
|
|||
injection = None
|
||||
|
||||
if isinstance(arg, str) and arg.startswith("container."):
|
||||
injection = self._resolve_provider(arg[len("container.") :])
|
||||
injection = self._resolve_provider(arg[len("container."):])
|
||||
|
||||
# TODO: refactoring
|
||||
if isinstance(arg, dict):
|
||||
|
@ -132,23 +125,16 @@ class SchemaProcessorV1:
|
|||
provider_type = _get_provider_cls(arg.get("provider"))
|
||||
provides = arg.get("provides")
|
||||
if provides:
|
||||
if isinstance(provides, str) and provides.startswith(
|
||||
"container."
|
||||
):
|
||||
provides = self._resolve_provider(
|
||||
provides[len("container.") :]
|
||||
)
|
||||
if isinstance(provides, str) and provides.startswith("container."):
|
||||
provides = self._resolve_provider(provides[len("container."):])
|
||||
else:
|
||||
provides = _import_string(provides)
|
||||
provider_args.append(provides)
|
||||
for provider_arg in arg.get("args", []):
|
||||
if isinstance(
|
||||
provider_arg, str
|
||||
) and provider_arg.startswith("container."):
|
||||
if isinstance(provider_arg, str) \
|
||||
and provider_arg.startswith("container."):
|
||||
provider_args.append(
|
||||
self._resolve_provider(
|
||||
provider_arg[len("container.") :]
|
||||
),
|
||||
self._resolve_provider(provider_arg[len("container."):]),
|
||||
)
|
||||
injection = provider_type(*provider_args)
|
||||
|
||||
|
@ -172,7 +158,7 @@ class SchemaProcessorV1:
|
|||
for segment in segments[1:]:
|
||||
parentheses = ""
|
||||
if "(" in segment and ")" in segment:
|
||||
parentheses = segment[segment.find("(") : segment.rfind(")") + 1]
|
||||
parentheses = segment[segment.find("("):segment.rfind(")")+1]
|
||||
segment = segment.replace(parentheses, "")
|
||||
|
||||
try:
|
||||
|
@ -204,12 +190,10 @@ def _get_provider_cls(provider_cls_name: str) -> Type[providers.Provider]:
|
|||
if custom_provider_type:
|
||||
return custom_provider_type
|
||||
|
||||
raise SchemaError(f'Undefined provider class "{provider_cls_name}"')
|
||||
raise SchemaError(f"Undefined provider class \"{provider_cls_name}\"")
|
||||
|
||||
|
||||
def _fetch_provider_cls_from_std(
|
||||
provider_cls_name: str,
|
||||
) -> Optional[Type[providers.Provider]]:
|
||||
def _fetch_provider_cls_from_std(provider_cls_name: str) -> Optional[Type[providers.Provider]]:
|
||||
return getattr(providers, provider_cls_name, None)
|
||||
|
||||
|
||||
|
@ -217,16 +201,12 @@ def _import_provider_cls(provider_cls_name: str) -> Optional[Type[providers.Prov
|
|||
try:
|
||||
cls = _import_string(provider_cls_name)
|
||||
except (ImportError, ValueError) as exception:
|
||||
raise SchemaError(
|
||||
f'Can not import provider "{provider_cls_name}"'
|
||||
) from exception
|
||||
raise SchemaError(f"Can not import provider \"{provider_cls_name}\"") from exception
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
if isinstance(cls, type) and not issubclass(cls, providers.Provider):
|
||||
raise SchemaError(
|
||||
f'Provider class "{cls}" is not a subclass of providers base class'
|
||||
)
|
||||
raise SchemaError(f"Provider class \"{cls}\" is not a subclass of providers base class")
|
||||
return cls
|
||||
|
||||
|
||||
|
|
|
@ -1,45 +1,34 @@
|
|||
"""Wiring module."""
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import importlib
|
||||
import importlib.machinery
|
||||
import inspect
|
||||
import pkgutil
|
||||
import warnings
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from inspect import isbuiltin, isclass
|
||||
from types import ModuleType
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
AsyncIterator,
|
||||
Callable,
|
||||
Dict,
|
||||
Optional,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
Protocol,
|
||||
Set,
|
||||
Callable,
|
||||
Any,
|
||||
Tuple,
|
||||
Type,
|
||||
Dict,
|
||||
Generic,
|
||||
TypeVar,
|
||||
Type,
|
||||
Union,
|
||||
Set,
|
||||
cast,
|
||||
)
|
||||
from warnings import warn
|
||||
|
||||
try:
|
||||
from typing import Self
|
||||
except ImportError:
|
||||
from typing_extensions import Self
|
||||
|
||||
try:
|
||||
from functools import cache
|
||||
except ImportError:
|
||||
from functools import lru_cache
|
||||
|
||||
cache = lru_cache(maxsize=None)
|
||||
if sys.version_info < (3, 7):
|
||||
from typing import GenericMeta
|
||||
else:
|
||||
class GenericMeta(type):
|
||||
...
|
||||
|
||||
# Hotfix, see: https://github.com/ets-labs/python-dependency-injector/issues/362
|
||||
if sys.version_info >= (3, 9):
|
||||
|
@ -47,64 +36,34 @@ if sys.version_info >= (3, 9):
|
|||
else:
|
||||
GenericAlias = None
|
||||
|
||||
if sys.version_info >= (3, 9):
|
||||
from typing import Annotated, get_args, get_origin
|
||||
else:
|
||||
try:
|
||||
from typing_extensions import Annotated, get_args, get_origin
|
||||
except ImportError:
|
||||
Annotated = object()
|
||||
|
||||
# For preventing NameError. Never executes
|
||||
def get_args(hint):
|
||||
return ()
|
||||
|
||||
def get_origin(tp):
|
||||
return None
|
||||
try:
|
||||
import fastapi.params
|
||||
except ImportError:
|
||||
fastapi = None
|
||||
|
||||
|
||||
MARKER_EXTRACTORS: List[Callable[[Any], Any]] = []
|
||||
INSPECT_EXCLUSION_FILTERS: List[Callable[[Any], bool]] = [isbuiltin]
|
||||
|
||||
with suppress(ImportError):
|
||||
from fastapi.params import Depends as FastAPIDepends
|
||||
|
||||
def extract_marker_from_fastapi(param: Any) -> Any:
|
||||
if isinstance(param, FastAPIDepends):
|
||||
return param.dependency
|
||||
return None
|
||||
|
||||
MARKER_EXTRACTORS.append(extract_marker_from_fastapi)
|
||||
|
||||
with suppress(ImportError):
|
||||
from fast_depends.dependencies import Depends as FastDepends
|
||||
|
||||
def extract_marker_from_fast_depends(param: Any) -> Any:
|
||||
if isinstance(param, FastDepends):
|
||||
return param.dependency
|
||||
return None
|
||||
|
||||
MARKER_EXTRACTORS.append(extract_marker_from_fast_depends)
|
||||
try:
|
||||
import starlette.requests
|
||||
except ImportError:
|
||||
starlette = None
|
||||
|
||||
|
||||
with suppress(ImportError):
|
||||
from starlette.requests import Request as StarletteRequest
|
||||
|
||||
def is_starlette_request_cls(obj: Any) -> bool:
|
||||
return isclass(obj) and _safe_is_subclass(obj, StarletteRequest)
|
||||
|
||||
INSPECT_EXCLUSION_FILTERS.append(is_starlette_request_cls)
|
||||
try:
|
||||
import werkzeug.local
|
||||
except ImportError:
|
||||
werkzeug = None
|
||||
|
||||
|
||||
with suppress(ImportError):
|
||||
from werkzeug.local import LocalProxy as WerkzeugLocalProxy
|
||||
from . import providers
|
||||
|
||||
def is_werkzeug_local_proxy(obj: Any) -> bool:
|
||||
return isinstance(obj, WerkzeugLocalProxy)
|
||||
|
||||
INSPECT_EXCLUSION_FILTERS.append(is_werkzeug_local_proxy)
|
||||
|
||||
from . import providers # noqa: E402
|
||||
if sys.version_info[:2] == (3, 5):
|
||||
warnings.warn(
|
||||
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
|
||||
"This does not mean that there will be any immediate breaking changes, "
|
||||
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
|
||||
category=DeprecationWarning,
|
||||
)
|
||||
|
||||
__all__ = (
|
||||
"wire",
|
||||
|
@ -128,15 +87,7 @@ __all__ = (
|
|||
|
||||
T = TypeVar("T")
|
||||
F = TypeVar("F", bound=Callable[..., Any])
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .containers import Container
|
||||
else:
|
||||
Container = Any
|
||||
|
||||
|
||||
class DIWiringWarning(RuntimeWarning):
|
||||
"""Base class for all warnings raised by the wiring module."""
|
||||
Container = Any
|
||||
|
||||
|
||||
class PatchedRegistry:
|
||||
|
@ -148,9 +99,7 @@ class PatchedRegistry:
|
|||
def register_callable(self, patched: "PatchedCallable") -> None:
|
||||
self._callables[patched.patched] = patched
|
||||
|
||||
def get_callables_from_module(
|
||||
self, module: ModuleType
|
||||
) -> Iterator[Callable[..., Any]]:
|
||||
def get_callables_from_module(self, module: ModuleType) -> Iterator[Callable[..., Any]]:
|
||||
for patched_callable in self._callables.values():
|
||||
if not patched_callable.is_in_module(module):
|
||||
continue
|
||||
|
@ -165,9 +114,7 @@ class PatchedRegistry:
|
|||
def register_attribute(self, patched: "PatchedAttribute") -> None:
|
||||
self._attributes.add(patched)
|
||||
|
||||
def get_attributes_from_module(
|
||||
self, module: ModuleType
|
||||
) -> Iterator["PatchedAttribute"]:
|
||||
def get_attributes_from_module(self, module: ModuleType) -> Iterator["PatchedAttribute"]:
|
||||
for attribute in self._attributes:
|
||||
if not attribute.is_in_module(module):
|
||||
continue
|
||||
|
@ -192,11 +139,11 @@ class PatchedCallable:
|
|||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
patched: Optional[Callable[..., Any]] = None,
|
||||
original: Optional[Callable[..., Any]] = None,
|
||||
reference_injections: Optional[Dict[Any, Any]] = None,
|
||||
reference_closing: Optional[Dict[Any, Any]] = None,
|
||||
self,
|
||||
patched: Optional[Callable[..., Any]] = None,
|
||||
original: Optional[Callable[..., Any]] = None,
|
||||
reference_injections: Optional[Dict[Any, Any]] = None,
|
||||
reference_closing: Optional[Dict[Any, Any]] = None,
|
||||
) -> None:
|
||||
self.patched = patched
|
||||
self.original = original
|
||||
|
@ -267,21 +214,18 @@ class ProvidersMap:
|
|||
)
|
||||
|
||||
def resolve_provider(
|
||||
self,
|
||||
provider: Union[providers.Provider, str],
|
||||
modifier: Optional["Modifier"] = None,
|
||||
self,
|
||||
provider: Union[providers.Provider, str],
|
||||
modifier: Optional["Modifier"] = None,
|
||||
) -> Optional[providers.Provider]:
|
||||
if isinstance(provider, providers.Delegate):
|
||||
return self._resolve_delegate(provider)
|
||||
elif isinstance(
|
||||
provider,
|
||||
(
|
||||
providers.ProvidedInstance,
|
||||
providers.AttributeGetter,
|
||||
providers.ItemGetter,
|
||||
providers.MethodCaller,
|
||||
),
|
||||
):
|
||||
elif isinstance(provider, (
|
||||
providers.ProvidedInstance,
|
||||
providers.AttributeGetter,
|
||||
providers.ItemGetter,
|
||||
providers.MethodCaller,
|
||||
)):
|
||||
return self._resolve_provided_instance(provider)
|
||||
elif isinstance(provider, providers.ConfigurationOption):
|
||||
return self._resolve_config_option(provider)
|
||||
|
@ -293,9 +237,9 @@ class ProvidersMap:
|
|||
return self._resolve_provider(provider)
|
||||
|
||||
def _resolve_string_id(
|
||||
self,
|
||||
id: str,
|
||||
modifier: Optional["Modifier"] = None,
|
||||
self,
|
||||
id: str,
|
||||
modifier: Optional["Modifier"] = None,
|
||||
) -> Optional[providers.Provider]:
|
||||
if id == self.CONTAINER_STRING_ID:
|
||||
return self._container.__self__
|
||||
|
@ -312,19 +256,16 @@ class ProvidersMap:
|
|||
return provider
|
||||
|
||||
def _resolve_provided_instance(
|
||||
self,
|
||||
original: providers.Provider,
|
||||
self,
|
||||
original: providers.Provider,
|
||||
) -> Optional[providers.Provider]:
|
||||
modifiers = []
|
||||
while isinstance(
|
||||
original,
|
||||
(
|
||||
while isinstance(original, (
|
||||
providers.ProvidedInstance,
|
||||
providers.AttributeGetter,
|
||||
providers.ItemGetter,
|
||||
providers.MethodCaller,
|
||||
),
|
||||
):
|
||||
)):
|
||||
modifiers.insert(0, original)
|
||||
original = original.provides
|
||||
|
||||
|
@ -348,8 +289,8 @@ class ProvidersMap:
|
|||
return new
|
||||
|
||||
def _resolve_delegate(
|
||||
self,
|
||||
original: providers.Delegate,
|
||||
self,
|
||||
original: providers.Delegate,
|
||||
) -> Optional[providers.Provider]:
|
||||
provider = self._resolve_provider(original.provides)
|
||||
if provider:
|
||||
|
@ -357,11 +298,11 @@ class ProvidersMap:
|
|||
return provider
|
||||
|
||||
def _resolve_config_option(
|
||||
self,
|
||||
original: providers.ConfigurationOption,
|
||||
as_: Any = None,
|
||||
self,
|
||||
original: providers.ConfigurationOption,
|
||||
as_: Any = None,
|
||||
) -> Optional[providers.Provider]:
|
||||
original_root = original._get_root()
|
||||
original_root = original.root
|
||||
new = self._resolve_provider(original_root)
|
||||
if new is None:
|
||||
return None
|
||||
|
@ -383,8 +324,8 @@ class ProvidersMap:
|
|||
return new
|
||||
|
||||
def _resolve_provider(
|
||||
self,
|
||||
original: providers.Provider,
|
||||
self,
|
||||
original: providers.Provider,
|
||||
) -> Optional[providers.Provider]:
|
||||
try:
|
||||
return self._map[original]
|
||||
|
@ -393,9 +334,9 @@ class ProvidersMap:
|
|||
|
||||
@classmethod
|
||||
def _create_providers_map(
|
||||
cls,
|
||||
current_container: Container,
|
||||
original_container: Container,
|
||||
cls,
|
||||
current_container: Container,
|
||||
original_container: Container,
|
||||
) -> Dict[providers.Provider, providers.Provider]:
|
||||
current_providers = current_container.providers
|
||||
current_providers["__self__"] = current_container.__self__
|
||||
|
@ -408,9 +349,8 @@ class ProvidersMap:
|
|||
original_provider = original_providers[provider_name]
|
||||
providers_map[original_provider] = current_provider
|
||||
|
||||
if isinstance(current_provider, providers.Container) and isinstance(
|
||||
original_provider, providers.Container
|
||||
):
|
||||
if isinstance(current_provider, providers.Container) \
|
||||
and isinstance(original_provider, providers.Container):
|
||||
subcontainer_map = cls._create_providers_map(
|
||||
current_container=current_provider.container,
|
||||
original_container=original_provider.container,
|
||||
|
@ -420,19 +360,35 @@ class ProvidersMap:
|
|||
return providers_map
|
||||
|
||||
|
||||
def is_excluded_from_inspect(obj: Any) -> bool:
|
||||
for is_excluded in INSPECT_EXCLUSION_FILTERS:
|
||||
if is_excluded(obj):
|
||||
class InspectFilter:
|
||||
|
||||
def is_excluded(self, instance: object) -> bool:
|
||||
if self._is_werkzeug_local_proxy(instance):
|
||||
return True
|
||||
return False
|
||||
elif self._is_starlette_request_cls(instance):
|
||||
return True
|
||||
elif self._is_builtin(instance):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _is_werkzeug_local_proxy(self, instance: object) -> bool:
|
||||
return werkzeug and isinstance(instance, werkzeug.local.LocalProxy)
|
||||
|
||||
def _is_starlette_request_cls(self, instance: object) -> bool:
|
||||
return starlette \
|
||||
and isinstance(instance, type) \
|
||||
and _safe_is_subclass(instance, starlette.requests.Request)
|
||||
|
||||
def _is_builtin(self, instance: object) -> bool:
|
||||
return inspect.isbuiltin(instance)
|
||||
|
||||
|
||||
def wire( # noqa: C901
|
||||
container: Container,
|
||||
*,
|
||||
modules: Optional[Iterable[ModuleType]] = None,
|
||||
packages: Optional[Iterable[ModuleType]] = None,
|
||||
keep_cache: bool = False,
|
||||
container: Container,
|
||||
*,
|
||||
modules: Optional[Iterable[ModuleType]] = None,
|
||||
packages: Optional[Iterable[ModuleType]] = None,
|
||||
) -> None:
|
||||
"""Wire container providers with provided packages and modules."""
|
||||
modules = [*modules] if modules else []
|
||||
|
@ -444,8 +400,8 @@ def wire( # noqa: C901
|
|||
providers_map = ProvidersMap(container)
|
||||
|
||||
for module in modules:
|
||||
for member_name, member in _get_members_and_annotated(module):
|
||||
if is_excluded_from_inspect(member):
|
||||
for member_name, member in inspect.getmembers(module):
|
||||
if _inspect_filter.is_excluded(member):
|
||||
continue
|
||||
|
||||
if _is_marker(member):
|
||||
|
@ -455,32 +411,25 @@ def wire( # noqa: C901
|
|||
elif inspect.isclass(member):
|
||||
cls = member
|
||||
try:
|
||||
cls_members = _get_members_and_annotated(cls)
|
||||
cls_members = inspect.getmembers(cls)
|
||||
except Exception: # noqa
|
||||
# Hotfix, see: https://github.com/ets-labs/python-dependency-injector/issues/441
|
||||
continue
|
||||
else:
|
||||
for cls_member_name, cls_member in cls_members:
|
||||
if _is_marker(cls_member):
|
||||
_patch_attribute(
|
||||
cls, cls_member_name, cls_member, providers_map
|
||||
)
|
||||
_patch_attribute(cls, cls_member_name, cls_member, providers_map)
|
||||
elif _is_method(cls_member):
|
||||
_patch_method(
|
||||
cls, cls_member_name, cls_member, providers_map
|
||||
)
|
||||
_patch_method(cls, cls_member_name, cls_member, providers_map)
|
||||
|
||||
for patched in _patched_registry.get_callables_from_module(module):
|
||||
_bind_injections(patched, providers_map)
|
||||
|
||||
if not keep_cache:
|
||||
clear_cache()
|
||||
|
||||
|
||||
def unwire( # noqa: C901
|
||||
*,
|
||||
modules: Optional[Iterable[ModuleType]] = None,
|
||||
packages: Optional[Iterable[ModuleType]] = None,
|
||||
*,
|
||||
modules: Optional[Iterable[ModuleType]] = None,
|
||||
packages: Optional[Iterable[ModuleType]] = None,
|
||||
) -> None:
|
||||
"""Wire provided packages and modules with previous wired providers."""
|
||||
modules = [*modules] if modules else []
|
||||
|
@ -494,9 +443,7 @@ def unwire( # noqa: C901
|
|||
if inspect.isfunction(member):
|
||||
_unpatch(module, name, member)
|
||||
elif inspect.isclass(member):
|
||||
for method_name, method in inspect.getmembers(
|
||||
member, inspect.isfunction
|
||||
):
|
||||
for method_name, method in inspect.getmembers(member, inspect.isfunction):
|
||||
_unpatch(member, method_name, method)
|
||||
|
||||
for patched in _patched_registry.get_callables_from_module(module):
|
||||
|
@ -510,20 +457,15 @@ def unwire( # noqa: C901
|
|||
def inject(fn: F) -> F:
|
||||
"""Decorate callable with injecting decorator."""
|
||||
reference_injections, reference_closing = _fetch_reference_injections(fn)
|
||||
|
||||
if not reference_injections:
|
||||
warn("@inject is not required here", DIWiringWarning, stacklevel=2)
|
||||
return fn
|
||||
|
||||
patched = _get_patched(fn, reference_injections, reference_closing)
|
||||
return cast(F, patched)
|
||||
|
||||
|
||||
def _patch_fn(
|
||||
module: ModuleType,
|
||||
name: str,
|
||||
fn: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
module: ModuleType,
|
||||
name: str,
|
||||
fn: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
) -> None:
|
||||
if not _is_patched(fn):
|
||||
reference_injections, reference_closing = _fetch_reference_injections(fn)
|
||||
|
@ -537,16 +479,14 @@ def _patch_fn(
|
|||
|
||||
|
||||
def _patch_method(
|
||||
cls: Type,
|
||||
name: str,
|
||||
method: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
cls: Type,
|
||||
name: str,
|
||||
method: Callable[..., Any],
|
||||
providers_map: ProvidersMap,
|
||||
) -> None:
|
||||
if (
|
||||
hasattr(cls, "__dict__")
|
||||
and name in cls.__dict__
|
||||
and isinstance(cls.__dict__[name], (classmethod, staticmethod))
|
||||
):
|
||||
if hasattr(cls, "__dict__") \
|
||||
and name in cls.__dict__ \
|
||||
and isinstance(cls.__dict__[name], (classmethod, staticmethod)):
|
||||
method = cls.__dict__[name]
|
||||
fn = method.__func__
|
||||
else:
|
||||
|
@ -560,10 +500,6 @@ def _patch_method(
|
|||
|
||||
_bind_injections(fn, providers_map)
|
||||
|
||||
if fn is method:
|
||||
# Hotfix, see: https://github.com/ets-labs/python-dependency-injector/issues/884
|
||||
return
|
||||
|
||||
if isinstance(method, (classmethod, staticmethod)):
|
||||
fn = type(method)(fn)
|
||||
|
||||
|
@ -571,15 +507,13 @@ def _patch_method(
|
|||
|
||||
|
||||
def _unpatch(
|
||||
module: ModuleType,
|
||||
name: str,
|
||||
fn: Callable[..., Any],
|
||||
module: ModuleType,
|
||||
name: str,
|
||||
fn: Callable[..., Any],
|
||||
) -> None:
|
||||
if (
|
||||
hasattr(module, "__dict__")
|
||||
and name in module.__dict__
|
||||
and isinstance(module.__dict__[name], (classmethod, staticmethod))
|
||||
):
|
||||
if hasattr(module, "__dict__") \
|
||||
and name in module.__dict__ \
|
||||
and isinstance(module.__dict__[name], (classmethod, staticmethod)):
|
||||
method = module.__dict__[name]
|
||||
fn = method.__func__
|
||||
|
||||
|
@ -590,10 +524,10 @@ def _unpatch(
|
|||
|
||||
|
||||
def _patch_attribute(
|
||||
member: Any,
|
||||
name: str,
|
||||
marker: "_Marker",
|
||||
providers_map: ProvidersMap,
|
||||
member: Any,
|
||||
name: str,
|
||||
marker: "_Marker",
|
||||
providers_map: ProvidersMap,
|
||||
) -> None:
|
||||
provider = providers_map.resolve_provider(marker.provider, marker.modifier)
|
||||
if provider is None:
|
||||
|
@ -614,37 +548,16 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None:
|
|||
setattr(patched.member, patched.name, patched.marker)
|
||||
|
||||
|
||||
def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
|
||||
if get_origin(parameter.annotation) is Annotated:
|
||||
args = get_args(parameter.annotation)
|
||||
if len(args) > 1:
|
||||
marker = args[1]
|
||||
else:
|
||||
marker = None
|
||||
else:
|
||||
marker = parameter.default
|
||||
|
||||
for marker_extractor in MARKER_EXTRACTORS:
|
||||
if _marker := marker_extractor(marker):
|
||||
marker = _marker
|
||||
break
|
||||
|
||||
if not isinstance(marker, _Marker):
|
||||
return None
|
||||
|
||||
return marker
|
||||
|
||||
|
||||
@cache
|
||||
def _fetch_reference_injections( # noqa: C901
|
||||
fn: Callable[..., Any],
|
||||
fn: Callable[..., Any],
|
||||
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
|
||||
# Hotfix, see:
|
||||
# - https://github.com/ets-labs/python-dependency-injector/issues/362
|
||||
# - https://github.com/ets-labs/python-dependency-injector/issues/398
|
||||
if GenericAlias and any(
|
||||
(fn is GenericAlias, getattr(fn, "__func__", None) is GenericAlias)
|
||||
):
|
||||
if GenericAlias and any((
|
||||
fn is GenericAlias,
|
||||
getattr(fn, "__func__", None) is GenericAlias
|
||||
)):
|
||||
fn = fn.__init__
|
||||
|
||||
try:
|
||||
|
@ -660,11 +573,18 @@ def _fetch_reference_injections( # noqa: C901
|
|||
injections = {}
|
||||
closing = {}
|
||||
for parameter_name, parameter in signature.parameters.items():
|
||||
marker = _extract_marker(parameter)
|
||||
|
||||
if marker is None:
|
||||
if not isinstance(parameter.default, _Marker) \
|
||||
and not _is_fastapi_depends(parameter.default):
|
||||
continue
|
||||
|
||||
marker = parameter.default
|
||||
|
||||
if _is_fastapi_depends(marker):
|
||||
marker = marker.dependency
|
||||
|
||||
if not isinstance(marker, _Marker):
|
||||
continue
|
||||
|
||||
if isinstance(marker, Closing):
|
||||
marker = marker.provider
|
||||
closing[parameter_name] = marker
|
||||
|
@ -673,6 +593,22 @@ def _fetch_reference_injections( # noqa: C901
|
|||
return injections, closing
|
||||
|
||||
|
||||
def _locate_dependent_closing_args(provider: providers.Provider) -> Dict[str, providers.Provider]:
|
||||
if not hasattr(provider, "args"):
|
||||
return {}
|
||||
|
||||
closing_deps = {}
|
||||
for arg in provider.args:
|
||||
if not isinstance(arg, providers.Provider) or not hasattr(arg, "args"):
|
||||
continue
|
||||
|
||||
if not arg.args and isinstance(arg, providers.Resource):
|
||||
return {str(id(arg)): arg}
|
||||
else:
|
||||
closing_deps += _locate_dependent_closing_args(arg)
|
||||
return closing_deps
|
||||
|
||||
|
||||
def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> None:
|
||||
patched_callable = _patched_registry.get_callable(fn)
|
||||
if patched_callable is None:
|
||||
|
@ -694,9 +630,9 @@ def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> Non
|
|||
|
||||
if injection in patched_callable.reference_closing:
|
||||
patched_callable.add_closing(injection, provider)
|
||||
|
||||
for resource in provider.traverse(types=[providers.Resource]):
|
||||
patched_callable.add_closing(str(id(resource)), resource)
|
||||
deps = _locate_dependent_closing_args(provider)
|
||||
for key, dep in deps.items():
|
||||
patched_callable.add_closing(key, dep)
|
||||
|
||||
|
||||
def _unbind_injections(fn: Callable[..., Any]) -> None:
|
||||
|
@ -711,8 +647,8 @@ def _fetch_modules(package):
|
|||
if not hasattr(package, "__path__") or not hasattr(package, "__name__"):
|
||||
return modules
|
||||
for module_info in pkgutil.walk_packages(
|
||||
path=package.__path__,
|
||||
prefix=package.__name__ + ".",
|
||||
path=package.__path__,
|
||||
prefix=package.__name__ + ".",
|
||||
):
|
||||
module = importlib.import_module(module_info.name)
|
||||
modules.append(module)
|
||||
|
@ -728,9 +664,9 @@ def _is_marker(member) -> bool:
|
|||
|
||||
|
||||
def _get_patched(
|
||||
fn: F,
|
||||
reference_injections: Dict[Any, Any],
|
||||
reference_closing: Dict[Any, Any],
|
||||
fn: F,
|
||||
reference_injections: Dict[Any, Any],
|
||||
reference_closing: Dict[Any, Any],
|
||||
) -> F:
|
||||
patched_object = PatchedCallable(
|
||||
original=fn,
|
||||
|
@ -740,8 +676,6 @@ def _get_patched(
|
|||
|
||||
if inspect.iscoroutinefunction(fn):
|
||||
patched = _get_async_patched(fn, patched_object)
|
||||
elif inspect.isasyncgenfunction(fn):
|
||||
patched = _get_async_gen_patched(fn, patched_object)
|
||||
else:
|
||||
patched = _get_sync_patched(fn, patched_object)
|
||||
|
||||
|
@ -751,16 +685,18 @@ def _get_patched(
|
|||
return patched
|
||||
|
||||
|
||||
def _is_fastapi_depends(param: Any) -> bool:
|
||||
return fastapi and isinstance(param, fastapi.params.Depends)
|
||||
|
||||
|
||||
def _is_patched(fn) -> bool:
|
||||
return _patched_registry.has_callable(fn)
|
||||
|
||||
|
||||
def _is_declarative_container(instance: Any) -> bool:
|
||||
return (
|
||||
isinstance(instance, type)
|
||||
and getattr(instance, "__IS_CONTAINER__", False) is True
|
||||
and getattr(instance, "declarative_parent", None) is None
|
||||
)
|
||||
return (isinstance(instance, type)
|
||||
and getattr(instance, "__IS_CONTAINER__", False) is True
|
||||
and getattr(instance, "declarative_parent", None) is None)
|
||||
|
||||
|
||||
def _safe_is_subclass(instance: Any, cls: Type) -> bool:
|
||||
|
@ -773,10 +709,11 @@ def _safe_is_subclass(instance: Any, cls: Type) -> bool:
|
|||
class Modifier:
|
||||
|
||||
def modify(
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider: ...
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider:
|
||||
...
|
||||
|
||||
|
||||
class TypeModifier(Modifier):
|
||||
|
@ -785,9 +722,9 @@ class TypeModifier(Modifier):
|
|||
self.type_ = type_
|
||||
|
||||
def modify(
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider:
|
||||
return provider.as_(self.type_)
|
||||
|
||||
|
@ -812,22 +749,22 @@ class RequiredModifier(Modifier):
|
|||
def __init__(self) -> None:
|
||||
self.type_modifier = None
|
||||
|
||||
def as_int(self) -> Self:
|
||||
def as_int(self) -> "RequiredModifier":
|
||||
self.type_modifier = TypeModifier(int)
|
||||
return self
|
||||
|
||||
def as_float(self) -> Self:
|
||||
def as_float(self) -> "RequiredModifier":
|
||||
self.type_modifier = TypeModifier(float)
|
||||
return self
|
||||
|
||||
def as_(self, type_: Type) -> Self:
|
||||
def as_(self, type_: Type) -> "RequiredModifier":
|
||||
self.type_modifier = TypeModifier(type_)
|
||||
return self
|
||||
|
||||
def modify(
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider:
|
||||
provider = provider.required()
|
||||
if self.type_modifier:
|
||||
|
@ -846,9 +783,9 @@ class InvariantModifier(Modifier):
|
|||
self.id = id
|
||||
|
||||
def modify(
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
self,
|
||||
provider: providers.ConfigurationOption,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider:
|
||||
invariant_segment = providers_map.resolve_provider(self.id)
|
||||
return provider[invariant_segment]
|
||||
|
@ -868,22 +805,22 @@ class ProvidedInstance(Modifier):
|
|||
def __init__(self) -> None:
|
||||
self.segments = []
|
||||
|
||||
def __getattr__(self, item: str) -> Self:
|
||||
def __getattr__(self, item):
|
||||
self.segments.append((self.TYPE_ATTRIBUTE, item))
|
||||
return self
|
||||
|
||||
def __getitem__(self, item) -> Self:
|
||||
def __getitem__(self, item):
|
||||
self.segments.append((self.TYPE_ITEM, item))
|
||||
return self
|
||||
|
||||
def call(self) -> Self:
|
||||
def call(self):
|
||||
self.segments.append((self.TYPE_CALL, None))
|
||||
return self
|
||||
|
||||
def modify(
|
||||
self,
|
||||
provider: providers.Provider,
|
||||
providers_map: ProvidersMap,
|
||||
self,
|
||||
provider: providers.Provider,
|
||||
providers_map: ProvidersMap,
|
||||
) -> providers.Provider:
|
||||
provider = provider.provided
|
||||
for type_, value in self.segments:
|
||||
|
@ -901,56 +838,47 @@ def provided() -> ProvidedInstance:
|
|||
return ProvidedInstance()
|
||||
|
||||
|
||||
MarkerItem = Union[
|
||||
str,
|
||||
providers.Provider[Any],
|
||||
Tuple[str, TypeModifier],
|
||||
Type[Container],
|
||||
"_Marker",
|
||||
]
|
||||
class ClassGetItemMeta(GenericMeta):
|
||||
def __getitem__(cls, item):
|
||||
# Spike for Python 3.6
|
||||
if isinstance(item, tuple):
|
||||
return cls(*item)
|
||||
return cls(item)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
class _Marker(Generic[T], metaclass=ClassGetItemMeta):
|
||||
|
||||
class _Marker(Protocol):
|
||||
__IS_MARKER__: bool
|
||||
__IS_MARKER__ = True
|
||||
|
||||
def __call__(self) -> Self: ...
|
||||
def __getattr__(self, item: str) -> Self: ...
|
||||
def __getitem__(self, item: Any) -> Any: ...
|
||||
|
||||
Provide: _Marker
|
||||
Provider: _Marker
|
||||
Closing: _Marker
|
||||
else:
|
||||
|
||||
class _Marker:
|
||||
|
||||
__IS_MARKER__ = True
|
||||
|
||||
def __init__(
|
||||
def __init__(
|
||||
self,
|
||||
provider: Union[providers.Provider, Container, str],
|
||||
modifier: Optional[Modifier] = None,
|
||||
) -> None:
|
||||
if _is_declarative_container(provider):
|
||||
provider = provider.__self__
|
||||
self.provider = provider
|
||||
self.modifier = modifier
|
||||
) -> None:
|
||||
if _is_declarative_container(provider):
|
||||
provider = provider.__self__
|
||||
self.provider = provider
|
||||
self.modifier = modifier
|
||||
|
||||
def __class_getitem__(cls, item: MarkerItem) -> Self:
|
||||
if isinstance(item, tuple):
|
||||
return cls(*item)
|
||||
return cls(item)
|
||||
def __class_getitem__(cls, item) -> T:
|
||||
if isinstance(item, tuple):
|
||||
return cls(*item)
|
||||
return cls(item)
|
||||
|
||||
def __call__(self) -> Self:
|
||||
return self
|
||||
def __call__(self) -> T:
|
||||
return self
|
||||
|
||||
class Provide(_Marker): ...
|
||||
|
||||
class Provider(_Marker): ...
|
||||
class Provide(_Marker):
|
||||
...
|
||||
|
||||
class Closing(_Marker): ...
|
||||
|
||||
class Provider(_Marker):
|
||||
...
|
||||
|
||||
|
||||
class Closing(_Marker):
|
||||
...
|
||||
|
||||
|
||||
class AutoLoader:
|
||||
|
@ -1000,7 +928,8 @@ class AutoLoader:
|
|||
super().exec_module(module)
|
||||
loader.wire_module(module)
|
||||
|
||||
class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader): ...
|
||||
class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader):
|
||||
...
|
||||
|
||||
loader_details = [
|
||||
(SourcelessFileLoader, importlib.machinery.BYTECODE_SUFFIXES),
|
||||
|
@ -1049,71 +978,24 @@ def is_loader_installed() -> bool:
|
|||
|
||||
|
||||
_patched_registry = PatchedRegistry()
|
||||
_inspect_filter = InspectFilter()
|
||||
_loader = AutoLoader()
|
||||
|
||||
# Optimizations
|
||||
from ._cwiring import DependencyResolver # noqa: E402
|
||||
from ._cwiring import _get_sync_patched # noqa
|
||||
from ._cwiring import _async_inject # noqa
|
||||
|
||||
|
||||
# Wiring uses the following Python wrapper because there is
|
||||
# no possibility to compile a first-type citizen coroutine in Cython.
|
||||
def _get_async_patched(fn: F, patched: PatchedCallable) -> F:
|
||||
@functools.wraps(fn)
|
||||
async def _patched(*args: Any, **raw_kwargs: Any) -> Any:
|
||||
resolver = DependencyResolver(raw_kwargs, patched.injections, patched.closing)
|
||||
|
||||
async with resolver as kwargs:
|
||||
return await fn(*args, **kwargs)
|
||||
|
||||
return cast(F, _patched)
|
||||
|
||||
|
||||
def _get_async_gen_patched(fn: F, patched: PatchedCallable) -> F:
|
||||
@functools.wraps(fn)
|
||||
async def _patched(*args: Any, **raw_kwargs: Any) -> AsyncIterator[Any]:
|
||||
resolver = DependencyResolver(raw_kwargs, patched.injections, patched.closing)
|
||||
|
||||
async with resolver as kwargs:
|
||||
async for obj in fn(*args, **kwargs):
|
||||
yield obj
|
||||
|
||||
return cast(F, _patched)
|
||||
|
||||
|
||||
def _get_sync_patched(fn: F, patched: PatchedCallable) -> F:
|
||||
@functools.wraps(fn)
|
||||
def _patched(*args: Any, **raw_kwargs: Any) -> Any:
|
||||
resolver = DependencyResolver(raw_kwargs, patched.injections, patched.closing)
|
||||
|
||||
with resolver as kwargs:
|
||||
return fn(*args, **kwargs)
|
||||
|
||||
return cast(F, _patched)
|
||||
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
|
||||
def _get_annotations(obj: Any) -> Dict[str, Any]:
|
||||
return inspect.get_annotations(obj)
|
||||
|
||||
else:
|
||||
|
||||
def _get_annotations(obj: Any) -> Dict[str, Any]:
|
||||
return getattr(obj, "__annotations__", {})
|
||||
|
||||
|
||||
def _get_members_and_annotated(obj: Any) -> Iterable[Tuple[str, Any]]:
|
||||
members = inspect.getmembers(obj)
|
||||
annotations = _get_annotations(obj)
|
||||
for annotation_name, annotation in annotations.items():
|
||||
if get_origin(annotation) is Annotated:
|
||||
args = get_args(annotation)
|
||||
if len(args) > 1:
|
||||
member = args[1]
|
||||
members.append((annotation_name, member))
|
||||
return members
|
||||
|
||||
|
||||
def clear_cache() -> None:
|
||||
"""Clear all caches used by :func:`wire`."""
|
||||
_fetch_reference_injections.cache_clear()
|
||||
async def _patched(*args, **kwargs):
|
||||
return await _async_inject(
|
||||
fn,
|
||||
args,
|
||||
kwargs,
|
||||
patched.injections,
|
||||
patched.closing,
|
||||
)
|
||||
return _patched
|
||||
|
|
10
tests/.configs/pytest-py27.ini
Normal file
10
tests/.configs/pytest-py27.ini
Normal file
|
@ -0,0 +1,10 @@
|
|||
[pytest]
|
||||
testpaths = tests/unit/
|
||||
python_files = test_*_py2_py3.py
|
||||
asyncio_mode = auto
|
||||
filterwarnings =
|
||||
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Please use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
|
||||
ignore:The \`scipy(.*?)\` namespace is deprecated(.*):DeprecationWarning
|
||||
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*
|
10
tests/.configs/pytest-py35.ini
Normal file
10
tests/.configs/pytest-py35.ini
Normal file
|
@ -0,0 +1,10 @@
|
|||
[pytest]
|
||||
testpaths = tests/unit/
|
||||
python_files = test_*_py3.py
|
||||
asyncio_mode = auto
|
||||
filterwarnings =
|
||||
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Please use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
|
||||
ignore:The \`scipy(.*?)\` namespace is deprecated(.*):DeprecationWarning
|
||||
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*
|
13
tests/.configs/pytest.ini
Normal file
13
tests/.configs/pytest.ini
Normal file
|
@ -0,0 +1,13 @@
|
|||
[pytest]
|
||||
testpaths = tests/unit/
|
||||
python_files = test_*_py3*.py
|
||||
asyncio_mode = auto
|
||||
markers =
|
||||
pydantic: Tests with Pydantic as a dependency
|
||||
filterwarnings =
|
||||
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\.0\.0:DeprecationWarning
|
||||
ignore:Please use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
|
||||
ignore:Please import \`.*?\` from the \`scipy(.*?)\` namespace(.*):DeprecationWarning
|
||||
ignore:\`scipy(.*?)\` is deprecated(.*):DeprecationWarning
|
||||
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*
|
|
@ -1,10 +1,12 @@
|
|||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Animal: ...
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Cat(Animal): ...
|
||||
class Cat(Animal):
|
||||
...
|
||||
|
||||
|
||||
# Test 1: to check Aggregate provider
|
||||
|
@ -18,19 +20,13 @@ val1: str = provider1("a")
|
|||
|
||||
provider1_set_non_string_keys: providers.Aggregate[str] = providers.Aggregate()
|
||||
provider1_set_non_string_keys.set_providers({Cat: providers.Object("str")})
|
||||
provider_set_non_string_1: providers.Provider[str] = (
|
||||
provider1_set_non_string_keys.providers[Cat]
|
||||
)
|
||||
provider_set_non_string_1: providers.Provider[str] = provider1_set_non_string_keys.providers[Cat]
|
||||
|
||||
provider1_new_non_string_keys: providers.Aggregate[str] = providers.Aggregate(
|
||||
{Cat: providers.Object("str")},
|
||||
)
|
||||
factory_new_non_string_1: providers.Provider[str] = (
|
||||
provider1_new_non_string_keys.providers[Cat]
|
||||
)
|
||||
factory_new_non_string_1: providers.Provider[str] = provider1_new_non_string_keys.providers[Cat]
|
||||
|
||||
provider1_no_explicit_typing = providers.Aggregate(a=providers.Object("str"))
|
||||
provider1_no_explicit_typing_factory: providers.Provider[str] = (
|
||||
provider1_no_explicit_typing.providers["a"]
|
||||
)
|
||||
provider1_no_explicit_typing_factory: providers.Provider[str] = provider1_no_explicit_typing.providers["a"]
|
||||
provider1_no_explicit_typing_object: str = provider1_no_explicit_typing("a")
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from typing import Any, Callable, Dict, Optional, Tuple, Type
|
||||
from typing import Callable, Optional, Tuple, Any, Dict, Type
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Animal: ...
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Cat(Animal):
|
||||
|
@ -33,7 +34,7 @@ kwargs4: Dict[str, Any] = provider4.kwargs
|
|||
|
||||
# Test 5: to check the provided instance interface
|
||||
provider5 = providers.Callable(Animal)
|
||||
provided5: Animal = provider5.provided()
|
||||
provided5: providers.ProvidedInstance = provider5.provided
|
||||
attr_getter5: providers.AttributeGetter = provider5.provided.attr
|
||||
item_getter5: providers.ItemGetter = provider5.provided["item"]
|
||||
method_caller: providers.MethodCaller = provider5.provided.method.call(123, arg=324)
|
||||
|
@ -52,13 +53,10 @@ 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)
|
||||
|
||||
|
||||
# Test 10: to check the .provides
|
||||
provider10 = providers.Callable(Cat)
|
||||
provides10: Optional[Callable[..., Cat]] = provider10.provides
|
||||
|
@ -70,5 +68,5 @@ provides11: Optional[Callable[..., Animal]] = provider11.provides
|
|||
assert provides11 is Cat
|
||||
|
||||
# Test 12: to check string imports
|
||||
provider12: providers.Callable[Dict[Any, Any]] = providers.Callable("builtins.dict")
|
||||
provider12: providers.Callable[dict] = providers.Callable("builtins.dict")
|
||||
provider12.set_provides("builtins.dict")
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
|
||||
from pydantic_settings import BaseSettings as PydanticSettings
|
||||
from typing import Any
|
||||
|
||||
from dependency_injector import providers
|
||||
from pydantic_settings import BaseSettings as PydanticSettings
|
||||
|
||||
|
||||
# Test 1: to check the getattr
|
||||
config1: providers.Configuration = providers.Configuration()
|
||||
provider1: providers.Provider[Dict[str, Any]] = providers.Factory(dict, a=config1.a)
|
||||
provider1: providers.Provider[dict] = providers.Factory(dict, a=config1.a)
|
||||
|
||||
# Test 2: to check the from_*() method
|
||||
config2 = providers.Configuration()
|
||||
|
@ -68,9 +68,7 @@ config5_pydantic = providers.Configuration(
|
|||
pydantic_settings=[PydanticSettings()],
|
||||
)
|
||||
config5_pydantic.set_pydantic_settings([PydanticSettings()])
|
||||
config5_pydantic_settings: list[PydanticSettings] = (
|
||||
config5_pydantic.get_pydantic_settings()
|
||||
)
|
||||
config5_pydantic_settings: list[PydanticSettings] = config5_pydantic.get_pydantic_settings()
|
||||
|
||||
# Test 6: to check init arguments
|
||||
config6 = providers.Configuration(
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from typing import Any
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Container: ...
|
||||
class Container:
|
||||
...
|
||||
|
||||
|
||||
# Test 1: to check the return type
|
||||
|
@ -12,4 +11,4 @@ var1: Container = provider1()
|
|||
|
||||
# Test 2: to check the getattr
|
||||
provider2 = providers.Container(Container)
|
||||
attr: providers.Provider[Any] = provider2.attr
|
||||
attr: providers.Provider = provider2.attr
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
from typing import Awaitable, Coroutine
|
||||
from typing import Coroutine
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
async def _coro() -> None: ...
|
||||
|
||||
async def _coro() -> None:
|
||||
...
|
||||
|
||||
# Test 1: to check the return type
|
||||
provider1 = providers.Coroutine(_coro)
|
||||
var1: Awaitable[None] = provider1()
|
||||
var1: Coroutine = provider1()
|
||||
|
||||
# Test 2: to check string imports
|
||||
provider2: providers.Coroutine[None] = providers.Coroutine("_coro")
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Any, Dict
|
||||
from typing import Dict
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
@ -10,7 +10,7 @@ class Container1(containers.DeclarativeContainer):
|
|||
|
||||
container1 = Container1()
|
||||
container1_type: containers.Container = Container1()
|
||||
provider1: providers.Provider[int] = container1.provider
|
||||
provider1: providers.Provider = container1.provider
|
||||
val1: int = container1.provider(3)
|
||||
|
||||
|
||||
|
@ -20,7 +20,8 @@ class Container21(containers.DeclarativeContainer):
|
|||
|
||||
|
||||
@containers.override(Container21)
|
||||
class Container22(containers.DeclarativeContainer): ...
|
||||
class Container22(containers.DeclarativeContainer):
|
||||
...
|
||||
|
||||
|
||||
# Test 3: to check @copy decorator
|
||||
|
@ -29,14 +30,14 @@ class Container31(containers.DeclarativeContainer):
|
|||
|
||||
|
||||
@containers.copy(Container31)
|
||||
class Container32(containers.DeclarativeContainer): ...
|
||||
class Container32(containers.DeclarativeContainer):
|
||||
...
|
||||
|
||||
|
||||
# Test 4: to override()
|
||||
class Container4(containers.DeclarativeContainer):
|
||||
provider = providers.Factory(int)
|
||||
|
||||
|
||||
container4 = Container4()
|
||||
container4.override(Container4())
|
||||
|
||||
|
@ -46,7 +47,7 @@ class Container5(containers.DeclarativeContainer):
|
|||
provider = providers.Factory(int)
|
||||
|
||||
|
||||
dependencies: Dict[str, providers.Provider[Any]] = Container5.dependencies
|
||||
dependencies: Dict[str, providers.Provider] = Container5.dependencies
|
||||
|
||||
|
||||
# Test 6: to check base class
|
||||
|
@ -61,7 +62,6 @@ container6: containers.Container = Container6()
|
|||
class Container7(containers.DeclarativeContainer):
|
||||
provider = providers.Factory(str)
|
||||
|
||||
|
||||
container7 = Container7()
|
||||
container7.override_providers(provider="new_value")
|
||||
with container7.override_providers(a=providers.Provider()):
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
from typing import Any, Optional
|
||||
from typing import Optional
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
# Test 1: to check the return type
|
||||
provider1 = providers.Delegate(providers.Provider())
|
||||
var1: providers.Provider[Any] = 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[Any] = await provider2() # type: ignore
|
||||
var2: providers.Provider[Any] = await provider2.async_()
|
||||
|
||||
var1: providers.Provider = await provider2() # type: ignore
|
||||
var2: providers.Provider = await provider2.async_()
|
||||
|
||||
# Test 3: to check class type from provider
|
||||
provider3 = providers.Delegate(providers.Provider())
|
||||
provided_provides: Optional[providers.Provider[Any]] = provider3.provides
|
||||
provided_provides: Optional[providers.Provider] = provider3.provides
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
from typing import Any
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check the getattr type
|
||||
provider1 = providers.DependenciesContainer(
|
||||
a=providers.Provider(),
|
||||
b=providers.Provider(),
|
||||
)
|
||||
a1: providers.Provider[Any] = provider1.a
|
||||
b1: providers.Provider[Any] = provider1.b
|
||||
a1: providers.Provider = provider1.a
|
||||
b1: providers.Provider = provider1.b
|
||||
c1: providers.ProvidedInstance = provider1.c.provided
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from typing import Any, Type
|
||||
from typing import Type
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Animal: ...
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Cat(Animal):
|
||||
|
||||
def __init__(self, *a: Any, **kw: Any) -> None: ...
|
||||
def __init__(self, *_, **__): ...
|
||||
|
||||
|
||||
# Test 1: to check the return type
|
||||
|
@ -22,8 +23,6 @@ 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_()
|
||||
|
|
|
@ -2,6 +2,7 @@ from typing import Any, Dict
|
|||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check the return type (class)
|
||||
provider1 = providers.Dict(
|
||||
a1=providers.Factory(object),
|
||||
|
@ -16,9 +17,7 @@ var2: Dict[Any, Any] = provider2()
|
|||
|
||||
|
||||
# Test 3: to check init with non-string keys
|
||||
provider3 = providers.Dict(
|
||||
{object(): providers.Factory(object)}, a2=providers.Factory(object)
|
||||
)
|
||||
provider3 = providers.Dict({object(): providers.Factory(object)}, a2=providers.Factory(object))
|
||||
var3: Dict[Any, Any] = provider3()
|
||||
|
||||
|
||||
|
@ -35,7 +34,7 @@ provider5 = providers.Dict(
|
|||
a1=providers.Factory(object),
|
||||
a2=providers.Factory(object),
|
||||
)
|
||||
provided5: dict[Any, Any] = provider5.provided()
|
||||
provided5: providers.ProvidedInstance = provider5.provided
|
||||
|
||||
|
||||
# Test 6: to check the return type with await
|
||||
|
@ -43,8 +42,6 @@ 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_()
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from typing import Any, Dict
|
||||
from typing import Dict
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
# Test 1: to check setattr
|
||||
container1 = containers.DynamicContainer()
|
||||
container1.abc = providers.Provider()
|
||||
|
@ -22,7 +23,7 @@ container4.set_providers(a=providers.Provider())
|
|||
|
||||
# Test 5: to check .dependencies attribute
|
||||
container5 = containers.DynamicContainer()
|
||||
dependencies: Dict[str, providers.Provider[Any]] = container5.dependencies
|
||||
dependencies: Dict[str, providers.Provider] = container5.dependencies
|
||||
|
||||
# Test 6: to check base class
|
||||
container6: containers.Container = containers.DynamicContainer()
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from typing import Any, Callable, Dict, Optional, Tuple, Type
|
||||
from typing import Callable, Optional, Tuple, Any, Dict, Type
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Animal: ...
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Cat(Animal):
|
||||
|
||||
def __init__(self, *a: Any, **kw: Any) -> None: ...
|
||||
def __init__(self, *_, **__): ...
|
||||
|
||||
@classmethod
|
||||
def create(cls) -> Animal:
|
||||
|
@ -36,7 +37,7 @@ attributes4: Dict[str, Any] = provider4.attributes
|
|||
|
||||
# Test 5: to check the provided instance interface
|
||||
provider5 = providers.Factory(Animal)
|
||||
provided5: Animal = provider5.provided()
|
||||
provided5: providers.ProvidedInstance = provider5.provided
|
||||
attr_getter5: providers.AttributeGetter = provider5.provided.attr
|
||||
item_getter5: providers.ItemGetter = provider5.provided["item"]
|
||||
method_caller5: providers.MethodCaller = provider5.provided.method.call(123, arg=324)
|
||||
|
@ -62,29 +63,17 @@ factory_a_9: providers.Factory[str] = provider9.a
|
|||
factory_b_9: providers.Factory[str] = provider9.b
|
||||
val9: str = provider9("a")
|
||||
|
||||
provider9_set_non_string_keys: providers.FactoryAggregate[str] = (
|
||||
providers.FactoryAggregate()
|
||||
)
|
||||
provider9_set_non_string_keys: providers.FactoryAggregate[str] = providers.FactoryAggregate()
|
||||
provider9_set_non_string_keys.set_factories({Cat: providers.Factory(str, "str")})
|
||||
factory_set_non_string_9: providers.Factory[str] = (
|
||||
provider9_set_non_string_keys.factories[Cat]
|
||||
)
|
||||
factory_set_non_string_9: providers.Factory[str] = provider9_set_non_string_keys.factories[Cat]
|
||||
|
||||
provider9_new_non_string_keys: providers.FactoryAggregate[str] = (
|
||||
providers.FactoryAggregate(
|
||||
{Cat: providers.Factory(str, "str")},
|
||||
)
|
||||
)
|
||||
factory_new_non_string_9: providers.Factory[str] = (
|
||||
provider9_new_non_string_keys.factories[Cat]
|
||||
provider9_new_non_string_keys: providers.FactoryAggregate[str] = providers.FactoryAggregate(
|
||||
{Cat: providers.Factory(str, "str")},
|
||||
)
|
||||
factory_new_non_string_9: providers.Factory[str] = provider9_new_non_string_keys.factories[Cat]
|
||||
|
||||
provider9_no_explicit_typing = providers.FactoryAggregate(
|
||||
a=providers.Factory(str, "str")
|
||||
)
|
||||
provider9_no_explicit_typing_factory: providers.Factory[str] = (
|
||||
provider9_no_explicit_typing.factories["a"]
|
||||
)
|
||||
provider9_no_explicit_typing = providers.FactoryAggregate(a=providers.Factory(str, "str"))
|
||||
provider9_no_explicit_typing_factory: providers.Factory[str] = provider9_no_explicit_typing.factories["a"]
|
||||
provider9_no_explicit_typing_object: str = provider9_no_explicit_typing("a")
|
||||
|
||||
# Test 10: to check the explicit typing
|
||||
|
@ -93,13 +82,10 @@ 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)
|
||||
|
||||
|
||||
# Test 12: to check class type from .provides
|
||||
provider12 = providers.Factory(Cat)
|
||||
provided_cls12: Type[Animal] = provider12.cls
|
||||
|
@ -115,5 +101,5 @@ provided_provides13: Optional[Callable[..., Animal]] = provider13.provides
|
|||
assert provided_provides13 is not None and provided_provides13() == Cat()
|
||||
|
||||
# Test 14: to check string imports
|
||||
provider14: providers.Factory[Dict[Any, Any]] = providers.Factory("builtins.dict")
|
||||
provider14: providers.Factory[dict] = providers.Factory("builtins.dict")
|
||||
provider14.set_provides("builtins.dict")
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from typing import Any, List, Tuple
|
||||
from typing import Tuple, Any, List
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check the return type (class)
|
||||
provider1 = providers.List(
|
||||
providers.Factory(object),
|
||||
|
@ -22,7 +23,7 @@ provider3 = providers.List(
|
|||
providers.Factory(object),
|
||||
providers.Factory(object),
|
||||
)
|
||||
provided3: List[Any] = provider3.provided()
|
||||
provided3: providers.ProvidedInstance = provider3.provided
|
||||
attr_getter3: providers.AttributeGetter = provider3.provided.attr
|
||||
item_getter3: providers.ItemGetter = provider3.provided["item"]
|
||||
method_caller3: providers.MethodCaller = provider3.provided.method.call(123, arg=324)
|
||||
|
@ -32,8 +33,6 @@ 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_()
|
||||
|
|
|
@ -1,27 +1,25 @@
|
|||
from typing import Optional, Type
|
||||
from typing import Type, Optional
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check the return type
|
||||
provider1 = providers.Object(int(3))
|
||||
var1: int = provider1()
|
||||
|
||||
# Test 2: to check the provided instance interface
|
||||
provider2 = providers.Object(int)
|
||||
provided2: Type[int] = provider2.provided()
|
||||
provided2: providers.ProvidedInstance = provider2.provided
|
||||
attr_getter2: providers.AttributeGetter = provider2.provided.attr
|
||||
item_getter2: providers.ItemGetter = provider2.provided["item"]
|
||||
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_()
|
||||
|
||||
|
||||
# Test 4: to check class type from provider
|
||||
provider4 = providers.Object(int("1"))
|
||||
provided_provides: Optional[int] = provider4.provides
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
from typing import Any
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check .provided attribute
|
||||
provider1: providers.Provider[int] = providers.Object(1)
|
||||
provided: int = provider1.provided()
|
||||
provider1_delegate: providers.Provider[int] = provider1.provider
|
||||
provided: providers.ProvidedInstance = provider1.provided
|
||||
|
||||
# Test 2: to check async mode API
|
||||
provider2: providers.Provider[Any] = providers.Provider()
|
||||
provider2: providers.Provider = providers.Provider()
|
||||
provider2.enable_async_mode()
|
||||
provider2.disable_async_mode()
|
||||
provider2.reset_async_mode()
|
||||
|
|
|
@ -1,13 +1,4 @@
|
|||
from typing import (
|
||||
Any,
|
||||
AsyncGenerator,
|
||||
AsyncIterator,
|
||||
Dict,
|
||||
Generator,
|
||||
Iterator,
|
||||
List,
|
||||
Optional,
|
||||
)
|
||||
from typing import List, Iterator, Generator, AsyncIterator, AsyncGenerator, Optional
|
||||
|
||||
from dependency_injector import providers, resources
|
||||
|
||||
|
@ -41,10 +32,11 @@ var3: List[int] = provider3()
|
|||
|
||||
# Test 4: to check the return type with resource subclass
|
||||
class MyResource4(resources.Resource[List[int]]):
|
||||
def init(self, *args: Any, **kwargs: Any) -> List[int]:
|
||||
def init(self, *args, **kwargs) -> List[int]:
|
||||
return []
|
||||
|
||||
def shutdown(self, resource: Optional[List[int]]) -> None: ...
|
||||
def shutdown(self, resource: Optional[List[int]]) -> None:
|
||||
...
|
||||
|
||||
|
||||
provider4 = providers.Resource(MyResource4)
|
||||
|
@ -92,10 +84,11 @@ async def _provide7() -> None:
|
|||
|
||||
# Test 8: to check the return type with async resource subclass
|
||||
class MyResource8(resources.AsyncResource[List[int]]):
|
||||
async def init(self, *args: Any, **kwargs: Any) -> List[int]:
|
||||
async def init(self, *args, **kwargs) -> List[int]:
|
||||
return []
|
||||
|
||||
async def shutdown(self, resource: Optional[List[int]]) -> None: ...
|
||||
async def shutdown(self, resource: Optional[List[int]]) -> None:
|
||||
...
|
||||
|
||||
|
||||
provider8 = providers.Resource(MyResource8)
|
||||
|
@ -107,5 +100,5 @@ async def _provide8() -> None:
|
|||
|
||||
|
||||
# Test 9: to check string imports
|
||||
provider9: providers.Resource[Dict[Any, Any]] = providers.Resource("builtins.dict")
|
||||
provider9: providers.Resource[dict] = providers.Resource("builtins.dict")
|
||||
provider9.set_provides("builtins.dict")
|
||||
|
|
|
@ -2,6 +2,7 @@ from typing import Any
|
|||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
# Test 1: to check the return type
|
||||
provider1 = providers.Selector(
|
||||
lambda: "a",
|
||||
|
@ -27,7 +28,7 @@ provider3 = providers.Selector(
|
|||
a=providers.Factory(object),
|
||||
b=providers.Factory(object),
|
||||
)
|
||||
attr3: providers.Provider[Any] = provider3.a
|
||||
attr3: providers.Provider = provider3.a
|
||||
|
||||
# Test 4: to check the return type with await
|
||||
provider4 = providers.Selector(
|
||||
|
@ -35,8 +36,6 @@ provider4 = providers.Selector(
|
|||
a=providers.Factory(object),
|
||||
b=providers.Factory(object),
|
||||
)
|
||||
|
||||
|
||||
async def _async4() -> None:
|
||||
var1: Any = await provider4()
|
||||
var1: Any = await provider4() # type: ignore
|
||||
var2: Any = await provider4.async_()
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from typing import Any, Callable, Dict, Optional, Tuple, Type
|
||||
from typing import Callable, Optional, Tuple, Any, Dict, Type
|
||||
|
||||
from dependency_injector import providers
|
||||
|
||||
|
||||
class Animal: ...
|
||||
class Animal:
|
||||
...
|
||||
|
||||
|
||||
class Cat(Animal):
|
||||
|
||||
def __init__(self, *a: Any, **kw: Any) -> None: ...
|
||||
def __init__(self, *_, **__): ...
|
||||
|
||||
@classmethod
|
||||
def create(cls) -> Animal:
|
||||
|
@ -36,7 +37,7 @@ attributes4: Dict[str, Any] = provider4.attributes
|
|||
|
||||
# Test 5: to check the provided instance interface
|
||||
provider5 = providers.Singleton(Animal)
|
||||
provided5: Animal = provider5.provided()
|
||||
provided5: providers.ProvidedInstance = provider5.provided
|
||||
attr_getter5: providers.AttributeGetter = provider5.provided.attr
|
||||
item_getter5: providers.ItemGetter = provider5.provided["item"]
|
||||
method_caller5: providers.MethodCaller = provider5.provided.method.call(123, arg=324)
|
||||
|
@ -71,13 +72,10 @@ 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)
|
||||
|
||||
|
||||
# Test 14: to check class from .provides
|
||||
provider14 = providers.Singleton(Cat)
|
||||
provided_cls14: Type[Cat] = provider14.cls
|
||||
|
@ -93,5 +91,5 @@ provided_provides15: Optional[Callable[..., Animal]] = provider15.provides
|
|||
assert provided_provides15 is not None and provided_provides15() == Cat()
|
||||
|
||||
# Test 16: to check string imports
|
||||
provider16: providers.Singleton[Dict[Any, Any]] = providers.Singleton("builtins.dict")
|
||||
provider16: providers.Singleton[dict] = providers.Singleton("builtins.dict")
|
||||
provider16.set_provides("builtins.dict")
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
from typing import Iterator
|
||||
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from dependency_injector.containers import DeclarativeContainer
|
||||
from dependency_injector.providers import Object, Resource
|
||||
from dependency_injector.wiring import Closing, Provide, required
|
||||
|
||||
|
||||
def _resource() -> Iterator[int]:
|
||||
yield 1
|
||||
|
||||
|
||||
class Container(DeclarativeContainer):
|
||||
value = Object(1)
|
||||
res = Resource(_resource)
|
||||
|
||||
|
||||
def default_by_ref(value: int = Provide[Container.value]) -> None: ...
|
||||
def default_by_string(value: int = Provide["value"]) -> None: ...
|
||||
def default_by_string_with_modifier(
|
||||
value: int = Provide["value", required().as_int()]
|
||||
) -> None: ...
|
||||
def default_container(container: Container = Provide[Container]) -> None: ...
|
||||
def default_with_closing(value: int = Closing[Provide[Container.res]]) -> None: ...
|
||||
def annotated_by_ref(value: Annotated[int, Provide[Container.value]]) -> None: ...
|
||||
def annotated_by_string(value: Annotated[int, Provide["value"]]) -> None: ...
|
||||
def annotated_by_string_with_modifier(
|
||||
value: Annotated[int, Provide["value", required().as_int()]],
|
||||
) -> None: ...
|
||||
def annotated_container(
|
||||
container: Annotated[Container, Provide[Container]],
|
||||
) -> None: ...
|
||||
def annotated_with_closing(
|
||||
value: Annotated[int, Closing[Provide[Container.res]]],
|
||||
) -> None: ...
|
|
@ -145,121 +145,3 @@ async def test_shutdown_sync_and_async_ordering():
|
|||
await container.shutdown_resources()
|
||||
assert initialized_resources == ["r1", "r2", "r3", "r1", "r2", "r3"]
|
||||
assert shutdown_resources == ["r3", "r2", "r1", "r3", "r2", "r1"]
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_init_and_shutdown_scoped_resources():
|
||||
initialized_resources = []
|
||||
shutdown_resources = []
|
||||
|
||||
def _sync_resource(name, **_):
|
||||
initialized_resources.append(name)
|
||||
yield name
|
||||
shutdown_resources.append(name)
|
||||
|
||||
async def _async_resource(name, **_):
|
||||
initialized_resources.append(name)
|
||||
yield name
|
||||
shutdown_resources.append(name)
|
||||
|
||||
|
||||
class ResourceA(providers.Resource):
|
||||
pass
|
||||
|
||||
|
||||
class ResourceB(providers.Resource):
|
||||
pass
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
resource_a = ResourceA(
|
||||
_sync_resource,
|
||||
name="ra1",
|
||||
)
|
||||
resource_b1 = ResourceB(
|
||||
_sync_resource,
|
||||
name="rb1",
|
||||
r1=resource_a,
|
||||
)
|
||||
resource_b2 = ResourceB(
|
||||
_async_resource,
|
||||
name="rb2",
|
||||
r2=resource_b1,
|
||||
)
|
||||
|
||||
container = Container()
|
||||
|
||||
container.init_resources(resource_type=ResourceA)
|
||||
assert initialized_resources == ["ra1"]
|
||||
assert shutdown_resources == []
|
||||
|
||||
container.shutdown_resources(resource_type=ResourceA)
|
||||
assert initialized_resources == ["ra1"]
|
||||
assert shutdown_resources == ["ra1"]
|
||||
|
||||
await container.init_resources(resource_type=ResourceB)
|
||||
assert initialized_resources == ["ra1", "ra1", "rb1", "rb2"]
|
||||
assert shutdown_resources == ["ra1"]
|
||||
|
||||
await container.shutdown_resources(resource_type=ResourceB)
|
||||
assert initialized_resources == ["ra1", "ra1", "rb1", "rb2"]
|
||||
assert shutdown_resources == ["ra1", "rb2", "rb1"]
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_init_and_shutdown_all_scoped_resources_using_default_value():
|
||||
initialized_resources = []
|
||||
shutdown_resources = []
|
||||
|
||||
def _sync_resource(name, **_):
|
||||
initialized_resources.append(name)
|
||||
yield name
|
||||
shutdown_resources.append(name)
|
||||
|
||||
async def _async_resource(name, **_):
|
||||
initialized_resources.append(name)
|
||||
yield name
|
||||
shutdown_resources.append(name)
|
||||
|
||||
|
||||
class ResourceA(providers.Resource):
|
||||
pass
|
||||
|
||||
|
||||
class ResourceB(providers.Resource):
|
||||
pass
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
resource_a = ResourceA(
|
||||
_sync_resource,
|
||||
name="r1",
|
||||
)
|
||||
resource_b1 = ResourceB(
|
||||
_sync_resource,
|
||||
name="r2",
|
||||
r1=resource_a,
|
||||
)
|
||||
resource_b2 = ResourceB(
|
||||
_async_resource,
|
||||
name="r3",
|
||||
r2=resource_b1,
|
||||
)
|
||||
|
||||
container = Container()
|
||||
|
||||
await container.init_resources()
|
||||
assert initialized_resources == ["r1", "r2", "r3"]
|
||||
assert shutdown_resources == []
|
||||
|
||||
await container.shutdown_resources()
|
||||
assert initialized_resources == ["r1", "r2", "r3"]
|
||||
assert shutdown_resources == ["r3", "r2", "r1"]
|
||||
|
||||
await container.init_resources()
|
||||
assert initialized_resources == ["r1", "r2", "r3", "r1", "r2", "r3"]
|
||||
assert shutdown_resources == ["r3", "r2", "r1"]
|
||||
|
||||
await container.shutdown_resources()
|
||||
assert initialized_resources == ["r1", "r2", "r3", "r1", "r2", "r3"]
|
||||
assert shutdown_resources == ["r3", "r2", "r1", "r3", "r2", "r1"]
|
||||
|
|
|
@ -325,19 +325,6 @@ def test_init_shutdown_nested_resources():
|
|||
assert _init2.shutdown_counter == 2
|
||||
|
||||
|
||||
def test_init_shutdown_resources_wrong_type() -> None:
|
||||
class Container(containers.DeclarativeContainer):
|
||||
pass
|
||||
|
||||
c = Container()
|
||||
|
||||
with raises(TypeError, match=r"resource_type must be a subclass of Resource provider"):
|
||||
c.init_resources(int) # type: ignore[arg-type]
|
||||
|
||||
with raises(TypeError, match=r"resource_type must be a subclass of Resource provider"):
|
||||
c.shutdown_resources(int) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def test_reset_singletons():
|
||||
class SubSubContainer(containers.DeclarativeContainer):
|
||||
singleton = providers.Singleton(object)
|
||||
|
|
|
@ -11,7 +11,7 @@ def index():
|
|||
return "Hello World!"
|
||||
|
||||
|
||||
def _test():
|
||||
def test():
|
||||
return "Test!"
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ class ApplicationContainer(containers.DeclarativeContainer):
|
|||
app = flask.Application(Flask, __name__)
|
||||
|
||||
index_view = flask.View(index)
|
||||
test_view = flask.View(_test)
|
||||
test_view = flask.View(test)
|
||||
test_class_view = flask.ClassBasedView(Test)
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from typing import AsyncIterator, Iterator, TypeVar
|
||||
from typing import AsyncIterator, Iterator
|
||||
from unittest.mock import ANY
|
||||
|
||||
from pytest import mark
|
||||
|
@ -7,12 +7,6 @@ from dependency_injector.containers import DeclarativeContainer
|
|||
from dependency_injector.ext.starlette import Lifespan
|
||||
from dependency_injector.providers import Resource
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class XResource(Resource[T]):
|
||||
"""A test provider"""
|
||||
|
||||
|
||||
class TestLifespan:
|
||||
@mark.parametrize("sync", [False, True])
|
||||
|
@ -34,15 +28,11 @@ class TestLifespan:
|
|||
yield
|
||||
shutdown = True
|
||||
|
||||
def nope():
|
||||
assert False, "should not be called"
|
||||
|
||||
class Container(DeclarativeContainer):
|
||||
x = XResource(sync_resource if sync else async_resource)
|
||||
y = Resource(nope)
|
||||
x = Resource(sync_resource if sync else async_resource)
|
||||
|
||||
container = Container()
|
||||
lifespan = Lifespan(container, resource_type=XResource)
|
||||
lifespan = Lifespan(container)
|
||||
|
||||
async with lifespan(ANY) as scope:
|
||||
assert scope is None
|
||||
|
|
|
@ -5,23 +5,6 @@ import os
|
|||
from pytest import mark, raises
|
||||
|
||||
|
||||
def test_no_env_variable_interpolation(config, ini_config_file_3):
|
||||
config.from_ini(ini_config_file_3, envs_required=None)
|
||||
|
||||
assert config() == {
|
||||
"section1": {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
},
|
||||
}
|
||||
assert config.section1() == {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
}
|
||||
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
|
||||
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
|
||||
|
||||
|
||||
def test_env_variable_interpolation(config, ini_config_file_3):
|
||||
config.from_ini(ini_config_file_3)
|
||||
|
||||
|
|
|
@ -6,23 +6,6 @@ import os
|
|||
from pytest import mark, raises
|
||||
|
||||
|
||||
def test_no_env_variable_interpolation(config, json_config_file_3):
|
||||
config.from_json(json_config_file_3, envs_required=None)
|
||||
|
||||
assert config() == {
|
||||
"section1": {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
},
|
||||
}
|
||||
assert config.section1() == {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
}
|
||||
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
|
||||
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
|
||||
|
||||
|
||||
def test_env_variable_interpolation(config, json_config_file_3):
|
||||
config.from_json(json_config_file_3)
|
||||
|
||||
|
|
|
@ -6,23 +6,6 @@ import yaml
|
|||
from pytest import mark, raises
|
||||
|
||||
|
||||
def test_no_env_variable_interpolation(config, yaml_config_file_3):
|
||||
config.from_yaml(yaml_config_file_3, envs_required=None)
|
||||
|
||||
assert config() == {
|
||||
"section1": {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
},
|
||||
}
|
||||
assert config.section1() == {
|
||||
"value1": "${CONFIG_TEST_ENV}",
|
||||
"value2": "${CONFIG_TEST_PATH}/path",
|
||||
}
|
||||
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
|
||||
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
|
||||
|
||||
|
||||
def test_env_variable_interpolation(config, yaml_config_file_3):
|
||||
config.from_yaml(yaml_config_file_3)
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""Coroutine provider tests."""
|
||||
import sys
|
||||
|
||||
from dependency_injector import providers, errors
|
||||
from pytest import mark, raises
|
||||
|
@ -209,17 +208,3 @@ def test_repr():
|
|||
"<dependency_injector.providers."
|
||||
"Coroutine({0}) at {1}>".format(repr(example), hex(id(provider)))
|
||||
)
|
||||
|
||||
|
||||
@mark.skipif(sys.version_info > (3, 15), reason="requires Python<3.16")
|
||||
def test_asyncio_iscoroutinefunction() -> None:
|
||||
from asyncio.coroutines import iscoroutinefunction
|
||||
|
||||
assert iscoroutinefunction(providers.Coroutine(example))
|
||||
|
||||
|
||||
@mark.skipif(sys.version_info < (3, 12), reason="requires Python>=3.12")
|
||||
def test_inspect_iscoroutinefunction() -> None:
|
||||
from inspect import iscoroutinefunction
|
||||
|
||||
assert iscoroutinefunction(providers.Coroutine(example))
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
import asyncio
|
||||
import inspect
|
||||
from contextlib import asynccontextmanager
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
from pytest import mark, raises
|
||||
|
||||
from dependency_injector import containers, providers, resources
|
||||
from pytest import mark, raises
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
|
@ -35,6 +34,7 @@ async def test_init_async_function():
|
|||
|
||||
|
||||
@mark.asyncio
|
||||
@mark.skipif(sys.version_info < (3, 6), reason="requires Python 3.6+")
|
||||
async def test_init_async_generator():
|
||||
resource = object()
|
||||
|
||||
|
@ -71,46 +71,6 @@ async def test_init_async_generator():
|
|||
assert _init.shutdown_counter == 2
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_init_async_context_manager() -> None:
|
||||
resource = object()
|
||||
|
||||
init_counter = 0
|
||||
shutdown_counter = 0
|
||||
|
||||
@asynccontextmanager
|
||||
async def _init():
|
||||
nonlocal init_counter, shutdown_counter
|
||||
|
||||
await asyncio.sleep(0.001)
|
||||
init_counter += 1
|
||||
|
||||
yield resource
|
||||
|
||||
await asyncio.sleep(0.001)
|
||||
shutdown_counter += 1
|
||||
|
||||
provider = providers.Resource(_init)
|
||||
|
||||
result1 = await provider()
|
||||
assert result1 is resource
|
||||
assert init_counter == 1
|
||||
assert shutdown_counter == 0
|
||||
|
||||
await provider.shutdown()
|
||||
assert init_counter == 1
|
||||
assert shutdown_counter == 1
|
||||
|
||||
result2 = await provider()
|
||||
assert result2 is resource
|
||||
assert init_counter == 2
|
||||
assert shutdown_counter == 1
|
||||
|
||||
await provider.shutdown()
|
||||
assert init_counter == 2
|
||||
assert shutdown_counter == 2
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_init_async_class():
|
||||
resource = object()
|
||||
|
|
|
@ -2,12 +2,10 @@
|
|||
|
||||
import decimal
|
||||
import sys
|
||||
from contextlib import contextmanager
|
||||
from typing import Any
|
||||
|
||||
from pytest import mark, raises
|
||||
|
||||
from dependency_injector import containers, errors, providers, resources
|
||||
from dependency_injector import containers, providers, resources, errors
|
||||
from pytest import raises, mark
|
||||
|
||||
|
||||
def init_fn(*args, **kwargs):
|
||||
|
@ -125,41 +123,6 @@ def test_init_generator():
|
|||
assert _init.shutdown_counter == 2
|
||||
|
||||
|
||||
def test_init_context_manager() -> None:
|
||||
init_counter, shutdown_counter = 0, 0
|
||||
|
||||
@contextmanager
|
||||
def _init():
|
||||
nonlocal init_counter, shutdown_counter
|
||||
|
||||
init_counter += 1
|
||||
yield
|
||||
shutdown_counter += 1
|
||||
|
||||
init_counter = 0
|
||||
shutdown_counter = 0
|
||||
|
||||
provider = providers.Resource(_init)
|
||||
|
||||
result1 = provider()
|
||||
assert result1 is None
|
||||
assert init_counter == 1
|
||||
assert shutdown_counter == 0
|
||||
|
||||
provider.shutdown()
|
||||
assert init_counter == 1
|
||||
assert shutdown_counter == 1
|
||||
|
||||
result2 = provider()
|
||||
assert result2 is None
|
||||
assert init_counter == 2
|
||||
assert shutdown_counter == 1
|
||||
|
||||
provider.shutdown()
|
||||
assert init_counter == 2
|
||||
assert shutdown_counter == 2
|
||||
|
||||
|
||||
def test_init_class():
|
||||
class TestResource(resources.Resource):
|
||||
init_counter = 0
|
||||
|
@ -227,7 +190,7 @@ def test_init_class_abc_shutdown_definition_is_not_required():
|
|||
|
||||
def test_init_not_callable():
|
||||
provider = providers.Resource(1)
|
||||
with raises(TypeError, match=r"object is not callable"):
|
||||
with raises(errors.Error):
|
||||
provider.init()
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import asyncio
|
||||
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Closing, Provide, inject
|
||||
from dependency_injector.wiring import inject, Provide, Closing
|
||||
|
||||
|
||||
class TestResource:
|
||||
|
@ -44,15 +42,6 @@ async def async_injection(
|
|||
return resource1, resource2
|
||||
|
||||
|
||||
@inject
|
||||
async def async_generator_injection(
|
||||
resource1: object = Provide[Container.resource1],
|
||||
resource2: object = Closing[Provide[Container.resource2]],
|
||||
):
|
||||
yield resource1
|
||||
yield resource2
|
||||
|
||||
|
||||
@inject
|
||||
async def async_injection_with_closing(
|
||||
resource1: object = Closing[Provide[Container.resource1]],
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
"""Test module for wiring with Annotated."""
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
if sys.version_info < (3, 9):
|
||||
pytest.skip("Annotated is only available in Python 3.9+", allow_module_level=True)
|
||||
|
||||
from decimal import Decimal
|
||||
from typing import Callable, Annotated
|
||||
|
||||
from dependency_injector import providers
|
||||
from dependency_injector.wiring import inject, Provide, Provider
|
||||
|
||||
from .container import Container, SubContainer
|
||||
from .service import Service
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
service_provider: Annotated[Callable[..., Service], Provider[Container.service]]
|
||||
undefined: Annotated[Callable, Provide[providers.Provider()]]
|
||||
|
||||
class TestClass:
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
service_provider: Annotated[Callable[..., Service], Provider[Container.service]]
|
||||
undefined: Annotated[Callable, Provide[providers.Provider()]]
|
||||
|
||||
@inject
|
||||
def __init__(self, service: Annotated[Service, Provide[Container.service]]):
|
||||
self.service = service
|
||||
|
||||
@inject
|
||||
def method(self, service: Annotated[Service, Provide[Container.service]]):
|
||||
return service
|
||||
|
||||
@classmethod
|
||||
@inject
|
||||
def class_method(cls, service: Annotated[Service, Provide[Container.service]]):
|
||||
return service
|
||||
|
||||
@staticmethod
|
||||
@inject
|
||||
def static_method(service: Annotated[Service, Provide[Container.service]]):
|
||||
return service
|
||||
|
||||
@inject
|
||||
def test_function(service: Annotated[Service, Provide[Container.service]]):
|
||||
return service
|
||||
|
||||
@inject
|
||||
def test_function_provider(service_provider: Annotated[Callable[..., Service], Provider[Container.service]]):
|
||||
service = service_provider()
|
||||
return service
|
||||
|
||||
@inject
|
||||
def test_config_value(
|
||||
value_int: Annotated[int, Provide[Container.config.a.b.c.as_int()]],
|
||||
value_float: Annotated[float, Provide[Container.config.a.b.c.as_float()]],
|
||||
value_str: Annotated[str, Provide[Container.config.a.b.c.as_(str)]],
|
||||
value_decimal: Annotated[Decimal, Provide[Container.config.a.b.c.as_(Decimal)]],
|
||||
value_required: Annotated[str, Provide[Container.config.a.b.c.required()]],
|
||||
value_required_int: Annotated[int, Provide[Container.config.a.b.c.required().as_int()]],
|
||||
value_required_float: Annotated[float, Provide[Container.config.a.b.c.required().as_float()]],
|
||||
value_required_str: Annotated[str, Provide[Container.config.a.b.c.required().as_(str)]],
|
||||
value_required_decimal: Annotated[str, Provide[Container.config.a.b.c.required().as_(Decimal)]],
|
||||
):
|
||||
return (
|
||||
value_int,
|
||||
value_float,
|
||||
value_str,
|
||||
value_decimal,
|
||||
value_required,
|
||||
value_required_int,
|
||||
value_required_float,
|
||||
value_required_str,
|
||||
value_required_decimal,
|
||||
)
|
||||
|
||||
@inject
|
||||
def test_config_value_required_undefined(
|
||||
value_required: Annotated[int, Provide[Container.config.a.b.c.required()]],
|
||||
):
|
||||
return value_required
|
||||
|
||||
@inject
|
||||
def test_provide_provider(service_provider: Annotated[Callable[..., Service], Provide[Container.service.provider]]):
|
||||
service = service_provider()
|
||||
return service
|
||||
|
||||
@inject
|
||||
def test_provider_provider(service_provider: Annotated[Callable[..., Service], Provider[Container.service.provider]]):
|
||||
service = service_provider()
|
||||
return service
|
||||
|
||||
@inject
|
||||
def test_provided_instance(some_value: Annotated[int, Provide[Container.service.provided.foo["bar"].call()]]):
|
||||
return some_value
|
||||
|
||||
@inject
|
||||
def test_subcontainer_provider(some_value: Annotated[int, Provide[Container.sub.int_object]]):
|
||||
return some_value
|
||||
|
||||
@inject
|
||||
def test_config_invariant(some_value: Annotated[int, Provide[Container.config.option[Container.config.switch]]]):
|
||||
return some_value
|
||||
|
||||
@inject
|
||||
def test_provide_from_different_containers(
|
||||
service: Annotated[Service, Provide[Container.service]],
|
||||
some_value: Annotated[int, Provide[SubContainer.int_object]],
|
||||
):
|
||||
return service, some_value
|
||||
|
||||
class ClassDecorator:
|
||||
def __init__(self, fn):
|
||||
self._fn = fn
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self._fn(*args, **kwargs)
|
||||
|
||||
@ClassDecorator
|
||||
@inject
|
||||
def test_class_decorator(service: Annotated[Service, Provide[Container.service]]):
|
||||
return service
|
||||
|
||||
def test_container(container: Annotated[Container, Provide[Container]]):
|
||||
return container.service()
|
|
@ -1,11 +1,7 @@
|
|||
import sys
|
||||
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from fastapi import FastAPI, Depends
|
||||
from fastapi import (
|
||||
Request,
|
||||
) # See: https://github.com/ets-labs/python-dependency-injector/issues/398
|
||||
from fastapi import Request # See: https://github.com/ets-labs/python-dependency-injector/issues/398
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
@ -32,16 +28,11 @@ async def index(service: Service = Depends(Provide[Container.service])):
|
|||
return {"result": result}
|
||||
|
||||
|
||||
@app.api_route("/annotated")
|
||||
@inject
|
||||
async def annotated(service: Annotated[Service, Depends(Provide[Container.service])]):
|
||||
result = await service.process()
|
||||
return {"result": result}
|
||||
|
||||
|
||||
@app.get("/auth")
|
||||
@inject
|
||||
def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
|
||||
def read_current_user(
|
||||
credentials: HTTPBasicCredentials = Depends(security)
|
||||
):
|
||||
return {"username": credentials.username, "password": credentials.password}
|
||||
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import sys
|
||||
|
||||
from fast_depends import Depends
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
|
||||
class CoefficientService:
|
||||
@staticmethod
|
||||
def get_coefficient() -> float:
|
||||
return 1.2
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
service = providers.Factory(CoefficientService)
|
||||
|
||||
|
||||
@inject
|
||||
def apply_coefficient(
|
||||
a: int,
|
||||
coefficient_provider: CoefficientService = Depends(Provide[Container.service]),
|
||||
) -> float:
|
||||
return a * coefficient_provider.get_coefficient()
|
||||
|
||||
|
||||
@inject
|
||||
def apply_coefficient_annotated(
|
||||
a: int,
|
||||
coefficient_provider: Annotated[
|
||||
CoefficientService, Depends(Provide[Container.service])
|
||||
],
|
||||
) -> float:
|
||||
return a * coefficient_provider.get_coefficient()
|
||||
|
||||
|
||||
container = Container()
|
||||
container.wire(modules=[sys.modules[__name__]])
|
|
@ -1,5 +1,3 @@
|
|||
from typing_extensions import Annotated
|
||||
|
||||
from flask import Flask, jsonify, request, current_app, session, g
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
@ -28,12 +26,5 @@ def index(service: Service = Provide[Container.service]):
|
|||
return jsonify({"result": result})
|
||||
|
||||
|
||||
@app.route("/annotated")
|
||||
@inject
|
||||
def annotated(service: Annotated[Service, Provide[Container.service]]):
|
||||
result = service.process()
|
||||
return jsonify({"result": result})
|
||||
|
||||
|
||||
container = Container()
|
||||
container.wire(modules=[__name__])
|
||||
|
|
|
@ -1,81 +1,41 @@
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Closing, Provide, inject
|
||||
|
||||
|
||||
class Counter:
|
||||
def __init__(self) -> None:
|
||||
self._init = 0
|
||||
self._shutdown = 0
|
||||
|
||||
def init(self) -> None:
|
||||
self._init += 1
|
||||
|
||||
def shutdown(self) -> None:
|
||||
self._shutdown += 1
|
||||
|
||||
def reset(self) -> None:
|
||||
self._init = 0
|
||||
self._shutdown = 0
|
||||
from dependency_injector.wiring import inject, Provide, Closing
|
||||
|
||||
|
||||
class Service:
|
||||
def __init__(self, counter: Optional[Counter] = None, **dependencies: Any) -> None:
|
||||
self.counter = counter or Counter()
|
||||
self.dependencies = dependencies
|
||||
init_counter: int = 0
|
||||
shutdown_counter: int = 0
|
||||
|
||||
def init(self) -> None:
|
||||
self.counter.init()
|
||||
@classmethod
|
||||
def reset_counter(cls):
|
||||
cls.init_counter = 0
|
||||
cls.shutdown_counter = 0
|
||||
|
||||
def shutdown(self) -> None:
|
||||
self.counter.shutdown()
|
||||
@classmethod
|
||||
def init(cls):
|
||||
cls.init_counter += 1
|
||||
|
||||
@property
|
||||
def init_counter(self) -> int:
|
||||
return self.counter._init
|
||||
|
||||
@property
|
||||
def shutdown_counter(self) -> int:
|
||||
return self.counter._shutdown
|
||||
@classmethod
|
||||
def shutdown(cls):
|
||||
cls.shutdown_counter += 1
|
||||
|
||||
|
||||
class FactoryService:
|
||||
def __init__(self, service: Service, service2: Service):
|
||||
def __init__(self, service: Service):
|
||||
self.service = service
|
||||
self.service2 = service2
|
||||
|
||||
|
||||
class NestedService:
|
||||
def __init__(self, factory_service: FactoryService):
|
||||
self.factory_service = factory_service
|
||||
|
||||
|
||||
def init_service(counter: Counter, _list: List[int], _dict: Dict[str, int]):
|
||||
service = Service(counter, _list=_list, _dict=_dict)
|
||||
def init_service():
|
||||
service = Service()
|
||||
service.init()
|
||||
yield service
|
||||
service.shutdown()
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
config = providers.Configuration(default={"a": 1, "b": 4})
|
||||
counter = providers.Singleton(Counter)
|
||||
_list = providers.List(
|
||||
providers.Callable(lambda a: a, a=config.a), providers.Callable(lambda b: b, 2)
|
||||
)
|
||||
_dict = providers.Dict(
|
||||
a=providers.Callable(lambda a: a, a=3), b=providers.Callable(lambda b: b, config.b)
|
||||
)
|
||||
service = providers.Resource(init_service, counter, _list, _dict=_dict)
|
||||
service2 = providers.Resource(init_service, counter, _list, _dict=_dict)
|
||||
factory_service = providers.Factory(FactoryService, service, service2)
|
||||
factory_service_kwargs = providers.Factory(
|
||||
FactoryService,
|
||||
service=service,
|
||||
service2=service2,
|
||||
)
|
||||
nested_service = providers.Factory(NestedService, factory_service)
|
||||
|
||||
service = providers.Resource(init_service)
|
||||
factory_service = providers.Factory(FactoryService, service)
|
||||
|
||||
|
||||
@inject
|
||||
|
@ -84,21 +44,5 @@ def test_function(service: Service = Closing[Provide["service"]]):
|
|||
|
||||
|
||||
@inject
|
||||
def test_function_dependency(
|
||||
factory: FactoryService = Closing[Provide["factory_service"]],
|
||||
):
|
||||
def test_function_dependency(factory: FactoryService = Closing[Provide["factory_service"]]):
|
||||
return factory
|
||||
|
||||
|
||||
@inject
|
||||
def test_function_dependency_kwargs(
|
||||
factory: FactoryService = Closing[Provide["factory_service_kwargs"]],
|
||||
):
|
||||
return factory
|
||||
|
||||
|
||||
@inject
|
||||
def test_function_nested_dependency(
|
||||
nested: NestedService = Closing[Provide["nested_service"]],
|
||||
):
|
||||
return nested
|
||||
|
|
|
@ -32,23 +32,6 @@ async def test_async_injections():
|
|||
assert asyncinjections.resource2.shutdown_counter == 0
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_async_generator_injections() -> None:
|
||||
resources = []
|
||||
|
||||
async for resource in asyncinjections.async_generator_injection():
|
||||
resources.append(resource)
|
||||
|
||||
assert len(resources) == 2
|
||||
assert resources[0] is asyncinjections.resource1
|
||||
assert asyncinjections.resource1.init_counter == 1
|
||||
assert asyncinjections.resource1.shutdown_counter == 0
|
||||
|
||||
assert resources[1] is asyncinjections.resource2
|
||||
assert asyncinjections.resource2.init_counter == 1
|
||||
assert asyncinjections.resource2.shutdown_counter == 1
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_async_injections_with_closing():
|
||||
resource1, resource2 = await asyncinjections.async_injection_with_closing()
|
||||
|
|
|
@ -1,176 +0,0 @@
|
|||
"""Main wiring tests for Annotated attribute and argument injection."""
|
||||
|
||||
from decimal import Decimal
|
||||
import typing
|
||||
|
||||
from dependency_injector import errors
|
||||
from dependency_injector.wiring import Closing, Provide, Provider, wire
|
||||
from pytest import fixture, mark, raises
|
||||
|
||||
from samples.wiring import module_annotated as module, package, resourceclosing
|
||||
from samples.wiring.service import Service
|
||||
from samples.wiring.container import Container, SubContainer
|
||||
|
||||
@fixture(autouse=True)
|
||||
def container():
|
||||
container = Container(config={"a": {"b": {"c": 10}}})
|
||||
container.wire(
|
||||
modules=[module],
|
||||
packages=[package],
|
||||
)
|
||||
yield container
|
||||
container.unwire()
|
||||
|
||||
@fixture
|
||||
def subcontainer():
|
||||
container = SubContainer()
|
||||
container.wire(
|
||||
modules=[module],
|
||||
packages=[package],
|
||||
)
|
||||
yield container
|
||||
container.unwire()
|
||||
|
||||
@fixture
|
||||
def resourceclosing_container():
|
||||
container = resourceclosing.Container()
|
||||
container.wire(modules=[resourceclosing])
|
||||
yield container
|
||||
container.unwire()
|
||||
|
||||
def test_module_attributes_wiring():
|
||||
assert isinstance(module.service, Service)
|
||||
assert isinstance(module.service_provider(), Service)
|
||||
assert isinstance(module.__annotations__['undefined'], typing._AnnotatedAlias)
|
||||
|
||||
def test_class_wiring():
|
||||
test_class_object = module.TestClass()
|
||||
assert isinstance(test_class_object.service, Service)
|
||||
|
||||
def test_class_wiring_context_arg(container: Container):
|
||||
test_service = container.service()
|
||||
test_class_object = module.TestClass(service=test_service)
|
||||
assert test_class_object.service is test_service
|
||||
|
||||
def test_class_method_wiring():
|
||||
test_class_object = module.TestClass()
|
||||
service = test_class_object.method()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_class_classmethod_wiring():
|
||||
service = module.TestClass.class_method()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_instance_classmethod_wiring():
|
||||
instance = module.TestClass()
|
||||
service = instance.class_method()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_class_staticmethod_wiring():
|
||||
service = module.TestClass.static_method()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_instance_staticmethod_wiring():
|
||||
instance = module.TestClass()
|
||||
service = instance.static_method()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_class_attribute_wiring():
|
||||
assert isinstance(module.TestClass.service, Service)
|
||||
assert isinstance(module.TestClass.service_provider(), Service)
|
||||
assert isinstance(module.TestClass.__annotations__['undefined'], typing._AnnotatedAlias)
|
||||
|
||||
def test_function_wiring():
|
||||
service = module.test_function()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_function_wiring_context_arg(container: Container):
|
||||
test_service = container.service()
|
||||
service = module.test_function(service=test_service)
|
||||
assert service is test_service
|
||||
|
||||
def test_function_wiring_provider():
|
||||
service = module.test_function_provider()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_function_wiring_provider_context_arg(container: Container):
|
||||
test_service = container.service()
|
||||
service = module.test_function_provider(service_provider=lambda: test_service)
|
||||
assert service is test_service
|
||||
|
||||
def test_configuration_option():
|
||||
(
|
||||
value_int,
|
||||
value_float,
|
||||
value_str,
|
||||
value_decimal,
|
||||
value_required,
|
||||
value_required_int,
|
||||
value_required_float,
|
||||
value_required_str,
|
||||
value_required_decimal,
|
||||
) = module.test_config_value()
|
||||
|
||||
assert value_int == 10
|
||||
assert value_float == 10.0
|
||||
assert value_str == "10"
|
||||
assert value_decimal == Decimal(10)
|
||||
assert value_required == 10
|
||||
assert value_required_int == 10
|
||||
assert value_required_float == 10.0
|
||||
assert value_required_str == "10"
|
||||
assert value_required_decimal == Decimal(10)
|
||||
|
||||
def test_configuration_option_required_undefined(container: Container):
|
||||
container.config.reset_override()
|
||||
with raises(errors.Error, match="Undefined configuration option \"config.a.b.c\""):
|
||||
module.test_config_value_required_undefined()
|
||||
|
||||
def test_provide_provider():
|
||||
service = module.test_provide_provider()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_provider_provider():
|
||||
service = module.test_provider_provider()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_provided_instance(container: Container):
|
||||
class TestService:
|
||||
foo = {"bar": lambda: 10}
|
||||
|
||||
with container.service.override(TestService()):
|
||||
some_value = module.test_provided_instance()
|
||||
assert some_value == 10
|
||||
|
||||
def test_subcontainer():
|
||||
some_value = module.test_subcontainer_provider()
|
||||
assert some_value == 1
|
||||
|
||||
def test_config_invariant(container: Container):
|
||||
config = {
|
||||
"option": {
|
||||
"a": 1,
|
||||
"b": 2,
|
||||
},
|
||||
"switch": "a",
|
||||
}
|
||||
container.config.from_dict(config)
|
||||
|
||||
value_default = module.test_config_invariant()
|
||||
assert value_default == 1
|
||||
|
||||
with container.config.switch.override("a"):
|
||||
value_a = module.test_config_invariant()
|
||||
assert value_a == 1
|
||||
|
||||
with container.config.switch.override("b"):
|
||||
value_b = module.test_config_invariant()
|
||||
assert value_b == 2
|
||||
|
||||
def test_class_decorator():
|
||||
service = module.test_class_decorator()
|
||||
assert isinstance(service, Service)
|
||||
|
||||
def test_container():
|
||||
service = module.test_container()
|
||||
assert isinstance(service, Service)
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
from decimal import Decimal
|
||||
|
||||
from pytest import fixture, mark, raises
|
||||
from samples.wiringstringids import module, package, resourceclosing
|
||||
from samples.wiringstringids.container import Container, SubContainer
|
||||
from samples.wiringstringids.service import Service
|
||||
|
||||
from dependency_injector import errors
|
||||
from dependency_injector.wiring import Closing, Provide, Provider, wire
|
||||
from pytest import fixture, mark, raises
|
||||
|
||||
from samples.wiringstringids import module, package, resourceclosing
|
||||
from samples.wiringstringids.service import Service
|
||||
from samples.wiringstringids.container import Container, SubContainer
|
||||
|
||||
|
||||
@fixture(autouse=True)
|
||||
|
@ -34,11 +34,10 @@ def subcontainer():
|
|||
|
||||
|
||||
@fixture
|
||||
def resourceclosing_container(request):
|
||||
def resourceclosing_container():
|
||||
container = resourceclosing.Container()
|
||||
container.wire(modules=[resourceclosing])
|
||||
with container.reset_singletons():
|
||||
yield container
|
||||
yield container
|
||||
container.unwire()
|
||||
|
||||
|
||||
|
@ -275,65 +274,42 @@ def test_wire_multiple_containers():
|
|||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_resource():
|
||||
resourceclosing.Service.reset_counter()
|
||||
|
||||
result_1 = resourceclosing.test_function()
|
||||
assert isinstance(result_1, resourceclosing.Service)
|
||||
assert result_1.init_counter == 1
|
||||
assert result_1.shutdown_counter == 1
|
||||
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
|
||||
|
||||
result_2 = resourceclosing.test_function()
|
||||
assert isinstance(result_2, resourceclosing.Service)
|
||||
assert result_2.init_counter == 2
|
||||
assert result_2.shutdown_counter == 2
|
||||
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
|
||||
|
||||
assert result_1 is not result_2
|
||||
|
||||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_dependency_resource():
|
||||
resourceclosing.Service.reset_counter()
|
||||
|
||||
result_1 = resourceclosing.test_function_dependency()
|
||||
assert isinstance(result_1, resourceclosing.FactoryService)
|
||||
assert result_1.service.init_counter == 2
|
||||
assert result_1.service.shutdown_counter == 2
|
||||
assert result_1.service.init_counter == 1
|
||||
assert result_1.service.shutdown_counter == 1
|
||||
|
||||
result_2 = resourceclosing.test_function_dependency()
|
||||
|
||||
assert isinstance(result_2, resourceclosing.FactoryService)
|
||||
assert result_2.service.init_counter == 4
|
||||
assert result_2.service.shutdown_counter == 4
|
||||
|
||||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_dependency_resource_kwargs():
|
||||
result_1 = resourceclosing.test_function_dependency_kwargs()
|
||||
assert isinstance(result_1, resourceclosing.FactoryService)
|
||||
assert result_1.service.init_counter == 2
|
||||
assert result_1.service.shutdown_counter == 2
|
||||
|
||||
result_2 = resourceclosing.test_function_dependency_kwargs()
|
||||
assert isinstance(result_2, resourceclosing.FactoryService)
|
||||
assert result_2.service.init_counter == 4
|
||||
assert result_2.service.shutdown_counter == 4
|
||||
|
||||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_nested_dependency_resource():
|
||||
result_1 = resourceclosing.test_function_nested_dependency()
|
||||
assert isinstance(result_1, resourceclosing.NestedService)
|
||||
assert result_1.factory_service.service.init_counter == 2
|
||||
assert result_1.factory_service.service.shutdown_counter == 2
|
||||
|
||||
result_2 = resourceclosing.test_function_nested_dependency()
|
||||
assert isinstance(result_2, resourceclosing.NestedService)
|
||||
assert result_2.factory_service.service.init_counter == 4
|
||||
assert result_2.factory_service.service.shutdown_counter == 4
|
||||
assert result_2.service.init_counter == 2
|
||||
assert result_2.service.shutdown_counter == 2
|
||||
|
||||
assert result_1 is not result_2
|
||||
|
||||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_resource_bypass_marker_injection():
|
||||
resourceclosing.Service.reset_counter()
|
||||
|
||||
result_1 = resourceclosing.test_function(service=Closing[Provide["service"]])
|
||||
assert isinstance(result_1, resourceclosing.Service)
|
||||
assert result_1.init_counter == 1
|
||||
|
@ -349,6 +325,7 @@ def test_closing_resource_bypass_marker_injection():
|
|||
|
||||
@mark.usefixtures("resourceclosing_container")
|
||||
def test_closing_resource_context():
|
||||
resourceclosing.Service.reset_counter()
|
||||
service = resourceclosing.Service()
|
||||
|
||||
result_1 = resourceclosing.test_function(service=service)
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
"""Tests for string module and package names."""
|
||||
|
||||
from typing import Iterator, Optional
|
||||
|
||||
from pytest import fixture, mark
|
||||
from samples.wiring.container import Container
|
||||
|
||||
from dependency_injector.wiring import _fetch_reference_injections
|
||||
|
||||
|
||||
@fixture
|
||||
def container() -> Iterator[Container]:
|
||||
container = Container()
|
||||
yield container
|
||||
container.unwire()
|
||||
|
||||
|
||||
@mark.parametrize(
|
||||
["arg_value", "wc_value", "empty_cache"],
|
||||
[
|
||||
(None, False, True),
|
||||
(False, True, True),
|
||||
(True, False, False),
|
||||
(None, True, False),
|
||||
],
|
||||
)
|
||||
def test_fetch_reference_injections_cache(
|
||||
container: Container,
|
||||
arg_value: Optional[bool],
|
||||
wc_value: bool,
|
||||
empty_cache: bool,
|
||||
) -> None:
|
||||
container.wiring_config.keep_cache = wc_value
|
||||
container.wire(
|
||||
modules=["samples.wiring.module"],
|
||||
packages=["samples.wiring.package"],
|
||||
keep_cache=arg_value,
|
||||
)
|
||||
cache_info = _fetch_reference_injections.cache_info()
|
||||
|
||||
if empty_cache:
|
||||
assert cache_info == (0, 0, None, 0)
|
||||
else:
|
||||
assert cache_info.hits > 0
|
||||
assert cache_info.misses > 0
|
||||
assert cache_info.currsize > 0
|
|
@ -4,17 +4,13 @@ from pytest_asyncio import fixture as aio_fixture
|
|||
|
||||
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
|
||||
import os
|
||||
|
||||
_SAMPLES_DIR = os.path.abspath(
|
||||
os.path.sep.join(
|
||||
(
|
||||
os.path.dirname(__file__),
|
||||
"../samples/",
|
||||
)
|
||||
),
|
||||
os.path.sep.join((
|
||||
os.path.dirname(__file__),
|
||||
"../samples/",
|
||||
)),
|
||||
)
|
||||
import sys
|
||||
|
||||
sys.path.append(_SAMPLES_DIR)
|
||||
|
||||
|
||||
|
@ -41,19 +37,6 @@ async def test_depends_marker_injection(async_client: AsyncClient):
|
|||
assert response.json() == {"result": "Foo"}
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_depends_with_annotated(async_client: AsyncClient):
|
||||
class ServiceMock:
|
||||
async def process(self):
|
||||
return "Foo"
|
||||
|
||||
with web.container.service.override(ServiceMock()):
|
||||
response = await async_client.get("/")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"result": "Foo"}
|
||||
|
||||
|
||||
@mark.asyncio
|
||||
async def test_depends_injection(async_client: AsyncClient):
|
||||
response = await async_client.get("/auth", auth=("john_smith", "secret"))
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
from wiringfastdepends import sample
|
||||
|
||||
|
||||
def test_apply_coefficient() -> None:
|
||||
assert sample.apply_coefficient(100) == 120.0
|
||||
|
||||
|
||||
def test_apply_coefficient_annotated() -> None:
|
||||
assert sample.apply_coefficient_annotated(100) == 120.0
|
|
@ -2,25 +2,19 @@ import json
|
|||
|
||||
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
|
||||
import os
|
||||
|
||||
_TOP_DIR = os.path.abspath(
|
||||
os.path.sep.join(
|
||||
(
|
||||
os.path.dirname(__file__),
|
||||
"../",
|
||||
)
|
||||
),
|
||||
os.path.sep.join((
|
||||
os.path.dirname(__file__),
|
||||
"../",
|
||||
)),
|
||||
)
|
||||
_SAMPLES_DIR = os.path.abspath(
|
||||
os.path.sep.join(
|
||||
(
|
||||
os.path.dirname(__file__),
|
||||
"../samples/",
|
||||
)
|
||||
),
|
||||
os.path.sep.join((
|
||||
os.path.dirname(__file__),
|
||||
"../samples/",
|
||||
)),
|
||||
)
|
||||
import sys
|
||||
|
||||
sys.path.append(_TOP_DIR)
|
||||
sys.path.append(_SAMPLES_DIR)
|
||||
|
||||
|
@ -35,13 +29,3 @@ def test_wiring_with_flask():
|
|||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.data) == {"result": "OK"}
|
||||
|
||||
|
||||
def test_wiring_with_annotated():
|
||||
client = web.app.test_client()
|
||||
|
||||
with web.app.app_context():
|
||||
response = client.get("/annotated")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert json.loads(response.data) == {"result": "OK"}
|
||||
|
|
|
@ -6,13 +6,6 @@ import inspect
|
|||
from dependency_injector.wiring import inject
|
||||
|
||||
|
||||
def test_isfunction():
|
||||
@inject
|
||||
def foo(): ...
|
||||
|
||||
assert inspect.isfunction(foo)
|
||||
|
||||
|
||||
def test_asyncio_iscoroutinefunction():
|
||||
@inject
|
||||
async def foo():
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user