Skip to content

Commit 193249f

Browse files
committed
Merge branch 'release/4.47.0'
2 parents 6e4794b + 01349c4 commit 193249f

26 files changed

+578
-114
lines changed

.cursor/rules/coding-guide.mdc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
description: Code in Python and Cython
3+
globs:
4+
alwaysApply: false
5+
---
6+
- Follow PEP 8 rules
7+
- When you write imports, split system, 3rd-party, and local imports with a new line
8+
- Have two empty lines between the import block and the rest of the code
9+
- Have an empty line (\n) at the end of every file
10+
- If a file is supposed to be run, always add ``if __name__ == 'main'``
11+
- Always follow a consistent pattern of using double or single quotes
12+
- When there is a class without a docblock, leave one blank line before its members, e.g.:
13+
```python
14+
class Container(containers.DeclarativeContainer):
15+
16+
service = providers.Factory(Service)
17+
```
18+
19+
- Avoid shortcuts in names unless absolutely necessary, exceptions:
20+
```
21+
arg
22+
args
23+
kwarg
24+
kwargs
25+
obj
26+
cls
27+
```
28+
29+
- Avoid inline comments unless absolutely necessary

.cursor/rules/makefile-commands.mdc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
description: Build and run tests
3+
globs:
4+
alwaysApply: false
5+
---
6+
- Use Makefile commands to build, test, lint and other similar operations when they are available.
7+
- Activate virtualenv before running any commands by ``. venv/bin/actvate``

.cursor/rules/run-examples.mdc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
description: Run examples
3+
globs:
4+
alwaysApply: false
5+
---
6+
- When you run an example from the ``examples/`` folder, switch to the example folder and run it from there.
7+
- If there are instructions on running the examples or its tests in readme, follow them
8+
- Activate virtualenv before running any commands by ``. venv/bin/actvate``

