mirror of
https://github.com/ets-labs/python-dependency-injector.git
synced 2025-07-14 18:12:21 +03:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2ca2420486 | ||
|
2d1562d536 | ||
|
5e0fd25b5d | ||
|
fad248b4c5 | ||
|
672cd48e7b | ||
|
0b7c72dc70 | ||
|
d694f40de7 | ||
|
5c4a31a518 | ||
|
5f99e25a4d | ||
|
1453db4da1 | ||
|
cc33a14edc | ||
|
2c6015057e | ||
|
c1a9c6b9be | ||
|
36f25dc8de | ||
|
33acc051f2 | ||
|
04df609631 | ||
|
2f64d2da60 | ||
|
a5277b4867 |
10
.coveragerc
Normal file
10
.coveragerc
Normal file
|
@ -0,0 +1,10 @@
|
|||
[run]
|
||||
source = src/dependency_injector
|
||||
omit = tests/unit
|
||||
plugins = Cython.Coverage
|
||||
|
||||
[report]
|
||||
show_missing = true
|
||||
|
||||
[html]
|
||||
directory=reports/unittests/
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
description: Code in Python and Cython
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- Follow PEP 8 rules
|
||||
- When you write imports, split system, 3rd-party, and local imports with a new line
|
||||
- Have two empty lines between the import block and the rest of the code
|
||||
- Have an empty line (\n) at the end of every file
|
||||
- If a file is supposed to be run, always add ``if __name__ == 'main'``
|
||||
- Always follow a consistent pattern of using double or single quotes
|
||||
- When there is a class without a docblock, leave one blank line before its members, e.g.:
|
||||
```python
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(Service)
|
||||
```
|
||||
|
||||
- Avoid shortcuts in names unless absolutely necessary, exceptions:
|
||||
```
|
||||
arg
|
||||
args
|
||||
kwarg
|
||||
kwargs
|
||||
obj
|
||||
cls
|
||||
```
|
||||
|
||||
- Avoid inline comments unless absolutely necessary
|
|
@ -1,7 +0,0 @@
|
|||
---
|
||||
description: Build and run tests
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- Use Makefile commands to build, test, lint and other similar operations when they are available.
|
||||
- Activate virtualenv before running any commands by ``. venv/bin/actvate``
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
description: Run examples
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
- When you run an example from the ``examples/`` folder, switch to the example folder and run it from there.
|
||||
- If there are instructions on running the examples or its tests in readme, follow them
|
||||
- Activate virtualenv before running any commands by ``. venv/bin/actvate``
|
|
@ -1,9 +0,0 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{py,pyi,pxd,pyx}]
|
||||
ij_visual_guides = 80,88
|
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
@ -1 +0,0 @@
|
|||
github: rmk135
|
90
.github/workflows/publishing.yml
vendored
90
.github/workflows/publishing.yml
vendored
|
@ -10,20 +10,20 @@ jobs:
|
|||
|
||||
tests:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.13
|
||||
python-version: 3.11
|
||||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
TOXENV: 3.13
|
||||
TOXENV: 3.11
|
||||
|
||||
linters:
|
||||
name: Run linters
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
toxenv: [flake8, pydocstyle, mypy, pylint]
|
||||
|
@ -31,7 +31,7 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.13
|
||||
python-version: 3.11
|
||||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
|
@ -40,18 +40,15 @@ jobs:
|
|||
build-sdist:
|
||||
name: Build source tarball
|
||||
needs: [tests, linters]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.13
|
||||
- run: |
|
||||
python -m pip install --upgrade build
|
||||
python -m build --sdist
|
||||
- uses: actions/upload-artifact@v4
|
||||
python-version: 3.11
|
||||
- run: python setup.py sdist
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cibw-sdist
|
||||
path: ./dist/*
|
||||
|
||||
build-wheels:
|
||||
|
@ -60,65 +57,62 @@ jobs:
|
|||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2022, macos-14]
|
||||
os: [ubuntu-22.04, windows-2019, macos-11]
|
||||
env:
|
||||
CIBW_ENABLE: pypy
|
||||
CIBW_ENVIRONMENT: >-
|
||||
PIP_CONFIG_SETTINGS="build_ext=-j4"
|
||||
DEPENDENCY_INJECTOR_LIMITED_API="1"
|
||||
CFLAGS="-g0"
|
||||
CIBW_SKIP: cp27-win*
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v3.0.0
|
||||
- uses: actions/upload-artifact@v4
|
||||
uses: pypa/cibuildwheel@v2.11.3
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
test-publish:
|
||||
name: Upload release to TestPyPI
|
||||
needs: [build-sdist, build-wheels]
|
||||
runs-on: ubuntu-latest
|
||||
environment: test-pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
build-wheels-linux-aarch64:
|
||||
name: Build wheels (ubuntu-22.04-aarch64)
|
||||
needs: [tests, linters]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up QEMU
|
||||
if: runner.os == 'Linux'
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Build wheels
|
||||
uses: pypa/cibuildwheel@v2.11.3
|
||||
env:
|
||||
CIBW_ARCHS_LINUX: aarch64
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
pattern: cibw-*
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
path: ./wheelhouse/*.whl
|
||||
|
||||
publish:
|
||||
name: Upload release to PyPI
|
||||
needs: [build-sdist, build-wheels, test-publish]
|
||||
runs-on: ubuntu-latest
|
||||
environment: pypi
|
||||
permissions:
|
||||
id-token: write
|
||||
name: Publish on PyPI
|
||||
needs: [build-sdist, build-wheels, build-wheels-linux-aarch64]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
pattern: cibw-*
|
||||
name: artifact
|
||||
path: dist
|
||||
merge-multiple: true
|
||||
- uses: pypa/gh-action-pypi-publish@release/v1
|
||||
- uses: pypa/gh-action-pypi-publish@master
|
||||
with:
|
||||
# user: __token__
|
||||
# password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
# For publishing to Test PyPI, uncomment next two lines:
|
||||
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
|
||||
publish-docs:
|
||||
name: Publish docs
|
||||
needs: [publish]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.13
|
||||
- run: pip install awscli
|
||||
python-version: 3.11
|
||||
- run: pip install -r requirements-doc.txt
|
||||
- run: pip install awscli
|
||||
- run: pip install -e .
|
||||
- run: (cd docs && make clean html)
|
||||
- run: |
|
||||
|
|
32
.github/workflows/tests-and-linters.yml
vendored
32
.github/workflows/tests-and-linters.yml
vendored
|
@ -4,12 +4,12 @@ on: [push, pull_request, workflow_dispatch]
|
|||
|
||||
jobs:
|
||||
|
||||
test-on-different-versions:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
tests-on-legacy-versions:
|
||||
name: Run tests on legacy versions
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
|
||||
python-version: [2.7, 3.5, 3.6, 3.7, pypy2.7, pypy3.9]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
|
@ -18,35 +18,39 @@ jobs:
|
|||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
DEPENDENCY_INJECTOR_LIMITED_API: 1
|
||||
TOXENV: ${{ matrix.python-version }}
|
||||
|
||||
test-different-pydantic-versions:
|
||||
name: Run tests with different pydantic versions
|
||||
test-on-different-versions:
|
||||
name: Run tests
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: [3.8, 3.9, "3.10", 3.11]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.12"
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- run: pip install tox
|
||||
- run: tox -e pydantic-v1,pydantic-v2
|
||||
- run: tox
|
||||
env:
|
||||
TOXENV: ${{ matrix.python-version }}
|
||||
|
||||
test-coverage:
|
||||
name: Run tests with coverage
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DEPENDENCY_INJECTOR_DEBUG_MODE: 1
|
||||
PIP_VERBOSE: 1
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.12
|
||||
- run: pip install tox
|
||||
- run: tox -vv
|
||||
python-version: 3.11
|
||||
- run: pip install tox cython
|
||||
- run: make cythonize
|
||||
- run: tox
|
||||
env:
|
||||
TOXENV: coveralls
|
||||
|
||||
|
@ -60,7 +64,7 @@ jobs:
|
|||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.13
|
||||
python-version: 3.11
|
||||
- run: pip install tox
|
||||
- run: tox
|
||||
env:
|
||||
|
|
15
.gitignore
vendored
15
.gitignore
vendored
|
@ -15,7 +15,6 @@ lib64/
|
|||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheelhouse/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
@ -64,13 +63,13 @@ venv*/
|
|||
# Vim Rope
|
||||
.ropeproject/
|
||||
|
||||
# Cython artifacts
|
||||
src/**/*.c
|
||||
src/**/*.h
|
||||
src/**/*.so
|
||||
src/**/*.html
|
||||
# C extensions
|
||||
src/dependency_injector/*.h
|
||||
src/dependency_injector/*.so
|
||||
src/dependency_injector/containers/*.h
|
||||
src/dependency_injector/containers/*.so
|
||||
src/dependency_injector/providers/*.h
|
||||
src/dependency_injector/providers/*.so
|
||||
|
||||
# Workspace for samples
|
||||
.workspace/
|
||||
|
||||
.vscode/
|
||||
|
|
49
.pylintrc
Normal file
49
.pylintrc
Normal file
|
@ -0,0 +1,49 @@
|
|||
[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,5 +20,3 @@ Dependency Injector Contributors
|
|||
+ Ngo Thanh Loi (Leonn) (loingo95)
|
||||
+ Thiago Hiromi (thiromi)
|
||||
+ Felipe Rubio (krouw)
|
||||
+ Anton Petrov (anton-petrov)
|
||||
+ ZipFile (ZipFile)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2024, Roman Mogylatov
|
||||
Copyright (c) 2022, Roman Mogylatov
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
recursive-include src/dependency_injector *.py* *.c py.typed
|
||||
recursive-include src/dependency_injector *.py* *.c
|
||||
recursive-include tests *.py
|
||||
include README.rst
|
||||
include CONTRIBUTORS.rst
|
||||
include LICENSE.rst
|
||||
include requirements.txt
|
||||
include setup.py
|
||||
include tox.ini
|
||||
include py.typed
|
||||
|
|
32
Makefile
32
Makefile
|
@ -1,6 +1,14 @@
|
|||
VERSION := $(shell python setup.py --version)
|
||||
|
||||
export COVERAGE_RCFILE := pyproject.toml
|
||||
CYTHON_SRC := $(shell find src/dependency_injector -name '*.pyx')
|
||||
|
||||
CYTHON_DIRECTIVES = -Xlanguage_level=2
|
||||
|
||||
ifdef DEPENDENCY_INJECTOR_DEBUG_MODE
|
||||
CYTHON_DIRECTIVES += -Xprofile=True
|
||||
CYTHON_DIRECTIVES += -Xlinetrace=True
|
||||
endif
|
||||
|
||||
|
||||
clean:
|
||||
# Clean sources
|
||||
|
@ -17,17 +25,21 @@ clean:
|
|||
find examples -name '*.py[co]' -delete
|
||||
find examples -name '__pycache__' -delete
|
||||
|
||||
build: clean
|
||||
# Compile C extensions
|
||||
python setup.py build_ext --inplace
|
||||
cythonize:
|
||||
# Compile Cython to C
|
||||
cython -a $(CYTHON_DIRECTIVES) $(CYTHON_SRC)
|
||||
# Move all Cython html reports
|
||||
mkdir -p reports/cython/
|
||||
find src -name '*.html' -exec mv {} reports/cython/ \;
|
||||
|
||||
build: clean cythonize
|
||||
# Compile C extensions
|
||||
python setup.py build_ext --inplace
|
||||
|
||||
docs-live:
|
||||
sphinx-autobuild docs docs/_build/html
|
||||
|
||||
install: uninstall clean build
|
||||
install: uninstall clean cythonize
|
||||
pip install -ve .
|
||||
|
||||
uninstall:
|
||||
|
@ -36,9 +48,9 @@ uninstall:
|
|||
test:
|
||||
# Unit tests with coverage report
|
||||
coverage erase
|
||||
coverage run -m pytest
|
||||
coverage report
|
||||
coverage html
|
||||
coverage run --rcfile=./.coveragerc -m pytest -c tests/.configs/pytest.ini
|
||||
coverage report --rcfile=./.coveragerc
|
||||
coverage html --rcfile=./.coveragerc
|
||||
|
||||
check:
|
||||
flake8 src/dependency_injector/
|
||||
|
@ -49,9 +61,9 @@ check:
|
|||
|
||||
mypy tests/typing
|
||||
|
||||
test-publish: build
|
||||
test-publish: cythonize
|
||||
# Create distributions
|
||||
python -m build --sdist
|
||||
python setup.py sdist
|
||||
# Upload distributions to PyPI
|
||||
twine upload --repository testpypi dist/dependency-injector-$(VERSION)*
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
:target: https://pypi.org/project/dependency-injector/
|
||||
:alt: Wheel
|
||||
|
||||
.. image:: https://img.shields.io/github/actions/workflow/status/ets-labs/python-dependency-injector/tests-and-linters.yml?branch=master
|
||||
.. image:: https://img.shields.io/github/workflow/status/ets-labs/python-dependency-injector/Tests%20and%20linters/master
|
||||
:target: https://github.com/ets-labs/python-dependency-injector/actions
|
||||
:alt: Build Status
|
||||
|
||||
|
|
9
docs/_static/custom.css
vendored
9
docs/_static/custom.css
vendored
|
@ -1,9 +0,0 @@
|
|||
.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
Normal file
11
docs/_static/disqus.js
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
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
1
docs/_static/sponsor.html
vendored
|
@ -1 +0,0 @@
|
|||
<iframe src="https://github.com/sponsors/rmk135/button" title="Sponsor Dependency Injector" height="32" width="114" style="border: 0; border-radius: 6px;"></iframe>
|
|
@ -1,9 +0,0 @@
|
|||
dependency_injector.ext.starlette
|
||||
=================================
|
||||
|
||||
.. automodule:: dependency_injector.ext.starlette
|
||||
:members:
|
||||
:inherited-members:
|
||||
:show-inheritance:
|
||||
|
||||
.. disqus::
|
|
@ -2,11 +2,10 @@ API Documentation
|
|||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 2
|
||||
|
||||
top-level
|
||||
providers
|
||||
containers
|
||||
wiring
|
||||
errors
|
||||
asgi-lifespan
|
||||
|
|
10
docs/conf.py
10
docs/conf.py
|
@ -33,7 +33,7 @@ sys.path.insert(0, os.path.abspath(".."))
|
|||
extensions = [
|
||||
"alabaster",
|
||||
"sphinx.ext.autodoc",
|
||||
"sphinx_disqus.disqus",
|
||||
"sphinxcontrib.disqus",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
|
@ -52,7 +52,7 @@ master_doc = "index"
|
|||
|
||||
# General information about the project.
|
||||
project = "Dependency Injector"
|
||||
copyright = "2024, Roman Mogylatov"
|
||||
copyright = "2022, Roman Mogylatov"
|
||||
author = "Roman Mogylatov"
|
||||
|
||||
# The version info for the project you"re documenting, acts as replacement for
|
||||
|
@ -72,7 +72,7 @@ release = version
|
|||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = "en"
|
||||
language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
|
@ -147,9 +147,6 @@ html_favicon = "favicon.ico"
|
|||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ["_static"]
|
||||
html_css_files = [
|
||||
"custom.css",
|
||||
]
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
|
@ -309,5 +306,4 @@ html_theme_options = {
|
|||
"description": "Dependency injection framework for Python by Roman Mogylatov",
|
||||
"code_font_size": "10pt",
|
||||
"analytics_id": "UA-67012059-1",
|
||||
"donate_url": "https://github.com/sponsors/rmk135",
|
||||
}
|
||||
|
|
|
@ -78,6 +78,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/aiohttp>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -84,6 +84,4 @@ 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>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
|
@ -90,6 +90,4 @@ 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>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -17,6 +17,4 @@ Listing of ``boto3_session_example.py``:
|
|||
.. literalinclude:: ../../examples/miniapps/boto3-session/boto3_session_example.py
|
||||
:language: python
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -129,6 +129,4 @@ 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>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -78,7 +78,7 @@ Container is wired to the ``views`` module in the app config ``web/apps.py``:
|
|||
|
||||
.. literalinclude:: ../../examples/miniapps/django/web/apps.py
|
||||
:language: python
|
||||
:emphasize-lines: 12
|
||||
:emphasize-lines: 13
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
@ -94,6 +94,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/django>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -95,6 +95,4 @@ See also:
|
|||
- Resource provider :ref:`resource-async-initializers`
|
||||
- Wiring :ref:`async-injections-wiring`
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -116,6 +116,4 @@ Sources
|
|||
|
||||
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::
|
||||
|
|
|
@ -76,6 +76,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/fastapi>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
.. _fastdepends-example:
|
||||
|
||||
FastDepends example
|
||||
===================
|
||||
|
||||
.. meta::
|
||||
:keywords: Python,Dependency Injection,FastDepends,Example
|
||||
:description: This example demonstrates a usage of the FastDepends and Dependency Injector.
|
||||
|
||||
|
||||
This example demonstrates how to use ``Dependency Injector`` with `FastDepends <https://github.com/Lancetnik/FastDepends>`_, a lightweight dependency injection framework inspired by FastAPI's dependency system, but without the web framework components.
|
||||
|
||||
Basic Usage
|
||||
-----------
|
||||
|
||||
The integration between FastDepends and Dependency Injector is straightforward. Simply use Dependency Injector's ``Provide`` marker within FastDepends' ``Depends`` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import sys
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from fast_depends import Depends
|
||||
|
||||
|
||||
class CoefficientService:
|
||||
@staticmethod
|
||||
def get_coefficient() -> float:
|
||||
return 1.2
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
service = providers.Factory(CoefficientService)
|
||||
|
||||
|
||||
@inject
|
||||
def apply_coefficient(
|
||||
a: int,
|
||||
coefficient_provider: CoefficientService = Depends(Provide[Container.service]),
|
||||
) -> float:
|
||||
return a * coefficient_provider.get_coefficient()
|
||||
|
||||
|
||||
container = Container()
|
||||
container.wire(modules=[sys.modules[__name__]])
|
||||
|
||||
apply_coefficient(100) == 120.0
|
|
@ -86,6 +86,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask-blueprints>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -84,6 +84,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/flask>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -22,6 +22,5 @@ Explore the examples to see the ``Dependency Injector`` in action.
|
|||
fastapi
|
||||
fastapi-redis
|
||||
fastapi-sqlalchemy
|
||||
fastdepends
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -77,6 +77,4 @@ Sources
|
|||
|
||||
Explore the sources on the `Github <https://github.com/ets-labs/python-dependency-injector/tree/master/examples/miniapps/sanic>`_.
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -50,7 +50,7 @@ Dependency Injector --- Dependency injection framework for Python
|
|||
:target: https://pypi.org/project/dependency-injector/
|
||||
:alt: Wheel
|
||||
|
||||
.. image:: https://img.shields.io/github/actions/workflow/status/ets-labs/python-dependency-injector/tests-and-linters.yml?branch=master
|
||||
.. image:: https://img.shields.io/github/workflow/status/ets-labs/python-dependency-injector/Tests%20and%20linters/master
|
||||
:target: https://github.com/ets-labs/python-dependency-injector/actions
|
||||
:alt: Build Status
|
||||
|
||||
|
|
|
@ -310,6 +310,4 @@ A few useful links related to a dependency injection design pattern for further
|
|||
+ https://github.com/ets-labs/python-dependency-injector
|
||||
+ https://pypi.org/project/dependency-injector/
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -31,7 +31,7 @@ Key features of the ``Dependency Injector``:
|
|||
|
||||
The framework stands on the `PEP20 (The Zen of Python) <https://www.python.org/dev/peps/pep-0020/>`_ principle:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Explicit is better than implicit
|
||||
|
||||
|
|
|
@ -7,118 +7,12 @@ that were made in every particular version.
|
|||
From version 0.7.6 *Dependency Injector* framework strictly
|
||||
follows `Semantic versioning`_
|
||||
|
||||
4.48.1
|
||||
------
|
||||
|
||||
* Improve performance of ``dependency_injector._cwiring.DependencyResolver``
|
||||
* Add ``typing-extensions`` as a dependency for older Python versions (<3.11)
|
||||
* Produce warning on ``@inject``s without ``Provide[...]`` marks
|
||||
* Add support for `resource_type` in ``Lifespan``s
|
||||
|
||||
4.48.0
|
||||
------
|
||||
|
||||
- Improve performance of wiring (`#897 <https://github.com/ets-labs/python-dependency-injector/pull/897>`_)
|
||||
- Add Context Manager support to Resource provider (`#899 <https://github.com/ets-labs/python-dependency-injector/pull/899>`_)
|
||||
- Add support for async generator injections (`#900 <https://github.com/ets-labs/python-dependency-injector/pull/900>`_)
|
||||
- Fix unintended dependency on ``typing_extensions`` (`#902 <https://github.com/ets-labs/python-dependency-injector/pull/902>`_)
|
||||
- Add support for Fast Depends (`#898 <https://github.com/ets-labs/python-dependency-injector/pull/898>`_)
|
||||
- Add ``resource_type`` parameter to init and shutdown resources using specialized providers (`#858 <https://github.com/ets-labs/python-dependency-injector/pull/858>`_)
|
||||
|
||||
4.47.1
|
||||
------
|
||||
|
||||
- Fix typing for wiring marker (`#892 <https://github.com/ets-labs/python-dependency-injector/pull/896>`_)
|
||||
- Strip debug symbols in wheels
|
||||
|
||||
4.47.0
|
||||
------
|
||||
|
||||
- Add support for ``Annotated`` type for module and class attribute injection in wiring,
|
||||
with updated documentation and examples.
|
||||
See discussion:
|
||||
https://github.com/ets-labs/python-dependency-injector/pull/721#issuecomment-2025263718
|
||||
- Fix ``root`` property shadowing in ``ConfigurationOption`` (`#875 <https://github.com/ets-labs/python-dependency-injector/pull/875>`_)
|
||||
- Fix incorrect monkeypatching during ``wire()`` that could violate MRO in some classes (`#886 <https://github.com/ets-labs/python-dependency-injector/pull/886>`_)
|
||||
- ABI3 wheels are now published for CPython.
|
||||
- Drop support of Python 3.7.
|
||||
|
||||
4.46.0
|
||||
------
|
||||
|
||||
- Add option to disable env var interpolation in configs (`#861 <https://github.com/ets-labs/python-dependency-injector/pull/861>`_)
|
||||
- Fix ``Closing`` dependency resolution (`#852 <https://github.com/ets-labs/python-dependency-injector/pull/852>`_)
|
||||
- Add support for ``inspect.iscoroutinefunction()`` in ``Coroutine`` provider (`#830 <https://github.com/ets-labs/python-dependency-injector/pull/830>`_)
|
||||
- Fix broken wiring of sync inject-decorated methods (`#673 <https://github.com/ets-labs/python-dependency-injector/pull/673>`_)
|
||||
- Add support for ``typing.Annotated`` (`#721 <https://github.com/ets-labs/python-dependency-injector/pull/721>`_, `#853 <https://github.com/ets-labs/python-dependency-injector/pull/853>`_)
|
||||
- Documentation updates for movie-lister example (`#747 <https://github.com/ets-labs/python-dependency-injector/pull/747>`_)
|
||||
- Fix type propagation in ``Provider.provider`` (`#744 <https://github.com/ets-labs/python-dependency-injector/pull/744>`_)
|
||||
|
||||
Many thanks for the contributions to:
|
||||
- `ZipFile <https://github.com/ZipFile>`_
|
||||
- `Yegor Statkevich <https://github.com/jazzthief>`_
|
||||
- `Federico Tomasi <https://github.com/federinik>`_
|
||||
- `Martin Lafrance <https://github.com/martlaf>`_
|
||||
- `Philip Bjorge <https://github.com/philipbjorge>`_
|
||||
- `Ilya Kazakov <https://github.com/mrKazzila>`_
|
||||
|
||||
4.45.0
|
||||
--------
|
||||
- Add Starlette lifespan handler implementation (`#683 <https://github.com/ets-labs/python-dependency-injector/pull/683>`_).
|
||||
- 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
|
||||
------
|
||||
Development version
|
||||
-------------------
|
||||
- Add support of Python 3.11.
|
||||
- Allow Closing to detect dependent resources `#633 <https://github.com/ets-labs/python-dependency-injector/issues/633>`_,
|
||||
`#636 <https://github.com/ets-labs/python-dependency-injector/pull/636>`_. Thanks `Jamie Stumme @StummeJ <https://github.com/StummeJ>`_
|
||||
for the contribution.
|
||||
- Update CI/CD to use Ubuntu 22.04.
|
||||
- Update CI/CD to ``actions/checkout@v3``, ``actions/setup-python@v4``, ``actions/upload-artifact@v3``, ``pypa/cibuildwheel@v2.11.3``,
|
||||
and ``actions/download-artifact@v3``.
|
||||
- Fix install crash on non-utf8 systems `#644 <https://github.com/ets-labs/python-dependency-injector/pull/644>`_.
|
||||
- Fix a bug in Windows build with default charset `#635 <https://github.com/ets-labs/python-dependency-injector/pull/635>`_.
|
||||
- Update FastAPI Redis example to use ``aioredis`` version 2 `#613 <https://github.com/ets-labs/python-dependency-injector/pull/613>`_.
|
||||
- Update documentation on creating custom providers `#598 <https://github.com/ets-labs/python-dependency-injector/pull/598>`_.
|
||||
- Update CI/CD to ``actions/checkout@v3``, ``actions/setup-python@v4``, ``actions/upload-artifact@v3``, and ``pypa/cibuildwheel@v2.11.3``.
|
||||
- Regenerate C sources using Cython 0.29.32.
|
||||
- Fix builds badge.
|
||||
|
||||
4.40.0
|
||||
------
|
||||
|
@ -395,8 +289,8 @@ Many thanks to `ZipFile <https://github.com/ZipFile>`_ for both contributions.
|
|||
- Make refactoring of wiring module and tests.
|
||||
See PR # `#406 <https://github.com/ets-labs/python-dependency-injector/issues/406>`_.
|
||||
Thanks to `@withshubh <https://github.com/withshubh>`_ for the contribution:
|
||||
- Remove unused imports in tests.
|
||||
- Use literal syntax to create data structure in tests.
|
||||
- Remove unused imports in tests.
|
||||
- Use literal syntax to create data structure in tests.
|
||||
- Add integration with a static analysis tool `DeepSource <https://deepsource.io/>`_.
|
||||
|
||||
4.26.0
|
||||
|
|
|
@ -183,22 +183,22 @@ See also: :ref:`configuration-envs-interpolation`.
|
|||
Loading from a Pydantic settings
|
||||
--------------------------------
|
||||
|
||||
``Configuration`` provider can load configuration from a ``pydantic_settings.BaseSettings`` object using the
|
||||
``Configuration`` provider can load configuration from a ``pydantic`` settings object using the
|
||||
:py:meth:`Configuration.from_pydantic` method:
|
||||
|
||||
.. literalinclude:: ../../examples/providers/configuration/configuration_pydantic.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 32
|
||||
:emphasize-lines: 31
|
||||
|
||||
To get the data from pydantic settings ``Configuration`` provider calls its ``model_dump()`` method.
|
||||
To get the data from pydantic settings ``Configuration`` provider calls ``Settings.dict()`` method.
|
||||
If you need to pass an argument to this call, use ``.from_pydantic()`` keyword arguments.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
container.config.from_pydantic(Settings(), exclude={"optional"})
|
||||
|
||||
Alternatively, you can provide a ``pydantic_settings.BaseSettings`` object over the configuration provider argument. In that case,
|
||||
Alternatively, you can provide a ``pydantic`` settings object over the configuration provider argument. In that case,
|
||||
the container will call ``config.from_pydantic()`` automatically:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -215,23 +215,18 @@ the container will call ``config.from_pydantic()`` automatically:
|
|||
|
||||
.. note::
|
||||
|
||||
``Dependency Injector`` doesn't install ``pydantic-settings`` by default.
|
||||
``Dependency Injector`` doesn't install ``pydantic`` by default.
|
||||
|
||||
You can install the ``Dependency Injector`` with an extra dependency::
|
||||
|
||||
pip install dependency-injector[pydantic2]
|
||||
pip install dependency-injector[pydantic]
|
||||
|
||||
or install ``pydantic-settings`` directly::
|
||||
or install ``pydantic`` directly::
|
||||
|
||||
pip install pydantic-settings
|
||||
pip install pydantic
|
||||
|
||||
*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
|
||||
-------------------------
|
||||
|
||||
|
@ -366,19 +361,6 @@ See also: :ref:`configuration-strict-mode`.
|
|||
|
||||
assert container.config.section.option() is None
|
||||
|
||||
If you want to disable environment variables interpolation, pass ``envs_required=None``:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: templates.yml
|
||||
|
||||
template_string: 'Hello, ${name}!'
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> container.config.from_yaml("templates.yml", envs_required=None)
|
||||
>>> container.config.template_string()
|
||||
'Hello, ${name}!'
|
||||
|
||||
Mandatory and optional sources
|
||||
------------------------------
|
||||
|
||||
|
|
|
@ -16,11 +16,10 @@ To create a custom provider you need to follow these rules:
|
|||
1. New provider class should inherit :py:class:`Provider`.
|
||||
2. You need to implement the ``Provider._provide()`` method.
|
||||
3. You need to implement the ``Provider.__deepcopy__()`` method. It should return an
|
||||
equivalent copy of a provider. All providers must be copied with the ``deepcopy()`` function
|
||||
from the ``providers`` module. It's essential to pass ``memo`` into ``deepcopy`` in order to keep
|
||||
the preconfigured ``args`` and ``kwargs`` of stored providers. After the a new provider object
|
||||
is created, use ``Provider._copy_overriding()`` method to copy all overriding providers. See the
|
||||
example below.
|
||||
equivalent copy of a provider. All providers must be copied with a ``deepcopy()`` function
|
||||
from the ``providers`` module. After the a new provider object is created use
|
||||
``Provider._copy_overriding()`` method to copy all overriding providers. See the example
|
||||
below.
|
||||
4. If new provider has a ``__init__()`` method, it should call the parent
|
||||
``Provider.__init__()``.
|
||||
5. If new provider stores any other providers, these providers should be listed in
|
||||
|
@ -34,7 +33,7 @@ To create a custom provider you need to follow these rules:
|
|||
.. note::
|
||||
1. Prefer delegation over inheritance. If you choose between inheriting a ``Factory`` or
|
||||
inheriting a ``Provider`` and use ``Factory`` internally - the last is better.
|
||||
2. When creating a new provider follow the ``Factory``-like injections style. Consistency matters.
|
||||
2. When create a new provider follow the ``Factory``-like injections style. Consistency matters.
|
||||
3. Use the ``__slots__`` attribute to make sure nothing could be attached to your provider. You
|
||||
will also save some memory.
|
||||
|
||||
|
|
|
@ -61,12 +61,11 @@ When you call ``.shutdown()`` method on a resource provider, it will remove the
|
|||
if any, and switch to uninitialized state. Some of resource initializer types support specifying custom
|
||||
resource shutdown.
|
||||
|
||||
Resource provider supports 4 types of initializers:
|
||||
Resource provider supports 3 types of initializers:
|
||||
|
||||
- Function
|
||||
- Context Manager
|
||||
- Generator (legacy)
|
||||
- Subclass of ``resources.Resource`` (legacy)
|
||||
- Generator
|
||||
- Subclass of ``resources.Resource``
|
||||
|
||||
Function initializer
|
||||
--------------------
|
||||
|
@ -104,44 +103,8 @@ you configure global resource:
|
|||
|
||||
Function initializer does not provide a way to specify custom resource shutdown.
|
||||
|
||||
Context Manager initializer
|
||||
---------------------------
|
||||
|
||||
This is an extension to the Function initializer. Resource provider automatically detects if the initializer returns a
|
||||
context manager and uses it to manage the resource lifecycle.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
class DatabaseConnection:
|
||||
def __init__(self, host, port, user, password):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.user = user
|
||||
self.password = password
|
||||
|
||||
def __enter__(self):
|
||||
print(f"Connecting to {self.host}:{self.port} as {self.user}")
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
print("Closing connection")
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
config = providers.Configuration()
|
||||
db = providers.Resource(
|
||||
DatabaseConnection,
|
||||
host=config.db.host,
|
||||
port=config.db.port,
|
||||
user=config.db.user,
|
||||
password=config.db.password,
|
||||
)
|
||||
|
||||
Generator initializer (legacy)
|
||||
------------------------------
|
||||
Generator initializer
|
||||
---------------------
|
||||
|
||||
Resource provider can use 2-step generators:
|
||||
|
||||
|
@ -191,13 +154,8 @@ object is not mandatory. You can leave ``yield`` statement empty:
|
|||
argument2=...,
|
||||
)
|
||||
|
||||
.. note::
|
||||
|
||||
Generator initializers are automatically wrapped with ``contextmanager`` or ``asynccontextmanager`` decorator when
|
||||
provided to a ``Resource`` provider.
|
||||
|
||||
Subclass initializer (legacy)
|
||||
-----------------------------
|
||||
Subclass initializer
|
||||
--------------------
|
||||
|
||||
You can create resource initializer by implementing a subclass of the ``resources.Resource``:
|
||||
|
||||
|
@ -252,72 +210,6 @@ first argument.
|
|||
|
||||
.. _resource-provider-wiring-closing:
|
||||
|
||||
Scoping Resources using specialized subclasses
|
||||
----------------------------------------------
|
||||
|
||||
You can use specialized subclasses of ``Resource`` provider to initialize and shutdown resources by type.
|
||||
Allowing for example to only initialize a subgroup of resources.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class ScopedResource(resources.Resource):
|
||||
pass
|
||||
|
||||
def init_service(name) -> Service:
|
||||
print(f"Init {name}")
|
||||
yield Service()
|
||||
print(f"Shutdown {name}")
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
scoped = ScopedResource(
|
||||
init_service,
|
||||
"scoped",
|
||||
)
|
||||
|
||||
generic = providers.Resource(
|
||||
init_service,
|
||||
"generic",
|
||||
)
|
||||
|
||||
|
||||
To initialize resources by type you can use ``init_resources(resource_type)`` and ``shutdown_resources(resource_type)``
|
||||
methods adding the resource type as an argument:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def main():
|
||||
container = Container()
|
||||
container.init_resources(ScopedResource)
|
||||
# Generates:
|
||||
# >>> Init scoped
|
||||
|
||||
container.shutdown_resources(ScopedResource)
|
||||
# Generates:
|
||||
# >>> Shutdown scoped
|
||||
|
||||
|
||||
And to initialize all resources you can use ``init_resources()`` and ``shutdown_resources()`` without arguments:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def main():
|
||||
container = Container()
|
||||
container.init_resources()
|
||||
# Generates:
|
||||
# >>> Init scoped
|
||||
# >>> Init generic
|
||||
|
||||
container.shutdown_resources()
|
||||
# Generates:
|
||||
# >>> Shutdown scoped
|
||||
# >>> Shutdown generic
|
||||
|
||||
|
||||
It works using the ``traverse()`` method to find all resources of the specified type, selecting all resources
|
||||
which are instances of the specified type.
|
||||
|
||||
|
||||
Resources, wiring, and per-function execution scope
|
||||
---------------------------------------------------
|
||||
|
||||
|
@ -371,11 +263,10 @@ Asynchronous function initializer:
|
|||
argument2=...,
|
||||
)
|
||||
|
||||
Asynchronous Context Manager initializer:
|
||||
Asynchronous generator initializer:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@asynccontextmanager
|
||||
async def init_async_resource(argument1=..., argument2=...):
|
||||
connection = await connect()
|
||||
yield connection
|
||||
|
@ -467,54 +358,5 @@ See also:
|
|||
- Wiring :ref:`async-injections-wiring`
|
||||
- :ref:`fastapi-redis-example`
|
||||
|
||||
ASGI Lifespan Protocol Support
|
||||
------------------------------
|
||||
|
||||
The :mod:`dependency_injector.ext.starlette` module provides a :class:`~dependency_injector.ext.starlette.Lifespan`
|
||||
class that integrates resource providers with ASGI applications using the `Lifespan Protocol`_. This allows resources to
|
||||
be automatically initialized at application startup and properly shut down when the application stops.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.ext.starlette import Lifespan
|
||||
from fastapi import FastAPI, Request, Depends, APIRouter
|
||||
|
||||
class Connection: ...
|
||||
|
||||
@asynccontextmanager
|
||||
async def init_database():
|
||||
print("opening database connection")
|
||||
yield Connection()
|
||||
print("closing database connection")
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/")
|
||||
@inject
|
||||
async def index(request: Request, db: Connection = Depends(Provide["db"])):
|
||||
# use the database connection here
|
||||
return "OK!"
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
__self__ = providers.Self()
|
||||
db = providers.Resource(init_database)
|
||||
lifespan = providers.Singleton(Lifespan, __self__)
|
||||
app = providers.Singleton(FastAPI, lifespan=lifespan)
|
||||
_include_router = providers.Resource(
|
||||
app.provided.include_router.call(),
|
||||
router,
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
container = Container()
|
||||
app = container.app()
|
||||
uvicorn.run(app, host="localhost", port=8000)
|
||||
|
||||
.. _Lifespan Protocol: https://asgi.readthedocs.io/en/latest/specs/lifespan.html
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -24,7 +24,7 @@ returns it on the rest of the calls.
|
|||
|
||||
.. note::
|
||||
|
||||
``Singleton`` provider makes dependencies injection only when it creates an object. When an object
|
||||
``Singleton`` provider makes dependencies injection only when creates an object. When an object
|
||||
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
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
.. list-table::
|
||||
:class: no-border
|
||||
:align: left
|
||||
|
||||
* - Sponsor the project on GitHub:
|
||||
- .. raw:: html
|
||||
:file: _static/sponsor.html
|
|
@ -257,7 +257,7 @@ Let's check that it works. Open another terminal session and use ``httpie``:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: http
|
||||
.. code-block:: json
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 844
|
||||
|
@ -596,7 +596,7 @@ and make a request to the API in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: http
|
||||
.. code-block:: json
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Content-Length: 492
|
||||
|
@ -859,6 +859,4 @@ What's next?
|
|||
- Know more about the :ref:`providers`
|
||||
- Go to the :ref:`contents`
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -18,7 +18,7 @@ In this tutorial we will use:
|
|||
|
||||
- Python 3
|
||||
- Docker
|
||||
- Docker Compose
|
||||
- Docker-compose
|
||||
|
||||
Start from the scratch or jump to the section:
|
||||
|
||||
|
@ -47,27 +47,28 @@ response it will log:
|
|||
Prerequisites
|
||||
-------------
|
||||
|
||||
We will use `docker compose <https://docs.docker.com/compose/>`_ in this tutorial. Let's check the versions:
|
||||
We will use `Docker <https://www.docker.com/>`_ and
|
||||
`docker-compose <https://docs.docker.com/compose/>`_ in this tutorial. Let's check the versions:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker --version
|
||||
docker compose version
|
||||
docker-compose --version
|
||||
|
||||
The output should look something like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Docker version 27.3.1, build ce12230
|
||||
Docker Compose version v2.29.7
|
||||
Docker version 20.10.5, build 55c4c88
|
||||
docker-compose version 1.29.0, build 07737305
|
||||
|
||||
.. 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:
|
||||
|
||||
- `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.
|
||||
|
||||
|
@ -128,13 +129,13 @@ Put next lines into the ``requirements.txt`` file:
|
|||
pytest-cov
|
||||
|
||||
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.13-bookworm`` as a base image.
|
||||
specify how to run it. We will use ``python:3.9-buster`` as a base image.
|
||||
|
||||
Put next lines into the ``Dockerfile`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
FROM python:3.13-bookworm
|
||||
FROM python:3.10-buster
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
|
@ -154,6 +155,8 @@ Put next lines into the ``docker-compose.yml`` file:
|
|||
|
||||
.. code-block:: yaml
|
||||
|
||||
version: "3.7"
|
||||
|
||||
services:
|
||||
|
||||
monitor:
|
||||
|
@ -168,7 +171,7 @@ Run in the terminal:
|
|||
|
||||
.. 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:
|
||||
|
||||
|
@ -181,7 +184,7 @@ After the build is done run the container:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
The output should look like:
|
||||
|
||||
|
@ -458,7 +461,7 @@ Run in the terminal:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
The output should look like:
|
||||
|
||||
|
@ -702,7 +705,7 @@ Run in the terminal:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
You should see:
|
||||
|
||||
|
@ -810,7 +813,7 @@ Run in the terminal:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
You should see:
|
||||
|
||||
|
@ -962,16 +965,15 @@ Run in the terminal:
|
|||
|
||||
.. 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:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
rootdir: /code
|
||||
plugins: cov-6.0.0, asyncio-0.24.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
plugins: asyncio-0.16.0, cov-3.0.0
|
||||
collected 2 items
|
||||
|
||||
monitoringdaemon/tests.py .. [100%]
|
||||
|
@ -1026,6 +1028,4 @@ What's next?
|
|||
- Know more about the :ref:`providers`
|
||||
- Go to the :ref:`contents`
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -84,7 +84,7 @@ Create next structure in the project root directory. All files are empty. That's
|
|||
|
||||
Initial project layout:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
./
|
||||
├── movies/
|
||||
|
@ -109,7 +109,7 @@ Now it's time to install the project requirements. We will use next packages:
|
|||
|
||||
Put next lines into the ``requirements.txt`` file:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
dependency-injector
|
||||
pyyaml
|
||||
|
@ -134,7 +134,7 @@ We will create a script that creates database files.
|
|||
First add the folder ``data/`` in the root of the project and then add the file
|
||||
``fixtures.py`` inside of it:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 2-3
|
||||
|
||||
./
|
||||
|
@ -205,13 +205,13 @@ Now run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
|
||||
OK
|
||||
|
||||
Check that files ``movies.csv`` and ``movies.db`` have appeared in the ``data/`` folder:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 4-5
|
||||
|
||||
./
|
||||
|
@ -289,7 +289,7 @@ After each step we will add the provider to the container.
|
|||
|
||||
Create the ``entities.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 10
|
||||
|
||||
./
|
||||
|
@ -356,7 +356,7 @@ Let's move on to the finders.
|
|||
|
||||
Create the ``finders.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 11
|
||||
|
||||
./
|
||||
|
@ -465,7 +465,7 @@ The configuration file is ready. Move on to the lister.
|
|||
|
||||
Create the ``listers.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 12
|
||||
|
||||
./
|
||||
|
@ -613,7 +613,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -752,7 +752,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -868,7 +868,7 @@ Run in the terminal line by line:
|
|||
|
||||
The output should be similar for each command:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: plain
|
||||
|
||||
Francis Lawrence movies:
|
||||
- Movie(title='The Hunger Games: Mockingjay - Part 2', year=2015, director='Francis Lawrence')
|
||||
|
@ -888,7 +888,7 @@ We will use `pytest <https://docs.pytest.org/en/stable/>`_ and
|
|||
|
||||
Create ``tests.py`` in the ``movies`` package:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block:: bash
|
||||
:emphasize-lines: 13
|
||||
|
||||
./
|
||||
|
@ -911,7 +911,7 @@ Create ``tests.py`` in the ``movies`` package:
|
|||
and put next into it:
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 41,50
|
||||
:emphasize-lines: 36,51
|
||||
|
||||
"""Tests module."""
|
||||
|
||||
|
@ -941,18 +941,13 @@ and put next into it:
|
|||
return container
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def finder_mock(container):
|
||||
def test_movies_directed_by(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
return finder_mock
|
||||
|
||||
|
||||
def test_movies_directed_by(container, finder_mock):
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_directed_by("Jon Favreau")
|
||||
|
@ -961,7 +956,13 @@ and put next into it:
|
|||
assert movies[0].title == "The Jungle Book"
|
||||
|
||||
|
||||
def test_movies_released_in(container, finder_mock):
|
||||
def test_movies_released_in(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_released_in(2015)
|
||||
|
@ -977,7 +978,7 @@ Run in the terminal:
|
|||
|
||||
You should see:
|
||||
|
||||
.. code-block:: text
|
||||
.. code-block::
|
||||
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: cov-3.0.0
|
||||
|
@ -994,9 +995,9 @@ You should see:
|
|||
movies/entities.py 7 1 86%
|
||||
movies/finders.py 26 13 50%
|
||||
movies/listers.py 8 0 100%
|
||||
movies/tests.py 24 0 100%
|
||||
movies/tests.py 23 0 100%
|
||||
------------------------------------------
|
||||
TOTAL 90 30 67%
|
||||
TOTAL 89 30 66%
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -1033,6 +1034,4 @@ What's next?
|
|||
- Know more about the :ref:`providers`
|
||||
- Go to the :ref:`contents`
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -280,7 +280,7 @@ Now let's fill in the layout.
|
|||
|
||||
Put next into the ``base.html``:
|
||||
|
||||
.. code-block:: jinja
|
||||
.. code-block:: html
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
@ -313,7 +313,7 @@ And put something to the index page.
|
|||
|
||||
Put next into the ``index.html``:
|
||||
|
||||
.. code-block:: jinja
|
||||
.. code-block:: html
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
|
@ -998,6 +998,5 @@ What's next?
|
|||
- Know more about the :ref:`providers`
|
||||
- Go to the :ref:`contents`
|
||||
|
||||
.. include:: ../sponsor.rst
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -64,7 +64,7 @@ FastAPI example:
|
|||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(service: Annotated[Service, Depends(Provide[Container.service])]):
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
value = await service.process()
|
||||
return {"result": value}
|
||||
|
||||
|
@ -127,7 +127,6 @@ To inject the provider itself use ``Provide[foo.provider]``:
|
|||
def foo(bar_provider: Factory[Bar] = Provide[Container.bar.provider]):
|
||||
bar = bar_provider(argument="baz")
|
||||
...
|
||||
|
||||
You can also use ``Provider[foo]`` for injecting the provider itself:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -255,43 +254,13 @@ To inject a container use special identifier ``<container>``:
|
|||
Making injections into modules and class attributes
|
||||
---------------------------------------------------
|
||||
|
||||
You can use wiring to make injections into modules and class attributes. Both the classic marker
|
||||
syntax and the ``Annotated`` form are supported.
|
||||
|
||||
Classic marker syntax:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
service: Service = Provide[Container.service]
|
||||
|
||||
class Main:
|
||||
service: Service = Provide[Container.service]
|
||||
|
||||
Full example of the classic marker syntax:
|
||||
You can use wiring to make injections into modules and class attributes.
|
||||
|
||||
.. literalinclude:: ../examples/wiring/example_attribute.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 14,19
|
||||
|
||||
Annotated form (Python 3.9+):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
class Main:
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
Full example of the annotated form:
|
||||
|
||||
.. literalinclude:: ../examples/wiring/example_attribute_annotated.py
|
||||
:language: python
|
||||
:lines: 3-
|
||||
:emphasize-lines: 16,21
|
||||
|
||||
You could also use string identifiers to avoid a dependency on a container:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -632,36 +601,6 @@ or with a single container ``register_loader_containers(container)`` multiple ti
|
|||
To unregister a container use ``unregister_loader_containers(container)``.
|
||||
Wiring module will uninstall the import hook when unregister last container.
|
||||
|
||||
Few notes on performance
|
||||
------------------------
|
||||
|
||||
``.wire()`` utilize caching to speed up the wiring process. At the end it clears the cache to avoid memory leaks.
|
||||
But this may not always be desirable, when you want to keep the cache for the next wiring
|
||||
(e.g. due to usage of multiple containers or during unit tests).
|
||||
|
||||
To keep the cache after wiring, you can set flag ``keep_cache=True`` (works with ``WiringConfiguration`` too):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
container1.wire(
|
||||
modules=["yourapp.module1", "yourapp.module2"],
|
||||
keep_cache=True,
|
||||
)
|
||||
container2.wire(
|
||||
modules=["yourapp.module2", "yourapp.module3"],
|
||||
keep_cache=True,
|
||||
)
|
||||
...
|
||||
|
||||
and then clear it manually when you need it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from dependency_injector.wiring import clear_cache
|
||||
|
||||
clear_cache()
|
||||
|
||||
|
||||
Integration with other frameworks
|
||||
---------------------------------
|
||||
|
||||
|
@ -693,6 +632,5 @@ Take a look at other application examples:
|
|||
- :ref:`fastapi-example`
|
||||
- :ref:`fastapi-redis-example`
|
||||
- :ref:`fastapi-sqlalchemy-example`
|
||||
- :ref:`fastdepends-example`
|
||||
|
||||
.. disqus::
|
||||
|
|
|
@ -98,9 +98,8 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.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
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: asyncio-0.16.0, anyio-3.3.4, aiohttp-0.3.0, cov-3.0.0
|
||||
collected 3 items
|
||||
|
||||
giphynavigator/tests.py ... [100%]
|
||||
|
|
|
@ -3,15 +3,11 @@
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
|
||||
from giphynavigator.application import create_app
|
||||
from giphynavigator.giphy import GiphyClient
|
||||
|
||||
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
app = create_app()
|
||||
|
@ -19,9 +15,9 @@ def app():
|
|||
app.container.unwire()
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def client(app, aiohttp_client):
|
||||
return await aiohttp_client(app)
|
||||
@pytest.fixture
|
||||
def client(app, aiohttp_client, loop):
|
||||
return loop.run_until_complete(aiohttp_client(app))
|
||||
|
||||
|
||||
async def test_index(client, app):
|
||||
|
|
|
@ -2,5 +2,4 @@ dependency-injector
|
|||
aiohttp
|
||||
pyyaml
|
||||
pytest-aiohttp
|
||||
pytest-asyncio
|
||||
pytest-cov
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.13-bookworm
|
||||
FROM python:3.10-buster
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ Build the Docker image:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose build
|
||||
docker-compose build
|
||||
|
||||
Run the docker-compose environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
The output should be something like:
|
||||
|
||||
|
@ -59,16 +59,15 @@ To run the tests do:
|
|||
|
||||
.. 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:
|
||||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
rootdir: /code
|
||||
plugins: cov-6.0.0, asyncio-0.24.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
plugins: asyncio-0.16.0, cov-3.0.0
|
||||
collected 2 items
|
||||
|
||||
monitoringdaemon/tests.py .. [100%]
|
||||
|
|
|
@ -61,7 +61,7 @@ async def test_example_monitor(container, caplog):
|
|||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatcher(container, caplog):
|
||||
async def test_dispatcher(container, caplog, event_loop):
|
||||
caplog.set_level("INFO")
|
||||
|
||||
example_monitor_mock = mock.AsyncMock()
|
||||
|
@ -72,7 +72,6 @@ async def test_dispatcher(container, caplog):
|
|||
httpbin_monitor=httpbin_monitor_mock,
|
||||
):
|
||||
dispatcher = container.dispatcher()
|
||||
event_loop = asyncio.get_running_loop()
|
||||
event_loop.create_task(dispatcher.start())
|
||||
await asyncio.sleep(0.1)
|
||||
dispatcher.stop()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.13-bookworm
|
||||
FROM python:3.9-buster
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
|
|
|
@ -12,38 +12,47 @@ Build the Docker image:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose build
|
||||
docker-compose build
|
||||
|
||||
Run the docker-compose environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
The output should be something like:
|
||||
|
||||
.. code-block::
|
||||
|
||||
fastapi-redis-redis-1 | 1:C 19 Dec 2022 02:33:02.484 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
|
||||
fastapi-redis-redis-1 | 1:C 19 Dec 2022 02:33:02.484 # Redis version=7.0.5, bits=64, commit=00000000, modified=0, pid=1, just started
|
||||
fastapi-redis-redis-1 | 1:C 19 Dec 2022 02:33:02.484 # Configuration loaded
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.485 * monotonic clock: POSIX clock_gettime
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.485 * Running mode=standalone, port=6379.
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.485 # Server initialized
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.487 * Loading RDB produced by version 7.0.5
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.487 * RDB age 58 seconds
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.487 * RDB memory usage when created 0.85 Mb
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.487 * Done loading RDB, keys loaded: 0, keys expired: 0.
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.487 * DB loaded from disk: 0.000 seconds
|
||||
fastapi-redis-redis-1 | 1:M 19 Dec 2022 02:33:02.488 * Ready to accept connections
|
||||
fastapi-redis-example-1 | INFO: Started server process [1]
|
||||
fastapi-redis-example-1 | INFO: Waiting for application startup.
|
||||
fastapi-redis-example-1 | INFO: Application startup complete.
|
||||
fastapi-redis-example-1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||
fastapi-redis-example-1 | INFO: 172.18.0.1:63998 - "GET / HTTP/1.1" 200 OK
|
||||
fastapi-redis-example-1 | INFO: 172.18.0.1:63998 - "GET /favicon.ico HTTP/1.1" 404 Not Found
|
||||
fastapi-redis-example-1 | INFO: 172.18.0.1:63998 - "GET / HTTP/1.1" 200 OK
|
||||
fastapi-redis-example-1 | INFO: 172.18.0.1:63998 - "GET / HTTP/1.1" 200 OK
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:14.115 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:14.115 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=1, just started
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:14.115 # Configuration loaded
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.116 * Running mode=standalone, port=6379.
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.116 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.116 # Server initialized
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.117 * Loading RDB produced by version 6.0.9
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.117 * RDB age 1 seconds
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.117 * RDB memory usage when created 0.77 Mb
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.117 * DB loaded from disk: 0.000 seconds
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:14.117 * Ready to accept connections
|
||||
redis_1 | 1:signal-handler (1609728137) Received SIGTERM scheduling shutdown...
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:17.984 # User requested shutdown...
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:17.984 # Redis is now ready to exit, bye bye...
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:22.035 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:22.035 # Redis version=6.0.9, bits=64, commit=00000000, modified=0, pid=1, just started
|
||||
redis_1 | 1:C 04 Jan 2022 02:42:22.035 # Configuration loaded
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * Running mode=standalone, port=6379.
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 # Server initialized
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * Loading RDB produced by version 6.0.9
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * RDB age 9 seconds
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * RDB memory usage when created 0.77 Mb
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * DB loaded from disk: 0.000 seconds
|
||||
redis_1 | 1:M 04 Jan 2022 02:42:22.037 * Ready to accept connections
|
||||
example_1 | INFO: Started server process [1]
|
||||
example_1 | INFO: Waiting for application startup.
|
||||
example_1 | INFO: Application startup complete.
|
||||
example_1 | INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||
|
||||
Test
|
||||
----
|
||||
|
@ -54,16 +63,16 @@ To run the tests do:
|
|||
|
||||
.. 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:
|
||||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||
platform linux -- Python 3.9, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
|
||||
rootdir: /code
|
||||
plugins: cov-6.0.0, asyncio-0.24.0, anyio-4.7.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
plugins: cov-2.10.1, asyncio-0.14.0
|
||||
collected 1 item
|
||||
|
||||
fastapiredis/tests.py . [100%]
|
||||
|
||||
|
@ -71,10 +80,10 @@ The output should be something like:
|
|||
Name Stmts Miss Cover
|
||||
-------------------------------------------------
|
||||
fastapiredis/__init__.py 0 0 100%
|
||||
fastapiredis/application.py 14 0 100%
|
||||
fastapiredis/application.py 15 0 100%
|
||||
fastapiredis/containers.py 6 0 100%
|
||||
fastapiredis/redis.py 7 4 43%
|
||||
fastapiredis/services.py 7 3 57%
|
||||
fastapiredis/tests.py 18 0 100%
|
||||
-------------------------------------------------
|
||||
TOTAL 52 7 87%
|
||||
TOTAL 53 7 87%
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
"""Application module."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from fastapi import FastAPI, Depends
|
||||
|
||||
from .containers import Container
|
||||
from .services import Service
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(
|
||||
service: Annotated[Service, Depends(Provide[Container.service])]
|
||||
) -> dict[str, str]:
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
value = await service.process()
|
||||
return {"result": value}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"""Redis client module."""
|
||||
|
||||
from typing import AsyncIterator
|
||||
|
||||
from redis.asyncio import from_url, Redis
|
||||
from aioredis import create_redis_pool, Redis
|
||||
|
||||
|
||||
async def init_redis_pool(host: str, password: str) -> AsyncIterator[Redis]:
|
||||
session = from_url(f"redis://{host}", password=password, encoding="utf-8", decode_responses=True)
|
||||
yield session
|
||||
session.close()
|
||||
await session.wait_closed()
|
||||
pool = await create_redis_pool(f"redis://{host}", password=password)
|
||||
yield pool
|
||||
pool.close()
|
||||
await pool.wait_closed()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Services module."""
|
||||
|
||||
from redis.asyncio import Redis
|
||||
from aioredis import Redis
|
||||
|
||||
|
||||
class Service:
|
||||
|
@ -9,4 +9,4 @@ class Service:
|
|||
|
||||
async def process(self) -> str:
|
||||
await self._redis.set("my-key", "value")
|
||||
return await self._redis.get("my-key")
|
||||
return await self._redis.get("my-key", encoding="utf-8")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from httpx import AsyncClient
|
||||
|
||||
from .application import app, container
|
||||
from .services import Service
|
||||
|
@ -11,10 +11,7 @@ from .services import Service
|
|||
|
||||
@pytest.fixture
|
||||
def client(event_loop):
|
||||
client = AsyncClient(
|
||||
transport=ASGITransport(app=app),
|
||||
base_url="http://test",
|
||||
)
|
||||
client = AsyncClient(app=app, base_url="http://test")
|
||||
yield client
|
||||
event_loop.run_until_complete(client.aclose())
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
dependency-injector
|
||||
fastapi
|
||||
uvicorn
|
||||
redis>=4.2
|
||||
aioredis<2 # TODO: Update example to work with aioredis >= 2.0
|
||||
|
||||
# For testing:
|
||||
pytest
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
from typing import Annotated
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
from fastapi import FastAPI, Depends
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
|
@ -21,9 +18,7 @@ app = FastAPI()
|
|||
|
||||
@app.api_route("/")
|
||||
@inject
|
||||
async def index(
|
||||
service: Annotated[Service, Depends(Provide[Container.service])]
|
||||
) -> dict[str, str]:
|
||||
async def index(service: Service = Depends(Provide[Container.service])):
|
||||
result = await service.process()
|
||||
return {"result": result}
|
||||
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from httpx import AsyncClient
|
||||
|
||||
from fastapi_di_example import app, container, Service
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def client():
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app),
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
@pytest.fixture
|
||||
async def client(event_loop):
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
yield client
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM python:3.13-bookworm
|
||||
FROM python:3.10-buster
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV HOST=0.0.0.0
|
||||
|
|
|
@ -15,13 +15,13 @@ Build the Docker image:
|
|||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose build
|
||||
docker-compose build
|
||||
|
||||
Run the docker-compose environment:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker compose up
|
||||
docker-compose up
|
||||
|
||||
The output should be something like:
|
||||
|
||||
|
@ -67,15 +67,15 @@ To run the tests do:
|
|||
|
||||
.. 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:
|
||||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.13.1, pytest-8.3.4, pluggy-1.5.0
|
||||
platform linux -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
rootdir: /code
|
||||
plugins: cov-6.0.0, anyio-4.7.0
|
||||
plugins: cov-3.0.0
|
||||
collected 7 items
|
||||
|
||||
webapp/tests.py ....... [100%]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
dependency-injector
|
||||
fastapi[standard]
|
||||
fastapi
|
||||
uvicorn
|
||||
pyyaml
|
||||
sqlalchemy
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
"""Endpoints module."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, Response, status
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
||||
from .containers import Container
|
||||
from .repositories import NotFoundError
|
||||
from .services import UserService
|
||||
from .repositories import NotFoundError
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
@ -16,7 +13,7 @@ router = APIRouter()
|
|||
@router.get("/users")
|
||||
@inject
|
||||
def get_list(
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
return user_service.get_users()
|
||||
|
||||
|
@ -24,8 +21,8 @@ def get_list(
|
|||
@router.get("/users/{user_id}")
|
||||
@inject
|
||||
def get_by_id(
|
||||
user_id: int,
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_id: int,
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
try:
|
||||
return user_service.get_user_by_id(user_id)
|
||||
|
@ -36,7 +33,7 @@ def get_by_id(
|
|||
@router.post("/users", status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
def add(
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
return user_service.create_user()
|
||||
|
||||
|
@ -44,9 +41,9 @@ def add(
|
|||
@router.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
def remove(
|
||||
user_id: int,
|
||||
user_service: Annotated[UserService, Depends(Provide[Container.user_service])],
|
||||
) -> Response:
|
||||
user_id: int,
|
||||
user_service: UserService = Depends(Provide[Container.user_service]),
|
||||
):
|
||||
try:
|
||||
user_service.delete_user_by_id(user_id)
|
||||
except NotFoundError:
|
||||
|
|
|
@ -101,9 +101,9 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.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
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: asyncio-0.16.0, cov-3.0.0
|
||||
collected 3 items
|
||||
|
||||
giphynavigator/tests.py ... [100%]
|
||||
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
"""Endpoints module."""
|
||||
|
||||
from typing import Annotated, List
|
||||
from typing import Optional, List
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
|
||||
from .containers import Container
|
||||
from .services import SearchService
|
||||
from .containers import Container
|
||||
|
||||
|
||||
class Gif(BaseModel):
|
||||
|
@ -27,15 +26,11 @@ router = APIRouter()
|
|||
@router.get("/", response_model=Response)
|
||||
@inject
|
||||
async def index(
|
||||
default_query: Annotated[str, Depends(Provide[Container.config.default.query])],
|
||||
default_limit: Annotated[
|
||||
int, Depends(Provide[Container.config.default.limit.as_int()])
|
||||
],
|
||||
search_service: Annotated[
|
||||
SearchService, Depends(Provide[Container.search_service])
|
||||
],
|
||||
query: str | None = None,
|
||||
limit: int | None = None,
|
||||
query: Optional[str] = None,
|
||||
limit: Optional[str] = None,
|
||||
default_query: str = Depends(Provide[Container.config.default.query]),
|
||||
default_limit: int = Depends(Provide[Container.config.default.limit.as_int()]),
|
||||
search_service: SearchService = Depends(Provide[Container.search_service]),
|
||||
):
|
||||
query = query or default_query
|
||||
limit = limit or default_limit
|
||||
|
|
|
@ -3,19 +3,15 @@
|
|||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
from httpx import AsyncClient
|
||||
|
||||
from giphynavigator.application import app
|
||||
from giphynavigator.giphy import GiphyClient
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
@pytest.fixture
|
||||
async def client():
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app),
|
||||
base_url="http://test",
|
||||
) as client:
|
||||
async with AsyncClient(app=app, base_url="http://test") as client:
|
||||
yield client
|
||||
|
||||
|
||||
|
|
|
@ -81,9 +81,8 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||
plugins: cov-6.0.0, flask-1.3.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: cov-3.0.0, flask-1.2.0
|
||||
collected 2 items
|
||||
|
||||
githubnavigator/tests.py .. [100%]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Application module."""
|
||||
|
||||
from flask import Flask
|
||||
from flask_bootstrap import Bootstrap4
|
||||
from flask_bootstrap import Bootstrap
|
||||
|
||||
from .containers import Container
|
||||
from .blueprints import example
|
||||
|
@ -15,7 +15,7 @@ def create_app() -> Flask:
|
|||
app.container = container
|
||||
app.register_blueprint(example.blueprint)
|
||||
|
||||
bootstrap = Bootstrap4()
|
||||
bootstrap = Bootstrap()
|
||||
bootstrap.init_app(app)
|
||||
|
||||
return app
|
||||
|
|
|
@ -81,9 +81,8 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||
plugins: cov-6.0.0, flask-1.3.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: cov-3.0.0, flask-1.2.0
|
||||
collected 2 items
|
||||
|
||||
githubnavigator/tests.py .. [100%]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
"""Application module."""
|
||||
|
||||
from flask import Flask
|
||||
from flask_bootstrap import Bootstrap4
|
||||
from flask_bootstrap import Bootstrap
|
||||
|
||||
from .containers import Container
|
||||
from . import views
|
||||
|
@ -15,7 +15,7 @@ def create_app() -> Flask:
|
|||
app.container = container
|
||||
app.add_url_rule("/", "index", views.index)
|
||||
|
||||
bootstrap = Bootstrap4()
|
||||
bootstrap = Bootstrap()
|
||||
bootstrap.init_app(app)
|
||||
|
||||
return app
|
||||
|
|
|
@ -58,8 +58,8 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||
plugins: cov-6.0.0
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: cov-3.0.0
|
||||
collected 2 items
|
||||
|
||||
movies/tests.py .. [100%]
|
||||
|
|
|
@ -18,9 +18,10 @@ SQLITE_FILE = DIR / "movies.db"
|
|||
|
||||
|
||||
def create_csv(movies_data, path):
|
||||
with open(path, "w", newline="") as opened_file:
|
||||
with open(path, "w") as opened_file:
|
||||
writer = csv.writer(opened_file)
|
||||
writer.writerows(movies_data)
|
||||
for row in movies_data:
|
||||
writer.writerow(row)
|
||||
|
||||
|
||||
def create_sqlite(movies_data, path):
|
||||
|
|
|
@ -29,7 +29,7 @@ class CsvMovieFinder(MovieFinder):
|
|||
super().__init__(movie_factory)
|
||||
|
||||
def find_all(self) -> List[Movie]:
|
||||
with open(self._csv_file_path, newline="") as csv_file:
|
||||
with open(self._csv_file_path) as csv_file:
|
||||
csv_reader = csv.reader(csv_file, delimiter=self._delimiter)
|
||||
return [self._movie_factory(*row) for row in csv_reader]
|
||||
|
||||
|
|
|
@ -26,18 +26,13 @@ def container():
|
|||
return container
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def finder_mock(container):
|
||||
def test_movies_directed_by(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
return finder_mock
|
||||
|
||||
|
||||
def test_movies_directed_by(container, finder_mock):
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_directed_by("Jon Favreau")
|
||||
|
@ -46,7 +41,13 @@ def test_movies_directed_by(container, finder_mock):
|
|||
assert movies[0].title == "The Jungle Book"
|
||||
|
||||
|
||||
def test_movies_released_in(container, finder_mock):
|
||||
def test_movies_released_in(container):
|
||||
finder_mock = mock.Mock()
|
||||
finder_mock.find_all.return_value = [
|
||||
container.movie("The 33", 2015, "Patricia Riggen"),
|
||||
container.movie("The Jungle Book", 2016, "Jon Favreau"),
|
||||
]
|
||||
|
||||
with container.finder.override(finder_mock):
|
||||
lister = container.lister()
|
||||
movies = lister.movies_released_in(2015)
|
||||
|
|
|
@ -27,7 +27,7 @@ To run the application do:
|
|||
.. code-block:: bash
|
||||
|
||||
export GIPHY_API_KEY=wBJ2wZG7SRqfrU9nPgPiWvORmloDyuL0
|
||||
sanic giphynavigator.application:create_app
|
||||
python -m giphynavigator
|
||||
|
||||
The output should be something like:
|
||||
|
||||
|
@ -98,9 +98,8 @@ The output should be something like:
|
|||
|
||||
.. code-block::
|
||||
|
||||
platform linux -- Python 3.12.3, pytest-8.3.2, pluggy-1.5.0
|
||||
plugins: cov-6.0.0, anyio-4.4.0, asyncio-0.24.0
|
||||
asyncio: mode=Mode.STRICT, default_loop_scope=None
|
||||
platform darwin -- Python 3.10.0, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
|
||||
plugins: sanic-1.9.1, anyio-3.3.4, cov-3.0.0
|
||||
collected 3 items
|
||||
|
||||
giphynavigator/tests.py ... [100%]
|
||||
|
|
|
@ -8,8 +8,6 @@ from sanic import Sanic
|
|||
from giphynavigator.application import create_app
|
||||
from giphynavigator.giphy import GiphyClient
|
||||
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def app():
|
||||
|
@ -19,7 +17,12 @@ def app():
|
|||
app.ctx.container.unwire()
|
||||
|
||||
|
||||
async def test_index(app):
|
||||
@pytest.fixture
|
||||
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.search.return_value = {
|
||||
"data": [
|
||||
|
@ -29,7 +32,7 @@ async def test_index(app):
|
|||
}
|
||||
|
||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||
_, response = await app.asgi_client.get(
|
||||
response = await test_client.get(
|
||||
"/",
|
||||
params={
|
||||
"query": "test",
|
||||
|
@ -38,7 +41,7 @@ async def test_index(app):
|
|||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json
|
||||
data = response.json()
|
||||
assert data == {
|
||||
"query": "test",
|
||||
"limit": 10,
|
||||
|
@ -49,30 +52,30 @@ async def test_index(app):
|
|||
}
|
||||
|
||||
|
||||
async def test_index_no_data(app):
|
||||
async def test_index_no_data(app, test_client):
|
||||
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
||||
giphy_client_mock.search.return_value = {
|
||||
"data": [],
|
||||
}
|
||||
|
||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||
_, response = await app.asgi_client.get("/")
|
||||
response = await test_client.get("/")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json
|
||||
data = response.json()
|
||||
assert data["gifs"] == []
|
||||
|
||||
|
||||
async def test_index_default_params(app):
|
||||
async def test_index_default_params(app, test_client):
|
||||
giphy_client_mock = mock.AsyncMock(spec=GiphyClient)
|
||||
giphy_client_mock.search.return_value = {
|
||||
"data": [],
|
||||
}
|
||||
|
||||
with app.ctx.container.giphy_client.override(giphy_client_mock):
|
||||
_, response = await app.asgi_client.get("/")
|
||||
response = await test_client.get("/")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json
|
||||
data = response.json()
|
||||
assert data["query"] == app.ctx.container.config.default.query()
|
||||
assert data["limit"] == app.ctx.container.config.default.limit()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
dependency-injector
|
||||
sanic
|
||||
sanic-testing
|
||||
sanic<=21.6
|
||||
aiohttp
|
||||
pyyaml
|
||||
pytest-sanic
|
||||
pytest-cov
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
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).
|
|
@ -1,59 +0,0 @@
|
|||
#!/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,
|
||||
)
|
|
@ -1,3 +0,0 @@
|
|||
dependency-injector
|
||||
starlette
|
||||
uvicorn
|
|
@ -3,7 +3,7 @@
|
|||
import os
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from pydantic import BaseSettings, Field
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
||||
|
@ -11,16 +11,15 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "SECRET"
|
|||
|
||||
|
||||
class AwsSettings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_prefix="aws_")
|
||||
|
||||
access_key_id: str
|
||||
secret_access_key: str
|
||||
access_key_id: str = Field(env="aws_access_key_id")
|
||||
secret_access_key: str = Field(env="aws_secret_access_key")
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
|
||||
aws: AwsSettings = AwsSettings()
|
||||
optional: str = "default_value"
|
||||
optional: str = Field(default="default_value")
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import os
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from pydantic import BaseSettings, Field
|
||||
|
||||
# Emulate environment variables
|
||||
os.environ["AWS_ACCESS_KEY_ID"] = "KEY"
|
||||
|
@ -11,16 +11,15 @@ os.environ["AWS_SECRET_ACCESS_KEY"] = "SECRET"
|
|||
|
||||
|
||||
class AwsSettings(BaseSettings):
|
||||
model_config = SettingsConfigDict(env_prefix="aws_")
|
||||
|
||||
access_key_id: str
|
||||
secret_access_key: str
|
||||
access_key_id: str = Field(env="aws_access_key_id")
|
||||
secret_access_key: str = Field(env="aws_secret_access_key")
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
|
||||
aws: AwsSettings = AwsSettings()
|
||||
optional: str = "default_value"
|
||||
optional: str = Field(default="default_value")
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
import sys
|
||||
import logging
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from contextlib import contextmanager
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
|
||||
|
||||
@contextmanager
|
||||
def init_thread_pool(max_workers: int):
|
||||
thread_pool = ThreadPoolExecutor(max_workers=max_workers)
|
||||
yield thread_pool
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide, inject
|
||||
from typing import Annotated
|
||||
|
||||
|
||||
class Service: ...
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
@ -13,16 +13,9 @@ class Container(containers.DeclarativeContainer):
|
|||
service = providers.Factory(Service)
|
||||
|
||||
|
||||
# You can place marker on parameter default value
|
||||
@inject
|
||||
def main(service: Service = Provide[Container.service]) -> None: ...
|
||||
|
||||
|
||||
# Also, you can place marker with typing.Annotated
|
||||
@inject
|
||||
def main_with_annotated(
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
) -> None: ...
|
||||
def main(service: Service = Provide[Container.service]) -> None:
|
||||
...
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
"""Wiring attribute example with Annotated."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from dependency_injector import containers, providers
|
||||
from dependency_injector.wiring import Provide
|
||||
|
||||
|
||||
class Service:
|
||||
...
|
||||
|
||||
|
||||
class Container(containers.DeclarativeContainer):
|
||||
|
||||
service = providers.Factory(Service)
|
||||
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
|
||||
class Main:
|
||||
|
||||
service: Annotated[Service, Provide[Container.service]]
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
container = Container()
|
||||
container.wire(modules=[__name__])
|
||||
|
||||
assert isinstance(service, Service)
|
||||
assert isinstance(Main.service, Service)
|
122
pyproject.toml
122
pyproject.toml
|
@ -1,122 +0,0 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "Cython>=3.1.1"]
|
||||
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.8"
|
||||
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.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"]
|
||||
dependencies = [
|
||||
# typing.Annotated since v3.9
|
||||
# typing.Self since v3.11
|
||||
"typing-extensions; python_version<'3.11'",
|
||||
]
|
||||
|
||||
[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"
|
||||
combine_as_imports = true
|
||||
|
||||
[tool.pylint.main]
|
||||
ignore = ["tests"]
|
||||
|
||||
[tool.pylint.design]
|
||||
min-public-methods = 0
|
||||
max-public-methods = 30
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests/unit/"]
|
||||
asyncio_mode = "auto"
|
||||
asyncio_default_fixture_loop_scope = "function"
|
||||
markers = [
|
||||
"pydantic: Tests with Pydantic as a dependency",
|
||||
]
|
||||
filterwarnings = [
|
||||
"ignore::dependency_injector.wiring.DIWiringWarning",
|
||||
"ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
|
||||
"ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
|
||||
"ignore:Please use \\`.*?\\` from the \\`scipy.*?\\`(.*?)namespace is deprecated\\.:DeprecationWarning",
|
||||
"ignore:Please import \\`.*?\\` from the \\`scipy(.*?)\\` namespace(.*):DeprecationWarning",
|
||||
"ignore:\\`scipy(.*?)\\` is deprecated(.*):DeprecationWarning",
|
||||
]
|
|
@ -1,11 +1,9 @@
|
|||
cython==3.1.1
|
||||
setuptools
|
||||
cython==0.29.32
|
||||
pytest
|
||||
pytest-asyncio
|
||||
tox
|
||||
coverage
|
||||
flake8
|
||||
flake8-pyproject
|
||||
pydocstyle
|
||||
sphinx_autobuild
|
||||
pip
|
||||
|
@ -14,12 +12,9 @@ pyyaml
|
|||
httpx
|
||||
fastapi
|
||||
pydantic
|
||||
pydantic-settings
|
||||
numpy
|
||||
scipy
|
||||
boto3
|
||||
mypy_boto3_s3
|
||||
typing_extensions
|
||||
fast-depends
|
||||
|
||||
-r requirements-ext.txt
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
# TODO: unpin 3.5.0 when this bug is fixed: https://github.com/sphinx-doc/sphinx/issues/8885
|
||||
sphinx
|
||||
sphinx<3.5.0
|
||||
|
||||
# TODO: unpin jinja2 after sphinx update to 4+
|
||||
jinja2
|
||||
jinja2<3.1
|
||||
|
||||
sphinx-disqus==1.3.0
|
||||
-e git+https://github.com/rmk135/sphinxcontrib-disqus.git#egg=sphinxcontrib-disqus
|
||||
|
||||
-r requirements-ext.txt
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
flask
|
||||
werkzeug
|
||||
aiohttp
|
||||
|
|
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
six>=1.7.0,<=1.16.0
|
|
@ -1,14 +1,13 @@
|
|||
[flake8]
|
||||
max_line_length = 120
|
||||
max_line_length = 100
|
||||
max_complexity = 10
|
||||
exclude = types.py
|
||||
extend-ignore = E203,E701
|
||||
per-file-ignores =
|
||||
examples/demo/*: F841
|
||||
examples/containers/traverse.py: E501
|
||||
examples/providers/async.py: F841
|
||||
examples/providers/async_overriding.py: F841
|
||||
examples/wiring/*: F821,F841
|
||||
examples/wiring/*: F841
|
||||
|
||||
[pydocstyle]
|
||||
ignore = D100,D101,D102,D105,D106,D107,D203,D213
|
||||
|
|
160
setup.py
160
setup.py
|
@ -1,55 +1,123 @@
|
|||
"""`Dependency injector` setup script."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
from Cython.Build import cythonize
|
||||
from Cython.Compiler import Options
|
||||
from setuptools import Extension, setup
|
||||
from setuptools import setup, Extension
|
||||
|
||||
debug = os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1"
|
||||
limited_api = (
|
||||
os.environ.get("DEPENDENCY_INJECTOR_LIMITED_API") == "1"
|
||||
and sys.implementation.name == "cpython"
|
||||
)
|
||||
defined_macros = []
|
||||
options = {}
|
||||
compiler_directives = {
|
||||
"language_level": 3,
|
||||
"profile": debug,
|
||||
"linetrace": debug,
|
||||
}
|
||||
Options.annotate = debug
|
||||
|
||||
# Defining setup variables:
|
||||
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:
|
||||
if debug:
|
||||
limited_api = False # line tracing is not part of the Limited API
|
||||
defined_macros.extend(
|
||||
[
|
||||
("CYTHON_TRACE", "1"),
|
||||
("CYTHON_TRACE_NOGIL", "1"),
|
||||
("CYTHON_CLINE_IN_TRACEBACK", "1"),
|
||||
]
|
||||
)
|
||||
if os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1":
|
||||
defined_macros["CYTHON_TRACE"] = 1
|
||||
defined_macros["CYTHON_TRACE_NOGIL"] = 1
|
||||
defined_macros["CYTHON_CLINE_IN_TRACEBACK"] = 1
|
||||
|
||||
if limited_api:
|
||||
options.setdefault("bdist_wheel", {})
|
||||
options["bdist_wheel"]["py_limited_api"] = "cp38"
|
||||
defined_macros.append(("Py_LIMITED_API", "0x03080000"))
|
||||
|
||||
setup(
|
||||
options=options,
|
||||
ext_modules=cythonize(
|
||||
[
|
||||
Extension(
|
||||
"*",
|
||||
["src/**/*.pyx"],
|
||||
define_macros=defined_macros,
|
||||
py_limited_api=limited_api,
|
||||
),
|
||||
],
|
||||
annotate=debug,
|
||||
show_all_warnings=True,
|
||||
compiler_directives=compiler_directives,
|
||||
),
|
||||
)
|
||||
setup(name="dependency-injector",
|
||||
version=version,
|
||||
description="Dependency injection framework for Python",
|
||||
long_description=description,
|
||||
author="Roman Mogylatov",
|
||||
author_email="rmogilatov@gmail.com",
|
||||
maintainer="Roman Mogylatov",
|
||||
maintainer_email="rmogilatov@gmail.com",
|
||||
url="https://github.com/ets-labs/python-dependency-injector",
|
||||
download_url="https://pypi.python.org/pypi/dependency_injector",
|
||||
packages=[
|
||||
"dependency_injector",
|
||||
"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."""
|
||||
|
||||
__version__ = "4.48.1"
|
||||
__version__ = "4.40.0"
|
||||
"""Version number.
|
||||
|
||||
:type: str
|
||||
|
|
0
src/dependency_injector/__init__.pyi
Normal file
0
src/dependency_injector/__init__.pyi
Normal file
18402
src/dependency_injector/_cwiring.c
Normal file
18402
src/dependency_injector/_cwiring.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user