mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-06-06 06:33:15 +03:00
Merge branch 'ets-labs:master' into provided-types
This commit is contained in:
commit
b547a9e088
10
.coveragerc
10
.coveragerc
|
@ -1,10 +0,0 @@
|
||||||
[run]
|
|
||||||
source = src/dependency_injector
|
|
||||||
omit = tests/unit
|
|
||||||
plugins = Cython.Coverage
|
|
||||||
|
|
||||||
[report]
|
|
||||||
show_missing = true
|
|
||||||
|
|
||||||
[html]
|
|
||||||
directory=reports/unittests/
|
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
github: rmk135
|
26
.github/workflows/publishing.yml
vendored
26
.github/workflows/publishing.yml
vendored
|
@ -15,11 +15,11 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.13
|
||||||
- run: pip install tox
|
- run: pip install tox
|
||||||
- run: tox
|
- run: tox
|
||||||
env:
|
env:
|
||||||
TOXENV: 3.11
|
TOXENV: 3.13
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
name: Run linters
|
name: Run linters
|
||||||
|
@ -31,7 +31,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.13
|
||||||
- run: pip install tox
|
- run: pip install tox
|
||||||
- run: tox
|
- run: tox
|
||||||
env:
|
env:
|
||||||
|
@ -45,8 +45,10 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.13
|
||||||
- run: python setup.py sdist
|
- run: |
|
||||||
|
python -m pip install --upgrade build
|
||||||
|
python -m build --sdist
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ./dist/*
|
path: ./dist/*
|
||||||
|
@ -57,13 +59,13 @@ jobs:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, windows-2019, macos-11]
|
os: [ubuntu-22.04, windows-2019, macos-14]
|
||||||
env:
|
env:
|
||||||
CIBW_SKIP: cp27-win*
|
CIBW_SKIP: cp27-*
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: pypa/cibuildwheel@v2.11.3
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: ./wheelhouse/*.whl
|
path: ./wheelhouse/*.whl
|
||||||
|
@ -72,13 +74,15 @@ jobs:
|
||||||
name: Build wheels (ubuntu-22.04-aarch64)
|
name: Build wheels (ubuntu-22.04-aarch64)
|
||||||
needs: [tests, linters]
|
needs: [tests, linters]
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
env:
|
||||||
|
CIBW_SKIP: cp27-*
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: pypa/cibuildwheel@v2.11.3
|
uses: pypa/cibuildwheel@v2.20.0
|
||||||
env:
|
env:
|
||||||
CIBW_ARCHS_LINUX: aarch64
|
CIBW_ARCHS_LINUX: aarch64
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
|
@ -110,9 +114,9 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.13
|
||||||
- run: pip install -r requirements-doc.txt
|
|
||||||
- run: pip install awscli
|
- run: pip install awscli
|
||||||
|
- run: pip install -r requirements-doc.txt
|
||||||
- run: pip install -e .
|
- run: pip install -e .
|
||||||
- run: (cd docs && make clean html)
|
- run: (cd docs && make clean html)
|
||||||
- run: |
|
- run: |
|
||||||
|
|
25
.github/workflows/tests-and-linters.yml
vendored
25
.github/workflows/tests-and-linters.yml
vendored
|
@ -9,7 +9,7 @@ jobs:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [2.7, 3.5, 3.6, 3.7, pypy2.7, pypy3.9]
|
python-version: [3.7]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
|
@ -25,7 +25,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: [3.8, 3.9, "3.10", 3.11]
|
python-version: [3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
|
@ -36,21 +36,32 @@ jobs:
|
||||||
env:
|
env:
|
||||||
TOXENV: ${{ matrix.python-version }}
|
TOXENV: ${{ matrix.python-version }}
|
||||||
|
|
||||||
|
test-different-pydantic-versions:
|
||||||
|
name: Run tests with different pydantic versions
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: "3.12"
|
||||||
|
- run: pip install tox
|
||||||
|
- run: tox -e pydantic-v1,pydantic-v2
|
||||||
|
|
||||||
test-coverage:
|
test-coverage:
|
||||||
name: Run tests with coverage
|
name: Run tests with coverage
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
DEPENDENCY_INJECTOR_DEBUG_MODE: 1
|
DEPENDENCY_INJECTOR_DEBUG_MODE: 1
|
||||||
|
PIP_VERBOSE: 1
|
||||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.12
|
||||||
- run: pip install tox cython
|
- run: pip install tox 'cython>=3,<4'
|
||||||
- run: make cythonize
|
- run: tox -vv
|
||||||
- run: tox
|
|
||||||
env:
|
env:
|
||||||
TOXENV: coveralls
|
TOXENV: coveralls
|
||||||
|
|
||||||
|
@ -64,7 +75,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-python@v4
|
- uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: 3.11
|
python-version: 3.13
|
||||||
- run: pip install tox
|
- run: pip install tox
|
||||||
- run: tox
|
- run: tox
|
||||||
env:
|
env:
|
||||||
|
|
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -63,13 +63,13 @@ venv*/
|
||||||
# Vim Rope
|
# Vim Rope
|
||||||
.ropeproject/
|
.ropeproject/
|
||||||
|
|
||||||
# C extensions
|
# Cython artifacts
|
||||||
src/dependency_injector/*.h
|
src/**/*.c
|
||||||
src/dependency_injector/*.so
|
src/**/*.h
|
||||||
src/dependency_injector/containers/*.h
|
src/**/*.so
|
||||||
src/dependency_injector/containers/*.so
|
src/**/*.html
|
||||||
src/dependency_injector/providers/*.h
|
|
||||||
src/dependency_injector/providers/*.so
|
|
||||||
|
|
||||||
# Workspace for samples
|
# Workspace for samples
|
||||||
.workspace/
|
.workspace/
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
49
.pylintrc
49
.pylintrc
|
@ -1,49 +0,0 @@
|
||||||
[MASTER]
|
|
||||||
|
|
||||||
# Add <file or directory> to the black list. It should be a base name, not a
|
|
||||||
# path. You may set this option multiple times.
|
|
||||||
ignore=utils,tests
|
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
|
||||||
|
|
||||||
# Disable the message(s) with the given id(s).
|
|
||||||
# disable-msg=
|
|
||||||
|
|
||||||
[SIMILARITIES]
|
|
||||||
|
|
||||||
# Minimum lines number of a similarity.
|
|
||||||
min-similarity-lines=5
|
|
||||||
|
|
||||||
[TYPECHECK]
|
|
||||||
ignore-mixin-members=yes
|
|
||||||
# ignored-classes=
|
|
||||||
zope=no
|
|
||||||
# generated-members=providedBy,implementedBy,rawDataReceived
|
|
||||||
|
|
||||||
[DESIGN]
|
|
||||||
# Maximum number of arguments for function / method
|
|
||||||
max-args=10
|
|
||||||
|
|
||||||
# Maximum number of locals for function / method body
|
|
||||||
max-locals=20
|
|
||||||
|
|
||||||
# Maximum number of return / yield for function / method body
|
|
||||||
max-returns=10
|
|
||||||
|
|
||||||
# Maximum number of branch for function / method body
|
|
||||||
max-branchs=10
|
|
||||||
|
|
||||||
# Maximum number of statements in function / method body
|
|
||||||
max-statements=60
|
|
||||||
|
|
||||||
# Maximum number of parents for a class (see R0901).
|
|
||||||
max-parents=10
|
|
||||||
|
|
||||||
# Maximum number of attributes for a class (see R0902).
|
|
||||||
max-attributes=30
|
|
||||||
|
|
||||||
# Minimum number of public methods for a class (see R0903).
|
|
||||||
min-public-methods=0
|
|
||||||
|
|
||||||
# Maximum number of public methods for a class (see R0904).
|
|
||||||
max-public-methods=30
|
|
|
@ -20,3 +20,5 @@ Dependency Injector Contributors
|
||||||
+ Ngo Thanh Loi (Leonn) (loingo95)
|
+ Ngo Thanh Loi (Leonn) (loingo95)
|
||||||
+ Thiago Hiromi (thiromi)
|
+ Thiago Hiromi (thiromi)
|
||||||
+ Felipe Rubio (krouw)
|
+ Felipe Rubio (krouw)
|
||||||
|
+ Anton Petrov (anton-petrov)
|
||||||
|
+ ZipFile (ZipFile)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2022, Roman Mogylatov
|
Copyright (c) 2024, Roman Mogylatov
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
32
Makefile
32
Makefile
|
@ -1,14 +1,6 @@
|
||||||
VERSION := $(shell python setup.py --version)
|
VERSION := $(shell python setup.py --version)
|
||||||
|
|
||||||
CYTHON_SRC := $(shell find src/dependency_injector -name '*.pyx')
|
export COVERAGE_RCFILE := pyproject.toml
|
||||||
|
|
||||||
CYTHON_DIRECTIVES = -Xlanguage_level=2
|
|
||||||
|
|
||||||
ifdef DEPENDENCY_INJECTOR_DEBUG_MODE
|
|
||||||
CYTHON_DIRECTIVES += -Xprofile=True
|
|
||||||
CYTHON_DIRECTIVES += -Xlinetrace=True
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
# Clean sources
|
# Clean sources
|
||||||
|
@ -25,21 +17,17 @@ clean:
|
||||||
find examples -name '*.py[co]' -delete
|
find examples -name '*.py[co]' -delete
|
||||||
find examples -name '__pycache__' -delete
|
find examples -name '__pycache__' -delete
|
||||||
|
|
||||||
cythonize:
|
build: clean
|
||||||
# Compile Cython to C
|
# Compile C extensions
|
||||||
cython -a $(CYTHON_DIRECTIVES) $(CYTHON_SRC)
|
python setup.py build_ext --inplace
|
||||||
# Move all Cython html reports
|
# Move all Cython html reports
|
||||||
mkdir -p reports/cython/
|
mkdir -p reports/cython/
|
||||||
find src -name '*.html' -exec mv {} reports/cython/ \;
|
find src -name '*.html' -exec mv {} reports/cython/ \;
|
||||||
|
|
||||||
build: clean cythonize
|
|
||||||
# Compile C extensions
|
|
||||||
python setup.py build_ext --inplace
|
|
||||||
|
|
||||||
docs-live:
|
docs-live:
|
||||||
sphinx-autobuild docs docs/_build/html
|
sphinx-autobuild docs docs/_build/html
|
||||||
|
|
||||||
install: uninstall clean cythonize
|
install: uninstall clean build
|
||||||
pip install -ve .
|
pip install -ve .
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
|
@ -48,9 +36,9 @@ uninstall:
|
||||||
test:
|
test:
|
||||||
# Unit tests with coverage report
|
# Unit tests with coverage report
|
||||||
coverage erase
|
coverage erase
|
||||||
coverage run --rcfile=./.coveragerc -m pytest -c tests/.configs/pytest.ini
|
coverage run -m pytest -c tests/.configs/pytest.ini
|
||||||
coverage report --rcfile=./.coveragerc
|
coverage report
|
||||||
coverage html --rcfile=./.coveragerc
|
coverage html
|
||||||
|
|
||||||
check:
|
check:
|
||||||
flake8 src/dependency_injector/
|
flake8 src/dependency_injector/
|
||||||
|
@ -61,9 +49,9 @@ check:
|
||||||
|
|
||||||
mypy tests/typing
|
mypy tests/typing
|
||||||
|
|
||||||
test-publish: cythonize
|
test-publish: build
|
||||||
# Create distributions
|
# Create distributions
|
||||||
python setup.py sdist
|
python -m build --sdist
|
||||||
# Upload distributions to PyPI
|
# Upload distributions to PyPI
|
||||||
twine upload --repository testpypi dist/dependency-injector-$(VERSION)*
|
twine upload --repository testpypi dist/dependency-injector-$(VERSION)*
|
||||||
|
|
||||||
|
|
9
docs/_static/custom.css
vendored
Normal file
9
docs/_static/custom.css
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
.no-border {
|
||||||
|
border: 0 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.no-border td {
|
||||||
|
border: 0px !important;
|
||||||
|
padding: 0px 10px 0px 0px !important;
|
||||||
|
}
|
11
docs/_static/disqus.js
vendored
11
docs/_static/disqus.js
vendored
|
@ -1,11 +0,0 @@
|
||||||
var disqus_shortname;
|
|
||||||
var disqus_identifier;
|
|
||||||
|
|
||||||
$(function() {
|
|
||||||
var disqus_thread = $("#disqus_thread");
|
|
||||||
disqus_shortname = disqus_thread.data('disqus-shortname');
|
|
||||||
disqus_identifier = disqus_thread.data('disqus-identifier');
|
|
||||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
|
||||||
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
|
|
||||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
|
||||||
});
|
|
1
docs/_static/sponsor.html
vendored
Normal file
1
docs/_static/sponsor.html
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<iframe src="https://github.com/sponsors/rmk135/button" title="Sponsor Dependency Injector" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe>
|
|
@ -33,7 +33,7 @@ sys.path.insert(0, os.path.abspath(".."))
|
||||||
extensions = [
|
extensions = [
|
||||||
"alabaster",
|
"alabaster",
|
||||||
"sphinx.ext.autodoc",
|
"sphinx.ext.autodoc",
|
||||||
"sphinxcontrib.disqus",
|
"sphinx_disqus.disqus",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
@ -52,7 +52,7 @@ master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = "Dependency Injector"
|
project = "Dependency Injector"
|
||||||
copyright = "2022, Roman Mogylatov"
|
copyright = "2024, Roman Mogylatov"
|
||||||
author = "Roman Mogylatov"
|
author = "Roman Mogylatov"
|
||||||
|
|
||||||
# The version info for the project you"re documenting, acts as replacement for
|
# The version info for the project you"re documenting, acts as replacement for
|
||||||
|
@ -147,6 +147,9 @@ html_favicon = "favicon.ico"
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ["_static"]
|
html_static_path = ["_static"]
|
||||||
|
html_css_files = [
|
||||||
|
"custom.css",
|
||||||
|
]
|
||||||
|
|
||||||
# Add any extra paths that contain custom files (such as robots.txt or
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
# .htaccess) here, relative to this directory. These files are copied
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
|
@ -306,4 +309,5 @@ html_theme_options = {
|
||||||
"description": "Dependency injection framework for Python by Roman Mogylatov",
|
"description": "Dependency injection framework for Python by Roman Mogylatov",
|
||||||
"code_font_size": "10pt",
|
"code_font_size": "10pt",
|
||||||
"analytics_id": "UA-67012059-1",
|
"analytics_id": "UA-67012059-1",
|
||||||
|
"donate_url": "https://github.com/sponsors/rmk135",
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,4 +78,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/aiohttp>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/aiohttp>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -84,4 +84,6 @@ Run the application
|
||||||
|
|
||||||
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/application-multiple-containers>`_.
|
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/application-multiple-containers>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
|
@ -90,4 +90,6 @@ Run the application
|
||||||
|
|
||||||
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/application-single-container>`_.
|
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/application-single-container>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -17,4 +17,6 @@ Listing of ``boto3_session_example.py``:
|
||||||
.. literalinclude:: ../../examples/miniapps/boto3-session/boto3_session_example.py
|
.. literalinclude:: ../../examples/miniapps/boto3-session/boto3_session_example.py
|
||||||
:language: python
|
:language: python
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -129,4 +129,6 @@ Run the application
|
||||||
|
|
||||||
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/decoupled-packages>`_.
|
You can find the source code and instructions for running on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/decoupled-packages>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -94,4 +94,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/django>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/django>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -95,4 +95,6 @@ See also:
|
||||||
- Resource provider :ref:`resource-async-initializers`
|
- Resource provider :ref:`resource-async-initializers`
|
||||||
- Wiring :ref:`async-injections-wiring`
|
- Wiring :ref:`async-injections-wiring`
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -116,4 +116,6 @@ Sources
|
||||||
|
|
||||||
The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi-sqlalchemy>`_.
|
The source code is available on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi-sqlalchemy>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -76,4 +76,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -86,4 +86,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask-blueprints>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask-blueprints>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -84,4 +84,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -77,4 +77,6 @@ Sources
|
||||||
|
|
||||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/sanic>`_.
|
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/sanic>`_.
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -9,11 +9,11 @@ Dependency Injector --- Dependency injection framework for Python
|
||||||
:description: Dependency Injector is a dependency injection framework
|
:description: Dependency Injector is a dependency injection framework
|
||||||
for Python. It helps to maintain you application structure.
|
for Python. It helps to maintain you application structure.
|
||||||
It was designed to be unified, developer-friendly
|
It was designed to be unified, developer-friendly
|
||||||
tool that helps to implement dependency injection design
|
tool that helps to implement dependency injection design
|
||||||
pattern in formal, pretty, Pythonic way. Dependency Injector
|
pattern in formal, pretty, Pythonic way. Dependency Injector
|
||||||
provides implementations of such popular design patterns
|
provides implementations of such popular design patterns
|
||||||
like IoC container, Factory and Singleton. Dependency
|
like IoC container, Factory and Singleton. Dependency
|
||||||
Injector providers are implemented as C extension types
|
Injector providers are implemented as C extension types
|
||||||
using Cython.
|
using Cython.
|
||||||
|
|
||||||
.. _index:
|
.. _index:
|
||||||
|
|
|
@ -310,4 +310,6 @@ A few useful links related to a dependency injection design pattern for further
|
||||||
+ https://github.com/ets-labs/python-dependency-injector
|
+ https://github.com/ets-labs/python-dependency-injector
|
||||||
+ https://pypi.org/project/dependency-injector/
|
+ https://pypi.org/project/dependency-injector/
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1,12 +1,54 @@
|
||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
This document describes all the changes in *Dependency Injector* framework
|
This document describes all the changes in *Dependency Injector* framework
|
||||||
that were made in every particular version.
|
that were made in every particular version.
|
||||||
|
|
||||||
From version 0.7.6 *Dependency Injector* framework strictly
|
From version 0.7.6 *Dependency Injector* framework strictly
|
||||||
follows `Semantic versioning`_
|
follows `Semantic versioning`_
|
||||||
|
|
||||||
|
4.45.0
|
||||||
|
--------
|
||||||
|
- Add Starlette lifespan handler implementation (`#683 <https://github.com/ets-labs/python-dependency-injector/pull/683>`_).
|
||||||
|
- Raise exception in ``ThreadLocalSingleton`` instead of hiding it in finally (`#845 <https://github.com/ets-labs/python-dependency-injector/pull/845>`_).
|
||||||
|
- Improve debuggability of ``deepcopy`` errors (`#839 <https://github.com/ets-labs/python-dependency-injector/pull/839>`_).
|
||||||
|
- Update examples (`#838 <https://github.com/ets-labs/python-dependency-injector/pull/838>`_).
|
||||||
|
- Upgrade testing dependencies (`#837 <https://github.com/ets-labs/python-dependency-injector/pull/837>`_).
|
||||||
|
- Add minor fixes to the documentation (`#709 <https://github.com/ets-labs/python-dependency-injector/pull/709>`_).
|
||||||
|
- Remove ``six`` from the dependencies (`3ba4704 <https://github.com/ets-labs/python-dependency-injector/commit/3ba4704bc1cb00310749fd2eda0c8221167c313c>`_).
|
||||||
|
|
||||||
|
Many thanks for the contributions to:
|
||||||
|
- `ZipFile <https://github.com/ZipFile>`_
|
||||||
|
- `František Trebuňa <https://github.com/gortibaldik>`_
|
||||||
|
- `JC (Jonathan Chen) <https://github.com/dijonkitchen>`_
|
||||||
|
|
||||||
|
4.44.0
|
||||||
|
--------
|
||||||
|
- Implement support for Pydantic 2. PR: `#832 <https://github.com/ets-labs/python-dependency-injector/pull/832>`_.
|
||||||
|
- Implement `PEP-517 <https://peps.python.org/pep-0517/>`_, `PEP-518 <https://peps.python.org/pep-0518/>`_, and
|
||||||
|
`PEP-621 <https://peps.python.org/pep-0621/>`_. PR: `#829 <https://github.com/ets-labs/python-dependency-injector/pull/829>`_.
|
||||||
|
|
||||||
|
Many thanks to `ZipFile <https://github.com/ZipFile>`_ for both contributions.
|
||||||
|
|
||||||
|
4.43.0
|
||||||
|
--------
|
||||||
|
- Add support for Python 3.13.
|
||||||
|
- Migrate to Cython 3 (version 3.0.11). Many thanks to `ZipFile <https://github.com/ZipFile>`_ for
|
||||||
|
this contribution `#813 <https://github.com/ets-labs/python-dependency-injector/pull/813>`_.
|
||||||
|
|
||||||
|
4.42.0
|
||||||
|
--------
|
||||||
|
- Promote release ``4.42.0b1`` to a production release.
|
||||||
|
- Fix the Disqus comment widget.
|
||||||
|
|
||||||
|
4.42.0b1
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Add support of Python 3.12.
|
||||||
|
- Drop support of Python 2.7, 3.5, and 3.6.
|
||||||
|
- Regenerate C sources using Cython 0.29.37.
|
||||||
|
- Update ``cibuildwheel`` to version ``2.20.0``.
|
||||||
|
|
||||||
4.41.0
|
4.41.0
|
||||||
------
|
------
|
||||||
- Add support of Python 3.11.
|
- Add support of Python 3.11.
|
||||||
|
@ -110,7 +152,7 @@ follows `Semantic versioning`_
|
||||||
- Fix a typo in ``Factory`` provider docs ``service.add_attributes(clent=client)``
|
- Fix a typo in ``Factory`` provider docs ``service.add_attributes(clent=client)``
|
||||||
`#499 <https://github.com/ets-labs/python-dependency-injector/issues/499>`_.
|
`#499 <https://github.com/ets-labs/python-dependency-injector/issues/499>`_.
|
||||||
Thanks to `@rajanjha786 <https://github.com/rajanjha786>`_ for the contribution.
|
Thanks to `@rajanjha786 <https://github.com/rajanjha786>`_ for the contribution.
|
||||||
- Fix a typo in ``boto3`` example
|
- Fix a typo in ``boto3`` example
|
||||||
`#511 <https://github.com/ets-labs/python-dependency-injector/issues/511>`_.
|
`#511 <https://github.com/ets-labs/python-dependency-injector/issues/511>`_.
|
||||||
Thanks to `@whysage <https://github.com/whysage>`_ for the contribution.
|
Thanks to `@whysage <https://github.com/whysage>`_ for the contribution.
|
||||||
|
|
||||||
|
@ -1310,24 +1352,24 @@ Misc:
|
||||||
------
|
------
|
||||||
- Add ``DependenciesContainer`` provider.
|
- Add ``DependenciesContainer`` provider.
|
||||||
- Add "use_cases" example miniapp.
|
- Add "use_cases" example miniapp.
|
||||||
- Update documentation requirements to use fixed version of
|
- Update documentation requirements to use fixed version of
|
||||||
``sphinxcontrib-disqus``.
|
``sphinxcontrib-disqus``.
|
||||||
|
|
||||||
|
|
||||||
3.9.1
|
3.9.1
|
||||||
-----
|
-----
|
||||||
- Fix docs build problem (``sphinx`` is frozen on ``1.5.6`` version because of
|
- Fix docs build problem (``sphinx`` is frozen on ``1.5.6`` version because of
|
||||||
incompatibility with ``sphinxcontrib-discus``).
|
incompatibility with ``sphinxcontrib-discus``).
|
||||||
- Add badge for docs.
|
- Add badge for docs.
|
||||||
|
|
||||||
3.9.0
|
3.9.0
|
||||||
-----
|
-----
|
||||||
- Change initialization of declarative container, so it accepts overriding
|
- Change initialization of declarative container, so it accepts overriding
|
||||||
providers as keyword arguments -
|
providers as keyword arguments -
|
||||||
``DeclarativeContainer(**overriding_providers)``.
|
``DeclarativeContainer(**overriding_providers)``.
|
||||||
- Add method to dynamic catalog for setting groups of providers -
|
- Add method to dynamic catalog for setting groups of providers -
|
||||||
``DynamicContainer.set_providers(**providers)``.
|
``DynamicContainer.set_providers(**providers)``.
|
||||||
- Add method to dynamic catalog for overriding groups of providers -
|
- Add method to dynamic catalog for overriding groups of providers -
|
||||||
``DynamicContainer.set_providers(**overriding_providers)``.
|
``DynamicContainer.set_providers(**overriding_providers)``.
|
||||||
- Rename ``ExternalDependency`` provider to ``Dependency``.
|
- Rename ``ExternalDependency`` provider to ``Dependency``.
|
||||||
- Add default value for ``instance_of`` argument of ``Dependency`` provider -
|
- Add default value for ``instance_of`` argument of ``Dependency`` provider -
|
||||||
|
@ -1359,7 +1401,7 @@ Misc:
|
||||||
3.7.0
|
3.7.0
|
||||||
-----
|
-----
|
||||||
- Add ``FactoryAggregate`` provider.
|
- Add ``FactoryAggregate`` provider.
|
||||||
- Add ``Provider.provider`` dynamic attribute that return new provider's
|
- Add ``Provider.provider`` dynamic attribute that return new provider's
|
||||||
delegate (alias of method ``Provider.delegate()``).
|
delegate (alias of method ``Provider.delegate()``).
|
||||||
- Add support of six 1.11.0.
|
- Add support of six 1.11.0.
|
||||||
- Regenerate C sources using Cython 0.27.1.
|
- Regenerate C sources using Cython 0.27.1.
|
||||||
|
@ -1376,7 +1418,7 @@ Misc:
|
||||||
|
|
||||||
3.5.0
|
3.5.0
|
||||||
-----
|
-----
|
||||||
- Add functionality for initializing ``Configuration`` provider with default
|
- Add functionality for initializing ``Configuration`` provider with default
|
||||||
values.
|
values.
|
||||||
|
|
||||||
3.4.8
|
3.4.8
|
||||||
|
@ -1399,7 +1441,7 @@ Misc:
|
||||||
|
|
||||||
3.4.4
|
3.4.4
|
||||||
-----
|
-----
|
||||||
- Add ``Provider.last_overriding`` read-only property that points to last
|
- Add ``Provider.last_overriding`` read-only property that points to last
|
||||||
overriding provider, if any. If target provider is not overridden, ``None``
|
overriding provider, if any. If target provider is not overridden, ``None``
|
||||||
would be returned.
|
would be returned.
|
||||||
- Update example of writing custom providers.
|
- Update example of writing custom providers.
|
||||||
|
@ -1413,7 +1455,7 @@ Misc:
|
||||||
3.4.2
|
3.4.2
|
||||||
-----
|
-----
|
||||||
- Make ``Provider`` overriding methods thread safe:
|
- Make ``Provider`` overriding methods thread safe:
|
||||||
``Provider.override(provider)``, ``Provider.reset_last_overriding()``,
|
``Provider.override(provider)``, ``Provider.reset_last_overriding()``,
|
||||||
``Provider.reset_override()``.
|
``Provider.reset_override()``.
|
||||||
- Refactor storage locking of ``ThreadSafeSingleton`` provider.
|
- Refactor storage locking of ``ThreadSafeSingleton`` provider.
|
||||||
- Fix few ``pydocstyle`` errors in examples.
|
- Fix few ``pydocstyle`` errors in examples.
|
||||||
|
@ -1485,8 +1527,8 @@ Misc:
|
||||||
|
|
||||||
3.2.4
|
3.2.4
|
||||||
-----
|
-----
|
||||||
- Switch to single version of documentation for getting shorter urls (without
|
- Switch to single version of documentation for getting shorter urls (without
|
||||||
``/en/stable/``). Add appropriate redirects for compatibility with previous
|
``/en/stable/``). Add appropriate redirects for compatibility with previous
|
||||||
links.
|
links.
|
||||||
- Update copyright date.
|
- Update copyright date.
|
||||||
|
|
||||||
|
@ -1505,7 +1547,7 @@ Misc:
|
||||||
|
|
||||||
3.2.0
|
3.2.0
|
||||||
-----
|
-----
|
||||||
- Add ``Configuration`` provider for late static binding of configuration
|
- Add ``Configuration`` provider for late static binding of configuration
|
||||||
options.
|
options.
|
||||||
|
|
||||||
3.1.5
|
3.1.5
|
||||||
|
@ -1515,7 +1557,7 @@ Misc:
|
||||||
|
|
||||||
3.1.4
|
3.1.4
|
||||||
-----
|
-----
|
||||||
- Move ``inline`` functions from class level to module level for removing them
|
- Move ``inline`` functions from class level to module level for removing them
|
||||||
from virtual table and enable inlining.
|
from virtual table and enable inlining.
|
||||||
|
|
||||||
3.1.3
|
3.1.3
|
||||||
|
@ -1547,34 +1589,34 @@ Misc:
|
||||||
|
|
||||||
- **Providers**
|
- **Providers**
|
||||||
|
|
||||||
1. All providers from ``dependency_injector.providers`` package are
|
1. All providers from ``dependency_injector.providers`` package are
|
||||||
implemented as C extension types using Cython.
|
implemented as C extension types using Cython.
|
||||||
2. Add ``BaseSingleton`` super class for all singleton providers.
|
2. Add ``BaseSingleton`` super class for all singleton providers.
|
||||||
3. Make ``Singleton`` provider not thread-safe. It makes performance of
|
3. Make ``Singleton`` provider not thread-safe. It makes performance of
|
||||||
``Singleton`` provider 10x times faster.
|
``Singleton`` provider 10x times faster.
|
||||||
4. Add ``ThreadSafeSingleton`` provider - thread-safe version of
|
4. Add ``ThreadSafeSingleton`` provider - thread-safe version of
|
||||||
``Singleton`` provider.
|
``Singleton`` provider.
|
||||||
5. Add ``ThreadLocalSingleton`` provider - ``Singleton`` provider that uses
|
5. Add ``ThreadLocalSingleton`` provider - ``Singleton`` provider that uses
|
||||||
thread-local storage.
|
thread-local storage.
|
||||||
6. Remove ``provides`` attribute from ``Factory`` and ``Singleton``
|
6. Remove ``provides`` attribute from ``Factory`` and ``Singleton``
|
||||||
providers.
|
providers.
|
||||||
7. Add ``set_args()`` and ``clear_args()`` methods for ``Callable``,
|
7. Add ``set_args()`` and ``clear_args()`` methods for ``Callable``,
|
||||||
``Factory`` and ``Singleton`` providers.
|
``Factory`` and ``Singleton`` providers.
|
||||||
|
|
||||||
- **Containers**
|
- **Containers**
|
||||||
|
|
||||||
1. Module ``dependency_injector.containers`` was split into submodules
|
1. Module ``dependency_injector.containers`` was split into submodules
|
||||||
without any functional changes.
|
without any functional changes.
|
||||||
|
|
||||||
- **Utils**
|
- **Utils**
|
||||||
|
|
||||||
1. Module ``dependency_injector.utils`` is split into
|
1. Module ``dependency_injector.utils`` is split into
|
||||||
``dependency_injector.containers`` and ``dependency_injector.providers``.
|
``dependency_injector.containers`` and ``dependency_injector.providers``.
|
||||||
|
|
||||||
- **Miscellaneous**
|
- **Miscellaneous**
|
||||||
|
|
||||||
1. Remove ``@inject`` decorator.
|
1. Remove ``@inject`` decorator.
|
||||||
2. Add makefile (``clean``, ``test``, ``build``, ``install``, ``uninstall``
|
2. Add makefile (``clean``, ``test``, ``build``, ``install``, ``uninstall``
|
||||||
& ``publish`` commands).
|
& ``publish`` commands).
|
||||||
3. Update repository structure:
|
3. Update repository structure:
|
||||||
|
|
||||||
|
@ -1641,7 +1683,7 @@ Misc:
|
||||||
|
|
||||||
2.0.0
|
2.0.0
|
||||||
------
|
------
|
||||||
- Introduce new injections style for ``Callable``, ``Factory`` &
|
- Introduce new injections style for ``Callable``, ``Factory`` &
|
||||||
``Singleton`` providers.
|
``Singleton`` providers.
|
||||||
- Drop providers: ``Static``, ``Value``, ``Function``, ``Class``, ``Config``.
|
- Drop providers: ``Static``, ``Value``, ``Function``, ``Class``, ``Config``.
|
||||||
- Increase performance of making injections in 2 times (+100%).
|
- Increase performance of making injections in 2 times (+100%).
|
||||||
|
@ -1654,8 +1696,8 @@ Misc:
|
||||||
|
|
||||||
1.17.0
|
1.17.0
|
||||||
------
|
------
|
||||||
- Add ``add_injections()`` method to ``Callable``, ``DelegatedCallable``,
|
- Add ``add_injections()`` method to ``Callable``, ``DelegatedCallable``,
|
||||||
``Factory``, ``DelegatedFactory``, ``Singleton`` and ``DelegatedSingleton``
|
``Factory``, ``DelegatedFactory``, ``Singleton`` and ``DelegatedSingleton``
|
||||||
providers.
|
providers.
|
||||||
- Fix bug with accessing to declarative catalog attributes from instance level.
|
- Fix bug with accessing to declarative catalog attributes from instance level.
|
||||||
|
|
||||||
|
@ -1683,14 +1725,14 @@ Misc:
|
||||||
- Add "Examples" section into documentation.
|
- Add "Examples" section into documentation.
|
||||||
- Add "Movie Lister" example.
|
- Add "Movie Lister" example.
|
||||||
- Add "Services" example.
|
- Add "Services" example.
|
||||||
- Move project documentation into organisation's domain
|
- Move project documentation into organisation's domain
|
||||||
(dependency-injector.ets-labs.org).
|
(dependency-injector.ets-labs.org).
|
||||||
|
|
||||||
1.15.2
|
1.15.2
|
||||||
------
|
------
|
||||||
- [Refactoring] split ``catalogs`` module into smaller modules,
|
- [Refactoring] split ``catalogs`` module into smaller modules,
|
||||||
``catalogs`` module become a package.
|
``catalogs`` module become a package.
|
||||||
- [Refactoring] split ``providers`` module into smaller modules,
|
- [Refactoring] split ``providers`` module into smaller modules,
|
||||||
``providers`` module become a package.
|
``providers`` module become a package.
|
||||||
- Update introduction documentation.
|
- Update introduction documentation.
|
||||||
|
|
||||||
|
@ -1700,7 +1742,7 @@ Misc:
|
||||||
|
|
||||||
1.15.0
|
1.15.0
|
||||||
------
|
------
|
||||||
- Add ``Provider.provide()`` method. ``Provider.__call__()`` become a
|
- Add ``Provider.provide()`` method. ``Provider.__call__()`` become a
|
||||||
reference to ``Provider.provide()``.
|
reference to ``Provider.provide()``.
|
||||||
- Add provider overriding context.
|
- Add provider overriding context.
|
||||||
- Update main examples and README.
|
- Update main examples and README.
|
||||||
|
@ -1730,7 +1772,7 @@ Misc:
|
||||||
|
|
||||||
1.14.6
|
1.14.6
|
||||||
------
|
------
|
||||||
- Add ``cls`` alias for ``provides`` attributes of ``Factory``,
|
- Add ``cls`` alias for ``provides`` attributes of ``Factory``,
|
||||||
``DelegatedFactory``, ``Singleton`` and ``DelegatedSingleton`` providers.
|
``DelegatedFactory``, ``Singleton`` and ``DelegatedSingleton`` providers.
|
||||||
|
|
||||||
1.14.5
|
1.14.5
|
||||||
|
@ -1789,27 +1831,27 @@ Misc:
|
||||||
|
|
||||||
1.11.1
|
1.11.1
|
||||||
------
|
------
|
||||||
Previous state of *Dependency Injector* framework (0.11.0 version) is
|
Previous state of *Dependency Injector* framework (0.11.0 version) is
|
||||||
considered to be production ready / stable, so current release is considered
|
considered to be production ready / stable, so current release is considered
|
||||||
to be the first major release.
|
to be the first major release.
|
||||||
|
|
||||||
- Increase major version.
|
- Increase major version.
|
||||||
- Backward compatibility with all previous versions above 0.7.6 has been saved.
|
- Backward compatibility with all previous versions above 0.7.6 has been saved.
|
||||||
|
|
||||||
0.11.0
|
0.11.0
|
||||||
------
|
------
|
||||||
- Rename ``AbstractCatalog`` to ``DeclarativeCatalog``
|
- Rename ``AbstractCatalog`` to ``DeclarativeCatalog``
|
||||||
(with backward compatibility).
|
(with backward compatibility).
|
||||||
- Rename ``catalog`` module to ``catalogs`` with backward compatibility.
|
- Rename ``catalog`` module to ``catalogs`` with backward compatibility.
|
||||||
- Implement dynamic binding of providers for ``DeclarativeCatalog``.
|
- Implement dynamic binding of providers for ``DeclarativeCatalog``.
|
||||||
- Add ``DynamicCatalog``.
|
- Add ``DynamicCatalog``.
|
||||||
- Change restrictions for providers-to-catalogs bindings - provider could be
|
- Change restrictions for providers-to-catalogs bindings - provider could be
|
||||||
bound to several catalogs with different names.
|
bound to several catalogs with different names.
|
||||||
- Restrict overriding of providers by themselves.
|
- Restrict overriding of providers by themselves.
|
||||||
- Restrict overriding of catalogs by themselves.
|
- Restrict overriding of catalogs by themselves.
|
||||||
- Make ``DeclarativeCatalog.last_overriding`` attribute to be ``None`` by
|
- Make ``DeclarativeCatalog.last_overriding`` attribute to be ``None`` by
|
||||||
default.
|
default.
|
||||||
- Make ``Provider.last_overriding`` attribute to be ``None`` by
|
- Make ``Provider.last_overriding`` attribute to be ``None`` by
|
||||||
default.
|
default.
|
||||||
- Refactor catalogs and providers modules.
|
- Refactor catalogs and providers modules.
|
||||||
- Add API documentation
|
- Add API documentation
|
||||||
|
@ -1817,7 +1859,7 @@ to be the first major release.
|
||||||
|
|
||||||
0.10.5
|
0.10.5
|
||||||
------
|
------
|
||||||
- Add more representable implementation for ``AbstractCatalog`` and
|
- Add more representable implementation for ``AbstractCatalog`` and
|
||||||
``AbstractCatalog.Bundle``.
|
``AbstractCatalog.Bundle``.
|
||||||
|
|
||||||
0.10.4
|
0.10.4
|
||||||
|
@ -1841,17 +1883,17 @@ to be the first major release.
|
||||||
- Add functionality for creating ``AbstractCatalog`` provider bundles.
|
- Add functionality for creating ``AbstractCatalog`` provider bundles.
|
||||||
- Improve ``AbstractCatalog`` inheritance.
|
- Improve ``AbstractCatalog`` inheritance.
|
||||||
- Improve ``AbstractCatalog`` overriding.
|
- Improve ``AbstractCatalog`` overriding.
|
||||||
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
|
- Add images for catalog "Writing catalogs" and "Operating with catalogs"
|
||||||
examples.
|
examples.
|
||||||
- Add functionality for using positional argument injections with
|
- Add functionality for using positional argument injections with
|
||||||
``Factory``, ``Singleton``, ``Callable`` providers and
|
``Factory``, ``Singleton``, ``Callable`` providers and
|
||||||
``inject`` decorator.
|
``inject`` decorator.
|
||||||
- Add functionality for decorating classes with ``@inject``.
|
- Add functionality for decorating classes with ``@inject``.
|
||||||
- Add ``Singleton.injections`` attribute that represents a tuple of all
|
- Add ``Singleton.injections`` attribute that represents a tuple of all
|
||||||
``Singleton`` injections (including args, kwargs, attributes and methods).
|
``Singleton`` injections (including args, kwargs, attributes and methods).
|
||||||
- Add ``Callable.injections`` attribute that represents a tuple of all
|
- Add ``Callable.injections`` attribute that represents a tuple of all
|
||||||
``Callable`` injections (including args and kwargs).
|
``Callable`` injections (including args and kwargs).
|
||||||
- Add optimization for ``Injection.value`` property that will compute
|
- Add optimization for ``Injection.value`` property that will compute
|
||||||
type of injection once, instead of doing this on every call.
|
type of injection once, instead of doing this on every call.
|
||||||
- Add ``VERSION`` constant for verification of currently installed version.
|
- Add ``VERSION`` constant for verification of currently installed version.
|
||||||
- Add support of Python 3.5.
|
- Add support of Python 3.5.
|
||||||
|
@ -1861,7 +1903,7 @@ to be the first major release.
|
||||||
0.9.5
|
0.9.5
|
||||||
-----
|
-----
|
||||||
- Change provider attributes scope to public.
|
- Change provider attributes scope to public.
|
||||||
- Add ``Factory.injections`` attribute that represents a tuple of all
|
- Add ``Factory.injections`` attribute that represents a tuple of all
|
||||||
``Factory`` injections (including kwargs, attributes and methods).
|
``Factory`` injections (including kwargs, attributes and methods).
|
||||||
|
|
||||||
0.9.4
|
0.9.4
|
||||||
|
@ -1878,14 +1920,14 @@ to be the first major release.
|
||||||
|
|
||||||
0.9.1
|
0.9.1
|
||||||
-----
|
-----
|
||||||
- Add simplified syntax of kwarg injections for ``di.Factory`` and
|
- Add simplified syntax of kwarg injections for ``di.Factory`` and
|
||||||
``di.Singleton`` providers:
|
``di.Singleton`` providers:
|
||||||
``di.Factory(SomeClass, dependency1=injectable_provider_or_value)``.
|
``di.Factory(SomeClass, dependency1=injectable_provider_or_value)``.
|
||||||
- Add simplified syntax of kwarg injections for ``di.Callable`` provider:
|
- Add simplified syntax of kwarg injections for ``di.Callable`` provider:
|
||||||
``di.Callable(some_callable, dependency1=injectable_provider_or_value)``
|
``di.Callable(some_callable, dependency1=injectable_provider_or_value)``
|
||||||
- Add simplified syntax of kwarg injections for ``@di.inject`` decorator:
|
- Add simplified syntax of kwarg injections for ``@di.inject`` decorator:
|
||||||
``@di.inject(dependency1=injectable_provider_or_value)``.
|
``@di.inject(dependency1=injectable_provider_or_value)``.
|
||||||
- Optimize ``@di.inject()`` decorations when they were made several times for
|
- Optimize ``@di.inject()`` decorations when they were made several times for
|
||||||
the same callback.
|
the same callback.
|
||||||
- Add minor refactorings.
|
- Add minor refactorings.
|
||||||
- Fix of minor documentation issues.
|
- Fix of minor documentation issues.
|
||||||
|
@ -1905,21 +1947,21 @@ to be the first major release.
|
||||||
0.7.6
|
0.7.6
|
||||||
-----
|
-----
|
||||||
|
|
||||||
- Adding support of six from 1.7.0 to 1.9.0.
|
- Adding support of six from 1.7.0 to 1.9.0.
|
||||||
- Factory / Singleton providers are free from restriction to operate with
|
- Factory / Singleton providers are free from restriction to operate with
|
||||||
classes only. This feature gives a change to use factory method and
|
classes only. This feature gives a change to use factory method and
|
||||||
functions with Factory / Singleton providers.
|
functions with Factory / Singleton providers.
|
||||||
- All attributes of all entities that have to be protected was renamed using
|
- All attributes of all entities that have to be protected was renamed using
|
||||||
``_protected`` manner.
|
``_protected`` manner.
|
||||||
- Providers extending was improved by implementing overriding logic in
|
- Providers extending was improved by implementing overriding logic in
|
||||||
``Provider.__call__()`` and moving providing logic into
|
``Provider.__call__()`` and moving providing logic into
|
||||||
``Provider._provide()``.
|
``Provider._provide()``.
|
||||||
- ``NewInstance`` provider was renamed to ``Factory`` provider.
|
- ``NewInstance`` provider was renamed to ``Factory`` provider.
|
||||||
``NewInstance`` still can be used, but it considered to be deprecated and
|
``NewInstance`` still can be used, but it considered to be deprecated and
|
||||||
will be removed in further releases.
|
will be removed in further releases.
|
||||||
- ``@inject`` decorator was refactored to keep all injections in
|
- ``@inject`` decorator was refactored to keep all injections in
|
||||||
``_injections`` attribute of decorated callback. It will give a possibility to
|
``_injections`` attribute of decorated callback. It will give a possibility to
|
||||||
track all the injections of particular callbacks and gives some performance
|
track all the injections of particular callbacks and gives some performance
|
||||||
boost due minimizing number of calls for doing injections.
|
boost due minimizing number of calls for doing injections.
|
||||||
- A lot of documentation updates were made.
|
- A lot of documentation updates were made.
|
||||||
- A lot of examples were added.
|
- A lot of examples were added.
|
||||||
|
|
|
@ -183,22 +183,22 @@ See also: :ref:`configuration-envs-interpolation`.
|
||||||
Loading from a Pydantic settings
|
Loading from a Pydantic settings
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
``Configuration`` provider can load configuration from a ``pydantic`` settings object using the
|
``Configuration`` provider can load configuration from a ``pydantic_settings.BaseSettings`` object using the
|
||||||
:py:meth:`Configuration.from_pydantic` method:
|
:py:meth:`Configuration.from_pydantic` method:
|
||||||
|
|
||||||
.. literalinclude:: ../../examples/providers/configuration/configuration_pydantic.py
|
.. literalinclude:: ../../examples/providers/configuration/configuration_pydantic.py
|
||||||
:language: python
|
:language: python
|
||||||
:lines: 3-
|
:lines: 3-
|
||||||
:emphasize-lines: 31
|
:emphasize-lines: 32
|
||||||
|
|
||||||
To get the data from pydantic settings ``Configuration`` provider calls ``Settings.dict()`` method.
|
To get the data from pydantic settings ``Configuration`` provider calls its ``model_dump()`` method.
|
||||||
If you need to pass an argument to this call, use ``.from_pydantic()`` keyword arguments.
|
If you need to pass an argument to this call, use ``.from_pydantic()`` keyword arguments.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
container.config.from_pydantic(Settings(), exclude={"optional"})
|
container.config.from_pydantic(Settings(), exclude={"optional"})
|
||||||
|
|
||||||
Alternatively, you can provide a ``pydantic`` settings object over the configuration provider argument. In that case,
|
Alternatively, you can provide a ``pydantic_settings.BaseSettings`` object over the configuration provider argument. In that case,
|
||||||
the container will call ``config.from_pydantic()`` automatically:
|
the container will call ``config.from_pydantic()`` automatically:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -215,18 +215,23 @@ the container will call ``config.from_pydantic()`` automatically:
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
``Dependency Injector`` doesn't install ``pydantic`` by default.
|
``Dependency Injector`` doesn't install ``pydantic-settings`` by default.
|
||||||
|
|
||||||
You can install the ``Dependency Injector`` with an extra dependency::
|
You can install the ``Dependency Injector`` with an extra dependency::
|
||||||
|
|
||||||
pip install dependency-injector[pydantic]
|
pip install dependency-injector[pydantic2]
|
||||||
|
|
||||||
or install ``pydantic`` directly::
|
or install ``pydantic-settings`` directly::
|
||||||
|
|
||||||
pip install pydantic
|
pip install pydantic-settings
|
||||||
|
|
||||||
*Don't forget to mirror the changes in the requirements file.*
|
*Don't forget to mirror the changes in the requirements file.*
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
For backward-compatibility, Pydantic v1 is still supported.
|
||||||
|
Passing ``pydantic.BaseSettings`` instances will work just as fine as ``pydantic_settings.BaseSettings``.
|
||||||
|
|
||||||
Loading from a dictionary
|
Loading from a dictionary
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ returns it on the rest of the calls.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
``Singleton`` provider makes dependencies injection only when creates an object. When an object
|
``Singleton`` provider makes dependencies injection only when it creates an object. When an object
|
||||||
is created and memorized ``Singleton`` provider just returns it without applying injections.
|
is created and memorized ``Singleton`` provider just returns it without applying injections.
|
||||||
|
|
||||||
Specialization of the provided type and abstract singletons work the same like like for the
|
Specialization of the provided type and abstract singletons work the same like like for the
|
||||||
|
|
7
docs/sponsor.rst
Normal file
7
docs/sponsor.rst
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.. list-table::
|
||||||
|
:class: no-border
|
||||||
|
:align: left
|
||||||
|
|
||||||
|
* - Sponsor the project on GitHub:
|
||||||
|
- .. raw:: html
|
||||||
|
:file: _static/sponsor.html
|
|
@ -859,4 +859,6 @@ What's next?
|
||||||
- Know more about the :ref:`providers`
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -18,7 +18,7 @@ In this tutorial we will use:
|
||||||
|
|
||||||
- Python 3
|
- Python 3
|
||||||
- Docker
|
- Docker
|
||||||
- Docker-compose
|
- Docker Compose
|
||||||
|
|
||||||
Start from the scratch or jump to the section:
|
Start from the scratch or jump to the section:
|
||||||
|
|
||||||
|
@ -47,28 +47,27 @@ response it will log:
|
||||||
Prerequisites
|
Prerequisites
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
We will use `Docker <https://www.docker.com/>`_ and
|
We will use `docker compose <https://docs.docker.com/compose/>`_ in this tutorial. Let's check the versions:
|
||||||
`docker-compose <https://docs.docker.com/compose/>`_ in this tutorial. Let's check the versions:
|
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker --version
|
docker --version
|
||||||
docker-compose --version
|
docker compose version
|
||||||
|
|
||||||
The output should look something like:
|
The output should look something like:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
Docker version 20.10.5, build 55c4c88
|
Docker version 27.3.1, build ce12230
|
||||||
docker-compose version 1.29.0, build 07737305
|
Docker Compose version v2.29.7
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
If you don't have ``Docker`` or ``docker-compose`` you need to install them before proceeding.
|
If you don't have ``Docker`` or ``docker compose`` you need to install them before proceeding.
|
||||||
Follow these installation guides:
|
Follow these installation guides:
|
||||||
|
|
||||||
- `Install Docker <https://docs.docker.com/get-docker/>`_
|
- `Install Docker <https://docs.docker.com/get-docker/>`_
|
||||||
- `Install docker-compose <https://docs.docker.com/compose/install/>`_
|
- `Install docker compose <https://docs.docker.com/compose/install/>`_
|
||||||
|
|
||||||
The prerequisites are satisfied. Let's get started with the project layout.
|
The prerequisites are satisfied. Let's get started with the project layout.
|
||||||
|
|
||||||
|
@ -129,13 +128,13 @@ Put next lines into the ``requirements.txt`` file:
|
||||||
pytest-cov
|
pytest-cov
|
||||||
|
|
||||||
Second, we need to create the ``Dockerfile``. It will describe the daemon's build process and
|
Second, we need to create the ``Dockerfile``. It will describe the daemon's build process and
|
||||||
specify how to run it. We will use ``python:3.9-buster`` as a base image.
|
specify how to run it. We will use ``python:3.13-bookworm`` as a base image.
|
||||||
|
|
||||||
Put next lines into the ``Dockerfile`` file:
|
Put next lines into the ``Dockerfile`` file:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
FROM python:3.10-buster
|
FROM python:3.13-bookworm
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
@ -155,8 +154,6 @@ Put next lines into the ``docker-compose.yml`` file:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. code-block:: yaml
|
||||||
|
|
||||||
version: "3.7"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
|
||||||
monitor:
|
monitor:
|
||||||
|
@ -171,7 +168,7 @@ Run in the terminal:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose build
|
docker compose build
|
||||||
|
|
||||||
The build process may take a couple of minutes. You should see something like this in the end:
|
The build process may take a couple of minutes. You should see something like this in the end:
|
||||||
|
|
||||||
|
@ -184,7 +181,7 @@ After the build is done run the container:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
The output should look like:
|
The output should look like:
|
||||||
|
|
||||||
|
@ -461,7 +458,7 @@ Run in the terminal:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
The output should look like:
|
The output should look like:
|
||||||
|
|
||||||
|
@ -705,7 +702,7 @@ Run in the terminal:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
You should see:
|
You should see:
|
||||||
|
|
||||||
|
@ -813,7 +810,7 @@ Run in the terminal:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
You should see:
|
You should see:
|
||||||
|
|
||||||
|
@ -965,15 +962,16 @@ Run in the terminal:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose run --rm monitor py.test monitoringdaemon/tests.py --cov=monitoringdaemon
|
docker compose run --rm monitor py.test monitoringdaemon/tests.py --cov=monitoringdaemon
|
||||||
|
|
||||||
You should see:
|
You should see:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||||
rootdir: /code
|
rootdir: /code
|
||||||
plugins: asyncio-0.16.0, cov-3.0.0
|
plugins: cov-6.0.0, asyncio-0.24.0
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
monitoringdaemon/tests.py .. [100%]
|
monitoringdaemon/tests.py .. [100%]
|
||||||
|
@ -1028,4 +1026,6 @@ What's next?
|
||||||
- Know more about the :ref:`providers`
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -1034,4 +1034,6 @@ What's next?
|
||||||
- Know more about the :ref:`providers`
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -998,5 +998,6 @@ What's next?
|
||||||
- Know more about the :ref:`providers`
|
- Know more about the :ref:`providers`
|
||||||
- Go to the :ref:`contents`
|
- Go to the :ref:`contents`
|
||||||
|
|
||||||
|
.. include:: ../sponsor.rst
|
||||||
|
|
||||||
.. disqus::
|
.. disqus::
|
||||||
|
|
|
@ -98,8 +98,9 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: asyncio-0.16.0, anyio-3.3.4, aiohttp-0.3.0, cov-3.0.0
|
plugins: cov-6.0.0, anyio-4.4.0, asyncio-0.24.0, aiohttp-1.0.5
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 3 items
|
collected 3 items
|
||||||
|
|
||||||
giphynavigator/tests.py ... [100%]
|
giphynavigator/tests.py ... [100%]
|
||||||
|
|
|
@ -3,11 +3,15 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
import pytest_asyncio
|
||||||
|
|
||||||
from giphynavigator.application import create_app
|
from giphynavigator.application import create_app
|
||||||
from giphynavigator.giphy import GiphyClient
|
from giphynavigator.giphy import GiphyClient
|
||||||
|
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def app():
|
def app():
|
||||||
app = create_app()
|
app = create_app()
|
||||||
|
@ -15,9 +19,9 @@ def app():
|
||||||
app.container.unwire()
|
app.container.unwire()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest_asyncio.fixture
|
||||||
def client(app, aiohttp_client, loop):
|
async def client(app, aiohttp_client):
|
||||||
return loop.run_until_complete(aiohttp_client(app))
|
return await aiohttp_client(app)
|
||||||
|
|
||||||
|
|
||||||
async def test_index(client, app):
|
async def test_index(client, app):
|
||||||
|
|
|
@ -2,4 +2,5 @@ dependency-injector
|
||||||
aiohttp
|
aiohttp
|
||||||
pyyaml
|
pyyaml
|
||||||
pytest-aiohttp
|
pytest-aiohttp
|
||||||
|
pytest-asyncio
|
||||||
pytest-cov
|
pytest-cov
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.10-buster
|
FROM python:3.13-bookworm
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
|
|
@ -13,13 +13,13 @@ Build the Docker image:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose build
|
docker compose build
|
||||||
|
|
||||||
Run the docker-compose environment:
|
Run the docker-compose environment:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
|
@ -59,15 +59,16 @@ To run the tests do:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose run --rm monitor py.test monitoringdaemon/tests.py --cov=monitoringdaemon
|
docker compose run --rm monitor py.test monitoringdaemon/tests.py --cov=monitoringdaemon
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||||
rootdir: /code
|
rootdir: /code
|
||||||
plugins: asyncio-0.16.0, cov-3.0.0
|
plugins: cov-6.0.0, asyncio-0.24.0
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
monitoringdaemon/tests.py .. [100%]
|
monitoringdaemon/tests.py .. [100%]
|
||||||
|
|
|
@ -61,7 +61,7 @@ async def test_example_monitor(container, caplog):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_dispatcher(container, caplog, event_loop):
|
async def test_dispatcher(container, caplog):
|
||||||
caplog.set_level("INFO")
|
caplog.set_level("INFO")
|
||||||
|
|
||||||
example_monitor_mock = mock.AsyncMock()
|
example_monitor_mock = mock.AsyncMock()
|
||||||
|
@ -72,6 +72,7 @@ async def test_dispatcher(container, caplog, event_loop):
|
||||||
httpbin_monitor=httpbin_monitor_mock,
|
httpbin_monitor=httpbin_monitor_mock,
|
||||||
):
|
):
|
||||||
dispatcher = container.dispatcher()
|
dispatcher = container.dispatcher()
|
||||||
|
event_loop = asyncio.get_running_loop()
|
||||||
event_loop.create_task(dispatcher.start())
|
event_loop.create_task(dispatcher.start())
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
dispatcher.stop()
|
dispatcher.stop()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.10-buster
|
FROM python:3.13-bookworm
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,13 @@ Build the Docker image:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose build
|
docker compose build
|
||||||
|
|
||||||
Run the docker-compose environment:
|
Run the docker-compose environment:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
|
@ -54,16 +54,16 @@ To run the tests do:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose run --rm example py.test fastapiredis/tests.py --cov=fastapiredis
|
docker compose run --rm example py.test fastapiredis/tests.py --cov=fastapiredis
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform linux -- Python 3.10.9, pytest-7.2.0, pluggy-1.0.0
|
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||||
rootdir: /code
|
rootdir: /code
|
||||||
plugins: cov-4.0.0, asyncio-0.20.3
|
plugins: cov-6.0.0, asyncio-0.24.0, anyio-4.7.0
|
||||||
collected 1 item
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
|
|
||||||
fastapiredis/tests.py . [100%]
|
fastapiredis/tests.py . [100%]
|
||||||
|
|
||||||
|
@ -77,4 +77,4 @@ The output should be something like:
|
||||||
fastapiredis/services.py 7 3 57%
|
fastapiredis/services.py 7 3 57%
|
||||||
fastapiredis/tests.py 18 0 100%
|
fastapiredis/tests.py 18 0 100%
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
TOTAL 52 7 87%
|
TOTAL 52 7 87%
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import AsyncIterator
|
from typing import AsyncIterator
|
||||||
|
|
||||||
from aioredis import from_url, Redis
|
from redis.asyncio import from_url, Redis
|
||||||
|
|
||||||
|
|
||||||
async def init_redis_pool(host: str, password: str) -> AsyncIterator[Redis]:
|
async def init_redis_pool(host: str, password: str) -> AsyncIterator[Redis]:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Services module."""
|
"""Services module."""
|
||||||
|
|
||||||
from aioredis import Redis
|
from redis.asyncio import Redis
|
||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from httpx import AsyncClient
|
from httpx import ASGITransport, AsyncClient
|
||||||
|
|
||||||
from .application import app, container
|
from .application import app, container
|
||||||
from .services import Service
|
from .services import Service
|
||||||
|
@ -11,7 +11,10 @@ from .services import Service
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def client(event_loop):
|
def client(event_loop):
|
||||||
client = AsyncClient(app=app, base_url="http://test")
|
client = AsyncClient(
|
||||||
|
transport=ASGITransport(app=app),
|
||||||
|
base_url="http://test",
|
||||||
|
)
|
||||||
yield client
|
yield client
|
||||||
event_loop.run_until_complete(client.aclose())
|
event_loop.run_until_complete(client.aclose())
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
dependency-injector
|
dependency-injector
|
||||||
fastapi
|
fastapi
|
||||||
uvicorn
|
uvicorn
|
||||||
aioredis
|
redis>=4.2
|
||||||
|
|
||||||
# For testing:
|
# For testing:
|
||||||
pytest
|
pytest
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from httpx import AsyncClient
|
import pytest_asyncio
|
||||||
|
from httpx import ASGITransport, AsyncClient
|
||||||
|
|
||||||
from fastapi_di_example import app, container, Service
|
from fastapi_di_example import app, container, Service
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest_asyncio.fixture
|
||||||
async def client(event_loop):
|
async def client():
|
||||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
async with AsyncClient(
|
||||||
|
transport=ASGITransport(app=app),
|
||||||
|
base_url="http://test",
|
||||||
|
) as client:
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.10-buster
|
FROM python:3.13-bookworm
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
ENV HOST=0.0.0.0
|
ENV HOST=0.0.0.0
|
||||||
|
|
|
@ -15,13 +15,13 @@ Build the Docker image:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose build
|
docker compose build
|
||||||
|
|
||||||
Run the docker-compose environment:
|
Run the docker-compose environment:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose up
|
docker compose up
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
|
@ -67,15 +67,15 @@ To run the tests do:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
docker-compose run --rm webapp py.test webapp/tests.py --cov=webapp
|
docker compose run --rm webapp py.test webapp/tests.py --cov=webapp
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||||
rootdir: /code
|
rootdir: /code
|
||||||
plugins: cov-3.0.0
|
plugins: cov-6.0.0, anyio-4.7.0
|
||||||
collected 7 items
|
collected 7 items
|
||||||
|
|
||||||
webapp/tests.py ....... [100%]
|
webapp/tests.py ....... [100%]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
dependency-injector
|
dependency-injector
|
||||||
fastapi
|
fastapi[standard]
|
||||||
uvicorn
|
uvicorn
|
||||||
pyyaml
|
pyyaml
|
||||||
sqlalchemy
|
sqlalchemy
|
||||||
|
|
|
@ -101,9 +101,9 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: asyncio-0.16.0, cov-3.0.0
|
plugins: cov-6.0.0, anyio-4.4.0, asyncio-0.24.0, aiohttp-1.0.5
|
||||||
collected 3 items
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
|
|
||||||
giphynavigator/tests.py ... [100%]
|
giphynavigator/tests.py ... [100%]
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,19 @@
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from httpx import AsyncClient
|
import pytest_asyncio
|
||||||
|
from httpx import ASGITransport, AsyncClient
|
||||||
|
|
||||||
from giphynavigator.application import app
|
from giphynavigator.application import app
|
||||||
from giphynavigator.giphy import GiphyClient
|
from giphynavigator.giphy import GiphyClient
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest_asyncio.fixture
|
||||||
async def client():
|
async def client():
|
||||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
async with AsyncClient(
|
||||||
|
transport=ASGITransport(app=app),
|
||||||
|
base_url="http://test",
|
||||||
|
) as client:
|
||||||
yield client
|
yield client
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,9 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: cov-3.0.0, flask-1.2.0
|
plugins: cov-6.0.0, flask-1.3.0
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
githubnavigator/tests.py .. [100%]
|
githubnavigator/tests.py .. [100%]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Application module."""
|
"""Application module."""
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_bootstrap import Bootstrap
|
from flask_bootstrap import Bootstrap4
|
||||||
|
|
||||||
from .containers import Container
|
from .containers import Container
|
||||||
from .blueprints import example
|
from .blueprints import example
|
||||||
|
@ -15,7 +15,7 @@ def create_app() -> Flask:
|
||||||
app.container = container
|
app.container = container
|
||||||
app.register_blueprint(example.blueprint)
|
app.register_blueprint(example.blueprint)
|
||||||
|
|
||||||
bootstrap = Bootstrap()
|
bootstrap = Bootstrap4()
|
||||||
bootstrap.init_app(app)
|
bootstrap.init_app(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -81,8 +81,9 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: cov-3.0.0, flask-1.2.0
|
plugins: cov-6.0.0, flask-1.3.0
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
githubnavigator/tests.py .. [100%]
|
githubnavigator/tests.py .. [100%]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""Application module."""
|
"""Application module."""
|
||||||
|
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_bootstrap import Bootstrap
|
from flask_bootstrap import Bootstrap4
|
||||||
|
|
||||||
from .containers import Container
|
from .containers import Container
|
||||||
from . import views
|
from . import views
|
||||||
|
@ -15,7 +15,7 @@ def create_app() -> Flask:
|
||||||
app.container = container
|
app.container = container
|
||||||
app.add_url_rule("/", "index", views.index)
|
app.add_url_rule("/", "index", views.index)
|
||||||
|
|
||||||
bootstrap = Bootstrap()
|
bootstrap = Bootstrap4()
|
||||||
bootstrap.init_app(app)
|
bootstrap.init_app(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
|
|
|
@ -58,8 +58,8 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: cov-3.0.0
|
plugins: cov-6.0.0
|
||||||
collected 2 items
|
collected 2 items
|
||||||
|
|
||||||
movies/tests.py .. [100%]
|
movies/tests.py .. [100%]
|
||||||
|
|
|
@ -27,7 +27,7 @@ To run the application do:
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
export GIPHY_API_KEY=wBJ2wZG7SRqfrU9nPgPiWvORmloDyuL0
|
export GIPHY_API_KEY=wBJ2wZG7SRqfrU9nPgPiWvORmloDyuL0
|
||||||
python -m giphynavigator
|
sanic giphynavigator.application:create_app
|
||||||
|
|
||||||
The output should be something like:
|
The output should be something like:
|
||||||
|
|
||||||
|
@ -98,8 +98,9 @@ The output should be something like:
|
||||||
|
|
||||||
.. code-block::
|
.. code-block::
|
||||||
|
|
||||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||||
plugins: sanic-1.9.1, anyio-3.3.4, cov-3.0.0
|
plugins: cov-6.0.0, anyio-4.4.0, asyncio-0.24.0
|
||||||
|
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||||
collected 3 items
|
collected 3 items
|
||||||
|
|
||||||
giphynavigator/tests.py ... [100%]
|
giphynavigator/tests.py ... [100%]
|
||||||
|
|
|
@ -8,6 +8,8 @@ from sanic import Sanic
|
||||||
from giphynavigator.application import create_app
|
from giphynavigator.application import create_app
|
||||||
from giphynavigator.giphy import GiphyClient
|
from giphynavigator.giphy import GiphyClient
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.asyncio
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def app():
|
def app():
|
||||||
|
@ -17,12 +19,7 @@ def app():
|
||||||
app.ctx.container.unwire()
|
app.ctx.container.unwire()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
async def test_index(app):
|
||||||
def test_client(loop, app, sanic_client):
|
|
||||||
return loop.run_until_complete(sanic_client(app))
|
|
||||||
|
|
||||||
|
|
||||||
async def test_index(app, test_client):
|
|
||||||
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
||||||
giphy_client_mock.search.return_value = {
|
giphy_client_mock.search.return_value = {
|
||||||
"data": [
|
"data": [
|
||||||
|
@ -32,7 +29,7 @@ async def test_index(app, test_client):
|
||||||
}
|
}
|
||||||
|
|
||||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||||
response = await test_client.get(
|
_, response = await app.asgi_client.get(
|
||||||
"/",
|
"/",
|
||||||
params={
|
params={
|
||||||
"query": "test",
|
"query": "test",
|
||||||
|
@ -41,7 +38,7 @@ async def test_index(app, test_client):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json
|
||||||
assert data == {
|
assert data == {
|
||||||
"query": "test",
|
"query": "test",
|
||||||
"limit": 10,
|
"limit": 10,
|
||||||
|
@ -52,30 +49,30 @@ async def test_index(app, test_client):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_index_no_data(app, test_client):
|
async def test_index_no_data(app):
|
||||||
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
||||||
giphy_client_mock.search.return_value = {
|
giphy_client_mock.search.return_value = {
|
||||||
"data": [],
|
"data": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||||
response = await test_client.get("/")
|
_, response = await app.asgi_client.get("/")
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json
|
||||||
assert data["gifs"] == []
|
assert data["gifs"] == []
|
||||||
|
|
||||||
|
|
||||||
async def test_index_default_params(app, test_client):
|
async def test_index_default_params(app):
|
||||||
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
||||||
giphy_client_mock.search.return_value = {
|
giphy_client_mock.search.return_value = {
|
||||||
"data": [],
|
"data": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||||
response = await test_client.get("/")
|
_, response = await app.asgi_client.get("/")
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
data = response.json()
|
data = response.json
|
||||||
assert data["query"] == app.ctx.container.config.default.query()
|
assert data["query"] == app.ctx.container.config.default.query()
|
||||||
assert data["limit"] == app.ctx.container.config.default.limit()
|
assert data["limit"] == app.ctx.container.config.default.limit()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
dependency-injector
|
dependency-injector
|
||||||
sanic<=21.6
|
sanic
|
||||||
|
sanic-testing
|
||||||
aiohttp
|
aiohttp
|
||||||
pyyaml
|
pyyaml
|
||||||
pytest-sanic
|
|
||||||
pytest-cov
|
pytest-cov
|
||||||
|
|
39
examples/miniapps/starlette-lifespan/README.rst
Normal file
39
examples/miniapps/starlette-lifespan/README.rst
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
Integration With Starlette-based Frameworks
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
This is a `Starlette <https://www.starlette.io/>`_ +
|
||||||
|
`Dependency Injector <https://python-dependency-injector.ets-labs.org/>`_ example application
|
||||||
|
utilizing `lifespan API <https://www.starlette.io/lifespan/>`_.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Pretty much `any framework built on top of Starlette <https://www.starlette.io/third-party-packages/#frameworks>`_
|
||||||
|
supports this feature (`FastAPI <https://fastapi.tiangolo.com/advanced/events/#lifespan>`_,
|
||||||
|
`Xpresso <https://xpresso-api.dev/latest/tutorial/lifespan/>`_, etc...).
|
||||||
|
|
||||||
|
Run
|
||||||
|
---
|
||||||
|
|
||||||
|
Create virtual environment:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python -m venv env
|
||||||
|
. env/bin/activate
|
||||||
|
|
||||||
|
Install requirements:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
To run the application do:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python example.py
|
||||||
|
# or (logging won't be configured):
|
||||||
|
uvicorn --factory example:container.app
|
||||||
|
|
||||||
|
After that visit http://127.0.0.1:8000/ in your browser or use CLI command (``curl``, ``httpie``,
|
||||||
|
etc).
|
59
examples/miniapps/starlette-lifespan/example.py
Executable file
59
examples/miniapps/starlette-lifespan/example.py
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from logging import basicConfig, getLogger
|
||||||
|
|
||||||
|
from dependency_injector.containers import DeclarativeContainer
|
||||||
|
from dependency_injector.ext.starlette import Lifespan
|
||||||
|
from dependency_injector.providers import Factory, Resource, Self, Singleton
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
from starlette.routing import Route
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
|
||||||
|
def init():
|
||||||
|
log = getLogger(__name__)
|
||||||
|
log.info("Inittializing resources")
|
||||||
|
yield
|
||||||
|
log.info("Cleaning up resources")
|
||||||
|
|
||||||
|
|
||||||
|
async def homepage(request: Request) -> JSONResponse:
|
||||||
|
global count
|
||||||
|
response = JSONResponse({"hello": "world", "count": count})
|
||||||
|
count += 1
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
class Container(DeclarativeContainer):
|
||||||
|
__self__ = Self()
|
||||||
|
lifespan = Singleton(Lifespan, __self__)
|
||||||
|
logging = Resource(
|
||||||
|
basicConfig,
|
||||||
|
level="DEBUG",
|
||||||
|
datefmt="%Y-%m-%d %H:%M",
|
||||||
|
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
||||||
|
)
|
||||||
|
init = Resource(init)
|
||||||
|
app = Factory(
|
||||||
|
Starlette,
|
||||||
|
debug=True,
|
||||||
|
lifespan=lifespan,
|
||||||
|
routes=[Route("/", homepage)],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
uvicorn.run(
|
||||||
|
container.app,
|
||||||
|
factory=True,
|
||||||
|
# NOTE: `None` prevents uvicorn from configuring logging, which is
|
||||||
|
# impossible via CLI
|
||||||
|
log_config=None,
|
||||||
|
)
|
3
examples/miniapps/starlette-lifespan/requirements.txt
Normal file
3
examples/miniapps/starlette-lifespan/requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
dependency-injector
|
||||||
|
starlette
|
||||||
|
uvicorn
|
|
@ -3,7 +3,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from pydantic import BaseSettings, Field
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
# Emulate environment variables
|
# Emulate environment variables
|
||||||
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
||||||
|
@ -11,15 +11,16 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "SECRET"
|
||||||
|
|
||||||
|
|
||||||
class AwsSettings(BaseSettings):
|
class AwsSettings(BaseSettings):
|
||||||
|
model_config = SettingsConfigDict(env_prefix="aws_")
|
||||||
|
|
||||||
access_key_id: str = Field(env="aws_access_key_id")
|
access_key_id: str
|
||||||
secret_access_key: str = Field(env="aws_secret_access_key")
|
secret_access_key: str
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
|
||||||
aws: AwsSettings = AwsSettings()
|
aws: AwsSettings = AwsSettings()
|
||||||
optional: str = Field(default="default_value")
|
optional: str = "default_value"
|
||||||
|
|
||||||
|
|
||||||
class Container(containers.DeclarativeContainer):
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from pydantic import BaseSettings, Field
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
# Emulate environment variables
|
# Emulate environment variables
|
||||||
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
||||||
|
@ -11,15 +11,16 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "SECRET"
|
||||||
|
|
||||||
|
|
||||||
class AwsSettings(BaseSettings):
|
class AwsSettings(BaseSettings):
|
||||||
|
model_config = SettingsConfigDict(env_prefix="aws_")
|
||||||
|
|
||||||
access_key_id: str = Field(env="aws_access_key_id")
|
access_key_id: str
|
||||||
secret_access_key: str = Field(env="aws_secret_access_key")
|
secret_access_key: str
|
||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
|
||||||
aws: AwsSettings = AwsSettings()
|
aws: AwsSettings = AwsSettings()
|
||||||
optional: str = Field(default="default_value")
|
optional: str = "default_value"
|
||||||
|
|
||||||
|
|
||||||
class Container(containers.DeclarativeContainer):
|
class Container(containers.DeclarativeContainer):
|
||||||
|
|
101
pyproject.toml
Normal file
101
pyproject.toml
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
[build-system]
|
||||||
|
requires = ["setuptools", "Cython"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "dependency-injector"
|
||||||
|
authors = [
|
||||||
|
{name = "Roman Mogylatov", email = "rmogilatov@gmail.com"},
|
||||||
|
]
|
||||||
|
maintainers = [
|
||||||
|
{name = "Roman Mogylatov", email = "rmogilatov@gmail.com"},
|
||||||
|
]
|
||||||
|
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.7"
|
||||||
|
keywords = [
|
||||||
|
"Dependency injection",
|
||||||
|
"DI",
|
||||||
|
"Inversion of Control",
|
||||||
|
"IoC",
|
||||||
|
"Factory",
|
||||||
|
"Singleton",
|
||||||
|
"Design patterns",
|
||||||
|
"Flask",
|
||||||
|
]
|
||||||
|
classifiers = [
|
||||||
|
"Development Status :: 5 - Production/Stable",
|
||||||
|
"Intended Audience :: Developers",
|
||||||
|
"License :: OSI Approved :: BSD License",
|
||||||
|
"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",
|
||||||
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
|
"Framework :: AsyncIO",
|
||||||
|
"Framework :: Bottle",
|
||||||
|
"Framework :: Django",
|
||||||
|
"Framework :: Flask",
|
||||||
|
"Framework :: Pylons",
|
||||||
|
"Framework :: Pyramid",
|
||||||
|
"Framework :: Pytest",
|
||||||
|
"Framework :: TurboGears",
|
||||||
|
"Topic :: Software Development",
|
||||||
|
"Topic :: Software Development :: Libraries",
|
||||||
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
|
]
|
||||||
|
dynamic = ["version"]
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
yaml = ["pyyaml"]
|
||||||
|
pydantic = ["pydantic"]
|
||||||
|
pydantic2 = ["pydantic-settings"]
|
||||||
|
flask = ["flask"]
|
||||||
|
aiohttp = ["aiohttp"]
|
||||||
|
|
||||||
|
[project.urls]
|
||||||
|
Homepage = "https://github.com/ets-labs/python-dependency-injector"
|
||||||
|
Documentation = "https://python-dependency-injector.ets-labs.org/"
|
||||||
|
Download = "https://pypi.python.org/pypi/dependency_injector"
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
package-dir = {"" = "src"}
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
|
|
||||||
|
[tool.setuptools.package-data]
|
||||||
|
dependency_injector = ["*.pxd", "*.pyi", "py.typed"]
|
||||||
|
|
||||||
|
[tool.setuptools.dynamic]
|
||||||
|
version = {attr = "dependency_injector.__version__"}
|
||||||
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
branch = false
|
||||||
|
relative_files = true
|
||||||
|
source_pkgs = ["dependency_injector"]
|
||||||
|
plugins = ["Cython.Coverage"]
|
||||||
|
|
||||||
|
[tool.coverage.html]
|
||||||
|
directory = "reports/unittests/"
|
||||||
|
|
||||||
|
[tool.coverage.report]
|
||||||
|
show_missing = true
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
|
[tool.pylint.main]
|
||||||
|
ignore = ["tests"]
|
||||||
|
|
||||||
|
[tool.pylint.design]
|
||||||
|
min-public-methods = 0
|
||||||
|
max-public-methods = 30
|
|
@ -1,9 +1,11 @@
|
||||||
cython==0.29.32
|
cython==3.0.11
|
||||||
|
setuptools
|
||||||
pytest
|
pytest
|
||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
tox
|
tox
|
||||||
coverage
|
coverage
|
||||||
flake8
|
flake8
|
||||||
|
flake8-pyproject
|
||||||
pydocstyle
|
pydocstyle
|
||||||
sphinx_autobuild
|
sphinx_autobuild
|
||||||
pip
|
pip
|
||||||
|
@ -11,7 +13,7 @@ mypy
|
||||||
pyyaml
|
pyyaml
|
||||||
httpx
|
httpx
|
||||||
fastapi
|
fastapi
|
||||||
pydantic
|
pydantic==1.10.17
|
||||||
numpy
|
numpy
|
||||||
scipy
|
scipy
|
||||||
boto3
|
boto3
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
# TODO: unpin 3.5.0 when this bug is fixed: https://github.com/sphinx-doc/sphinx/issues/8885
|
# TODO: unpin 3.5.0 when this bug is fixed: https://github.com/sphinx-doc/sphinx/issues/8885
|
||||||
sphinx<3.5.0
|
sphinx
|
||||||
|
|
||||||
# TODO: unpin jinja2 after sphinx update to 4+
|
# TODO: unpin jinja2 after sphinx update to 4+
|
||||||
jinja2<3.1
|
jinja2
|
||||||
|
|
||||||
-e git+https://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus
|
sphinx-disqus==1.3.0
|
||||||
|
|
||||||
-r requirements-ext.txt
|
-r requirements-ext.txt
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
flask
|
flask
|
||||||
|
werkzeug
|
||||||
aiohttp
|
aiohttp
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
six>=1.7.0,<=1.16.0
|
|
154
setup.py
154
setup.py
|
@ -1,130 +1,42 @@
|
||||||
"""`Dependency injector` setup script."""
|
"""`Dependency injector` setup script."""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from setuptools import setup, Extension
|
from Cython.Build import cythonize
|
||||||
|
from Cython.Compiler import Options
|
||||||
|
from setuptools import Extension, setup
|
||||||
|
|
||||||
|
debug = os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1"
|
||||||
def _open(filename):
|
defined_macros = []
|
||||||
if sys.version_info[0] == 2:
|
compiler_directives = {
|
||||||
return open(filename)
|
"language_level": 3,
|
||||||
return open(filename, encoding="utf-8")
|
"profile": debug,
|
||||||
|
"linetrace": debug,
|
||||||
|
}
|
||||||
# Defining setup variables:
|
Options.annotate = debug
|
||||||
defined_macros = dict()
|
|
||||||
defined_macros["CYTHON_CLINE_IN_TRACEBACK"] = 0
|
|
||||||
|
|
||||||
# Getting description:
|
|
||||||
with _open("README.rst") as readme_file:
|
|
||||||
description = readme_file.read()
|
|
||||||
|
|
||||||
# Getting requirements:
|
|
||||||
with _open("requirements.txt") as requirements_file:
|
|
||||||
requirements = requirements_file.readlines()
|
|
||||||
|
|
||||||
# Getting version:
|
|
||||||
with _open("src/dependency_injector/__init__.py") as init_file:
|
|
||||||
version = re.search("__version__ = \"(.*?)\"", init_file.read()).group(1)
|
|
||||||
|
|
||||||
# Adding debug options:
|
# Adding debug options:
|
||||||
if os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1":
|
if debug:
|
||||||
defined_macros["CYTHON_TRACE"] = 1
|
defined_macros.extend(
|
||||||
defined_macros["CYTHON_TRACE_NOGIL"] = 1
|
[
|
||||||
defined_macros["CYTHON_CLINE_IN_TRACEBACK"] = 1
|
("CYTHON_TRACE", "1"),
|
||||||
|
("CYTHON_TRACE_NOGIL", "1"),
|
||||||
|
("CYTHON_CLINE_IN_TRACEBACK", "1"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
setup(name="dependency-injector",
|
setup(
|
||||||
version=version,
|
ext_modules=cythonize(
|
||||||
description="Dependency injection framework for Python",
|
[
|
||||||
long_description=description,
|
Extension(
|
||||||
author="Roman Mogylatov",
|
"*",
|
||||||
author_email="rmogilatov@gmail.com",
|
["src/**/*.pyx"],
|
||||||
maintainer="Roman Mogylatov",
|
define_macros=defined_macros,
|
||||||
maintainer_email="rmogilatov@gmail.com",
|
),
|
||||||
url="https://github.com/ets-labs/python-dependency-injector",
|
],
|
||||||
download_url="https://pypi.python.org/pypi/dependency_injector",
|
annotate=debug,
|
||||||
packages=[
|
show_all_warnings=True,
|
||||||
"dependency_injector",
|
compiler_directives=compiler_directives,
|
||||||
"dependency_injector.ext",
|
),
|
||||||
],
|
)
|
||||||
package_dir={
|
|
||||||
"": "src",
|
|
||||||
},
|
|
||||||
package_data={
|
|
||||||
"dependency_injector": ["*.pxd", "*.pyi", "py.typed"],
|
|
||||||
},
|
|
||||||
ext_modules=[
|
|
||||||
Extension("dependency_injector.containers",
|
|
||||||
["src/dependency_injector/containers.c"],
|
|
||||||
define_macros=list(defined_macros.items()),
|
|
||||||
extra_compile_args=["-O2"]),
|
|
||||||
Extension("dependency_injector.providers",
|
|
||||||
["src/dependency_injector/providers.c"],
|
|
||||||
define_macros=list(defined_macros.items()),
|
|
||||||
extra_compile_args=["-O2"]),
|
|
||||||
Extension("dependency_injector._cwiring",
|
|
||||||
["src/dependency_injector/_cwiring.c"],
|
|
||||||
define_macros=list(defined_macros.items()),
|
|
||||||
extra_compile_args=["-O2"]),
|
|
||||||
],
|
|
||||||
install_requires=requirements,
|
|
||||||
extras_require={
|
|
||||||
"yaml": [
|
|
||||||
"pyyaml",
|
|
||||||
],
|
|
||||||
"pydantic": [
|
|
||||||
"pydantic",
|
|
||||||
],
|
|
||||||
"flask": [
|
|
||||||
"flask",
|
|
||||||
],
|
|
||||||
"aiohttp": [
|
|
||||||
"aiohttp",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
zip_safe=True,
|
|
||||||
license="BSD New",
|
|
||||||
platforms=["any"],
|
|
||||||
keywords=[
|
|
||||||
"Dependency injection",
|
|
||||||
"DI",
|
|
||||||
"Inversion of Control",
|
|
||||||
"IoC",
|
|
||||||
"Factory",
|
|
||||||
"Singleton",
|
|
||||||
"Design patterns",
|
|
||||||
"Flask",
|
|
||||||
],
|
|
||||||
classifiers=[
|
|
||||||
"Development Status :: 5 - Production/Stable",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"License :: OSI Approved :: BSD License",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
"Programming Language :: Python",
|
|
||||||
"Programming Language :: Python :: 2",
|
|
||||||
"Programming Language :: Python :: 2.7",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.5",
|
|
||||||
"Programming Language :: Python :: 3.6",
|
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
|
||||||
"Framework :: AsyncIO",
|
|
||||||
"Framework :: Bottle",
|
|
||||||
"Framework :: Django",
|
|
||||||
"Framework :: Flask",
|
|
||||||
"Framework :: Pylons",
|
|
||||||
"Framework :: Pyramid",
|
|
||||||
"Framework :: Pytest",
|
|
||||||
"Framework :: TurboGears",
|
|
||||||
"Topic :: Software Development",
|
|
||||||
"Topic :: Software Development :: Libraries",
|
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
||||||
])
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Top-level package."""
|
"""Top-level package."""
|
||||||
|
|
||||||
__version__ = "4.41.0"
|
__version__ = "4.45.0"
|
||||||
"""Version number.
|
"""Version number.
|
||||||
|
|
||||||
:type: str
|
:type: str
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -18,8 +18,6 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
yaml = None
|
yaml = None
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from . import providers, errors
|
from . import providers, errors
|
||||||
from .providers cimport __is_future_or_coroutine
|
from .providers cimport __is_future_or_coroutine
|
||||||
|
|
||||||
|
@ -201,7 +199,7 @@ class DynamicContainer(Container):
|
||||||
|
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
for name, provider in six.iteritems(providers):
|
for name, provider in providers.items():
|
||||||
setattr(self, name, provider)
|
setattr(self, name, provider)
|
||||||
|
|
||||||
def set_provider(self, name, provider):
|
def set_provider(self, name, provider):
|
||||||
|
@ -234,7 +232,7 @@ class DynamicContainer(Container):
|
||||||
|
|
||||||
self.overridden += (overriding,)
|
self.overridden += (overriding,)
|
||||||
|
|
||||||
for name, provider in six.iteritems(overriding.providers):
|
for name, provider in overriding.providers.items():
|
||||||
try:
|
try:
|
||||||
getattr(self, name).override(provider)
|
getattr(self, name).override(provider)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -250,7 +248,7 @@ class DynamicContainer(Container):
|
||||||
:rtype: None
|
:rtype: None
|
||||||
"""
|
"""
|
||||||
overridden_providers = []
|
overridden_providers = []
|
||||||
for name, overriding_provider in six.iteritems(overriding_providers):
|
for name, overriding_provider in overriding_providers.items():
|
||||||
container_provider = getattr(self, name)
|
container_provider = getattr(self, name)
|
||||||
container_provider.override(overriding_provider)
|
container_provider.override(overriding_provider)
|
||||||
overridden_providers.append(container_provider)
|
overridden_providers.append(container_provider)
|
||||||
|
@ -266,7 +264,7 @@ class DynamicContainer(Container):
|
||||||
|
|
||||||
self.overridden = self.overridden[:-1]
|
self.overridden = self.overridden[:-1]
|
||||||
|
|
||||||
for provider in six.itervalues(self.providers):
|
for provider in self.providers.values():
|
||||||
provider.reset_last_overriding()
|
provider.reset_last_overriding()
|
||||||
|
|
||||||
def reset_override(self):
|
def reset_override(self):
|
||||||
|
@ -276,7 +274,7 @@ class DynamicContainer(Container):
|
||||||
"""
|
"""
|
||||||
self.overridden = tuple()
|
self.overridden = tuple()
|
||||||
|
|
||||||
for provider in six.itervalues(self.providers):
|
for provider in self.providers.values():
|
||||||
provider.reset_override()
|
provider.reset_override()
|
||||||
|
|
||||||
def is_auto_wiring_enabled(self):
|
def is_auto_wiring_enabled(self):
|
||||||
|
@ -495,13 +493,13 @@ class DeclarativeContainerMetaClass(type):
|
||||||
|
|
||||||
containers = {
|
containers = {
|
||||||
name: container
|
name: container
|
||||||
for name, container in six.iteritems(attributes)
|
for name, container in attributes.items()
|
||||||
if is_container(container)
|
if is_container(container)
|
||||||
}
|
}
|
||||||
|
|
||||||
cls_providers = {
|
cls_providers = {
|
||||||
name: provider
|
name: provider
|
||||||
for name, provider in six.iteritems(attributes)
|
for name, provider in attributes.items()
|
||||||
if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
|
if isinstance(provider, providers.Provider) and not isinstance(provider, providers.Self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,7 +507,7 @@ class DeclarativeContainerMetaClass(type):
|
||||||
name: provider
|
name: provider
|
||||||
for base in bases
|
for base in bases
|
||||||
if is_container(base) and base is not DynamicContainer
|
if is_container(base) and base is not DynamicContainer
|
||||||
for name, provider in six.iteritems(base.providers)
|
for name, provider in base.providers.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
all_providers = {}
|
all_providers = {}
|
||||||
|
@ -536,10 +534,10 @@ class DeclarativeContainerMetaClass(type):
|
||||||
self.set_container(cls)
|
self.set_container(cls)
|
||||||
cls.__self__ = self
|
cls.__self__ = self
|
||||||
|
|
||||||
for provider in six.itervalues(cls.providers):
|
for provider in cls.providers.values():
|
||||||
_check_provider_type(cls, provider)
|
_check_provider_type(cls, provider)
|
||||||
|
|
||||||
for provider in six.itervalues(cls.cls_providers):
|
for provider in cls.cls_providers.values():
|
||||||
if isinstance(provider, providers.CHILD_PROVIDERS):
|
if isinstance(provider, providers.CHILD_PROVIDERS):
|
||||||
provider.assign_parent(cls)
|
provider.assign_parent(cls)
|
||||||
|
|
||||||
|
@ -641,8 +639,7 @@ class DeclarativeContainerMetaClass(type):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(DeclarativeContainerMetaClass)
|
class DeclarativeContainer(Container, metaclass=DeclarativeContainerMetaClass):
|
||||||
class DeclarativeContainer(Container):
|
|
||||||
"""Declarative inversion of control container.
|
"""Declarative inversion of control container.
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -767,7 +764,7 @@ class DeclarativeContainer(Container):
|
||||||
|
|
||||||
cls.overridden += (overriding,)
|
cls.overridden += (overriding,)
|
||||||
|
|
||||||
for name, provider in six.iteritems(overriding.cls_providers):
|
for name, provider in overriding.cls_providers.items():
|
||||||
try:
|
try:
|
||||||
getattr(cls, name).override(provider)
|
getattr(cls, name).override(provider)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -784,7 +781,7 @@ class DeclarativeContainer(Container):
|
||||||
|
|
||||||
cls.overridden = cls.overridden[:-1]
|
cls.overridden = cls.overridden[:-1]
|
||||||
|
|
||||||
for provider in six.itervalues(cls.providers):
|
for provider in cls.providers.values():
|
||||||
provider.reset_last_overriding()
|
provider.reset_last_overriding()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -795,7 +792,7 @@ class DeclarativeContainer(Container):
|
||||||
"""
|
"""
|
||||||
cls.overridden = tuple()
|
cls.overridden = tuple()
|
||||||
|
|
||||||
for provider in six.itervalues(cls.providers):
|
for provider in cls.providers.values():
|
||||||
provider.reset_override()
|
provider.reset_override()
|
||||||
|
|
||||||
|
|
||||||
|
@ -858,7 +855,7 @@ def copy(object base_container):
|
||||||
"""
|
"""
|
||||||
def _get_memo_for_matching_names(new_providers, base_providers):
|
def _get_memo_for_matching_names(new_providers, base_providers):
|
||||||
memo = {}
|
memo = {}
|
||||||
for new_provider_name, new_provider in six.iteritems(new_providers):
|
for new_provider_name, new_provider in new_providers.items():
|
||||||
if new_provider_name not in base_providers:
|
if new_provider_name not in base_providers:
|
||||||
continue
|
continue
|
||||||
source_provider = base_providers[new_provider_name]
|
source_provider = base_providers[new_provider_name]
|
||||||
|
@ -877,7 +874,7 @@ def copy(object base_container):
|
||||||
new_providers.update(providers.deepcopy(base_container.providers, memo))
|
new_providers.update(providers.deepcopy(base_container.providers, memo))
|
||||||
new_providers.update(providers.deepcopy(new_container.cls_providers, memo))
|
new_providers.update(providers.deepcopy(new_container.cls_providers, memo))
|
||||||
|
|
||||||
for name, provider in six.iteritems(new_providers):
|
for name, provider in new_providers.items():
|
||||||
setattr(new_container, name, provider)
|
setattr(new_container, name, provider)
|
||||||
return new_container
|
return new_container
|
||||||
|
|
||||||
|
|
|
@ -10,3 +10,24 @@ class Error(Exception):
|
||||||
|
|
||||||
class NoSuchProviderError(Error, AttributeError):
|
class NoSuchProviderError(Error, AttributeError):
|
||||||
"""Error that is raised when provider lookup is failed."""
|
"""Error that is raised when provider lookup is failed."""
|
||||||
|
|
||||||
|
|
||||||
|
class NonCopyableArgumentError(Error):
|
||||||
|
"""Error that is raised when provider argument is not deep-copyable."""
|
||||||
|
|
||||||
|
index: int
|
||||||
|
keyword: str
|
||||||
|
provider: object
|
||||||
|
|
||||||
|
def __init__(self, provider: object, index: int = -1, keyword: str = "") -> None:
|
||||||
|
self.provider = provider
|
||||||
|
self.index = index
|
||||||
|
self.keyword = keyword
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
s = (
|
||||||
|
f"keyword argument {self.keyword}"
|
||||||
|
if self.keyword
|
||||||
|
else f"argument at index {self.index}"
|
||||||
|
)
|
||||||
|
return f"Couldn't copy {s} for provider {self.provider!r}"
|
||||||
|
|
52
src/dependency_injector/ext/starlette.py
Normal file
52
src/dependency_injector/ext/starlette.py
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import sys
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 11): # pragma: no cover
|
||||||
|
from typing import Self
|
||||||
|
else: # pragma: no cover
|
||||||
|
from typing_extensions import Self
|
||||||
|
|
||||||
|
from dependency_injector.containers import Container
|
||||||
|
|
||||||
|
|
||||||
|
class Lifespan:
|
||||||
|
"""A starlette lifespan handler performing container resource initialization and shutdown.
|
||||||
|
|
||||||
|
See https://www.starlette.io/lifespan/ for details.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from dependency_injector.containers import DeclarativeContainer
|
||||||
|
from dependency_injector.ext.starlette import Lifespan
|
||||||
|
from dependency_injector.providers import Factory, Self, Singleton
|
||||||
|
from starlette.applications import Starlette
|
||||||
|
|
||||||
|
class Container(DeclarativeContainer):
|
||||||
|
__self__ = Self()
|
||||||
|
lifespan = Singleton(Lifespan, __self__)
|
||||||
|
app = Factory(Starlette, lifespan=lifespan)
|
||||||
|
|
||||||
|
:param container: container instance
|
||||||
|
"""
|
||||||
|
|
||||||
|
container: Container
|
||||||
|
|
||||||
|
def __init__(self, container: Container) -> None:
|
||||||
|
self.container = container
|
||||||
|
|
||||||
|
def __call__(self, app: Any) -> Self:
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aenter__(self) -> None:
|
||||||
|
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()
|
||||||
|
|
||||||
|
if result is not None:
|
||||||
|
await result
|
File diff suppressed because it is too large
Load Diff
|
@ -20,10 +20,10 @@ cdef tuple __COROUTINE_TYPES
|
||||||
|
|
||||||
# Base providers
|
# Base providers
|
||||||
cdef class Provider(object):
|
cdef class Provider(object):
|
||||||
cdef tuple __overridden
|
cdef tuple _overridden
|
||||||
cdef Provider __last_overriding
|
cdef Provider _last_overriding
|
||||||
cdef tuple __overrides
|
cdef tuple _overrides
|
||||||
cdef int __async_mode
|
cdef int _async_mode
|
||||||
|
|
||||||
cpdef bint is_async_mode_enabled(self)
|
cpdef bint is_async_mode_enabled(self)
|
||||||
cpdef bint is_async_mode_disabled(self)
|
cpdef bint is_async_mode_disabled(self)
|
||||||
|
@ -34,32 +34,32 @@ cdef class Provider(object):
|
||||||
|
|
||||||
|
|
||||||
cdef class Object(Provider):
|
cdef class Object(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Self(Provider):
|
cdef class Self(Provider):
|
||||||
cdef object __container
|
cdef object _container
|
||||||
cdef tuple __alt_names
|
cdef tuple _alt_names
|
||||||
|
|
||||||
|
|
||||||
cdef class Delegate(Provider):
|
cdef class Delegate(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Aggregate(Provider):
|
cdef class Aggregate(Provider):
|
||||||
cdef dict __providers
|
cdef dict _providers
|
||||||
|
|
||||||
cdef Provider __get_provider(self, object provider_name)
|
cdef Provider __get_provider(self, object provider_name)
|
||||||
|
|
||||||
|
|
||||||
cdef class Dependency(Provider):
|
cdef class Dependency(Provider):
|
||||||
cdef object __instance_of
|
cdef object _instance_of
|
||||||
cdef object __default
|
cdef object _default
|
||||||
cdef object __parent
|
cdef object _parent
|
||||||
|
|
||||||
|
|
||||||
cdef class ExternalDependency(Dependency):
|
cdef class ExternalDependency(Dependency):
|
||||||
|
@ -67,21 +67,21 @@ cdef class ExternalDependency(Dependency):
|
||||||
|
|
||||||
|
|
||||||
cdef class DependenciesContainer(Object):
|
cdef class DependenciesContainer(Object):
|
||||||
cdef dict __providers
|
cdef dict _providers
|
||||||
cdef object __parent
|
cdef object _parent
|
||||||
|
|
||||||
cpdef object _override_providers(self, object container)
|
cpdef object _override_providers(self, object container)
|
||||||
|
|
||||||
|
|
||||||
# Callable providers
|
# Callable providers
|
||||||
cdef class Callable(Provider):
|
cdef class Callable(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
|
|
||||||
cdef tuple __args
|
cdef tuple _args
|
||||||
cdef int __args_len
|
cdef int _args_len
|
||||||
|
|
||||||
cdef tuple __kwargs
|
cdef tuple _kwargs
|
||||||
cdef int __kwargs_len
|
cdef int _kwargs_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
@ -117,11 +117,11 @@ cdef class CoroutineDelegate(Delegate):
|
||||||
|
|
||||||
# Configuration providers
|
# Configuration providers
|
||||||
cdef class ConfigurationOption(Provider):
|
cdef class ConfigurationOption(Provider):
|
||||||
cdef tuple __name
|
cdef tuple _name
|
||||||
cdef Configuration __root
|
cdef Configuration _root
|
||||||
cdef dict __children
|
cdef dict _children
|
||||||
cdef bint __required
|
cdef bint _required
|
||||||
cdef object __cache
|
cdef object _cache
|
||||||
|
|
||||||
|
|
||||||
cdef class TypedConfigurationOption(Callable):
|
cdef class TypedConfigurationOption(Callable):
|
||||||
|
@ -129,22 +129,22 @@ cdef class TypedConfigurationOption(Callable):
|
||||||
|
|
||||||
|
|
||||||
cdef class Configuration(Object):
|
cdef class Configuration(Object):
|
||||||
cdef str __name
|
cdef str _name
|
||||||
cdef bint __strict
|
cdef bint __strict
|
||||||
cdef dict __children
|
cdef dict _children
|
||||||
cdef list __ini_files
|
cdef list _ini_files
|
||||||
cdef list __yaml_files
|
cdef list _yaml_files
|
||||||
cdef list __json_files
|
cdef list _json_files
|
||||||
cdef list __pydantic_settings
|
cdef list _pydantic_settings
|
||||||
cdef object __weakref__
|
cdef object __weakref__
|
||||||
|
|
||||||
|
|
||||||
# Factory providers
|
# Factory providers
|
||||||
cdef class Factory(Provider):
|
cdef class Factory(Provider):
|
||||||
cdef Callable __instantiator
|
cdef Callable _instantiator
|
||||||
|
|
||||||
cdef tuple __attributes
|
cdef tuple _attributes
|
||||||
cdef int __attributes_len
|
cdef int _attributes_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
@ -167,8 +167,8 @@ cdef class FactoryAggregate(Aggregate):
|
||||||
|
|
||||||
# Singleton providers
|
# Singleton providers
|
||||||
cdef class BaseSingleton(Provider):
|
cdef class BaseSingleton(Provider):
|
||||||
cdef Factory __instantiator
|
cdef Factory _instantiator
|
||||||
cdef object __storage
|
cdef object _storage
|
||||||
|
|
||||||
|
|
||||||
cdef class Singleton(BaseSingleton):
|
cdef class Singleton(BaseSingleton):
|
||||||
|
@ -181,7 +181,7 @@ cdef class DelegatedSingleton(Singleton):
|
||||||
|
|
||||||
|
|
||||||
cdef class ThreadSafeSingleton(BaseSingleton):
|
cdef class ThreadSafeSingleton(BaseSingleton):
|
||||||
cdef object __storage_lock
|
cdef object _storage_lock
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
@ -215,87 +215,87 @@ cdef class SingletonDelegate(Delegate):
|
||||||
# Miscellaneous providers
|
# Miscellaneous providers
|
||||||
|
|
||||||
cdef class List(Provider):
|
cdef class List(Provider):
|
||||||
cdef tuple __args
|
cdef tuple _args
|
||||||
cdef int __args_len
|
cdef int _args_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Dict(Provider):
|
cdef class Dict(Provider):
|
||||||
cdef tuple __kwargs
|
cdef tuple _kwargs
|
||||||
cdef int __kwargs_len
|
cdef int _kwargs_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Resource(Provider):
|
cdef class Resource(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
cdef bint __initialized
|
cdef bint _initialized
|
||||||
cdef object __shutdowner
|
cdef object _shutdowner
|
||||||
cdef object __resource
|
cdef object _resource
|
||||||
|
|
||||||
cdef tuple __args
|
cdef tuple _args
|
||||||
cdef int __args_len
|
cdef int _args_len
|
||||||
|
|
||||||
cdef tuple __kwargs
|
cdef tuple _kwargs
|
||||||
cdef int __kwargs_len
|
cdef int _kwargs_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Container(Provider):
|
cdef class Container(Provider):
|
||||||
cdef object __container_cls
|
cdef object _container_cls
|
||||||
cdef dict __overriding_providers
|
cdef dict _overriding_providers
|
||||||
cdef object __container
|
cdef object _container
|
||||||
cdef object __parent
|
cdef object _parent
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class Selector(Provider):
|
cdef class Selector(Provider):
|
||||||
cdef object __selector
|
cdef object _selector
|
||||||
cdef dict __providers
|
cdef dict _providers
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
# Provided instance
|
# Provided instance
|
||||||
|
|
||||||
cdef class ProvidedInstance(Provider):
|
cdef class ProvidedInstance(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class AttributeGetter(Provider):
|
cdef class AttributeGetter(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
cdef object __name
|
cdef object _name
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class ItemGetter(Provider):
|
cdef class ItemGetter(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
cdef object __name
|
cdef object _name
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef class MethodCaller(Provider):
|
cdef class MethodCaller(Provider):
|
||||||
cdef object __provides
|
cdef object _provides
|
||||||
cdef tuple __args
|
cdef tuple _args
|
||||||
cdef int __args_len
|
cdef int _args_len
|
||||||
cdef tuple __kwargs
|
cdef tuple _kwargs
|
||||||
cdef int __kwargs_len
|
cdef int _kwargs_len
|
||||||
|
|
||||||
cpdef object _provide(self, tuple args, dict kwargs)
|
cpdef object _provide(self, tuple args, dict kwargs)
|
||||||
|
|
||||||
|
|
||||||
# Injections
|
# Injections
|
||||||
cdef class Injection(object):
|
cdef class Injection(object):
|
||||||
cdef object __value
|
cdef object _value
|
||||||
cdef int __is_provider
|
cdef int _is_provider
|
||||||
cdef int __is_delegated
|
cdef int _is_delegated
|
||||||
cdef int __call
|
cdef int _call
|
||||||
|
|
||||||
|
|
||||||
cdef class PositionalInjection(Injection):
|
cdef class PositionalInjection(Injection):
|
||||||
|
@ -303,7 +303,7 @@ cdef class PositionalInjection(Injection):
|
||||||
|
|
||||||
|
|
||||||
cdef class NamedInjection(Injection):
|
cdef class NamedInjection(Injection):
|
||||||
cdef object __name
|
cdef object _name
|
||||||
|
|
||||||
|
|
||||||
cpdef tuple parse_positional_injections(tuple args)
|
cpdef tuple parse_positional_injections(tuple args)
|
||||||
|
@ -314,12 +314,12 @@ cpdef tuple parse_named_injections(dict kwargs)
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
cdef class OverridingContext(object):
|
cdef class OverridingContext(object):
|
||||||
cdef Provider __overridden
|
cdef Provider _overridden
|
||||||
cdef Provider __overriding
|
cdef Provider _overriding
|
||||||
|
|
||||||
|
|
||||||
cdef class BaseSingletonResetContext(object):
|
cdef class BaseSingletonResetContext(object):
|
||||||
cdef object __singleton
|
cdef object _singleton
|
||||||
|
|
||||||
|
|
||||||
cdef class SingletonResetContext(BaseSingletonResetContext):
|
cdef class SingletonResetContext(BaseSingletonResetContext):
|
||||||
|
@ -356,19 +356,19 @@ cpdef object deepcopy(object instance, dict memo=*)
|
||||||
|
|
||||||
# Inline helper functions
|
# Inline helper functions
|
||||||
cdef inline object __get_name(NamedInjection self):
|
cdef inline object __get_name(NamedInjection self):
|
||||||
return self.__name
|
return self._name
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __get_value(Injection self):
|
cdef inline object __get_value(Injection self):
|
||||||
if self.__call == 0:
|
if self._call == 0:
|
||||||
return self.__value
|
return self._value
|
||||||
return self.__value()
|
return self._value()
|
||||||
|
|
||||||
|
|
||||||
cdef inline object __get_value_kwargs(Injection self, dict kwargs):
|
cdef inline object __get_value_kwargs(Injection self, dict kwargs):
|
||||||
if self.__call == 0:
|
if self._call == 0:
|
||||||
return self.__value
|
return self._value
|
||||||
return self.__value(**kwargs)
|
return self._value(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
cdef inline tuple __separate_prefixed_kwargs(dict kwargs):
|
cdef inline tuple __separate_prefixed_kwargs(dict kwargs):
|
||||||
|
@ -633,14 +633,14 @@ cdef inline object __async_result_callback(object future_result, object future):
|
||||||
|
|
||||||
cdef inline object __callable_call(Callable self, tuple args, dict kwargs, ):
|
cdef inline object __callable_call(Callable self, tuple args, dict kwargs, ):
|
||||||
return __call(
|
return __call(
|
||||||
self.__provides,
|
self._provides,
|
||||||
args,
|
args,
|
||||||
self.__args,
|
self._args,
|
||||||
self.__args_len,
|
self._args_len,
|
||||||
kwargs,
|
kwargs,
|
||||||
self.__kwargs,
|
self._kwargs,
|
||||||
self.__kwargs_len,
|
self._kwargs_len,
|
||||||
self.__async_mode,
|
self._async_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -648,18 +648,18 @@ cdef inline object __factory_call(Factory self, tuple args, dict kwargs):
|
||||||
cdef object instance
|
cdef object instance
|
||||||
|
|
||||||
instance = __call(
|
instance = __call(
|
||||||
self.__instantiator.__provides,
|
self._instantiator._provides,
|
||||||
args,
|
args,
|
||||||
self.__instantiator.__args,
|
self._instantiator._args,
|
||||||
self.__instantiator.__args_len,
|
self._instantiator._args_len,
|
||||||
kwargs,
|
kwargs,
|
||||||
self.__instantiator.__kwargs,
|
self._instantiator._kwargs,
|
||||||
self.__instantiator.__kwargs_len,
|
self._instantiator._kwargs_len,
|
||||||
self.__async_mode,
|
self._async_mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.__attributes_len > 0:
|
if self._attributes_len > 0:
|
||||||
attributes = __provide_attributes(self.__attributes, self.__attributes_len)
|
attributes = __provide_attributes(self._attributes, self._attributes_len)
|
||||||
|
|
||||||
is_future_instance = __is_future_or_coroutine(instance)
|
is_future_instance = __is_future_or_coroutine(instance)
|
||||||
is_future_attributes = __is_future_or_coroutine(attributes)
|
is_future_attributes = __is_future_or_coroutine(attributes)
|
||||||
|
|
|
@ -530,7 +530,21 @@ def is_delegated(instance: Any) -> bool: ...
|
||||||
def represent_provider(provider: Provider, provides: Any) -> str: ...
|
def represent_provider(provider: Provider, provides: Any) -> str: ...
|
||||||
|
|
||||||
|
|
||||||
def deepcopy(instance: Any, memo: Optional[_Dict[Any, Any]] = None): Any: ...
|
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 merge_dicts(dict1: _Dict[Any, Any], dict2: _Dict[Any, Any]) -> _Dict[Any, Any]: ...
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,9 +2,12 @@
|
||||||
testpaths = tests/unit/
|
testpaths = tests/unit/
|
||||||
python_files = test_*_py3*.py
|
python_files = test_*_py3*.py
|
||||||
asyncio_mode = auto
|
asyncio_mode = auto
|
||||||
|
markers =
|
||||||
|
pydantic: Tests with Pydantic as a dependency
|
||||||
filterwarnings =
|
filterwarnings =
|
||||||
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
|
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: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 use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
|
||||||
ignore: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.*
|
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from dependency_injector import providers
|
from dependency_injector import providers
|
||||||
from pydantic import BaseSettings as PydanticSettings
|
from pydantic_settings import BaseSettings as PydanticSettings
|
||||||
|
|
||||||
|
|
||||||
# Test 1: to check the getattr
|
# Test 1: to check the getattr
|
||||||
config1 = providers.Configuration()
|
config1: providers.Configuration = providers.Configuration()
|
||||||
provider1 = providers.Factory(dict, a=config1.a)
|
provider1: providers.Provider[dict] = providers.Factory(dict, a=config1.a)
|
||||||
|
|
||||||
# Test 2: to check the from_*() method
|
# Test 2: to check the from_*() method
|
||||||
config2 = providers.Configuration()
|
config2 = providers.Configuration()
|
||||||
|
|
|
@ -4,6 +4,7 @@ from aiohttp import web, test_utils
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from dependency_injector.ext import aiohttp
|
from dependency_injector.ext import aiohttp
|
||||||
from pytest import fixture, mark
|
from pytest import fixture, mark
|
||||||
|
from pytest_asyncio import fixture as aio_fixture
|
||||||
|
|
||||||
|
|
||||||
async def index_view(_):
|
async def index_view(_):
|
||||||
|
@ -63,7 +64,7 @@ def app():
|
||||||
return app
|
return app
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@aio_fixture
|
||||||
async def client(app):
|
async def client(app):
|
||||||
async with test_utils.TestClient(test_utils.TestServer(app)) as client:
|
async with test_utils.TestClient(test_utils.TestServer(app)) as client:
|
||||||
yield client
|
yield client
|
||||||
|
|
41
tests/unit/ext/test_starlette.py
Normal file
41
tests/unit/ext/test_starlette.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
from typing import AsyncIterator, Iterator
|
||||||
|
from unittest.mock import ANY
|
||||||
|
|
||||||
|
from pytest import mark
|
||||||
|
|
||||||
|
from dependency_injector.containers import DeclarativeContainer
|
||||||
|
from dependency_injector.ext.starlette import Lifespan
|
||||||
|
from dependency_injector.providers import Resource
|
||||||
|
|
||||||
|
|
||||||
|
class TestLifespan:
|
||||||
|
@mark.parametrize("sync", [False, True])
|
||||||
|
@mark.asyncio
|
||||||
|
async def test_context_manager(self, sync: bool) -> None:
|
||||||
|
init, shutdown = False, False
|
||||||
|
|
||||||
|
def sync_resource() -> Iterator[None]:
|
||||||
|
nonlocal init, shutdown
|
||||||
|
|
||||||
|
init = True
|
||||||
|
yield
|
||||||
|
shutdown = True
|
||||||
|
|
||||||
|
async def async_resource() -> AsyncIterator[None]:
|
||||||
|
nonlocal init, shutdown
|
||||||
|
|
||||||
|
init = True
|
||||||
|
yield
|
||||||
|
shutdown = True
|
||||||
|
|
||||||
|
class Container(DeclarativeContainer):
|
||||||
|
x = Resource(sync_resource if sync else async_resource)
|
||||||
|
|
||||||
|
container = Container()
|
||||||
|
lifespan = Lifespan(container)
|
||||||
|
|
||||||
|
async with lifespan(ANY) as scope:
|
||||||
|
assert scope is None
|
||||||
|
assert init
|
||||||
|
|
||||||
|
assert shutdown
|
|
@ -1,41 +1,60 @@
|
||||||
"""Configuration.from_pydantic() tests."""
|
"""Configuration.from_pydantic() tests."""
|
||||||
|
|
||||||
import pydantic
|
from pydantic import BaseModel
|
||||||
from dependency_injector import providers, errors
|
|
||||||
|
try:
|
||||||
|
from pydantic_settings import (
|
||||||
|
BaseSettings, # type: ignore[import-not-found,unused-ignore]
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from pydantic import BaseSettings # type: ignore[no-redef,unused-ignore]
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
class BaseSettings: # type: ignore[no-redef]
|
||||||
|
"""No-op fallback"""
|
||||||
|
|
||||||
|
|
||||||
from pytest import fixture, mark, raises
|
from pytest import fixture, mark, raises
|
||||||
|
|
||||||
|
from dependency_injector import errors, providers
|
||||||
|
|
||||||
class Section11(pydantic.BaseModel):
|
pytestmark = mark.pydantic
|
||||||
value1 = 1
|
|
||||||
|
|
||||||
|
|
||||||
class Section12(pydantic.BaseModel):
|
class Section11(BaseModel):
|
||||||
value2 = 2
|
value1: int = 1
|
||||||
|
|
||||||
|
|
||||||
class Settings1(pydantic.BaseSettings):
|
class Section12(BaseModel):
|
||||||
section1 = Section11()
|
value2: int = 2
|
||||||
section2 = Section12()
|
|
||||||
|
|
||||||
|
|
||||||
class Section21(pydantic.BaseModel):
|
class Settings1(BaseSettings):
|
||||||
value1 = 11
|
section1: Section11 = Section11()
|
||||||
value11 = 11
|
section2: Section12 = Section12()
|
||||||
|
|
||||||
|
|
||||||
class Section3(pydantic.BaseModel):
|
class Section21(BaseModel):
|
||||||
value3 = 3
|
value1: int = 11
|
||||||
|
value11: int = 11
|
||||||
|
|
||||||
|
|
||||||
class Settings2(pydantic.BaseSettings):
|
class Section3(BaseModel):
|
||||||
section1 = Section21()
|
value3: int = 3
|
||||||
section3 = Section3()
|
|
||||||
|
|
||||||
|
class Settings2(BaseSettings):
|
||||||
|
section1: Section21 = Section21()
|
||||||
|
section3: Section3 = Section3()
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
def no_pydantic_module_installed():
|
def no_pydantic_module_installed():
|
||||||
providers.pydantic = None
|
has_pydantic_settings = providers.has_pydantic_settings
|
||||||
|
providers.has_pydantic_settings = False
|
||||||
yield
|
yield
|
||||||
providers.pydantic = pydantic
|
providers.has_pydantic_settings = has_pydantic_settings
|
||||||
|
|
||||||
|
|
||||||
def test(config):
|
def test(config):
|
||||||
|
@ -82,66 +101,70 @@ def test_merge(config):
|
||||||
|
|
||||||
|
|
||||||
def test_empty_settings(config):
|
def test_empty_settings(config):
|
||||||
config.from_pydantic(pydantic.BaseSettings())
|
config.from_pydantic(BaseSettings())
|
||||||
assert config() == {}
|
assert config() == {}
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_empty_settings_strict_mode(config):
|
def test_empty_settings_strict_mode(config):
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.from_pydantic(pydantic.BaseSettings())
|
config.from_pydantic(BaseSettings())
|
||||||
|
|
||||||
|
|
||||||
def test_option_empty_settings(config):
|
def test_option_empty_settings(config):
|
||||||
config.option.from_pydantic(pydantic.BaseSettings())
|
config.option.from_pydantic(BaseSettings())
|
||||||
assert config.option() == {}
|
assert config.option() == {}
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_option_empty_settings_strict_mode(config):
|
def test_option_empty_settings_strict_mode(config):
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.option.from_pydantic(pydantic.BaseSettings())
|
config.option.from_pydantic(BaseSettings())
|
||||||
|
|
||||||
|
|
||||||
def test_required_empty_settings(config):
|
def test_required_empty_settings(config):
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.from_pydantic(pydantic.BaseSettings(), required=True)
|
config.from_pydantic(BaseSettings(), required=True)
|
||||||
|
|
||||||
|
|
||||||
def test_required_option_empty_settings(config):
|
def test_required_option_empty_settings(config):
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.option.from_pydantic(pydantic.BaseSettings(), required=True)
|
config.option.from_pydantic(BaseSettings(), required=True)
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_not_required_empty_settings_strict_mode(config):
|
def test_not_required_empty_settings_strict_mode(config):
|
||||||
config.from_pydantic(pydantic.BaseSettings(), required=False)
|
config.from_pydantic(BaseSettings(), required=False)
|
||||||
assert config() == {}
|
assert config() == {}
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_not_required_option_empty_settings_strict_mode(config):
|
def test_not_required_option_empty_settings_strict_mode(config):
|
||||||
config.option.from_pydantic(pydantic.BaseSettings(), required=False)
|
config.option.from_pydantic(BaseSettings(), required=False)
|
||||||
assert config.option() == {}
|
assert config.option() == {}
|
||||||
assert config() == {"option": {}}
|
assert config() == {"option": {}}
|
||||||
|
|
||||||
|
|
||||||
def test_not_instance_of_settings(config):
|
def test_not_instance_of_settings(config):
|
||||||
with raises(errors.Error) as error:
|
with raises(
|
||||||
|
errors.Error,
|
||||||
|
match=(
|
||||||
|
r"Unable to recognize settings instance, expect \"pydantic(?:_settings)?\.BaseSettings\", "
|
||||||
|
r"got {0} instead".format({})
|
||||||
|
),
|
||||||
|
):
|
||||||
config.from_pydantic({})
|
config.from_pydantic({})
|
||||||
assert error.value.args[0] == (
|
|
||||||
"Unable to recognize settings instance, expect \"pydantic.BaseSettings\", "
|
|
||||||
"got {0} instead".format({})
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_option_not_instance_of_settings(config):
|
def test_option_not_instance_of_settings(config):
|
||||||
with raises(errors.Error) as error:
|
with raises(
|
||||||
|
errors.Error,
|
||||||
|
match=(
|
||||||
|
r"Unable to recognize settings instance, expect \"pydantic(?:_settings)?\.BaseSettings\", "
|
||||||
|
"got {0} instead".format({})
|
||||||
|
),
|
||||||
|
):
|
||||||
config.option.from_pydantic({})
|
config.option.from_pydantic({})
|
||||||
assert error.value.args[0] == (
|
|
||||||
"Unable to recognize settings instance, expect \"pydantic.BaseSettings\", "
|
|
||||||
"got {0} instead".format({})
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_subclass_instead_of_instance(config):
|
def test_subclass_instead_of_instance(config):
|
||||||
|
@ -164,21 +187,25 @@ def test_option_subclass_instead_of_instance(config):
|
||||||
|
|
||||||
@mark.usefixtures("no_pydantic_module_installed")
|
@mark.usefixtures("no_pydantic_module_installed")
|
||||||
def test_no_pydantic_installed(config):
|
def test_no_pydantic_installed(config):
|
||||||
with raises(errors.Error) as error:
|
with raises(
|
||||||
|
errors.Error,
|
||||||
|
match=(
|
||||||
|
r"Unable to load pydantic configuration - pydantic(?:_settings)? is not installed\. "
|
||||||
|
r"Install pydantic or install Dependency Injector with pydantic extras: "
|
||||||
|
r"\"pip install dependency-injector\[pydantic2?\]\""
|
||||||
|
),
|
||||||
|
):
|
||||||
config.from_pydantic(Settings1())
|
config.from_pydantic(Settings1())
|
||||||
assert error.value.args[0] == (
|
|
||||||
"Unable to load pydantic configuration - pydantic is not installed. "
|
|
||||||
"Install pydantic or install Dependency Injector with pydantic extras: "
|
|
||||||
"\"pip install dependency-injector[pydantic]\""
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@mark.usefixtures("no_pydantic_module_installed")
|
@mark.usefixtures("no_pydantic_module_installed")
|
||||||
def test_option_no_pydantic_installed(config):
|
def test_option_no_pydantic_installed(config):
|
||||||
with raises(errors.Error) as error:
|
with raises(
|
||||||
|
errors.Error,
|
||||||
|
match=(
|
||||||
|
r"Unable to load pydantic configuration - pydantic(?:_settings)? is not installed\. "
|
||||||
|
r"Install pydantic or install Dependency Injector with pydantic extras: "
|
||||||
|
r"\"pip install dependency-injector\[pydantic2?\]\""
|
||||||
|
),
|
||||||
|
):
|
||||||
config.option.from_pydantic(Settings1())
|
config.option.from_pydantic(Settings1())
|
||||||
assert error.value.args[0] == (
|
|
||||||
"Unable to load pydantic configuration - pydantic is not installed. "
|
|
||||||
"Install pydantic or install Dependency Injector with pydantic extras: "
|
|
||||||
"\"pip install dependency-injector[pydantic]\""
|
|
||||||
)
|
|
||||||
|
|
|
@ -1,35 +1,52 @@
|
||||||
"""Configuration.from_pydantic() tests."""
|
"""Configuration.from_pydantic() tests."""
|
||||||
|
|
||||||
import pydantic
|
from pydantic import BaseModel
|
||||||
from dependency_injector import providers
|
|
||||||
|
try:
|
||||||
|
from pydantic_settings import (
|
||||||
|
BaseSettings, # type: ignore[import-not-found,unused-ignore]
|
||||||
|
)
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from pydantic import BaseSettings # type: ignore[no-redef,unused-ignore]
|
||||||
|
except ImportError:
|
||||||
|
|
||||||
|
class BaseSettings: # type: ignore[no-redef]
|
||||||
|
"""No-op fallback"""
|
||||||
|
|
||||||
|
|
||||||
from pytest import fixture, mark, raises
|
from pytest import fixture, mark, raises
|
||||||
|
|
||||||
|
from dependency_injector import providers
|
||||||
|
|
||||||
class Section11(pydantic.BaseModel):
|
pytestmark = mark.pydantic
|
||||||
value1 = 1
|
|
||||||
|
|
||||||
|
|
||||||
class Section12(pydantic.BaseModel):
|
class Section11(BaseModel):
|
||||||
value2 = 2
|
value1: int = 1
|
||||||
|
|
||||||
|
|
||||||
class Settings1(pydantic.BaseSettings):
|
class Section12(BaseModel):
|
||||||
section1 = Section11()
|
value2: int = 2
|
||||||
section2 = Section12()
|
|
||||||
|
|
||||||
|
|
||||||
class Section21(pydantic.BaseModel):
|
class Settings1(BaseSettings):
|
||||||
value1 = 11
|
section1: Section11 = Section11()
|
||||||
value11 = 11
|
section2: Section12 = Section12()
|
||||||
|
|
||||||
|
|
||||||
class Section3(pydantic.BaseModel):
|
class Section21(BaseModel):
|
||||||
value3 = 3
|
value1: int = 11
|
||||||
|
value11: int = 11
|
||||||
|
|
||||||
|
|
||||||
class Settings2(pydantic.BaseSettings):
|
class Section3(BaseModel):
|
||||||
section1 = Section21()
|
value3: int = 3
|
||||||
section3 = Section3()
|
|
||||||
|
|
||||||
|
class Settings2(BaseSettings):
|
||||||
|
section1: Section21 = Section21()
|
||||||
|
section3: Section3 = Section3()
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@fixture
|
||||||
|
@ -86,10 +103,10 @@ def test_copy(config, pydantic_settings_1, pydantic_settings_2):
|
||||||
|
|
||||||
|
|
||||||
def test_set_pydantic_settings(config):
|
def test_set_pydantic_settings(config):
|
||||||
class Settings3(pydantic.BaseSettings):
|
class Settings3(BaseSettings):
|
||||||
...
|
...
|
||||||
|
|
||||||
class Settings4(pydantic.BaseSettings):
|
class Settings4(BaseSettings):
|
||||||
...
|
...
|
||||||
|
|
||||||
settings_3 = Settings3()
|
settings_3 = Settings3()
|
||||||
|
@ -100,27 +117,27 @@ def test_set_pydantic_settings(config):
|
||||||
|
|
||||||
|
|
||||||
def test_file_does_not_exist(config):
|
def test_file_does_not_exist(config):
|
||||||
config.set_pydantic_settings([pydantic.BaseSettings()])
|
config.set_pydantic_settings([BaseSettings()])
|
||||||
config.load()
|
config.load()
|
||||||
assert config() == {}
|
assert config() == {}
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_file_does_not_exist_strict_mode(config):
|
def test_file_does_not_exist_strict_mode(config):
|
||||||
config.set_pydantic_settings([pydantic.BaseSettings()])
|
config.set_pydantic_settings([BaseSettings()])
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.load()
|
config.load()
|
||||||
assert config() == {}
|
assert config() == {}
|
||||||
|
|
||||||
|
|
||||||
def test_required_file_does_not_exist(config):
|
def test_required_file_does_not_exist(config):
|
||||||
config.set_pydantic_settings([pydantic.BaseSettings()])
|
config.set_pydantic_settings([BaseSettings()])
|
||||||
with raises(ValueError):
|
with raises(ValueError):
|
||||||
config.load(required=True)
|
config.load(required=True)
|
||||||
|
|
||||||
|
|
||||||
@mark.parametrize("config_type", ["strict"])
|
@mark.parametrize("config_type", ["strict"])
|
||||||
def test_not_required_file_does_not_exist_strict_mode(config):
|
def test_not_required_file_does_not_exist_strict_mode(config):
|
||||||
config.set_pydantic_settings([pydantic.BaseSettings()])
|
config.set_pydantic_settings([BaseSettings()])
|
||||||
config.load(required=False)
|
config.load(required=False)
|
||||||
assert config() == {}
|
assert config() == {}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dependency_injector.containers import Container
|
||||||
|
from dependency_injector.providers import ThreadLocalSingleton
|
||||||
|
|
||||||
|
|
||||||
|
class FailingClass:
|
||||||
|
def __init__(self):
|
||||||
|
raise ValueError("FAILING CLASS")
|
||||||
|
|
||||||
|
|
||||||
|
class TestContainer(Container):
|
||||||
|
failing_class = ThreadLocalSingleton(FailingClass)
|
||||||
|
|
||||||
|
|
||||||
|
def test_on_failure_value_error_is_raised():
|
||||||
|
container = TestContainer()
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match="FAILING CLASS"):
|
||||||
|
container.failing_class()
|
65
tests/unit/providers/utils/test_deepcopy_py3.py
Normal file
65
tests/unit/providers/utils/test_deepcopy_py3.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import sys
|
||||||
|
from typing import Any, Dict, NoReturn
|
||||||
|
|
||||||
|
from pytest import raises
|
||||||
|
|
||||||
|
from dependency_injector.errors import NonCopyableArgumentError
|
||||||
|
from dependency_injector.providers import (
|
||||||
|
Provider,
|
||||||
|
deepcopy,
|
||||||
|
deepcopy_args,
|
||||||
|
deepcopy_kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NonCopiable:
|
||||||
|
def __deepcopy__(self, memo: Dict[int, Any]) -> NoReturn:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
def test_deepcopy_streams_not_copied() -> None:
|
||||||
|
l = [sys.stdin, sys.stdout, sys.stderr]
|
||||||
|
assert deepcopy(l) == l
|
||||||
|
|
||||||
|
|
||||||
|
def test_deepcopy_args() -> None:
|
||||||
|
provider = Provider[None]()
|
||||||
|
copiable = NonCopiable()
|
||||||
|
memo: Dict[int, Any] = {id(copiable): copiable}
|
||||||
|
|
||||||
|
assert deepcopy_args(provider, (1, copiable), memo) == (1, copiable)
|
||||||
|
|
||||||
|
|
||||||
|
def test_deepcopy_args_non_copiable() -> None:
|
||||||
|
provider = Provider[None]()
|
||||||
|
copiable = NonCopiable()
|
||||||
|
memo: Dict[int, Any] = {id(copiable): copiable}
|
||||||
|
|
||||||
|
with raises(
|
||||||
|
NonCopyableArgumentError,
|
||||||
|
match=r"^Couldn't copy argument at index 3 for provider ",
|
||||||
|
):
|
||||||
|
deepcopy_args(provider, (1, copiable, object(), NonCopiable()), memo)
|
||||||
|
|
||||||
|
|
||||||
|
def test_deepcopy_kwargs() -> None:
|
||||||
|
provider = Provider[None]()
|
||||||
|
copiable = NonCopiable()
|
||||||
|
memo: Dict[int, Any] = {id(copiable): copiable}
|
||||||
|
|
||||||
|
assert deepcopy_kwargs(provider, {"x": 1, "y": copiable}, memo) == {
|
||||||
|
"x": 1,
|
||||||
|
"y": copiable,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_deepcopy_kwargs_non_copiable() -> None:
|
||||||
|
provider = Provider[None]()
|
||||||
|
copiable = NonCopiable()
|
||||||
|
memo: Dict[int, Any] = {id(copiable): copiable}
|
||||||
|
|
||||||
|
with raises(
|
||||||
|
NonCopyableArgumentError,
|
||||||
|
match=r"^Couldn't copy keyword argument z for provider ",
|
||||||
|
):
|
||||||
|
deepcopy_kwargs(provider, {"x": 1, "y": copiable, "z": NonCopiable()}, memo)
|
|
@ -1,11 +1,9 @@
|
||||||
from flask import Flask, jsonify, request, current_app, session, g
|
from flask import Flask, jsonify, request, current_app, session, g
|
||||||
from flask import _request_ctx_stack, _app_ctx_stack
|
|
||||||
from dependency_injector import containers, providers
|
from dependency_injector import containers, providers
|
||||||
from dependency_injector.wiring import inject, Provide
|
from dependency_injector.wiring import inject, Provide
|
||||||
|
|
||||||
# This is here for testing wiring bypasses these objects without crashing
|
# This is here for testing wiring bypasses these objects without crashing
|
||||||
request, current_app, session, g # noqa
|
request, current_app, session, g # noqa
|
||||||
_request_ctx_stack, _app_ctx_stack # noqa
|
|
||||||
|
|
||||||
|
|
||||||
class Service:
|
class Service:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from httpx import AsyncClient
|
from httpx import ASGITransport, AsyncClient
|
||||||
from pytest import fixture, mark
|
from pytest import fixture, mark
|
||||||
|
from pytest_asyncio import fixture as aio_fixture
|
||||||
|
|
||||||
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
|
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
|
||||||
import os
|
import os
|
||||||
|
@ -16,9 +17,9 @@ sys.path.append(_SAMPLES_DIR)
|
||||||
from wiringfastapi import web
|
from wiringfastapi import web
|
||||||
|
|
||||||
|
|
||||||
@fixture
|
@aio_fixture
|
||||||
async def async_client():
|
async def async_client():
|
||||||
client = AsyncClient(app=web.app, base_url="http://test")
|
client = AsyncClient(transport=ASGITransport(app=web.app), base_url="http://test")
|
||||||
yield client
|
yield client
|
||||||
await client.aclose()
|
await client.aclose()
|
||||||
|
|
||||||
|
|
90
tox.ini
90
tox.ini
|
@ -1,87 +1,89 @@
|
||||||
[tox]
|
[tox]
|
||||||
|
parallel_show_output = true
|
||||||
envlist=
|
envlist=
|
||||||
coveralls, pylint, flake8, pydocstyle, 2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, pypy2.7, pypy3.9
|
coveralls, pylint, flake8, pydocstyle, pydantic-v1, pydantic-v2, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13, pypy3.9, pypy3.10
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps=
|
deps=
|
||||||
pytest
|
pytest
|
||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
# TODO: Hotfix, remove when fixed https://github.com/aio-libs/aiohttp/issues/5107
|
|
||||||
typing_extensions
|
|
||||||
httpx
|
httpx
|
||||||
fastapi
|
fastapi
|
||||||
|
flask
|
||||||
|
aiohttp
|
||||||
numpy
|
numpy
|
||||||
scipy
|
scipy
|
||||||
boto3
|
boto3
|
||||||
mypy_boto3_s3
|
mypy_boto3_s3
|
||||||
|
pydantic-settings
|
||||||
|
werkzeug
|
||||||
extras=
|
extras=
|
||||||
yaml
|
yaml
|
||||||
pydantic
|
|
||||||
flask
|
|
||||||
aiohttp
|
|
||||||
commands = pytest -c tests/.configs/pytest.ini
|
commands = pytest -c tests/.configs/pytest.ini
|
||||||
python_files = test_*_py3*.py
|
python_files = test_*_py3*.py
|
||||||
|
setenv =
|
||||||
|
COVERAGE_RCFILE = pyproject.toml
|
||||||
|
|
||||||
[testenv:coveralls]
|
[testenv:.pkg]
|
||||||
passenv = GITHUB_*, COVERALLS_*
|
passenv = DEPENDENCY_INJECTOR_*
|
||||||
basepython=python3.11
|
|
||||||
usedevelop=True
|
|
||||||
deps=
|
|
||||||
{[testenv]deps}
|
|
||||||
cython
|
|
||||||
coverage
|
|
||||||
coveralls
|
|
||||||
commands=
|
|
||||||
coverage erase
|
|
||||||
coverage run --rcfile=./.coveragerc -m pytest -c tests/.configs/pytest.ini
|
|
||||||
coverage report --rcfile=./.coveragerc
|
|
||||||
coveralls
|
|
||||||
|
|
||||||
[testenv:2.7]
|
[testenv:pydantic-{v1,v2}]
|
||||||
deps=
|
description = run tests with different pydantic versions
|
||||||
pytest
|
base_python = python3.12
|
||||||
extras=
|
deps =
|
||||||
yaml
|
v1: pydantic<2
|
||||||
flask
|
v2: pydantic-settings
|
||||||
commands = pytest -c tests/.configs/pytest-py27.ini
|
|
||||||
|
|
||||||
[testenv:3.5]
|
|
||||||
deps=
|
|
||||||
pytest
|
pytest
|
||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
contextvars
|
typing_extensions
|
||||||
extras=
|
httpx
|
||||||
yaml
|
fastapi
|
||||||
flask
|
flask
|
||||||
commands = pytest -c tests/.configs/pytest-py35.ini
|
aiohttp
|
||||||
|
numpy
|
||||||
|
scipy
|
||||||
|
boto3
|
||||||
|
mypy_boto3_s3
|
||||||
|
werkzeug
|
||||||
|
commands = pytest -c tests/.configs/pytest.ini -m pydantic
|
||||||
|
|
||||||
[testenv:pypy2.7]
|
[testenv:coveralls]
|
||||||
|
passenv = GITHUB_*, COVERALLS_*, DEPENDENCY_INJECTOR_*
|
||||||
|
basepython=python3.12 # TODO: Upgrade to version 3.13 is blocked by coveralls 4.0.1 not supporting Python 3.13
|
||||||
deps=
|
deps=
|
||||||
pytest
|
{[testenv]deps}
|
||||||
extras=
|
cython>=3,<4
|
||||||
yaml
|
coverage>=7
|
||||||
flask
|
coveralls>=4
|
||||||
commands = pytest -c tests/.configs/pytest-py27.ini
|
commands=
|
||||||
|
coverage erase
|
||||||
|
coverage run -m pytest -c tests/.configs/pytest.ini
|
||||||
|
coverage report
|
||||||
|
coveralls
|
||||||
|
|
||||||
[testenv:pypy3.9]
|
[testenv:pypy3.9]
|
||||||
deps=
|
deps=
|
||||||
pytest
|
pytest
|
||||||
pytest-asyncio
|
pytest-asyncio
|
||||||
httpx
|
httpx
|
||||||
|
flask
|
||||||
|
pydantic-settings
|
||||||
|
werkzeug
|
||||||
fastapi
|
fastapi
|
||||||
boto3
|
boto3
|
||||||
mypy_boto3_s3
|
mypy_boto3_s3
|
||||||
extras=
|
extras=
|
||||||
yaml
|
yaml
|
||||||
flask
|
commands = pytest -c tests/.configs/pytest-py35.ini
|
||||||
commands = pytest -c tests/.configs/pytest-py27.ini
|
|
||||||
|
|
||||||
|
|
||||||
[testenv:pylint]
|
[testenv:pylint]
|
||||||
deps=
|
deps=
|
||||||
pylint
|
pylint
|
||||||
|
flask
|
||||||
|
werkzeug
|
||||||
commands=
|
commands=
|
||||||
- pylint -f colorized --rcfile=./.pylintrc src/dependency_injector
|
- pylint -f colorized src/dependency_injector
|
||||||
|
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
deps=
|
deps=
|
||||||
|
@ -99,6 +101,8 @@ commands=
|
||||||
|
|
||||||
[testenv:mypy]
|
[testenv:mypy]
|
||||||
deps=
|
deps=
|
||||||
|
typing_extensions
|
||||||
|
pydantic-settings
|
||||||
mypy
|
mypy
|
||||||
commands=
|
commands=
|
||||||
mypy tests/typing
|
mypy tests/typing
|
||||||
|
|
Loading…
Reference in New Issue
Block a user