.github/workflows/publishing.yml

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,26 @@ jobs:
6262
matrix:
6363
os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-14]
6464
env:
65-
CIBW_SKIP: cp27-*
65+
CIBW_ENABLE: pypy
66+
CIBW_ENVIRONMENT: >-
67+
PIP_CONFIG_SETTINGS="build_ext=-j4"
68+
DEPENDENCY_INJECTOR_LIMITED_API="1"
6669
steps:
6770
- uses: actions/checkout@v3
6871
- name: Build wheels
69-
uses: pypa/cibuildwheel@v2.20.0
72+
uses: pypa/cibuildwheel@v2.23.3
7073
- uses: actions/upload-artifact@v4
7174
with:
7275
name: cibw-wheels-x86-${{ matrix.os }}-${{ strategy.job-index }}
7376
path: ./wheelhouse/*.whl
7477

75-
publish:
76-
name: Publish on PyPI
78+
test-publish:
79+
name: Upload release to TestPyPI
7780
needs: [build-sdist, build-wheels]
78-
runs-on: ubuntu-24.04
81+
runs-on: ubuntu-latest
82+
environment: test-pypi
83+
permissions:
84+
id-token: write
7985
steps:
8086
- uses: actions/download-artifact@v4
8187
with:
@@ -84,11 +90,22 @@ jobs:
8490
merge-multiple: true
8591
- uses: pypa/gh-action-pypi-publish@release/v1
8692
with:
87-
user: __token__
88-
password: ${{ secrets.PYPI_API_TOKEN }}
89-
# For publishing to Test PyPI, uncomment next two lines:
90-
# password: ${{ secrets.TEST_PYPI_API_TOKEN }}
91-
# repository_url: https://test.pypi.org/legacy/
93+
repository-url: https://test.pypi.org/legacy/
94+
95+
publish:
96+
name: Upload release to PyPI
97+
needs: [build-sdist, build-wheels, test-publish]
98+
runs-on: ubuntu-latest
99+
environment: pypi
100+
permissions:
101+
id-token: write
102+
steps:
103+
- uses: actions/download-artifact@v4
104+
with:
105+
pattern: cibw-*
106+
path: dist
107+
merge-multiple: true
108+
- uses: pypa/gh-action-pypi-publish@release/v1
92109

93110
publish-docs:
94111
name: Publish docs

.github/workflows/tests-and-linters.yml

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,12 @@ on: [push, pull_request, workflow_dispatch]
44

55
jobs:
66

7-
tests-on-legacy-versions:
8-
name: Run tests on legacy versions
9-
runs-on: ubuntu-20.04
10-
strategy:
11-
matrix:
12-
python-version: [3.7]
13-
steps:
14-
- uses: actions/checkout@v3
15-
- uses: actions/setup-python@v4
16-
with:
17-
python-version: ${{ matrix.python-version }}
18-
- run: pip install tox
19-
- run: tox
20-
env:
21-
TOXENV: ${{ matrix.python-version }}
22-
237
test-on-different-versions:
248
name: Run tests
259
runs-on: ubuntu-latest
2610
strategy:
2711
matrix:
28-
python-version: [3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
12+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
2913
steps:
3014
- uses: actions/checkout@v3
3115
- uses: actions/setup-python@v4
@@ -34,6 +18,7 @@ jobs:
3418
- run: pip install tox
3519
- run: tox
3620
env:
21+
DEPENDENCY_INJECTOR_LIMITED_API: 1
3722
TOXENV: ${{ matrix.python-version }}
3823

3924
test-different-pydantic-versions:
@@ -60,7 +45,7 @@ jobs:
6045
- uses: actions/setup-python@v4
6146
with:
6247
python-version: 3.12
63-
- run: pip install tox 'cython>=3,<4'
48+
- run: pip install tox
6449
- run: tox -vv
6550
env:
6651
TOXENV: coveralls

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ lib64/
1515
parts/
1616
sdist/
1717
var/
18+
wheelhouse/
1819
*.egg-info/
1920
.installed.cfg
2021
*.egg

MANIFEST.in

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
recursive-include src/dependency_injector *.py* *.c
1+
recursive-include src/dependency_injector *.py* *.c py.typed
22
recursive-include tests *.py
33
include README.rst
44
include CONTRIBUTORS.rst
55
include LICENSE.rst
6-
include requirements.txt
76
include setup.py
87
include tox.ini
9-
include py.typed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ uninstall:
3636
test:
3737
# Unit tests with coverage report
3838
coverage erase
39-
coverage run -m pytest -c tests/.configs/pytest.ini
39+
coverage run -m pytest
4040
coverage report
4141
coverage html
4242

docs/main/changelog.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ that were made in every particular version.
77
From version 0.7.6 *Dependency Injector* framework strictly
88
follows `Semantic versioning`_
99

10+
4.47.0
11+
-------
12+
13+
- Add support for ``Annotated`` type for module and class attribute injection in wiring,
14+
with updated documentation and examples.
15+
See discussion:
16+
https://github.com/ets-labs/python-dependency-injector/pull/721#issuecomment-2025263718
17+
- Fix ``root`` property shadowing in ``ConfigurationOption`` (`#875 https://github.com/ets-labs/python-dependency-injector/pull/875`_)
18+
- Fix incorrect monkeypatching during ``wire()`` that could violate MRO in some classes (`#886 https://github.com/ets-labs/python-dependency-injector/pull/886`_)
19+
- ABI3 wheels are now published for CPython.
20+
- Drop support of Python 3.7.
21+
1022
4.46.0
1123
------
1224

docs/wiring.rst

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,43 @@ To inject a container use special identifier ``<container>``:
254254
Making injections into modules and class attributes
255255
---------------------------------------------------
256256

257-
You can use wiring to make injections into modules and class attributes.
257+
You can use wiring to make injections into modules and class attributes. Both the classic marker
258+
syntax and the ``Annotated`` form are supported.
259+
260+
Classic marker syntax:
261+
262+
.. code-block:: python
263+
264+
service: Service = Provide[Container.service]
265+
266+
class Main:
267+
service: Service = Provide[Container.service]
268+
269+
Full example of the classic marker syntax:
258270

259271
.. literalinclude:: ../examples/wiring/example_attribute.py
260272
:language: python
261273
:lines: 3-
262274
:emphasize-lines: 14,19
263275

276+
Annotated form (Python 3.9+):
277+
278+
.. code-block:: python
279+
280+
from typing import Annotated
281+
282+
service: Annotated[Service, Provide[Container.service]]
283+
284+
class Main:
285+
service: Annotated[Service, Provide[Container.service]]
286+
287+
Full example of the annotated form:
288+
289+
.. literalinclude:: ../examples/wiring/example_attribute_annotated.py
290+
:language: python
291+
:lines: 3-
292+
:emphasize-lines: 16,21
293+
264294
You could also use string identifiers to avoid a dependency on a container:
265295

266296
.. code-block:: python
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""Wiring attribute example with Annotated."""
2+
3+
from typing import Annotated
4+
5+
from dependency_injector import containers, providers
6+
from dependency_injector.wiring import Provide
7+
8+
9+
class Service:
10+
...
11+
12+
13+
class Container(containers.DeclarativeContainer):
14+
15+
service = providers.Factory(Service)
16+
17+
18+
service: Annotated[Service, Provide[Container.service]]
19+
20+
21+
class Main:
22+
23+
service: Annotated[Service, Provide[Container.service]]
24+
25+
26+
if __name__ == "__main__":
27+
container = Container()
28+
container.wire(modules=[__name__])
29+
30+
assert isinstance(service, Service)
31+
assert isinstance(Main.service, Service)

pyproject.toml

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[build-system]
2-
requires = ["setuptools", "Cython"]
2+
requires = ["setuptools", "Cython>=3.1.1"]
33
build-backend = "setuptools.build_meta"
44

55
[project]
@@ -13,7 +13,7 @@ maintainers = [
1313
description = "Dependency injection framework for Python"
1414
readme = {file = "README.rst", content-type = "text/x-rst"}
1515
license = {file = "LICENSE.rst", content-type = "text/x-rst"}
16-
requires-python = ">=3.7"
16+
requires-python = ">=3.8"
1717
keywords = [
1818
"Dependency injection",
1919
"DI",
@@ -31,7 +31,6 @@ classifiers = [
3131
"Operating System :: OS Independent",
3232
"Programming Language :: Python",
3333
"Programming Language :: Python :: 3",
34-
"Programming Language :: Python :: 3.7",
3534
"Programming Language :: Python :: 3.8",
3635
"Programming Language :: Python :: 3.9",
3736
"Programming Language :: Python :: 3.10",
@@ -99,3 +98,18 @@ ignore = ["tests"]
9998
[tool.pylint.design]
10099
min-public-methods = 0
101100
max-public-methods = 30
101+
102+
[tool.pytest.ini_options]
103+
testpaths = ["tests/unit/"]
104+
asyncio_mode = "auto"
105+
asyncio_default_fixture_loop_scope = "function"
106+
markers = [
107+
"pydantic: Tests with Pydantic as a dependency",
108+
]
109+
filterwarnings = [
110+
"ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
111+
"ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\\.0\\.0:DeprecationWarning",
112+
"ignore:Please use \\`.*?\\` from the \\`scipy.*?\\`(.*?)namespace is deprecated\\.:DeprecationWarning",
113+
"ignore:Please import \\`.*?\\` from the \\`scipy(.*?)\\` namespace(.*):DeprecationWarning",
114+
"ignore:\\`scipy(.*?)\\` is deprecated(.*):DeprecationWarning",
115+
]

requirements-dev.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cython==3.0.11
1+
cython==3.1.1
22
setuptools
33
pytest
44
pytest-asyncio
@@ -13,7 +13,8 @@ mypy
1313
pyyaml
1414
httpx
1515
fastapi
16-
pydantic==1.10.17
16+
pydantic
17+
pydantic-settings
1718
numpy
1819
scipy
1920
boto3

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ per-file-ignores =
88
examples/containers/traverse.py: E501
99
examples/providers/async.py: F841
1010
examples/providers/async_overriding.py: F841
11-
examples/wiring/*: F841
11+
examples/wiring/*: F821,F841
1212

1313
[pydocstyle]
1414
ignore = D100,D101,D102,D105,D106,D107,D203,D213

setup.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
"""`Dependency injector` setup script."""
22

33
import os
4+
import sys
45

56
from Cython.Build import cythonize
67
from Cython.Compiler import Options
78
from setuptools import Extension, setup
89

910
debug = os.environ.get("DEPENDENCY_INJECTOR_DEBUG_MODE") == "1"
11+
limited_api = (
12+
os.environ.get("DEPENDENCY_INJECTOR_LIMITED_API") == "1"
13+
and sys.implementation.name == "cpython"
14+
)
1015
defined_macros = []
16+
options = {}
1117
compiler_directives = {
1218
"language_level": 3,
1319
"profile": debug,
@@ -17,6 +23,7 @@
1723

1824
# Adding debug options:
1925
if debug:
26+
limited_api = False # line tracing is not part of the Limited API
2027
defined_macros.extend(
2128
[
2229
("CYTHON_TRACE", "1"),
@@ -25,14 +32,20 @@
2532
]
2633
)
2734

35+
if limited_api:
36+
options.setdefault("bdist_wheel", {})
37+
options["bdist_wheel"]["py_limited_api"] = "cp38"
38+
defined_macros.append(("Py_LIMITED_API", "0x03080000"))
2839

2940
setup(
41+
options=options,
3042
ext_modules=cythonize(
3143
[
3244
Extension(
3345
"*",
3446
["src/**/*.pyx"],
3547
define_macros=defined_macros,
48+
py_limited_api=limited_api,
3649
),
3750
],
3851
annotate=debug,

0 commit comments

Comments
 (0)