Compare commits

..

No commits in common. "master" and "4.45.0" have entirely different histories.

47 changed files with 716 additions and 978 deletions

View File

@ -10,7 +10,7 @@ jobs:
tests:
name: Run tests
runs-on: ubuntu-24.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@ -23,7 +23,7 @@ jobs:
linters:
name: Run linters
runs-on: ubuntu-24.04
runs-on: ubuntu-22.04
strategy:
matrix:
toxenv: [flake8, pydocstyle, mypy, pylint]
@ -40,7 +40,7 @@ jobs:
build-sdist:
name: Build source tarball
needs: [tests, linters]
runs-on: ubuntu-24.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
@ -49,9 +49,8 @@ jobs:
- run: |
python -m pip install --upgrade build
python -m build --sdist
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
name: cibw-sdist
path: ./dist/*
build-wheels:
@ -60,28 +59,45 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-14]
os: [ubuntu-22.04, windows-2019, macos-14]
env:
CIBW_SKIP: cp27-*
steps:
- uses: actions/checkout@v3
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
with:
path: ./wheelhouse/*.whl
build-wheels-linux-aarch64:
name: Build wheels (ubuntu-22.04-aarch64)
needs: [tests, linters]
runs-on: ubuntu-22.04
env:
CIBW_SKIP: cp27-*
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
if: runner.os == 'Linux'
uses: docker/setup-qemu-action@v2
- name: Build wheels
uses: pypa/cibuildwheel@v2.20.0
env:
CIBW_ARCHS_LINUX: aarch64
- uses: actions/upload-artifact@v3
with:
name: cibw-wheels-x86-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
publish:
name: Publish on PyPI
needs: [build-sdist, build-wheels]
runs-on: ubuntu-24.04
needs: [build-sdist, build-wheels, build-wheels-linux-aarch64]
runs-on: ubuntu-22.04
steps:
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v3
with:
pattern: cibw-*
name: artifact
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
@ -93,7 +109,7 @@ jobs:
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

View File

@ -7,25 +7,6 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_
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>`_).

View File

@ -366,19 +366,6 @@ See also: :ref:`configuration-strict-mode`.
assert container.config.section.option() is None
If you want to disable environment variables interpolation, pass ``envs_required=None``:
.. code-block:: yaml
:caption: templates.yml
template_string: 'Hello, ${name}!'
.. code-block:: python
>>> container.config.from_yaml("templates.yml", envs_required=None)
>>> container.config.template_string()
'Hello, ${name}!'
Mandatory and optional sources
------------------------------

View File

@ -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)
@ -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::

View File

@ -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}

View File

@ -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}

View File

@ -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}

View File

@ -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:

View File

@ -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

View File

@ -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)

View File

@ -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__":

View File

@ -18,6 +18,5 @@ numpy
scipy
boto3
mypy_boto3_s3
typing_extensions
-r requirements-ext.txt

View File

@ -2,7 +2,6 @@
max_line_length = 120
max_complexity = 10
exclude = types.py
extend-ignore = E203,E701
per-file-ignores =
examples/demo/*: F841
examples/containers/traverse.py: E501

View File

@ -1,6 +1,6 @@
"""Top-level package."""
__version__ = "4.46.0"
__version__ = "4.45.0"
"""Version number.
:type: str

View File

@ -2,39 +2,44 @@
import asyncio
import collections.abc
import functools
import inspect
import types
from .wiring import _Marker
from . import providers
from .wiring import _Marker, PatchedCallable
from .providers cimport Provider, Resource
from .providers cimport Provider
def _sync_inject(object fn, tuple args, dict kwargs, dict injections, dict closings, /):
cdef object result
cdef dict to_inject
cdef object arg_key
cdef Provider provider
def _get_sync_patched(fn, patched: PatchedCallable):
@functools.wraps(fn)
def _patched(*args, **kwargs):
cdef object result
cdef dict to_inject
cdef object arg_key
cdef Provider provider
to_inject = kwargs.copy()
for arg_key, provider in injections.items():
if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker):
to_inject[arg_key] = provider()
to_inject = kwargs.copy()
for arg_key, provider in patched.injections.items():
if arg_key not in kwargs or isinstance(kwargs[arg_key], _Marker):
to_inject[arg_key] = provider()
result = fn(*args, **to_inject)
result = fn(*args, **to_inject)
if closings:
for arg_key, provider in closings.items():
if arg_key in kwargs and not isinstance(kwargs[arg_key], _Marker):
continue
if not isinstance(provider, Resource):
continue
provider.shutdown()
if patched.closing:
for arg_key, provider in patched.closing.items():
if arg_key in kwargs and not isinstance(kwargs[arg_key], _Marker):
continue
if not isinstance(provider, providers.Resource):
continue
provider.shutdown()
return result
return result
return _patched
async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dict closings, /):
async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dict closings):
cdef object result
cdef dict to_inject
cdef list to_inject_await = []
@ -64,7 +69,7 @@ async def _async_inject(object fn, tuple args, dict kwargs, dict injections, dic
for arg_key, provider in closings.items():
if arg_key in kwargs and isinstance(kwargs[arg_key], _Marker):
continue
if not isinstance(provider, Resource):
if not isinstance(provider, providers.Resource):
continue
shutdown = provider.shutdown()
if _isawaitable(shutdown):

View File

@ -19,24 +19,21 @@ from typing import (
from .providers import Provider, Self, ProviderParent
C_Base = TypeVar("C_Base", bound="Container")
C = TypeVar("C", bound="DeclarativeContainer")
C_Overriding = TypeVar("C_Overriding", bound="DeclarativeContainer")
T = TypeVar("T")
TT = TypeVar("TT")
class WiringConfiguration:
modules: List[Any]
packages: List[Any]
from_package: Optional[str]
auto_wire: bool
def __init__(
self,
modules: Optional[Iterable[Any]] = None,
packages: Optional[Iterable[Any]] = None,
from_package: Optional[str] = None,
auto_wire: bool = True,
) -> None: ...
def __init__(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None, auto_wire: bool = True) -> None: ...
class Container:
provider_type: Type[Provider] = Provider
@ -54,18 +51,11 @@ class Container:
def set_providers(self, **providers: Provider): ...
def set_provider(self, name: str, provider: Provider) -> None: ...
def override(self, overriding: Union[Container, Type[Container]]) -> None: ...
def override_providers(
self, **overriding_providers: Union[Provider, Any]
) -> ProvidersOverridingContext[C_Base]: ...
def override_providers(self, **overriding_providers: Union[Provider, Any]) -> ProvidersOverridingContext[C_Base]: ...
def reset_last_overriding(self) -> None: ...
def reset_override(self) -> None: ...
def is_auto_wiring_enabled(self) -> bool: ...
def wire(
self,
modules: Optional[Iterable[Any]] = None,
packages: Optional[Iterable[Any]] = None,
from_package: Optional[str] = None,
) -> None: ...
def wire(self, modules: Optional[Iterable[Any]] = None, packages: Optional[Iterable[Any]] = None, from_package: Optional[str] = None) -> None: ...
def unwire(self) -> None: ...
def init_resources(self) -> Optional[Awaitable]: ...
def shutdown_resources(self) -> Optional[Awaitable]: ...
@ -74,9 +64,7 @@ class Container:
def reset_singletons(self) -> SingletonResetContext[C_Base]: ...
def check_dependencies(self) -> None: ...
def from_schema(self, schema: Dict[Any, Any]) -> None: ...
def from_yaml_schema(
self, filepath: Union[Path, str], loader: Optional[Any] = None
) -> None: ...
def from_yaml_schema(self, filepath: Union[Path, str], loader: Optional[Any]=None) -> None: ...
def from_json_schema(self, filepath: Union[Path, str]) -> None: ...
@overload
def resolve_provider_name(self, provider: Provider) -> str: ...
@ -94,8 +82,10 @@ class Container:
@overload
def traverse(cls, types: Optional[Iterable[Type[TT]]] = None) -> Iterator[TT]: ...
class DynamicContainer(Container): ...
class DeclarativeContainer(Container):
cls_providers: ClassVar[Dict[str, Provider]]
inherited_providers: ClassVar[Dict[str, Provider]]
@ -103,28 +93,29 @@ class DeclarativeContainer(Container):
@classmethod
def override(cls, overriding: Union[Container, Type[Container]]) -> None: ...
@classmethod
def override_providers(
cls, **overriding_providers: Union[Provider, Any]
) -> ProvidersOverridingContext[C_Base]: ...
def override_providers(cls, **overriding_providers: Union[Provider, Any]) -> ProvidersOverridingContext[C_Base]: ...
@classmethod
def reset_last_overriding(cls) -> None: ...
@classmethod
def reset_override(cls) -> None: ...
class ProvidersOverridingContext(Generic[T]):
def __init__(
self, container: T, overridden_providers: Iterable[Union[Provider, Any]]
) -> None: ...
def __init__(self, container: T, overridden_providers: Iterable[Union[Provider, Any]]) -> None: ...
def __enter__(self) -> T: ...
def __exit__(self, *_: Any) -> None: ...
class SingletonResetContext(Generic[T]):
def __init__(self, container: T): ...
def __enter__(self) -> T: ...
def __exit__(self, *_: Any) -> None: ...
def override(
container: Type[C],
) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
def override(container: Type[C]) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
def copy(container: Type[C]) -> _Callable[[Type[C_Overriding]], Type[C_Overriding]]: ...
def is_container(instance: Any) -> bool: ...

View File

@ -1,11 +1,17 @@
"""Containers module."""
import asyncio
import contextlib
import copy as copy_module
import json
import sys
import importlib
import inspect
import warnings
try:
import asyncio
except ImportError:
asyncio = None
try:
import yaml
@ -14,7 +20,24 @@ except ImportError:
from . import providers, errors
from .providers cimport __is_future_or_coroutine
from .wiring import wire, unwire
if sys.version_info[:2] >= (3, 6):
from .wiring import wire, unwire
else:
def wire(*args, **kwargs):
raise NotImplementedError("Wiring requires Python 3.6 or above")
def unwire(*args, **kwargs):
raise NotImplementedError("Wiring requires Python 3.6 or above")
if sys.version_info[:2] == (3, 5):
warnings.warn(
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
"This does not mean that there will be any immediate breaking changes, "
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
category=DeprecationWarning,
)
class WiringConfiguration:
@ -30,7 +53,7 @@ class WiringConfiguration:
return self.__class__(self.modules, self.packages, self.from_package, self.auto_wire)
class Container:
class Container(object):
"""Abstract container."""

View File

@ -38,11 +38,9 @@ class View(providers.Callable):
def as_view(self):
"""Return aiohttp view function."""
@functools.wraps(self.provides)
async def _view(request, *args, **kwargs):
return await self.__call__(request, *args, **kwargs)
return _view
@ -51,8 +49,6 @@ class ClassBasedView(providers.Factory):
def as_view(self):
"""Return aiohttp view function."""
async def _view(request, *args, **kwargs):
return await self.__call__(request, *args, **kwargs)
return _view

View File

@ -2,13 +2,22 @@ from typing import Awaitable as _Awaitable
from dependency_injector import providers
class Application(providers.Singleton): ...
class Extension(providers.Singleton): ...
class Middleware(providers.DelegatedCallable): ...
class MiddlewareFactory(providers.Factory): ...
class View(providers.Callable):
def as_view(self) -> _Awaitable: ...
class ClassBasedView(providers.Factory):
def as_view(self) -> _Awaitable: ...

View File

@ -45,7 +45,6 @@ class ClassBasedView(providers.Factory):
def as_view(provider, name=None):
"""Transform class-based view provider to view function."""
if isinstance(provider, providers.Factory):
def view(*args, **kwargs):
self = provider()
return self.dispatch_request(*args, **kwargs)
@ -53,13 +52,12 @@ def as_view(provider, name=None):
assert name, 'Argument "endpoint" is required for class-based views'
view.__name__ = name
elif isinstance(provider, providers.Callable):
def view(*args, **kwargs):
return provider(*args, **kwargs)
view.__name__ = provider.provides.__name__
else:
raise errors.Error("Undefined provider type")
raise errors.Error('Undefined provider type')
view.__doc__ = provider.provides.__doc__
view.__module__ = provider.provides.__module__
@ -67,14 +65,14 @@ def as_view(provider, name=None):
if isinstance(provider.provides, type):
view.view_class = provider.provides
if hasattr(provider.provides, "decorators"):
if hasattr(provider.provides, 'decorators'):
for decorator in provider.provides.decorators:
view = decorator(view)
if hasattr(provider.provides, "methods"):
if hasattr(provider.provides, 'methods'):
view.methods = provider.provides.methods
if hasattr(provider.provides, "provide_automatic_options"):
if hasattr(provider.provides, 'provide_automatic_options'):
view.provide_automatic_options = provider.provides.provide_automatic_options
return view

View File

@ -3,17 +3,22 @@ from typing import Union, Optional, Callable as _Callable, Any
from flask import request as flask_request
from dependency_injector import providers
request: providers.Object[flask_request]
class Application(providers.Singleton): ...
class Extension(providers.Singleton): ...
class View(providers.Callable):
def as_view(self) -> _Callable[..., Any]: ...
class ClassBasedView(providers.Factory):
def as_view(self, name: str) -> _Callable[..., Any]: ...
def as_view(
provider: Union[View, ClassBasedView], name: Optional[str] = None
) -> _Callable[..., Any]: ...
def as_view(provider: Union[View, ClassBasedView], name: Optional[str] = None) -> _Callable[..., Any]: ...

View File

@ -1,6 +1,10 @@
"""Providers module."""
import asyncio
try:
import asyncio
except ImportError:
asyncio = None
import functools
cimport cython
@ -15,7 +19,7 @@ cdef tuple __COROUTINE_TYPES
# Base providers
cdef class Provider:
cdef class Provider(object):
cdef tuple _overridden
cdef Provider _last_overriding
cdef tuple _overrides
@ -287,7 +291,7 @@ cdef class MethodCaller(Provider):
# Injections
cdef class Injection:
cdef class Injection(object):
cdef object _value
cdef int _is_provider
cdef int _is_delegated
@ -309,12 +313,12 @@ cpdef tuple parse_named_injections(dict kwargs)
# Utils
cdef class OverridingContext:
cdef class OverridingContext(object):
cdef Provider _overridden
cdef Provider _overriding
cdef class BaseSingletonResetContext:
cdef class BaseSingletonResetContext(object):
cdef object _singleton

View File

@ -33,6 +33,7 @@ except ImportError:
from . import resources
Injection = Any
ProviderParent = Union["Provider", Any]
T = TypeVar("T")
@ -40,13 +41,16 @@ TT = TypeVar("TT")
P = TypeVar("P", bound="Provider")
BS = TypeVar("BS", bound="BaseSingleton")
class Provider(Generic[T]):
def __init__(self) -> None: ...
@overload
def __call__(self, *args: Injection, **kwargs: Injection) -> T: ...
@overload
def __call__(self, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
def async_(self, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
def __deepcopy__(self, memo: Optional[_Dict[Any, Any]]) -> Provider: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
@ -63,9 +67,9 @@ class Provider(Generic[T]):
def unregister_overrides(self, provider: Union[Provider, Any]) -> None: ...
def delegate(self) -> Provider: ...
@property
def provider(self) -> Provider[T]: ...
def provider(self) -> Provider: ...
@property
def provided(self) -> ProvidedInstance[T]: ...
def provided(self) -> ProvidedInstance: ...
def enable_async_mode(self) -> None: ...
def disable_async_mode(self) -> None: ...
def reset_async_mode(self) -> None: ...
@ -74,12 +78,9 @@ class Provider(Generic[T]):
def is_async_mode_undefined(self) -> bool: ...
@property
def related(self) -> _Iterator[Provider]: ...
def traverse(
self, types: Optional[_Iterable[Type[TT]]] = None
) -> _Iterator[TT]: ...
def _copy_overridings(
self, copied: Provider, memo: Optional[_Dict[Any, Any]]
) -> None: ...
def traverse(self, types: Optional[_Iterable[Type[TT]]] = None) -> _Iterator[TT]: ...
def _copy_overridings(self, copied: Provider, memo: Optional[_Dict[Any, Any]]) -> None: ...
class Object(Provider[T]):
def __init__(self, provides: Optional[T] = None) -> None: ...
@ -87,6 +88,7 @@ class Object(Provider[T]):
def provides(self) -> Optional[T]: ...
def set_provides(self, provides: Optional[T]) -> Object: ...
class Self(Provider[T]):
def __init__(self, container: Optional[T] = None) -> None: ...
def set_container(self, container: T) -> None: ...
@ -94,51 +96,41 @@ class Self(Provider[T]):
@property
def alt_names(self) -> Tuple[Any]: ...
class Delegate(Provider[Provider]):
def __init__(self, provides: Optional[Provider] = None) -> None: ...
@property
def provides(self) -> Optional[Provider]: ...
def set_provides(self, provides: Optional[Provider]) -> Delegate: ...
class Aggregate(Provider[T]):
def __init__(
self,
provider_dict: Optional[_Dict[Any, Provider[T]]] = None,
**provider_kwargs: Provider[T],
): ...
def __init__(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]): ...
def __getattr__(self, provider_name: Any) -> Provider[T]: ...
@overload
def __call__(
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
) -> T: ...
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> T: ...
@overload
def __call__(
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
) -> Awaitable[T]: ...
def async_(
self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection
) -> Awaitable[T]: ...
def __call__(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
def async_(self, provider_name: Optional[Any] = None, *args: Injection, **kwargs: Injection) -> Awaitable[T]: ...
@property
def providers(self) -> _Dict[Any, Provider[T]]: ...
def set_providers(
self,
provider_dict: Optional[_Dict[Any, Provider[T]]] = None,
**provider_kwargs: Provider[T],
) -> Aggregate[T]: ...
def set_providers(self, provider_dict: Optional[_Dict[Any, Provider[T]]] = None, **provider_kwargs: Provider[T]) -> Aggregate[T]: ...
class Dependency(Provider[T]):
def __init__(
self,
instance_of: Type[T] = object,
default: Optional[Union[Provider, Any]] = None,
) -> None: ...
def __init__(self, instance_of: Type[T] = object, default: Optional[Union[Provider, Any]] = None) -> None: ...
def __getattr__(self, name: str) -> Any: ...
@property
def instance_of(self) -> Type[T]: ...
def set_instance_of(self, instance_of: Type[T]) -> Dependency[T]: ...
@property
def default(self) -> Provider[T]: ...
def set_default(self, default: Optional[Union[Provider, Any]]) -> Dependency[T]: ...
@property
def is_defined(self) -> bool: ...
def provided_by(self, provider: Provider) -> OverridingContext[P]: ...
@ -148,8 +140,10 @@ class Dependency(Provider[T]):
def parent_name(self) -> Optional[str]: ...
def assign_parent(self, parent: ProviderParent) -> None: ...
class ExternalDependency(Dependency[T]): ...
class DependenciesContainer(Object):
def __init__(self, **dependencies: Provider) -> None: ...
def __getattr__(self, name: str) -> Provider: ...
@ -162,18 +156,12 @@ class DependenciesContainer(Object):
def parent_name(self) -> Optional[str]: ...
def assign_parent(self, parent: ProviderParent) -> None: ...
class Callable(Provider[T]):
def __init__(
self,
provides: Optional[Union[_Callable[..., T], str]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@property
def provides(self) -> Optional[_Callable[..., T]]: ...
def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]]
) -> Callable[T]: ...
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> Callable[T]: ...
@property
def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Callable[T]: ...
@ -185,23 +173,32 @@ class Callable(Provider[T]):
def set_kwargs(self, **kwargs: Injection) -> Callable[T]: ...
def clear_kwargs(self) -> Callable[T]: ...
class DelegatedCallable(Callable[T]): ...
class AbstractCallable(Callable[T]):
def override(self, provider: Callable) -> OverridingContext[P]: ...
class CallableDelegate(Delegate):
def __init__(self, callable: Callable) -> None: ...
class Coroutine(Callable[T]): ...
class DelegatedCoroutine(Coroutine[T]): ...
class AbstractCoroutine(Coroutine[T]):
def override(self, provider: Coroutine) -> OverridingContext[P]: ...
class CoroutineDelegate(Delegate):
def __init__(self, coroutine: Coroutine) -> None: ...
class ConfigurationOption(Provider[Any]):
UNDEFINED: object
def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
@ -215,137 +212,89 @@ class ConfigurationOption(Provider[Any]):
def get_name_segments(self) -> Tuple[Union[str, Provider]]: ...
def as_int(self) -> TypedConfigurationOption[int]: ...
def as_float(self) -> TypedConfigurationOption[float]: ...
def as_(
self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection
) -> TypedConfigurationOption[T]: ...
def as_(self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection) -> TypedConfigurationOption[T]: ...
def required(self) -> ConfigurationOption: ...
def is_required(self) -> bool: ...
def update(self, value: Any) -> None: ...
def from_ini(
self,
filepath: Union[Path, str],
required: bool = False,
envs_required: Optional[bool] = False,
) -> None: ...
def from_yaml(
self,
filepath: Union[Path, str],
required: bool = False,
loader: Optional[Any] = None,
envs_required: Optional[bool] = False,
) -> None: ...
def from_json(
self,
filepath: Union[Path, str],
required: bool = False,
envs_required: Optional[bool] = False,
) -> None: ...
def from_pydantic(
self, settings: PydanticSettings, required: bool = False, **kwargs: Any
) -> None: ...
def from_ini(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
def from_yaml(self, filepath: Union[Path, str], required: bool = False, loader: Optional[Any] = None, envs_required: bool = False) -> None: ...
def from_json(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
def from_pydantic(self, settings: PydanticSettings, required: bool = False, **kwargs: Any) -> None: ...
def from_dict(self, options: _Dict[str, Any], required: bool = False) -> None: ...
def from_env(
self,
name: str,
default: Optional[Any] = None,
required: bool = False,
as_: Optional[_Callable[..., Any]] = None,
) -> None: ...
def from_env(self, name: str, default: Optional[Any] = None, required: bool = False, as_: Optional[_Callable[..., Any]] = None) -> None: ...
def from_value(self, value: Any) -> None: ...
class TypedConfigurationOption(Callable[T]):
@property
def option(self) -> ConfigurationOption: ...
class Configuration(Object[Any]):
DEFAULT_NAME: str = "config"
def __init__(
self,
name: str = DEFAULT_NAME,
default: Optional[Any] = None,
*,
strict: bool = False,
ini_files: Optional[_Iterable[Union[Path, str]]] = None,
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
json_files: Optional[_Iterable[Union[Path, str]]] = None,
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
self,
name: str = DEFAULT_NAME,
default: Optional[Any] = None,
*,
strict: bool = False,
ini_files: Optional[_Iterable[Union[Path, str]]] = None,
yaml_files: Optional[_Iterable[Union[Path, str]]] = None,
json_files: Optional[_Iterable[Union[Path, str]]] = None,
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
) -> None: ...
def __enter__(self) -> Configuration: ...
def __enter__(self) -> Configuration : ...
def __exit__(self, *exc_info: Any) -> None: ...
def __getattr__(self, item: str) -> ConfigurationOption: ...
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
def get_name(self) -> str: ...
def set_name(self, name: str) -> Configuration: ...
def get_default(self) -> _Dict[Any, Any]: ...
def set_default(self, default: _Dict[Any, Any]): ...
def get_strict(self) -> bool: ...
def set_strict(self, strict: bool) -> Configuration: ...
def get_children(self) -> _Dict[str, ConfigurationOption]: ...
def set_children(
self, children: _Dict[str, ConfigurationOption]
) -> Configuration: ...
def set_children(self, children: _Dict[str, ConfigurationOption]) -> Configuration: ...
def get_ini_files(self) -> _List[Union[Path, str]]: ...
def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_yaml_files(self) -> _List[Union[Path, str]]: ...
def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_json_files(self) -> _List[Union[Path, str]]: ...
def set_json_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ...
def get_pydantic_settings(self) -> _List[PydanticSettings]: ...
def set_pydantic_settings(
self, settings: _Iterable[PydanticSettings]
) -> Configuration: ...
def set_pydantic_settings(self, settings: _Iterable[PydanticSettings]) -> Configuration: ...
def load(self, required: bool = False, envs_required: bool = False) -> None: ...
def get(self, selector: str) -> Any: ...
def set(self, selector: str, value: Any) -> OverridingContext[P]: ...
def reset_cache(self) -> None: ...
def update(self, value: Any) -> None: ...
def from_ini(
self,
filepath: Union[Path, str],
required: bool = False,
envs_required: bool = False,
) -> None: ...
def from_yaml(
self,
filepath: Union[Path, str],
required: bool = False,
loader: Optional[Any] = None,
envs_required: bool = False,
) -> None: ...
def from_json(
self,
filepath: Union[Path, str],
required: bool = False,
envs_required: bool = False,
) -> None: ...
def from_pydantic(
self, settings: PydanticSettings, required: bool = False, **kwargs: Any
) -> None: ...
def from_ini(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
def from_yaml(self, filepath: Union[Path, str], required: bool = False, loader: Optional[Any] = None, envs_required: bool = False) -> None: ...
def from_json(self, filepath: Union[Path, str], required: bool = False, envs_required: bool = False) -> None: ...
def from_pydantic(self, settings: PydanticSettings, required: bool = False, **kwargs: Any) -> None: ...
def from_dict(self, options: _Dict[str, Any], required: bool = False) -> None: ...
def from_env(
self,
name: str,
default: Optional[Any] = None,
required: bool = False,
as_: Optional[_Callable[..., Any]] = None,
) -> None: ...
def from_env(self, name: str, default: Optional[Any] = None, required: bool = False, as_: Optional[_Callable[..., Any]] = None) -> None: ...
def from_value(self, value: Any) -> None: ...
class Factory(Provider[T]):
provided_type: Optional[Type]
def __init__(
self,
provides: Optional[Union[_Callable[..., T], str]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@property
def cls(self) -> Type[T]: ...
@property
def provides(self) -> Optional[_Callable[..., T]]: ...
def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]]
) -> Factory[T]: ...
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> Factory[T]: ...
@property
def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Factory[T]: ...
@ -362,39 +311,33 @@ class Factory(Provider[T]):
def set_attributes(self, **kwargs: Injection) -> Factory[T]: ...
def clear_attributes(self) -> Factory[T]: ...
class DelegatedFactory(Factory[T]): ...
class AbstractFactory(Factory[T]):
def override(self, provider: Factory) -> OverridingContext[P]: ...
class FactoryDelegate(Delegate):
def __init__(self, factory: Factory): ...
class FactoryAggregate(Aggregate[T]):
def __getattr__(self, provider_name: Any) -> Factory[T]: ...
@property
def factories(self) -> _Dict[Any, Factory[T]]: ...
def set_factories(
self,
provider_dict: Optional[_Dict[Any, Factory[T]]] = None,
**provider_kwargs: Factory[T],
) -> FactoryAggregate[T]: ...
def set_factories(self, provider_dict: Optional[_Dict[Any, Factory[T]]] = None, **provider_kwargs: Factory[T]) -> FactoryAggregate[T]: ...
class BaseSingleton(Provider[T]):
provided_type = Optional[Type]
def __init__(
self,
provides: Optional[Union[_Callable[..., T], str]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@property
def cls(self) -> Type[T]: ...
@property
def provides(self) -> Optional[_Callable[..., T]]: ...
def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]]
) -> BaseSingleton[T]: ...
def set_provides(self, provides: Optional[Union[_Callable[..., T], str]]) -> BaseSingleton[T]: ...
@property
def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> BaseSingleton[T]: ...
@ -413,20 +356,36 @@ class BaseSingleton(Provider[T]):
def reset(self) -> SingletonResetContext[BS]: ...
def full_reset(self) -> SingletonFullResetContext[BS]: ...
class Singleton(BaseSingleton[T]): ...
class DelegatedSingleton(Singleton[T]): ...
class ThreadSafeSingleton(Singleton[T]): ...
class DelegatedThreadSafeSingleton(ThreadSafeSingleton[T]): ...
class ThreadLocalSingleton(BaseSingleton[T]): ...
class ContextLocalSingleton(BaseSingleton[T]): ...
class DelegatedThreadLocalSingleton(ThreadLocalSingleton[T]): ...
class AbstractSingleton(BaseSingleton[T]):
def override(self, provider: BaseSingleton) -> OverridingContext[P]: ...
class SingletonDelegate(Delegate):
def __init__(self, singleton: BaseSingleton): ...
class List(Provider[_List]):
def __init__(self, *args: Injection): ...
@property
@ -435,63 +394,29 @@ class List(Provider[_List]):
def set_args(self, *args: Injection) -> List[T]: ...
def clear_args(self) -> List[T]: ...
class Dict(Provider[_Dict]):
def __init__(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection
): ...
def __init__(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection): ...
@property
def kwargs(self) -> _Dict[Any, Injection]: ...
def add_kwargs(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection
) -> Dict: ...
def set_kwargs(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection
) -> Dict: ...
def add_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
def set_kwargs(self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection) -> Dict: ...
def clear_kwargs(self) -> Dict: ...
class Resource(Provider[T]):
@overload
def __init__(
self,
provides: Optional[Type[resources.Resource[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Type[resources.Resource[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@overload
def __init__(
self,
provides: Optional[Type[resources.AsyncResource[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Type[resources.AsyncResource[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@overload
def __init__(
self,
provides: Optional[_Callable[..., _Iterator[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[_Callable[..., _Iterator[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@overload
def __init__(
self,
provides: Optional[_Callable[..., _AsyncIterator[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[_Callable[..., _AsyncIterator[T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@overload
def __init__(
self,
provides: Optional[_Callable[..., _Coroutine[Injection, Injection, T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[_Callable[..., _Coroutine[Injection, Injection, T]]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@overload
def __init__(
self,
provides: Optional[Union[_Callable[..., T], str]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
def __init__(self, provides: Optional[Union[_Callable[..., T], str]] = None, *args: Injection, **kwargs: Injection) -> None: ...
@property
def provides(self) -> Optional[_Callable[..., Any]]: ...
def set_provides(self, provides: Optional[Any]) -> Resource[T]: ...
@ -510,13 +435,9 @@ class Resource(Provider[T]):
def init(self) -> Optional[Awaitable[T]]: ...
def shutdown(self) -> Optional[Awaitable]: ...
class Container(Provider[T]):
def __init__(
self,
container_cls: Type[T],
container: Optional[T] = None,
**overriding_providers: Union[Provider, Any],
) -> None: ...
def __init__(self, container_cls: Type[T], container: Optional[T] = None, **overriding_providers: Union[Provider, Any]) -> None: ...
def __getattr__(self, name: str) -> Provider: ...
@property
def container(self) -> T: ...
@ -527,51 +448,50 @@ class Container(Provider[T]):
def parent_name(self) -> Optional[str]: ...
def assign_parent(self, parent: ProviderParent) -> None: ...
class Selector(Provider[Any]):
def __init__(
self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider
): ...
def __init__(self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider): ...
def __getattr__(self, name: str) -> Provider: ...
@property
def selector(self) -> Optional[_Callable[..., Any]]: ...
def set_selector(self, selector: Optional[_Callable[..., Any]]) -> Selector: ...
@property
def providers(self) -> _Dict[str, Provider]: ...
def set_providers(self, **providers: Provider) -> Selector: ...
class ProvidedInstanceFluentInterface:
def __getattr__(self, item: Any) -> AttributeGetter: ...
def __getitem__(self, item: Any) -> ItemGetter: ...
def call(self, *args: Injection, **kwargs: Injection) -> MethodCaller: ...
@property
def provides(self) -> Optional[Provider]: ...
def set_provides(
self, provides: Optional[Provider]
) -> ProvidedInstanceFluentInterface: ...
def set_provides(self, provides: Optional[Provider]) -> ProvidedInstanceFluentInterface: ...
class ProvidedInstance(Provider, ProvidedInstanceFluentInterface):
def __init__(self, provides: Optional[Provider] = None) -> None: ...
class AttributeGetter(Provider, ProvidedInstanceFluentInterface):
def __init__(
self, provides: Optional[Provider] = None, name: Optional[str] = None
) -> None: ...
def __init__(self, provides: Optional[Provider] = None, name: Optional[str] = None) -> None: ...
@property
def name(self) -> Optional[str]: ...
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ...
class ItemGetter(Provider, ProvidedInstanceFluentInterface):
def __init__(
self, provides: Optional[Provider] = None, name: Optional[str] = None
) -> None: ...
def __init__(self, provides: Optional[Provider] = None, name: Optional[str] = None) -> None: ...
@property
def name(self) -> Optional[str]: ...
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ...
class MethodCaller(Provider, ProvidedInstanceFluentInterface):
def __init__(
self, provides: Optional[Provider] = None, *args: Injection, **kwargs: Injection
) -> None: ...
def __init__(self, provides: Optional[Provider] = None, *args: Injection, **kwargs: Injection) -> None: ...
class OverridingContext(Generic[T]):
def __init__(self, overridden: Provider, overriding: Provider): ...
@ -580,39 +500,61 @@ class OverridingContext(Generic[T]):
pass
...
class BaseSingletonResetContext(Generic[T]):
def __init__(self, provider: T): ...
def __enter__(self) -> T: ...
def __exit__(self, *_: Any) -> None: ...
class SingletonResetContext(BaseSingletonResetContext): ...
class SingletonFullResetContext(BaseSingletonResetContext): ...
class SingletonResetContext(BaseSingletonResetContext):
...
class SingletonFullResetContext(BaseSingletonResetContext):
...
CHILD_PROVIDERS: Tuple[Provider]
def is_provider(instance: Any) -> bool: ...
def ensure_is_provider(instance: Any) -> Provider: ...
def is_delegated(instance: Any) -> bool: ...
def represent_provider(provider: Provider, provides: Any) -> str: ...
def deepcopy(instance: Any, memo: Optional[_Dict[Any, Any]] = None) -> Any: ...
def deepcopy_args(
provider: Provider[Any],
args: Tuple[Any, ...],
memo: Optional[_Dict[int, Any]] = None,
) -> Tuple[Any, ...]: ...
def deepcopy_kwargs(
provider: Provider[Any],
kwargs: _Dict[str, Any],
memo: Optional[_Dict[int, Any]] = None,
) -> Dict[str, Any]: ...
def merge_dicts(dict1: _Dict[Any, Any], dict2: _Dict[Any, Any]) -> _Dict[Any, Any]: ...
def traverse(
*providers: Provider, types: Optional[_Iterable[Type]] = None
) -> _Iterator[Provider]: ...
def traverse(*providers: Provider, types: Optional[_Iterable[Type]]=None) -> _Iterator[Provider]: ...
if yaml:
class YamlLoader(yaml.SafeLoader): ...
else:
class YamlLoader: ...

View File

@ -2,9 +2,6 @@
from __future__ import absolute_import
import asyncio
import builtins
import contextvars
import copy
import errno
import functools
@ -15,22 +12,36 @@ import os
import re
import sys
import threading
import types
import warnings
from configparser import ConfigParser as IniConfigParser
try:
from inspect import _is_coroutine_mark as _is_coroutine_marker
import contextvars
except ImportError:
try:
# Python >=3.12.0,<3.12.5
from inspect import _is_coroutine_marker
except ImportError:
contextvars = None
try:
import builtins
except ImportError:
# Python 2.7
import __builtin__ as builtins
try:
import asyncio
except ImportError:
asyncio = None
_is_coroutine_marker = None
else:
if sys.version_info >= (3, 5, 3):
import asyncio.coroutines
_is_coroutine_marker = asyncio.coroutines._is_coroutine
else:
_is_coroutine_marker = True
try:
from asyncio.coroutines import _is_coroutine
import ConfigParser as iniconfigparser
except ImportError:
_is_coroutine = True
import configparser as iniconfigparser
try:
import yaml
@ -66,11 +77,29 @@ from .errors import (
cimport cython
if sys.version_info[0] == 3: # pragma: no cover
CLASS_TYPES = (type,)
else: # pragma: no cover
CLASS_TYPES = (type, types.ClassType)
copy._deepcopy_dispatch[types.MethodType] = \
lambda obj, memo: type(obj)(obj.im_func,
copy.deepcopy(obj.im_self, memo),
obj.im_class)
if sys.version_info[:2] == (3, 5):
warnings.warn(
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
"This does not mean that there will be any immediate breaking changes, "
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
category=DeprecationWarning,
)
config_env_marker_pattern = re.compile(
r"\${(?P<name>[^}^{:]+)(?P<separator>:?)(?P<default>.*?)}",
)
cdef str _resolve_config_env_markers(config_content: str, envs_required: bool):
def _resolve_config_env_markers(config_content, envs_required=False):
"""Replace environment variable markers with their values."""
findings = list(config_env_marker_pattern.finditer(config_content))
@ -89,19 +118,28 @@ cdef str _resolve_config_env_markers(config_content: str, envs_required: bool):
return config_content
cdef object _parse_ini_file(filepath, envs_required: bool | None):
parser = IniConfigParser()
with open(filepath) as config_file:
config_string = config_file.read()
if envs_required is not None:
if sys.version_info[0] == 3:
def _parse_ini_file(filepath, envs_required=False):
parser = iniconfigparser.ConfigParser()
with open(filepath) as config_file:
config_string = _resolve_config_env_markers(
config_string,
config_file.read(),
envs_required=envs_required,
)
parser.read_string(config_string)
return parser
parser.read_string(config_string)
return parser
else:
import StringIO
def _parse_ini_file(filepath, envs_required=False):
parser = iniconfigparser.ConfigParser()
with open(filepath) as config_file:
config_string = _resolve_config_env_markers(
config_file.read(),
envs_required=envs_required,
)
parser.readfp(StringIO.StringIO(config_string))
return parser
if yaml:
@ -125,7 +163,7 @@ cdef int ASYNC_MODE_ENABLED = 1
cdef int ASYNC_MODE_DISABLED = 2
cdef set __iscoroutine_typecache = set()
cdef tuple __COROUTINE_TYPES = asyncio.coroutines._COROUTINE_TYPES
cdef tuple __COROUTINE_TYPES = asyncio.coroutines._COROUTINE_TYPES if asyncio else tuple()
cdef dict pydantic_settings_to_dict(settings, dict kwargs):
if not has_pydantic_settings:
@ -135,7 +173,7 @@ cdef dict pydantic_settings_to_dict(settings, dict kwargs):
f"\"pip install dependency-injector[{pydantic_extra}]\""
)
if isinstance(settings, type) and issubclass(settings, PydanticSettings):
if isinstance(settings, CLASS_TYPES) and issubclass(settings, PydanticSettings):
raise Error(
"Got settings class, but expect instance: "
"instead \"{0}\" use \"{0}()\"".format(settings.__name__)
@ -153,7 +191,7 @@ cdef dict pydantic_settings_to_dict(settings, dict kwargs):
return settings.model_dump(mode="python", **kwargs)
cdef class Provider:
cdef class Provider(object):
"""Base provider class.
:py:class:`Provider` is callable (implements ``__call__`` method). Every
@ -875,9 +913,12 @@ cdef class Dependency(Provider):
def set_instance_of(self, instance_of):
"""Set type."""
if not isinstance(instance_of, type):
if not isinstance(instance_of, CLASS_TYPES):
raise TypeError(
f"\"instance_of\" is not a class (got {instance_of!r}))",
"\"instance_of\" has incorrect type (expected {0}, got {1}))".format(
CLASS_TYPES,
instance_of,
),
)
self._instance_of = instance_of
return self
@ -1434,11 +1475,12 @@ cdef class Coroutine(Callable):
some_coroutine.add_kwargs(keyword_argument1=3, keyword_argument=4)
"""
_is_coroutine_marker = _is_coroutine_marker # Python >=3.12
_is_coroutine = _is_coroutine # Python <3.16
_is_coroutine = _is_coroutine_marker
def set_provides(self, provides):
"""Set provider provides."""
if not asyncio:
raise Error("Package asyncio is not available")
provides = _resolve_string_import(provides)
if provides and not asyncio.iscoroutinefunction(provides):
raise Error(f"Provider {_class_qualname(self)} expected to get coroutine function, "
@ -1671,7 +1713,7 @@ cdef class ConfigurationOption(Provider):
try:
parser = _parse_ini_file(
filepath,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
except IOError as exception:
if required is not False \
@ -1730,11 +1772,10 @@ cdef class ConfigurationOption(Provider):
raise
return
if envs_required is not None:
config_content = _resolve_config_env_markers(
config_content,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config_content = _resolve_config_env_markers(
config_content,
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config = yaml.load(config_content, loader)
current_config = self.__call__()
@ -1769,11 +1810,10 @@ cdef class ConfigurationOption(Provider):
raise
return
if envs_required is not None:
config_content = _resolve_config_env_markers(
config_content,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config_content = _resolve_config_env_markers(
config_content,
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config = json.loads(config_content)
current_config = self.__call__()
@ -2226,7 +2266,7 @@ cdef class Configuration(Object):
try:
parser = _parse_ini_file(
filepath,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
except IOError as exception:
if required is not False \
@ -2285,11 +2325,10 @@ cdef class Configuration(Object):
raise
return
if envs_required is not None:
config_content = _resolve_config_env_markers(
config_content,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config_content = _resolve_config_env_markers(
config_content,
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config = yaml.load(config_content, loader)
current_config = self.__call__()
@ -2324,11 +2363,10 @@ cdef class Configuration(Object):
raise
return
if envs_required is not None:
config_content = _resolve_config_env_markers(
config_content,
envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config_content = _resolve_config_env_markers(
config_content,
envs_required=envs_required if envs_required is not UNDEFINED else self._is_strict_mode_enabled(),
)
config = json.loads(config_content)
current_config = self.__call__()
@ -3937,14 +3975,18 @@ cdef class Resource(Provider):
@staticmethod
def _is_resource_subclass(instance):
if not isinstance(instance, type):
if sys.version_info < (3, 5):
return False
if not isinstance(instance, CLASS_TYPES):
return
from . import resources
return issubclass(instance, resources.Resource)
@staticmethod
def _is_async_resource_subclass(instance):
if not isinstance(instance, type):
if sys.version_info < (3, 5):
return False
if not isinstance(instance, CLASS_TYPES):
return
from . import resources
return issubclass(instance, resources.AsyncResource)
@ -4602,7 +4644,7 @@ cdef class MethodCaller(Provider):
future_result.set_result(result)
cdef class Injection:
cdef class Injection(object):
"""Abstract injection class."""
@ -4729,7 +4771,7 @@ cpdef tuple parse_named_injections(dict kwargs):
return tuple(injections)
cdef class OverridingContext:
cdef class OverridingContext(object):
"""Provider overriding context.
:py:class:`OverridingContext` is used by :py:meth:`Provider.override` for
@ -4765,7 +4807,7 @@ cdef class OverridingContext:
self._overridden.reset_last_overriding()
cdef class BaseSingletonResetContext:
cdef class BaseSingletonResetContext(object):
def __init__(self, Provider provider):
self._singleton = provider
@ -4801,7 +4843,7 @@ cpdef bint is_provider(object instance):
:rtype: bool
"""
return (not isinstance(instance, type) and
return (not isinstance(instance, CLASS_TYPES) and
getattr(instance, "__IS_PROVIDER__", False) is True)
@ -4829,7 +4871,7 @@ cpdef bint is_delegated(object instance):
:rtype: bool
"""
return (not isinstance(instance, type) and
return (not isinstance(instance, CLASS_TYPES) and
getattr(instance, "__IS_DELEGATED__", False) is True)
@ -4860,7 +4902,7 @@ cpdef bint is_container_instance(object instance):
:rtype: bool
"""
return (not isinstance(instance, type) and
return (not isinstance(instance, CLASS_TYPES) and
getattr(instance, "__IS_CONTAINER__", False) is True)
@ -4872,7 +4914,7 @@ cpdef bint is_container_class(object instance):
:rtype: bool
"""
return (isinstance(instance, type) and
return (isinstance(instance, CLASS_TYPES) and
getattr(instance, "__IS_CONTAINER__", False) is True)

View File

@ -10,14 +10,18 @@ T = TypeVar("T")
class Resource(Generic[T], metaclass=abc.ABCMeta):
@abc.abstractmethod
def init(self, *args, **kwargs) -> Optional[T]: ...
def init(self, *args, **kwargs) -> Optional[T]:
...
def shutdown(self, resource: Optional[T]) -> None: ...
def shutdown(self, resource: Optional[T]) -> None:
...
class AsyncResource(Generic[T], metaclass=abc.ABCMeta):
@abc.abstractmethod
async def init(self, *args, **kwargs) -> Optional[T]: ...
async def init(self, *args, **kwargs) -> Optional[T]:
...
async def shutdown(self, resource: Optional[T]) -> None: ...
async def shutdown(self, resource: Optional[T]) -> None:
...

View File

@ -27,9 +27,9 @@ class SchemaProcessorV1:
return self._container.providers
def _create_providers(
self,
provider_schema: ProviderSchema,
container: Optional[containers.Container] = None,
self,
provider_schema: ProviderSchema,
container: Optional[containers.Container] = None,
) -> None:
if container is None:
container = self._container
@ -57,9 +57,9 @@ class SchemaProcessorV1:
self._create_providers(provider_schema=data, container=provider)
def _setup_injections( # noqa: C901
self,
provider_schema: ProviderSchema,
container: Optional[containers.Container] = None,
self,
provider_schema: ProviderSchema,
container: Optional[containers.Container] = None,
) -> None:
if container is None:
container = self._container
@ -72,7 +72,7 @@ class SchemaProcessorV1:
provides = data.get("provides")
if provides:
if isinstance(provides, str) and provides.startswith("container."):
provides = self._resolve_provider(provides[len("container.") :])
provides = self._resolve_provider(provides[len("container."):])
else:
provides = _import_string(provides)
provider.set_provides(provides)
@ -83,7 +83,7 @@ class SchemaProcessorV1:
injection = None
if isinstance(arg, str) and arg.startswith("container."):
injection = self._resolve_provider(arg[len("container.") :])
injection = self._resolve_provider(arg[len("container."):])
# TODO: refactoring
if isinstance(arg, dict):
@ -91,23 +91,16 @@ class SchemaProcessorV1:
provider_type = _get_provider_cls(arg.get("provider"))
provides = arg.get("provides")
if provides:
if isinstance(provides, str) and provides.startswith(
"container."
):
provides = self._resolve_provider(
provides[len("container.") :]
)
if isinstance(provides, str) and provides.startswith("container."):
provides = self._resolve_provider(provides[len("container."):])
else:
provides = _import_string(provides)
provider_args.append(provides)
for provider_arg in arg.get("args", []):
if isinstance(
provider_arg, str
) and provider_arg.startswith("container."):
if isinstance(provider_arg, str) \
and provider_arg.startswith("container."):
provider_args.append(
self._resolve_provider(
provider_arg[len("container.") :]
),
self._resolve_provider(provider_arg[len("container."):]),
)
injection = provider_type(*provider_args)
@ -124,7 +117,7 @@ class SchemaProcessorV1:
injection = None
if isinstance(arg, str) and arg.startswith("container."):
injection = self._resolve_provider(arg[len("container.") :])
injection = self._resolve_provider(arg[len("container."):])
# TODO: refactoring
if isinstance(arg, dict):
@ -132,23 +125,16 @@ class SchemaProcessorV1:
provider_type = _get_provider_cls(arg.get("provider"))
provides = arg.get("provides")
if provides:
if isinstance(provides, str) and provides.startswith(
"container."
):
provides = self._resolve_provider(
provides[len("container.") :]
)
if isinstance(provides, str) and provides.startswith("container."):
provides = self._resolve_provider(provides[len("container."):])
else:
provides = _import_string(provides)
provider_args.append(provides)
for provider_arg in arg.get("args", []):
if isinstance(
provider_arg, str
) and provider_arg.startswith("container."):
if isinstance(provider_arg, str) \
and provider_arg.startswith("container."):
provider_args.append(
self._resolve_provider(
provider_arg[len("container.") :]
),
self._resolve_provider(provider_arg[len("container."):]),
)
injection = provider_type(*provider_args)
@ -172,7 +158,7 @@ class SchemaProcessorV1:
for segment in segments[1:]:
parentheses = ""
if "(" in segment and ")" in segment:
parentheses = segment[segment.find("(") : segment.rfind(")") + 1]
parentheses = segment[segment.find("("):segment.rfind(")")+1]
segment = segment.replace(parentheses, "")
try:
@ -204,12 +190,10 @@ def _get_provider_cls(provider_cls_name: str) -> Type[providers.Provider]:
if custom_provider_type:
return custom_provider_type
raise SchemaError(f'Undefined provider class "{provider_cls_name}"')
raise SchemaError(f"Undefined provider class \"{provider_cls_name}\"")
def _fetch_provider_cls_from_std(
provider_cls_name: str,
) -> Optional[Type[providers.Provider]]:
def _fetch_provider_cls_from_std(provider_cls_name: str) -> Optional[Type[providers.Provider]]:
return getattr(providers, provider_cls_name, None)
@ -217,16 +201,12 @@ def _import_provider_cls(provider_cls_name: str) -> Optional[Type[providers.Prov
try:
cls = _import_string(provider_cls_name)
except (ImportError, ValueError) as exception:
raise SchemaError(
f'Can not import provider "{provider_cls_name}"'
) from exception
raise SchemaError(f"Can not import provider \"{provider_cls_name}\"") from exception
except AttributeError:
return None
else:
if isinstance(cls, type) and not issubclass(cls, providers.Provider):
raise SchemaError(
f'Provider class "{cls}" is not a subclass of providers base class'
)
raise SchemaError(f"Provider class \"{cls}\" is not a subclass of providers base class")
return cls

View File

@ -1,28 +1,34 @@
"""Wiring module."""
import functools
import inspect
import importlib
import importlib.machinery
import inspect
import pkgutil
import warnings
import sys
from types import ModuleType
from typing import (
Any,
Callable,
Dict,
Generic,
Optional,
Iterable,
Iterator,
Optional,
Set,
Callable,
Any,
Tuple,
Type,
Dict,
Generic,
TypeVar,
Type,
Union,
Set,
cast,
)
if sys.version_info < (3, 7):
from typing import GenericMeta
else:
class GenericMeta(type):
...
# Hotfix, see: https://github.com/ets-labs/python-dependency-injector/issues/362
if sys.version_info >= (3, 9):
@ -30,21 +36,6 @@ if sys.version_info >= (3, 9):
else:
GenericAlias = None
if sys.version_info >= (3, 9):
from typing import Annotated, get_args, get_origin
else:
try:
from typing_extensions import Annotated, get_args, get_origin
except ImportError:
Annotated = object()
# For preventing NameError. Never executes
def get_args(hint):
return ()
def get_origin(tp):
return None
try:
import fastapi.params
@ -66,6 +57,13 @@ except ImportError:
from . import providers
if sys.version_info[:2] == (3, 5):
warnings.warn(
"Dependency Injector will drop support of Python 3.5 after Jan 1st of 2022. "
"This does not mean that there will be any immediate breaking changes, "
"but tests will no longer be executed on Python 3.5, and bugs will not be addressed.",
category=DeprecationWarning,
)
__all__ = (
"wire",
@ -101,9 +99,7 @@ class PatchedRegistry:
def register_callable(self, patched: "PatchedCallable") -> None:
self._callables[patched.patched] = patched
def get_callables_from_module(
self, module: ModuleType
) -> Iterator[Callable[..., Any]]:
def get_callables_from_module(self, module: ModuleType) -> Iterator[Callable[..., Any]]:
for patched_callable in self._callables.values():
if not patched_callable.is_in_module(module):
continue
@ -118,9 +114,7 @@ class PatchedRegistry:
def register_attribute(self, patched: "PatchedAttribute") -> None:
self._attributes.add(patched)
def get_attributes_from_module(
self, module: ModuleType
) -> Iterator["PatchedAttribute"]:
def get_attributes_from_module(self, module: ModuleType) -> Iterator["PatchedAttribute"]:
for attribute in self._attributes:
if not attribute.is_in_module(module):
continue
@ -145,11 +139,11 @@ class PatchedCallable:
)
def __init__(
self,
patched: Optional[Callable[..., Any]] = None,
original: Optional[Callable[..., Any]] = None,
reference_injections: Optional[Dict[Any, Any]] = None,
reference_closing: Optional[Dict[Any, Any]] = None,
self,
patched: Optional[Callable[..., Any]] = None,
original: Optional[Callable[..., Any]] = None,
reference_injections: Optional[Dict[Any, Any]] = None,
reference_closing: Optional[Dict[Any, Any]] = None,
) -> None:
self.patched = patched
self.original = original
@ -220,21 +214,18 @@ class ProvidersMap:
)
def resolve_provider(
self,
provider: Union[providers.Provider, str],
modifier: Optional["Modifier"] = None,
self,
provider: Union[providers.Provider, str],
modifier: Optional["Modifier"] = None,
) -> Optional[providers.Provider]:
if isinstance(provider, providers.Delegate):
return self._resolve_delegate(provider)
elif isinstance(
provider,
(
providers.ProvidedInstance,
providers.AttributeGetter,
providers.ItemGetter,
providers.MethodCaller,
),
):
elif isinstance(provider, (
providers.ProvidedInstance,
providers.AttributeGetter,
providers.ItemGetter,
providers.MethodCaller,
)):
return self._resolve_provided_instance(provider)
elif isinstance(provider, providers.ConfigurationOption):
return self._resolve_config_option(provider)
@ -246,9 +237,9 @@ class ProvidersMap:
return self._resolve_provider(provider)
def _resolve_string_id(
self,
id: str,
modifier: Optional["Modifier"] = None,
self,
id: str,
modifier: Optional["Modifier"] = None,
) -> Optional[providers.Provider]:
if id == self.CONTAINER_STRING_ID:
return self._container.__self__
@ -265,19 +256,16 @@ class ProvidersMap:
return provider
def _resolve_provided_instance(
self,
original: providers.Provider,
self,
original: providers.Provider,
) -> Optional[providers.Provider]:
modifiers = []
while isinstance(
original,
(
while isinstance(original, (
providers.ProvidedInstance,
providers.AttributeGetter,
providers.ItemGetter,
providers.MethodCaller,
),
):
)):
modifiers.insert(0, original)
original = original.provides
@ -301,8 +289,8 @@ class ProvidersMap:
return new
def _resolve_delegate(
self,
original: providers.Delegate,
self,
original: providers.Delegate,
) -> Optional[providers.Provider]:
provider = self._resolve_provider(original.provides)
if provider:
@ -310,9 +298,9 @@ class ProvidersMap:
return provider
def _resolve_config_option(
self,
original: providers.ConfigurationOption,
as_: Any = None,
self,
original: providers.ConfigurationOption,
as_: Any = None,
) -> Optional[providers.Provider]:
original_root = original.root
new = self._resolve_provider(original_root)
@ -336,8 +324,8 @@ class ProvidersMap:
return new
def _resolve_provider(
self,
original: providers.Provider,
self,
original: providers.Provider,
) -> Optional[providers.Provider]:
try:
return self._map[original]
@ -346,9 +334,9 @@ class ProvidersMap:
@classmethod
def _create_providers_map(
cls,
current_container: Container,
original_container: Container,
cls,
current_container: Container,
original_container: Container,
) -> Dict[providers.Provider, providers.Provider]:
current_providers = current_container.providers
current_providers["__self__"] = current_container.__self__
@ -361,9 +349,8 @@ class ProvidersMap:
original_provider = original_providers[provider_name]
providers_map[original_provider] = current_provider
if isinstance(current_provider, providers.Container) and isinstance(
original_provider, providers.Container
):
if isinstance(current_provider, providers.Container) \
and isinstance(original_provider, providers.Container):
subcontainer_map = cls._create_providers_map(
current_container=current_provider.container,
original_container=original_provider.container,
@ -389,21 +376,19 @@ class InspectFilter:
return werkzeug and isinstance(instance, werkzeug.local.LocalProxy)
def _is_starlette_request_cls(self, instance: object) -> bool:
return (
starlette
and isinstance(instance, type)
and _safe_is_subclass(instance, starlette.requests.Request)
)
return starlette \
and isinstance(instance, type) \
and _safe_is_subclass(instance, starlette.requests.Request)
def _is_builtin(self, instance: object) -> bool:
return inspect.isbuiltin(instance)
def wire( # noqa: C901
container: Container,
*,
modules: Optional[Iterable[ModuleType]] = None,
packages: Optional[Iterable[ModuleType]] = None,
container: Container,
*,
modules: Optional[Iterable[ModuleType]] = None,
packages: Optional[Iterable[ModuleType]] = None,
) -> None:
"""Wire container providers with provided packages and modules."""
modules = [*modules] if modules else []
@ -433,22 +418,18 @@ def wire( # noqa: C901
else:
for cls_member_name, cls_member in cls_members:
if _is_marker(cls_member):
_patch_attribute(
cls, cls_member_name, cls_member, providers_map
)
_patch_attribute(cls, cls_member_name, cls_member, providers_map)
elif _is_method(cls_member):
_patch_method(
cls, cls_member_name, cls_member, providers_map
)
_patch_method(cls, cls_member_name, cls_member, providers_map)
for patched in _patched_registry.get_callables_from_module(module):
_bind_injections(patched, providers_map)
def unwire( # noqa: C901
*,
modules: Optional[Iterable[ModuleType]] = None,
packages: Optional[Iterable[ModuleType]] = None,
*,
modules: Optional[Iterable[ModuleType]] = None,
packages: Optional[Iterable[ModuleType]] = None,
) -> None:
"""Wire provided packages and modules with previous wired providers."""
modules = [*modules] if modules else []
@ -462,9 +443,7 @@ def unwire( # noqa: C901
if inspect.isfunction(member):
_unpatch(module, name, member)
elif inspect.isclass(member):
for method_name, method in inspect.getmembers(
member, inspect.isfunction
):
for method_name, method in inspect.getmembers(member, inspect.isfunction):
_unpatch(member, method_name, method)
for patched in _patched_registry.get_callables_from_module(module):
@ -483,10 +462,10 @@ def inject(fn: F) -> F:
def _patch_fn(
module: ModuleType,
name: str,
fn: Callable[..., Any],
providers_map: ProvidersMap,
module: ModuleType,
name: str,
fn: Callable[..., Any],
providers_map: ProvidersMap,
) -> None:
if not _is_patched(fn):
reference_injections, reference_closing = _fetch_reference_injections(fn)
@ -500,16 +479,14 @@ def _patch_fn(
def _patch_method(
cls: Type,
name: str,
method: Callable[..., Any],
providers_map: ProvidersMap,
cls: Type,
name: str,
method: Callable[..., Any],
providers_map: ProvidersMap,
) -> None:
if (
hasattr(cls, "__dict__")
and name in cls.__dict__
and isinstance(cls.__dict__[name], (classmethod, staticmethod))
):
if hasattr(cls, "__dict__") \
and name in cls.__dict__ \
and isinstance(cls.__dict__[name], (classmethod, staticmethod)):
method = cls.__dict__[name]
fn = method.__func__
else:
@ -530,15 +507,13 @@ def _patch_method(
def _unpatch(
module: ModuleType,
name: str,
fn: Callable[..., Any],
module: ModuleType,
name: str,
fn: Callable[..., Any],
) -> None:
if (
hasattr(module, "__dict__")
and name in module.__dict__
and isinstance(module.__dict__[name], (classmethod, staticmethod))
):
if hasattr(module, "__dict__") \
and name in module.__dict__ \
and isinstance(module.__dict__[name], (classmethod, staticmethod)):
method = module.__dict__[name]
fn = method.__func__
@ -549,10 +524,10 @@ def _unpatch(
def _patch_attribute(
member: Any,
name: str,
marker: "_Marker",
providers_map: ProvidersMap,
member: Any,
name: str,
marker: "_Marker",
providers_map: ProvidersMap,
) -> None:
provider = providers_map.resolve_provider(marker.provider, marker.modifier)
if provider is None:
@ -573,33 +548,16 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None:
setattr(patched.member, patched.name, patched.marker)
def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
if get_origin(parameter.annotation) is Annotated:
marker = get_args(parameter.annotation)[1]
else:
marker = parameter.default
if not isinstance(marker, _Marker) and not _is_fastapi_depends(marker):
return None
if _is_fastapi_depends(marker):
marker = marker.dependency
if not isinstance(marker, _Marker):
return None
return marker
def _fetch_reference_injections( # noqa: C901
fn: Callable[..., Any],
fn: Callable[..., Any],
) -> Tuple[Dict[str, Any], Dict[str, Any]]:
# Hotfix, see:
# - https://github.com/ets-labs/python-dependency-injector/issues/362
# - https://github.com/ets-labs/python-dependency-injector/issues/398
if GenericAlias and any(
(fn is GenericAlias, getattr(fn, "__func__", None) is GenericAlias)
):
if GenericAlias and any((
fn is GenericAlias,
getattr(fn, "__func__", None) is GenericAlias
)):
fn = fn.__init__
try:
@ -615,11 +573,18 @@ def _fetch_reference_injections( # noqa: C901
injections = {}
closing = {}
for parameter_name, parameter in signature.parameters.items():
marker = _extract_marker(parameter)
if marker is None:
if not isinstance(parameter.default, _Marker) \
and not _is_fastapi_depends(parameter.default):
continue
marker = parameter.default
if _is_fastapi_depends(marker):
marker = marker.dependency
if not isinstance(marker, _Marker):
continue
if isinstance(marker, Closing):
marker = marker.provider
closing[parameter_name] = marker
@ -628,19 +593,20 @@ def _fetch_reference_injections( # noqa: C901
return injections, closing
def _locate_dependent_closing_args(
provider: providers.Provider, closing_deps: Dict[str, providers.Provider]
) -> Dict[str, providers.Provider]:
for arg in [
*getattr(provider, "args", []),
*getattr(provider, "kwargs", {}).values(),
]:
if not isinstance(arg, providers.Provider):
continue
if isinstance(arg, providers.Resource):
closing_deps[str(id(arg))] = arg
def _locate_dependent_closing_args(provider: providers.Provider) -> Dict[str, providers.Provider]:
if not hasattr(provider, "args"):
return {}
_locate_dependent_closing_args(arg, closing_deps)
closing_deps = {}
for arg in provider.args:
if not isinstance(arg, providers.Provider) or not hasattr(arg, "args"):
continue
if not arg.args and isinstance(arg, providers.Resource):
return {str(id(arg)): arg}
else:
closing_deps += _locate_dependent_closing_args(arg)
return closing_deps
def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> None:
@ -664,8 +630,7 @@ def _bind_injections(fn: Callable[..., Any], providers_map: ProvidersMap) -> Non
if injection in patched_callable.reference_closing:
patched_callable.add_closing(injection, provider)
deps = {}
_locate_dependent_closing_args(provider, deps)
deps = _locate_dependent_closing_args(provider)
for key, dep in deps.items():
patched_callable.add_closing(key, dep)
@ -682,8 +647,8 @@ def _fetch_modules(package):
if not hasattr(package, "__path__") or not hasattr(package, "__name__"):
return modules
for module_info in pkgutil.walk_packages(
path=package.__path__,
prefix=package.__name__ + ".",
path=package.__path__,
prefix=package.__name__ + ".",
):
module = importlib.import_module(module_info.name)
modules.append(module)
@ -699,9 +664,9 @@ def _is_marker(member) -> bool:
def _get_patched(
fn: F,
reference_injections: Dict[Any, Any],
reference_closing: Dict[Any, Any],
fn: F,
reference_injections: Dict[Any, Any],
reference_closing: Dict[Any, Any],
) -> F:
patched_object = PatchedCallable(
original=fn,
@ -729,11 +694,9 @@ def _is_patched(fn) -> bool:
def _is_declarative_container(instance: Any) -> bool:
return (
isinstance(instance, type)
and getattr(instance, "__IS_CONTAINER__", False) is True
and getattr(instance, "declarative_parent", None) is None
)
return (isinstance(instance, type)
and getattr(instance, "__IS_CONTAINER__", False) is True
and getattr(instance, "declarative_parent", None) is None)
def _safe_is_subclass(instance: Any, cls: Type) -> bool:
@ -746,10 +709,11 @@ def _safe_is_subclass(instance: Any, cls: Type) -> bool:
class Modifier:
def modify(
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
) -> providers.Provider: ...
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
) -> providers.Provider:
...
class TypeModifier(Modifier):
@ -758,9 +722,9 @@ class TypeModifier(Modifier):
self.type_ = type_
def modify(
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
) -> providers.Provider:
return provider.as_(self.type_)
@ -798,9 +762,9 @@ class RequiredModifier(Modifier):
return self
def modify(
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
) -> providers.Provider:
provider = provider.required()
if self.type_modifier:
@ -819,9 +783,9 @@ class InvariantModifier(Modifier):
self.id = id
def modify(
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
self,
provider: providers.ConfigurationOption,
providers_map: ProvidersMap,
) -> providers.Provider:
invariant_segment = providers_map.resolve_provider(self.id)
return provider[invariant_segment]
@ -854,9 +818,9 @@ class ProvidedInstance(Modifier):
return self
def modify(
self,
provider: providers.Provider,
providers_map: ProvidersMap,
self,
provider: providers.Provider,
providers_map: ProvidersMap,
) -> providers.Provider:
provider = provider.provided
for type_, value in self.segments:
@ -874,14 +838,22 @@ def provided() -> ProvidedInstance:
return ProvidedInstance()
class _Marker(Generic[T]):
class ClassGetItemMeta(GenericMeta):
def __getitem__(cls, item):
# Spike for Python 3.6
if isinstance(item, tuple):
return cls(*item)
return cls(item)
class _Marker(Generic[T], metaclass=ClassGetItemMeta):
__IS_MARKER__ = True
def __init__(
self,
provider: Union[providers.Provider, Container, str],
modifier: Optional[Modifier] = None,
self,
provider: Union[providers.Provider, Container, str],
modifier: Optional[Modifier] = None,
) -> None:
if _is_declarative_container(provider):
provider = provider.__self__
@ -897,13 +869,16 @@ class _Marker(Generic[T]):
return self
class Provide(_Marker): ...
class Provide(_Marker):
...
class Provider(_Marker): ...
class Provider(_Marker):
...
class Closing(_Marker): ...
class Closing(_Marker):
...
class AutoLoader:
@ -953,7 +928,8 @@ class AutoLoader:
super().exec_module(module)
loader.wire_module(module)
class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader): ...
class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader):
...
loader_details = [
(SourcelessFileLoader, importlib.machinery.BYTECODE_SUFFIXES),
@ -1006,7 +982,7 @@ _inspect_filter = InspectFilter()
_loader = AutoLoader()
# Optimizations
from ._cwiring import _sync_inject # noqa
from ._cwiring import _get_sync_patched # noqa
from ._cwiring import _async_inject # noqa
@ -1022,18 +998,4 @@ def _get_async_patched(fn: F, patched: PatchedCallable) -> F:
patched.injections,
patched.closing,
)
return cast(F, _patched)
def _get_sync_patched(fn: F, patched: PatchedCallable) -> F:
@functools.wraps(fn)
def _patched(*args, **kwargs):
return _sync_inject(
fn,
args,
kwargs,
patched.injections,
patched.closing,
)
return cast(F, _patched)
return _patched

View File

@ -0,0 +1,10 @@
[pytest]
testpaths = tests/unit/
python_files = test_*_py2_py3.py
asyncio_mode = auto
filterwarnings =
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\.0\.0:DeprecationWarning
ignore:Please use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
ignore:The \`scipy(.*?)\` namespace is deprecated(.*):DeprecationWarning
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*

View File

@ -0,0 +1,10 @@
[pytest]
testpaths = tests/unit/
python_files = test_*_py3.py
asyncio_mode = auto
filterwarnings =
ignore:Module \"dependency_injector.ext.aiohttp\" is deprecated since version 4\.0\.0:DeprecationWarning
ignore:Module \"dependency_injector.ext.flask\" is deprecated since version 4\.0\.0:DeprecationWarning
ignore:Please use \`.*?\` from the \`scipy.*?\`(.*?)namespace is deprecated\.:DeprecationWarning
ignore:The \`scipy(.*?)\` namespace is deprecated(.*):DeprecationWarning
ignore:ssl\.PROTOCOL_TLS is deprecated:DeprecationWarning:botocore.*

View File

@ -34,7 +34,7 @@ kwargs4: Dict[str, Any] = provider4.kwargs
# Test 5: to check the provided instance interface
provider5 = providers.Callable(Animal)
provided5: Animal = provider5.provided()
provided5: providers.ProvidedInstance = provider5.provided
attr_getter5: providers.AttributeGetter = provider5.provided.attr
item_getter5: providers.ItemGetter = provider5.provided["item"]
method_caller: providers.MethodCaller = provider5.provided.method.call(123, arg=324)

View File

@ -34,7 +34,7 @@ provider5 = providers.Dict(
a1=providers.Factory(object),
a2=providers.Factory(object),
)
provided5: dict[Any, Any] = provider5.provided()
provided5: providers.ProvidedInstance = provider5.provided
# Test 6: to check the return type with await

View File

@ -37,7 +37,7 @@ attributes4: Dict[str, Any] = provider4.attributes
# Test 5: to check the provided instance interface
provider5 = providers.Factory(Animal)
provided5: Animal = provider5.provided()
provided5: providers.ProvidedInstance = provider5.provided
attr_getter5: providers.AttributeGetter = provider5.provided.attr
item_getter5: providers.ItemGetter = provider5.provided["item"]
method_caller5: providers.MethodCaller = provider5.provided.method.call(123, arg=324)

View File

@ -23,7 +23,7 @@ provider3 = providers.List(
providers.Factory(object),
providers.Factory(object),
)
provided3: List[Any] = provider3.provided()
provided3: providers.ProvidedInstance = provider3.provided
attr_getter3: providers.AttributeGetter = provider3.provided.attr
item_getter3: providers.ItemGetter = provider3.provided["item"]
method_caller3: providers.MethodCaller = provider3.provided.method.call(123, arg=324)

View File

@ -9,7 +9,7 @@ var1: int = provider1()
# Test 2: to check the provided instance interface
provider2 = providers.Object(int)
provided2: Type[int] = provider2.provided()
provided2: providers.ProvidedInstance = provider2.provided
attr_getter2: providers.AttributeGetter = provider2.provided.attr
item_getter2: providers.ItemGetter = provider2.provided["item"]
method_caller2: providers.MethodCaller = provider2.provided.method.call(123, arg=324)

View File

@ -3,8 +3,7 @@ from dependency_injector import providers
# Test 1: to check .provided attribute
provider1: providers.Provider[int] = providers.Object(1)
provided: int = provider1.provided()
provider1_delegate: providers.Provider[int] = provider1.provider
provided: providers.ProvidedInstance = provider1.provided
# Test 2: to check async mode API
provider2: providers.Provider = providers.Provider()

View File

@ -37,7 +37,7 @@ attributes4: Dict[str, Any] = provider4.attributes
# Test 5: to check the provided instance interface
provider5 = providers.Singleton(Animal)
provided5: Animal = provider5.provided()
provided5: providers.ProvidedInstance = provider5.provided
attr_getter5: providers.AttributeGetter = provider5.provided.attr
item_getter5: providers.ItemGetter = provider5.provided["item"]
method_caller5: providers.MethodCaller = provider5.provided.method.call(123, arg=324)

View File

@ -5,23 +5,6 @@ import os
from pytest import mark, raises
def test_no_env_variable_interpolation(config, ini_config_file_3):
config.from_ini(ini_config_file_3, envs_required=None)
assert config() == {
"section1": {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
},
}
assert config.section1() == {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
}
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
def test_env_variable_interpolation(config, ini_config_file_3):
config.from_ini(ini_config_file_3)

View File

@ -6,23 +6,6 @@ import os
from pytest import mark, raises
def test_no_env_variable_interpolation(config, json_config_file_3):
config.from_json(json_config_file_3, envs_required=None)
assert config() == {
"section1": {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
},
}
assert config.section1() == {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
}
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
def test_env_variable_interpolation(config, json_config_file_3):
config.from_json(json_config_file_3)

View File

@ -6,23 +6,6 @@ import yaml
from pytest import mark, raises
def test_no_env_variable_interpolation(config, yaml_config_file_3):
config.from_yaml(yaml_config_file_3, envs_required=None)
assert config() == {
"section1": {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
},
}
assert config.section1() == {
"value1": "${CONFIG_TEST_ENV}",
"value2": "${CONFIG_TEST_PATH}/path",
}
assert config.section1.value1() == "${CONFIG_TEST_ENV}"
assert config.section1.value2() == "${CONFIG_TEST_PATH}/path"
def test_env_variable_interpolation(config, yaml_config_file_3):
config.from_yaml(yaml_config_file_3)

View File

@ -1,5 +1,4 @@
"""Coroutine provider tests."""
import sys
from dependency_injector import providers, errors
from pytest import mark, raises
@ -209,17 +208,3 @@ def test_repr():
"<dependency_injector.providers."
"Coroutine({0}) at {1}>".format(repr(example), hex(id(provider)))
)
@mark.skipif(sys.version_info > (3, 15), reason="requires Python<3.16")
def test_asyncio_iscoroutinefunction() -> None:
from asyncio.coroutines import iscoroutinefunction
assert iscoroutinefunction(providers.Coroutine(example))
@mark.skipif(sys.version_info < (3, 12), reason="requires Python>=3.12")
def test_inspect_iscoroutinefunction() -> None:
from inspect import iscoroutinefunction
assert iscoroutinefunction(providers.Coroutine(example))

View File

@ -1,11 +1,7 @@
import sys
from typing_extensions import Annotated
from fastapi import FastAPI, Depends
from fastapi import (
Request,
) # See: https://github.com/ets-labs/python-dependency-injector/issues/398
from fastapi import Request # See: https://github.com/ets-labs/python-dependency-injector/issues/398
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
@ -32,16 +28,11 @@ async def index(service: Service = Depends(Provide[Container.service])):
return {"result": result}
@app.api_route("/annotated")
@inject
async def annotated(service: Annotated[Service, Depends(Provide[Container.service])]):
result = await service.process()
return {"result": result}
@app.get("/auth")
@inject
def read_current_user(credentials: HTTPBasicCredentials = Depends(security)):
def read_current_user(
credentials: HTTPBasicCredentials = Depends(security)
):
return {"username": credentials.username, "password": credentials.password}

View File

@ -1,5 +1,3 @@
from typing_extensions import Annotated
from flask import Flask, jsonify, request, current_app, session, g
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
@ -28,12 +26,5 @@ def index(service: Service = Provide[Container.service]):
return jsonify({"result": result})
@app.route("/annotated")
@inject
def annotated(service: Annotated[Service, Provide[Container.service]]):
result = service.process()
return jsonify({"result": result})
container = Container()
container.wire(modules=[__name__])

View File

@ -1,80 +1,41 @@
from typing import Any, Dict, List, Optional
from dependency_injector import containers, providers
from dependency_injector.wiring import Closing, Provide, inject
class Counter:
def __init__(self) -> None:
self._init = 0
self._shutdown = 0
def init(self) -> None:
self._init += 1
def shutdown(self) -> None:
self._shutdown += 1
def reset(self) -> None:
self._init = 0
self._shutdown = 0
from dependency_injector.wiring import inject, Provide, Closing
class Service:
def __init__(self, counter: Optional[Counter] = None, **dependencies: Any) -> None:
self.counter = counter or Counter()
self.dependencies = dependencies
init_counter: int = 0
shutdown_counter: int = 0
def init(self) -> None:
self.counter.init()
@classmethod
def reset_counter(cls):
cls.init_counter = 0
cls.shutdown_counter = 0
def shutdown(self) -> None:
self.counter.shutdown()
@classmethod
def init(cls):
cls.init_counter += 1
@property
def init_counter(self) -> int:
return self.counter._init
@property
def shutdown_counter(self) -> int:
return self.counter._shutdown
@classmethod
def shutdown(cls):
cls.shutdown_counter += 1
class FactoryService:
def __init__(self, service: Service, service2: Service):
def __init__(self, service: Service):
self.service = service
self.service2 = service2
class NestedService:
def __init__(self, factory_service: FactoryService):
self.factory_service = factory_service
def init_service(counter: Counter, _list: List[int], _dict: Dict[str, int]):
service = Service(counter, _list=_list, _dict=_dict)
def init_service():
service = Service()
service.init()
yield service
service.shutdown()
class Container(containers.DeclarativeContainer):
counter = providers.Singleton(Counter)
_list = providers.List(
providers.Callable(lambda a: a, a=1), providers.Callable(lambda b: b, 2)
)
_dict = providers.Dict(
a=providers.Callable(lambda a: a, a=3), b=providers.Callable(lambda b: b, 4)
)
service = providers.Resource(init_service, counter, _list, _dict=_dict)
service2 = providers.Resource(init_service, counter, _list, _dict=_dict)
factory_service = providers.Factory(FactoryService, service, service2)
factory_service_kwargs = providers.Factory(
FactoryService,
service=service,
service2=service2,
)
nested_service = providers.Factory(NestedService, factory_service)
service = providers.Resource(init_service)
factory_service = providers.Factory(FactoryService, service)
@inject
@ -83,21 +44,5 @@ def test_function(service: Service = Closing[Provide["service"]]):
@inject
def test_function_dependency(
factory: FactoryService = Closing[Provide["factory_service"]],
):
def test_function_dependency(factory: FactoryService = Closing[Provide["factory_service"]]):
return factory
@inject
def test_function_dependency_kwargs(
factory: FactoryService = Closing[Provide["factory_service_kwargs"]],
):
return factory
@inject
def test_function_nested_dependency(
nested: NestedService = Closing[Provide["nested_service"]],
):
return nested

View File

@ -2,13 +2,13 @@
from decimal import Decimal
from pytest import fixture, mark, raises
from samples.wiringstringids import module, package, resourceclosing
from samples.wiringstringids.container import Container, SubContainer
from samples.wiringstringids.service import Service
from dependency_injector import errors
from dependency_injector.wiring import Closing, Provide, Provider, wire
from pytest import fixture, mark, raises
from samples.wiringstringids import module, package, resourceclosing
from samples.wiringstringids.service import Service
from samples.wiringstringids.container import Container, SubContainer
@fixture(autouse=True)
@ -34,11 +34,10 @@ def subcontainer():
@fixture
def resourceclosing_container(request):
def resourceclosing_container():
container = resourceclosing.Container()
container.wire(modules=[resourceclosing])
with container.reset_singletons():
yield container
yield container
container.unwire()
@ -275,65 +274,42 @@ def test_wire_multiple_containers():
@mark.usefixtures("resourceclosing_container")
def test_closing_resource():
resourceclosing.Service.reset_counter()
result_1 = resourceclosing.test_function()
assert isinstance(result_1, resourceclosing.Service)
assert result_1.init_counter == 1
assert result_1.shutdown_counter == 1
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
result_2 = resourceclosing.test_function()
assert isinstance(result_2, resourceclosing.Service)
assert result_2.init_counter == 2
assert result_2.shutdown_counter == 2
assert result_1.dependencies == {"_list": [1, 2], "_dict": {"a": 3, "b": 4}}
assert result_1 is not result_2
@mark.usefixtures("resourceclosing_container")
def test_closing_dependency_resource():
resourceclosing.Service.reset_counter()
result_1 = resourceclosing.test_function_dependency()
assert isinstance(result_1, resourceclosing.FactoryService)
assert result_1.service.init_counter == 2
assert result_1.service.shutdown_counter == 2
assert result_1.service.init_counter == 1
assert result_1.service.shutdown_counter == 1
result_2 = resourceclosing.test_function_dependency()
assert isinstance(result_2, resourceclosing.FactoryService)
assert result_2.service.init_counter == 4
assert result_2.service.shutdown_counter == 4
@mark.usefixtures("resourceclosing_container")
def test_closing_dependency_resource_kwargs():
result_1 = resourceclosing.test_function_dependency_kwargs()
assert isinstance(result_1, resourceclosing.FactoryService)
assert result_1.service.init_counter == 2
assert result_1.service.shutdown_counter == 2
result_2 = resourceclosing.test_function_dependency_kwargs()
assert isinstance(result_2, resourceclosing.FactoryService)
assert result_2.service.init_counter == 4
assert result_2.service.shutdown_counter == 4
@mark.usefixtures("resourceclosing_container")
def test_closing_nested_dependency_resource():
result_1 = resourceclosing.test_function_nested_dependency()
assert isinstance(result_1, resourceclosing.NestedService)
assert result_1.factory_service.service.init_counter == 2
assert result_1.factory_service.service.shutdown_counter == 2
result_2 = resourceclosing.test_function_nested_dependency()
assert isinstance(result_2, resourceclosing.NestedService)
assert result_2.factory_service.service.init_counter == 4
assert result_2.factory_service.service.shutdown_counter == 4
assert result_2.service.init_counter == 2
assert result_2.service.shutdown_counter == 2
assert result_1 is not result_2
@mark.usefixtures("resourceclosing_container")
def test_closing_resource_bypass_marker_injection():
resourceclosing.Service.reset_counter()
result_1 = resourceclosing.test_function(service=Closing[Provide["service"]])
assert isinstance(result_1, resourceclosing.Service)
assert result_1.init_counter == 1
@ -349,6 +325,7 @@ def test_closing_resource_bypass_marker_injection():
@mark.usefixtures("resourceclosing_container")
def test_closing_resource_context():
resourceclosing.Service.reset_counter()
service = resourceclosing.Service()
result_1 = resourceclosing.test_function(service=service)

View File

@ -4,17 +4,13 @@ from pytest_asyncio import fixture as aio_fixture
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
import os
_SAMPLES_DIR = os.path.abspath(
os.path.sep.join(
(
os.path.dirname(__file__),
"../samples/",
)
),
os.path.sep.join((
os.path.dirname(__file__),
"../samples/",
)),
)
import sys
sys.path.append(_SAMPLES_DIR)
@ -41,19 +37,6 @@ async def test_depends_marker_injection(async_client: AsyncClient):
assert response.json() == {"result": "Foo"}
@mark.asyncio
async def test_depends_with_annotated(async_client: AsyncClient):
class ServiceMock:
async def process(self):
return "Foo"
with web.container.service.override(ServiceMock()):
response = await async_client.get("/")
assert response.status_code == 200
assert response.json() == {"result": "Foo"}
@mark.asyncio
async def test_depends_injection(async_client: AsyncClient):
response = await async_client.get("/auth", auth=("john_smith", "secret"))

View File

@ -2,25 +2,19 @@ import json
# Runtime import to avoid syntax errors in samples on Python < 3.5 and reach top-dir
import os
_TOP_DIR = os.path.abspath(
os.path.sep.join(
(
os.path.dirname(__file__),
"../",
)
),
os.path.sep.join((
os.path.dirname(__file__),
"../",
)),
)
_SAMPLES_DIR = os.path.abspath(
os.path.sep.join(
(
os.path.dirname(__file__),
"../samples/",
)
),
os.path.sep.join((
os.path.dirname(__file__),
"../samples/",
)),
)
import sys
sys.path.append(_TOP_DIR)
sys.path.append(_SAMPLES_DIR)
@ -35,13 +29,3 @@ def test_wiring_with_flask():
assert response.status_code == 200
assert json.loads(response.data) == {"result": "OK"}
def test_wiring_with_annotated():
client = web.app.test_client()
with web.app.app_context():
response = client.get("/annotated")
assert response.status_code == 200
assert json.loads(response.data) == {"result": "OK"}

View File

@ -6,13 +6,6 @@ import inspect
from dependency_injector.wiring import inject
def test_isfunction():
@inject
def foo(): ...
assert inspect.isfunction(foo)
def test_asyncio_iscoroutinefunction():
@inject
async def foo():