Merge branch 'release/4.48.3'

This commit is contained in:
ZipFile 2025-12-04 18:31:06 +00:00
commit 964d932673
11 changed files with 313 additions and 155 deletions

View File

@ -7,6 +7,13 @@ that were made in every particular version.
From version 0.7.6 *Dependency Injector* framework strictly From version 0.7.6 *Dependency Injector* framework strictly
follows `Semantic versioning`_ follows `Semantic versioning`_
4.48.3
------
- Allow annotated marker to be anywhere in the annotation list. Thanks to `@BrianPugh <https://github.com/BrianPugh>`_ for `#939 <https://github.com/ets-labs/python-dependency-injector/issues/939>`_.
- Fix FastDepends v3 compatibility. Thanks to `@AndrianEquestrian <https://github.com/AndrianEquestrian>`_ for `#933 <https://github.com/ets-labs/python-dependency-injector/issues/933>`_.
- Various type annotation improvements for providers. Thanks to `@leonarduschen <https://github.com/leonarduschen>`_ for `#927 <https://github.com/ets-labs/python-dependency-injector/pull/927>`_, `#932 <https://github.com/ets-labs/python-dependency-injector/pull/932>`_ and `#935 <https://github.com/ets-labs/python-dependency-injector/pull/935>`_.
4.48.2 4.48.2
------ ------

View File

@ -55,7 +55,8 @@ dynamic = ["version"]
dependencies = [ dependencies = [
# typing.Annotated since v3.9 # typing.Annotated since v3.9
# typing.Self and typing.assert_never since v3.11 # typing.Self and typing.assert_never since v3.11
"typing-extensions; python_version<'3.11'", # typing.TypeVar default since v3.13
"typing-extensions; python_version<'3.13'",
] ]
[project.optional-dependencies] [project.optional-dependencies]

View File

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

View File

@ -1,26 +1,29 @@
from __future__ import annotations from __future__ import annotations
from contextlib import AbstractAsyncContextManager, AbstractContextManager
from pathlib import Path from pathlib import Path
from typing import ( from typing import (
Awaitable,
TypeVar,
Generic,
Type,
Callable as _Callable,
Any, Any,
Tuple, AsyncIterator as _AsyncIterator,
List as _List, Awaitable,
Dict as _Dict, Callable as _Callable,
Optional,
Union,
Coroutine as _Coroutine, Coroutine as _Coroutine,
Dict as _Dict,
Generator as _Generator,
Generic,
Iterable as _Iterable, Iterable as _Iterable,
Iterator as _Iterator, Iterator as _Iterator,
AsyncIterator as _AsyncIterator, List as _List,
Generator as _Generator, Mapping,
Optional,
Tuple,
Type,
Union,
overload, overload,
) )
from typing_extensions import Self as _Self, TypeVar
try: try:
import yaml import yaml
except ImportError: except ImportError:
@ -37,6 +40,7 @@ Injection = Any
ProviderParent = Union["Provider", Any] ProviderParent = Union["Provider", Any]
T = TypeVar("T") T = TypeVar("T")
TT = TypeVar("TT") TT = TypeVar("TT")
T_Any = TypeVar("T_Any", default=Any)
P = TypeVar("P", bound="Provider") P = TypeVar("P", bound="Provider")
BS = TypeVar("BS", bound="BaseSingleton") BS = TypeVar("BS", bound="BaseSingleton")
@ -65,7 +69,7 @@ class Provider(Generic[T]):
@property @property
def provider(self) -> Provider[T]: ... def provider(self) -> Provider[T]: ...
@property @property
def provided(self) -> ProvidedInstance[T]: ... def provided(self) -> ProvidedInstance: ...
def enable_async_mode(self) -> None: ... def enable_async_mode(self) -> None: ...
def disable_async_mode(self) -> None: ... def disable_async_mode(self) -> None: ...
def reset_async_mode(self) -> None: ... def reset_async_mode(self) -> None: ...
@ -85,7 +89,7 @@ class Object(Provider[T]):
def __init__(self, provides: Optional[T] = None) -> None: ... def __init__(self, provides: Optional[T] = None) -> None: ...
@property @property
def provides(self) -> Optional[T]: ... def provides(self) -> Optional[T]: ...
def set_provides(self, provides: Optional[T]) -> Object: ... def set_provides(self, provides: Optional[T]) -> _Self: ...
class Self(Provider[T]): class Self(Provider[T]):
def __init__(self, container: Optional[T] = None) -> None: ... def __init__(self, container: Optional[T] = None) -> None: ...
@ -98,12 +102,12 @@ class Delegate(Provider[Provider]):
def __init__(self, provides: Optional[Provider] = None) -> None: ... def __init__(self, provides: Optional[Provider] = None) -> None: ...
@property @property
def provides(self) -> Optional[Provider]: ... def provides(self) -> Optional[Provider]: ...
def set_provides(self, provides: Optional[Provider]) -> Delegate: ... def set_provides(self, provides: Optional[Provider]) -> _Self: ...
class Aggregate(Provider[T]): class Aggregate(Provider[T]):
def __init__( def __init__(
self, self,
provider_dict: Optional[_Dict[Any, Provider[T]]] = None, provider_dict: Optional[Mapping[Any, Provider[T]]] = None,
**provider_kwargs: Provider[T], **provider_kwargs: Provider[T],
): ... ): ...
def __getattr__(self, provider_name: Any) -> Provider[T]: ... def __getattr__(self, provider_name: Any) -> Provider[T]: ...
@ -122,9 +126,9 @@ class Aggregate(Provider[T]):
def providers(self) -> _Dict[Any, Provider[T]]: ... def providers(self) -> _Dict[Any, Provider[T]]: ...
def set_providers( def set_providers(
self, self,
provider_dict: Optional[_Dict[Any, Provider[T]]] = None, provider_dict: Optional[Mapping[Any, Provider[T]]] = None,
**provider_kwargs: Provider[T], **provider_kwargs: Provider[T],
) -> Aggregate[T]: ... ) -> _Self: ...
class Dependency(Provider[T]): class Dependency(Provider[T]):
def __init__( def __init__(
@ -135,10 +139,10 @@ class Dependency(Provider[T]):
def __getattr__(self, name: str) -> Any: ... def __getattr__(self, name: str) -> Any: ...
@property @property
def instance_of(self) -> Type[T]: ... def instance_of(self) -> Type[T]: ...
def set_instance_of(self, instance_of: Type[T]) -> Dependency[T]: ... def set_instance_of(self, instance_of: Type[T]) -> _Self: ...
@property @property
def default(self) -> Provider[T]: ... def default(self) -> Provider[T]: ...
def set_default(self, default: Optional[Union[Provider, Any]]) -> Dependency[T]: ... def set_default(self, default: Optional[Union[Provider, Any]]) -> _Self: ...
@property @property
def is_defined(self) -> bool: ... def is_defined(self) -> bool: ...
def provided_by(self, provider: Provider) -> OverridingContext[P]: ... def provided_by(self, provider: Provider) -> OverridingContext[P]: ...
@ -162,28 +166,28 @@ class DependenciesContainer(Object):
def parent_name(self) -> Optional[str]: ... def parent_name(self) -> Optional[str]: ...
def assign_parent(self, parent: ProviderParent) -> None: ... def assign_parent(self, parent: ProviderParent) -> None: ...
class Callable(Provider[T]): class Callable(Provider[T_Any]):
def __init__( def __init__(
self, self,
provides: Optional[Union[_Callable[..., T], str]] = None, provides: Optional[Union[_Callable[..., T_Any], str]] = None,
*args: Injection, *args: Injection,
**kwargs: Injection, **kwargs: Injection,
) -> None: ... ) -> None: ...
@property @property
def provides(self) -> Optional[_Callable[..., T]]: ... def provides(self) -> Optional[_Callable[..., T_Any]]: ...
def set_provides( def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]] self, provides: Optional[Union[_Callable[..., T_Any], str]]
) -> Callable[T]: ... ) -> _Self: ...
@property @property
def args(self) -> Tuple[Injection]: ... def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Callable[T]: ... def add_args(self, *args: Injection) -> _Self: ...
def set_args(self, *args: Injection) -> Callable[T]: ... def set_args(self, *args: Injection) -> _Self: ...
def clear_args(self) -> Callable[T]: ... def clear_args(self) -> _Self: ...
@property @property
def kwargs(self) -> _Dict[Any, Injection]: ... def kwargs(self) -> _Dict[str, Injection]: ...
def add_kwargs(self, **kwargs: Injection) -> Callable[T]: ... def add_kwargs(self, **kwargs: Injection) -> _Self: ...
def set_kwargs(self, **kwargs: Injection) -> Callable[T]: ... def set_kwargs(self, **kwargs: Injection) -> _Self: ...
def clear_kwargs(self) -> Callable[T]: ... def clear_kwargs(self) -> _Self: ...
class DelegatedCallable(Callable[T]): ... class DelegatedCallable(Callable[T]): ...
@ -205,7 +209,7 @@ class CoroutineDelegate(Delegate):
class ConfigurationOption(Provider[Any]): class ConfigurationOption(Provider[Any]):
UNDEFINED: object UNDEFINED: object
def __init__(self, name: Tuple[str], root: Configuration) -> None: ... def __init__(self, name: Tuple[str], root: Configuration) -> None: ...
def __enter__(self) -> ConfigurationOption: ... def __enter__(self) -> _Self: ...
def __exit__(self, *exc_info: Any) -> None: ... def __exit__(self, *exc_info: Any) -> None: ...
def __getattr__(self, item: str) -> ConfigurationOption: ... def __getattr__(self, item: str) -> ConfigurationOption: ...
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ... def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
@ -270,30 +274,26 @@ class Configuration(Object[Any]):
json_files: Optional[_Iterable[Union[Path, str]]] = None, json_files: Optional[_Iterable[Union[Path, str]]] = None,
pydantic_settings: Optional[_Iterable[PydanticSettings]] = None, pydantic_settings: Optional[_Iterable[PydanticSettings]] = None,
) -> None: ... ) -> None: ...
def __enter__(self) -> Configuration: ... def __enter__(self) -> _Self: ...
def __exit__(self, *exc_info: Any) -> None: ... def __exit__(self, *exc_info: Any) -> None: ...
def __getattr__(self, item: str) -> ConfigurationOption: ... def __getattr__(self, item: str) -> ConfigurationOption: ...
def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ... def __getitem__(self, item: Union[str, Provider]) -> ConfigurationOption: ...
def get_name(self) -> str: ... def get_name(self) -> str: ...
def set_name(self, name: str) -> Configuration: ... def set_name(self, name: str) -> _Self: ...
def get_default(self) -> _Dict[Any, Any]: ... def get_default(self) -> _Dict[Any, Any]: ...
def set_default(self, default: _Dict[Any, Any]): ... def set_default(self, default: _Dict[Any, Any]) -> _Self: ...
def get_strict(self) -> bool: ... def get_strict(self) -> bool: ...
def set_strict(self, strict: bool) -> Configuration: ... def set_strict(self, strict: bool) -> _Self: ...
def get_children(self) -> _Dict[str, ConfigurationOption]: ... def get_children(self) -> _Dict[str, ConfigurationOption]: ...
def set_children( def set_children(self, children: _Dict[str, ConfigurationOption]) -> _Self: ...
self, children: _Dict[str, ConfigurationOption]
) -> Configuration: ...
def get_ini_files(self) -> _List[Union[Path, str]]: ... def get_ini_files(self) -> _List[Union[Path, str]]: ...
def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ... def set_ini_files(self, files: _Iterable[Union[Path, str]]) -> _Self: ...
def get_yaml_files(self) -> _List[Union[Path, str]]: ... def get_yaml_files(self) -> _List[Union[Path, str]]: ...
def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ... def set_yaml_files(self, files: _Iterable[Union[Path, str]]) -> _Self: ...
def get_json_files(self) -> _List[Union[Path, str]]: ... def get_json_files(self) -> _List[Union[Path, str]]: ...
def set_json_files(self, files: _Iterable[Union[Path, str]]) -> Configuration: ... def set_json_files(self, files: _Iterable[Union[Path, str]]) -> _Self: ...
def get_pydantic_settings(self) -> _List[PydanticSettings]: ... def get_pydantic_settings(self) -> _List[PydanticSettings]: ...
def set_pydantic_settings( def set_pydantic_settings(self, settings: _Iterable[PydanticSettings]) -> _Self: ...
self, settings: _Iterable[PydanticSettings]
) -> Configuration: ...
def load(self, required: bool = False, envs_required: bool = False) -> None: ... def load(self, required: bool = False, envs_required: bool = False) -> None: ...
def get(self, selector: str) -> Any: ... def get(self, selector: str) -> Any: ...
def set(self, selector: str, value: Any) -> OverridingContext[P]: ... def set(self, selector: str, value: Any) -> OverridingContext[P]: ...
@ -345,22 +345,22 @@ class Factory(Provider[T]):
def provides(self) -> Optional[_Callable[..., T]]: ... def provides(self) -> Optional[_Callable[..., T]]: ...
def set_provides( def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]] self, provides: Optional[Union[_Callable[..., T], str]]
) -> Factory[T]: ... ) -> _Self: ...
@property @property
def args(self) -> Tuple[Injection]: ... def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Factory[T]: ... def add_args(self, *args: Injection) -> _Self: ...
def set_args(self, *args: Injection) -> Factory[T]: ... def set_args(self, *args: Injection) -> _Self: ...
def clear_args(self) -> Factory[T]: ... def clear_args(self) -> _Self: ...
@property @property
def kwargs(self) -> _Dict[Any, Injection]: ... def kwargs(self) -> _Dict[str, Injection]: ...
def add_kwargs(self, **kwargs: Injection) -> Factory[T]: ... def add_kwargs(self, **kwargs: Injection) -> _Self: ...
def set_kwargs(self, **kwargs: Injection) -> Factory[T]: ... def set_kwargs(self, **kwargs: Injection) -> _Self: ...
def clear_kwargs(self) -> Factory[T]: ... def clear_kwargs(self) -> _Self: ...
@property @property
def attributes(self) -> _Dict[Any, Injection]: ... def attributes(self) -> _Dict[str, Injection]: ...
def add_attributes(self, **kwargs: Injection) -> Factory[T]: ... def add_attributes(self, **kwargs: Injection) -> _Self: ...
def set_attributes(self, **kwargs: Injection) -> Factory[T]: ... def set_attributes(self, **kwargs: Injection) -> _Self: ...
def clear_attributes(self) -> Factory[T]: ... def clear_attributes(self) -> _Self: ...
class DelegatedFactory(Factory[T]): ... class DelegatedFactory(Factory[T]): ...
@ -376,7 +376,7 @@ class FactoryAggregate(Aggregate[T]):
def factories(self) -> _Dict[Any, Factory[T]]: ... def factories(self) -> _Dict[Any, Factory[T]]: ...
def set_factories( def set_factories(
self, self,
provider_dict: Optional[_Dict[Any, Factory[T]]] = None, provider_dict: Optional[Mapping[Any, Factory[T]]] = None,
**provider_kwargs: Factory[T], **provider_kwargs: Factory[T],
) -> FactoryAggregate[T]: ... ) -> FactoryAggregate[T]: ...
@ -394,22 +394,22 @@ class BaseSingleton(Provider[T]):
def provides(self) -> Optional[_Callable[..., T]]: ... def provides(self) -> Optional[_Callable[..., T]]: ...
def set_provides( def set_provides(
self, provides: Optional[Union[_Callable[..., T], str]] self, provides: Optional[Union[_Callable[..., T], str]]
) -> BaseSingleton[T]: ... ) -> _Self: ...
@property @property
def args(self) -> Tuple[Injection]: ... def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> BaseSingleton[T]: ... def add_args(self, *args: Injection) -> _Self: ...
def set_args(self, *args: Injection) -> BaseSingleton[T]: ... def set_args(self, *args: Injection) -> _Self: ...
def clear_args(self) -> BaseSingleton[T]: ... def clear_args(self) -> _Self: ...
@property @property
def kwargs(self) -> _Dict[Any, Injection]: ... def kwargs(self) -> _Dict[str, Injection]: ...
def add_kwargs(self, **kwargs: Injection) -> BaseSingleton[T]: ... def add_kwargs(self, **kwargs: Injection) -> _Self: ...
def set_kwargs(self, **kwargs: Injection) -> BaseSingleton[T]: ... def set_kwargs(self, **kwargs: Injection) -> _Self: ...
def clear_kwargs(self) -> BaseSingleton[T]: ... def clear_kwargs(self) -> _Self: ...
@property @property
def attributes(self) -> _Dict[Any, Injection]: ... def attributes(self) -> _Dict[str, Injection]: ...
def add_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ... def add_attributes(self, **kwargs: Injection) -> _Self: ...
def set_attributes(self, **kwargs: Injection) -> BaseSingleton[T]: ... def set_attributes(self, **kwargs: Injection) -> _Self: ...
def clear_attributes(self) -> BaseSingleton[T]: ... def clear_attributes(self) -> _Self: ...
def reset(self) -> SingletonResetContext[BS]: ... def reset(self) -> SingletonResetContext[BS]: ...
def full_reset(self) -> SingletonFullResetContext[BS]: ... def full_reset(self) -> SingletonFullResetContext[BS]: ...
@ -431,23 +431,23 @@ class List(Provider[_List]):
def __init__(self, *args: Injection): ... def __init__(self, *args: Injection): ...
@property @property
def args(self) -> Tuple[Injection]: ... def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> List[T]: ... def add_args(self, *args: Injection) -> _Self: ...
def set_args(self, *args: Injection) -> List[T]: ... def set_args(self, *args: Injection) -> _Self: ...
def clear_args(self) -> List[T]: ... def clear_args(self) -> _Self: ...
class Dict(Provider[_Dict]): class Dict(Provider[_Dict]):
def __init__( def __init__(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection self, dict_: Optional[Mapping[Any, Injection]] = None, **kwargs: Injection
): ... ): ...
@property @property
def kwargs(self) -> _Dict[Any, Injection]: ... def kwargs(self) -> _Dict[Any, Injection]: ...
def add_kwargs( def add_kwargs(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection self, dict_: Optional[Mapping[Any, Injection]] = None, **kwargs: Injection
) -> Dict: ... ) -> _Self: ...
def set_kwargs( def set_kwargs(
self, dict_: Optional[_Dict[Any, Injection]] = None, **kwargs: Injection self, dict_: Optional[Mapping[Any, Injection]] = None, **kwargs: Injection
) -> Dict: ... ) -> _Self: ...
def clear_kwargs(self) -> Dict: ... def clear_kwargs(self) -> _Self: ...
class Resource(Provider[T]): class Resource(Provider[T]):
@overload @overload
@ -465,6 +465,20 @@ class Resource(Provider[T]):
**kwargs: Injection, **kwargs: Injection,
) -> None: ... ) -> None: ...
@overload @overload
def __init__(
self,
provides: Optional[_Callable[..., AbstractContextManager[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
@overload
def __init__(
self,
provides: Optional[_Callable[..., AbstractAsyncContextManager[T]]] = None,
*args: Injection,
**kwargs: Injection,
) -> None: ...
@overload
def __init__( def __init__(
self, self,
provides: Optional[_Callable[..., _Iterator[T]]] = None, provides: Optional[_Callable[..., _Iterator[T]]] = None,
@ -494,17 +508,17 @@ class Resource(Provider[T]):
) -> None: ... ) -> None: ...
@property @property
def provides(self) -> Optional[_Callable[..., Any]]: ... def provides(self) -> Optional[_Callable[..., Any]]: ...
def set_provides(self, provides: Optional[Any]) -> Resource[T]: ... def set_provides(self, provides: Optional[Any]) -> _Self: ...
@property @property
def args(self) -> Tuple[Injection]: ... def args(self) -> Tuple[Injection]: ...
def add_args(self, *args: Injection) -> Resource[T]: ... def add_args(self, *args: Injection) -> _Self: ...
def set_args(self, *args: Injection) -> Resource[T]: ... def set_args(self, *args: Injection) -> _Self: ...
def clear_args(self) -> Resource[T]: ... def clear_args(self) -> _Self: ...
@property @property
def kwargs(self) -> _Dict[Any, Injection]: ... def kwargs(self) -> _Dict[str, Injection]: ...
def add_kwargs(self, **kwargs: Injection) -> Resource[T]: ... def add_kwargs(self, **kwargs: Injection) -> _Self: ...
def set_kwargs(self, **kwargs: Injection) -> Resource[T]: ... def set_kwargs(self, **kwargs: Injection) -> _Self: ...
def clear_kwargs(self) -> Resource[T]: ... def clear_kwargs(self) -> _Self: ...
@property @property
def initialized(self) -> bool: ... def initialized(self) -> bool: ...
def init(self) -> Optional[Awaitable[T]]: ... def init(self) -> Optional[Awaitable[T]]: ...
@ -527,17 +541,17 @@ class Container(Provider[T]):
def parent_name(self) -> Optional[str]: ... def parent_name(self) -> Optional[str]: ...
def assign_parent(self, parent: ProviderParent) -> None: ... def assign_parent(self, parent: ProviderParent) -> None: ...
class Selector(Provider[Any]): class Selector(Provider[T_Any]):
def __init__( def __init__(
self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider self, selector: Optional[_Callable[..., Any]] = None, **providers: Provider
): ... ): ...
def __getattr__(self, name: str) -> Provider: ... def __getattr__(self, name: str) -> Provider[T_Any]: ...
@property @property
def selector(self) -> Optional[_Callable[..., Any]]: ... def selector(self) -> Optional[_Callable[..., Any]]: ...
def set_selector(self, selector: Optional[_Callable[..., Any]]) -> Selector: ... def set_selector(self, selector: Optional[_Callable[..., Any]]) -> _Self: ...
@property @property
def providers(self) -> _Dict[str, Provider]: ... def providers(self) -> _Dict[str, Provider[T_Any]]: ...
def set_providers(self, **providers: Provider) -> Selector: ... def set_providers(self, **providers: Provider) -> _Self: ...
class ProvidedInstanceFluentInterface: class ProvidedInstanceFluentInterface:
def __getattr__(self, item: Any) -> AttributeGetter: ... def __getattr__(self, item: Any) -> AttributeGetter: ...
@ -545,9 +559,7 @@ class ProvidedInstanceFluentInterface:
def call(self, *args: Injection, **kwargs: Injection) -> MethodCaller: ... def call(self, *args: Injection, **kwargs: Injection) -> MethodCaller: ...
@property @property
def provides(self) -> Optional[Provider]: ... def provides(self) -> Optional[Provider]: ...
def set_provides( def set_provides(self, provides: Optional[Provider]) -> _Self: ...
self, provides: Optional[Provider]
) -> ProvidedInstanceFluentInterface: ...
class ProvidedInstance(Provider, ProvidedInstanceFluentInterface): class ProvidedInstance(Provider, ProvidedInstanceFluentInterface):
def __init__(self, provides: Optional[Provider] = None) -> None: ... def __init__(self, provides: Optional[Provider] = None) -> None: ...
@ -558,7 +570,7 @@ class AttributeGetter(Provider, ProvidedInstanceFluentInterface):
) -> None: ... ) -> None: ...
@property @property
def name(self) -> Optional[str]: ... def name(self) -> Optional[str]: ...
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ... def set_name(self, name: Optional[str]) -> _Self: ...
class ItemGetter(Provider, ProvidedInstanceFluentInterface): class ItemGetter(Provider, ProvidedInstanceFluentInterface):
def __init__( def __init__(
@ -566,7 +578,7 @@ class ItemGetter(Provider, ProvidedInstanceFluentInterface):
) -> None: ... ) -> None: ...
@property @property
def name(self) -> Optional[str]: ... def name(self) -> Optional[str]: ...
def set_name(self, name: Optional[str]) -> ProvidedInstanceFluentInterface: ... def set_name(self, name: Optional[str]) -> _Self: ...
class MethodCaller(Provider, ProvidedInstanceFluentInterface): class MethodCaller(Provider, ProvidedInstanceFluentInterface):
def __init__( def __init__(

View File

@ -76,8 +76,18 @@ with suppress(ImportError):
MARKER_EXTRACTORS.append(extract_marker_from_fastapi) MARKER_EXTRACTORS.append(extract_marker_from_fastapi)
with suppress(ImportError): with suppress(ImportError): # fast_depends >=3.0.0
from fast_depends.dependencies import Depends as FastDepends from fast_depends.dependencies.model import Dependant as FastDependant # type: ignore[attr-defined]
def extract_marker_from_dependant_fast_depends(param: Any) -> Any:
if isinstance(param, FastDependant):
return param.dependency
return None
MARKER_EXTRACTORS.append(extract_marker_from_dependant_fast_depends)
with suppress(ImportError): # fast_depends <3.0.0
from fast_depends.dependencies import Depends as FastDepends # type: ignore[attr-defined]
def extract_marker_from_fast_depends(param: Any) -> Any: def extract_marker_from_fast_depends(param: Any) -> Any:
if isinstance(param, FastDepends): if isinstance(param, FastDepends):
@ -672,23 +682,18 @@ def _unpatch_attribute(patched: PatchedAttribute) -> None:
def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]: def _extract_marker(parameter: inspect.Parameter) -> Optional["_Marker"]:
if get_origin(parameter.annotation) is Annotated: if get_origin(parameter.annotation) is Annotated:
args = get_args(parameter.annotation) candidates = get_args(parameter.annotation)[1:]
if len(args) > 1:
marker = args[1]
else:
marker = None
else: else:
marker = parameter.default candidates = (parameter.default,)
for marker_extractor in MARKER_EXTRACTORS: for marker in candidates:
if _marker := marker_extractor(marker): for marker_extractor in MARKER_EXTRACTORS:
marker = _marker if _marker := marker_extractor(marker):
break marker = _marker
break
if not isinstance(marker, _Marker): if _is_marker(marker):
return None return marker
return None
return marker
@cache @cache
@ -1213,9 +1218,11 @@ def _get_members_and_annotated(obj: Any) -> Iterable[Tuple[str, Any]]:
for annotation_name, annotation in annotations.items(): for annotation_name, annotation in annotations.items():
if get_origin(annotation) is Annotated: if get_origin(annotation) is Annotated:
args = get_args(annotation) args = get_args(annotation)
if len(args) > 1: # Search through all metadata items (args[1:]) for a DI marker
member = args[1] for arg in args[1:]:
members.append((annotation_name, member)) if _is_marker(arg):
members.append((annotation_name, arg))
break
return members return members

View File

@ -1,4 +1,5 @@
from dependency_injector import providers from dependency_injector import providers
from typing_extensions import assert_type, Any
class Animal: ... class Animal: ...
@ -8,29 +9,35 @@ class Cat(Animal): ...
# Test 1: to check Aggregate provider # Test 1: to check Aggregate provider
provider1: providers.Aggregate[str] = providers.Aggregate( provider1 = providers.Aggregate(
a=providers.Object("str1"), a=providers.Object("str1"),
b=providers.Object("str2"), b=providers.Object("str2"),
) )
provider_a_1: providers.Provider[str] = provider1.a provider_a_1 = provider1.a
provider_b_1: providers.Provider[str] = provider1.b provider_b_1: providers.Provider[str] = provider1.b
val1: str = provider1("a") val1 = provider1("a")
assert_type(provider1, providers.Aggregate[str])
assert_type(provider_a_1, providers.Provider[str])
assert_type(provider_b_1, providers.Provider[str])
assert_type(val1, str)
provider1_set_non_string_keys: providers.Aggregate[str] = providers.Aggregate() provider1_set_non_string_keys = providers.Aggregate[str]()
provider1_set_non_string_keys.set_providers({Cat: providers.Object("str")}) provider1_set_non_string_keys.set_providers({Cat: providers.Object("str")})
provider_set_non_string_1: providers.Provider[str] = ( provider_set_non_string_1 = provider1_set_non_string_keys.providers[Cat]
provider1_set_non_string_keys.providers[Cat] assert_type(provider_set_non_string_1, providers.Provider[str])
)
provider1_new_non_string_keys: providers.Aggregate[str] = providers.Aggregate(
provider1_new_non_string_keys = providers.Aggregate(
{Cat: providers.Object("str")}, {Cat: providers.Object("str")},
) )
factory_new_non_string_1: providers.Provider[str] = ( factory_new_non_string_1 = provider1_new_non_string_keys.providers[Cat]
provider1_new_non_string_keys.providers[Cat] assert_type(provider1_new_non_string_keys, providers.Aggregate[str])
) assert_type(factory_new_non_string_1, providers.Provider[str])
provider1_no_explicit_typing = providers.Aggregate(a=providers.Object("str")) provider1_no_explicit_typing = providers.Aggregate(a=providers.Object("str"))
provider1_no_explicit_typing_factory: providers.Provider[str] = ( provider1_no_explicit_typing_factory = provider1_no_explicit_typing.providers["a"]
provider1_no_explicit_typing.providers["a"] provider1_no_explicit_typing_object = provider1_no_explicit_typing("a")
)
provider1_no_explicit_typing_object: str = provider1_no_explicit_typing("a") assert_type(provider1_no_explicit_typing_factory, providers.Provider[str])
assert_type(provider1_no_explicit_typing_object, str)

View File

@ -1,4 +1,5 @@
from typing import Any, Callable, Dict, Optional, Tuple, Type from typing import Any, Callable, Dict, Optional, Tuple
from typing_extensions import assert_type
from dependency_injector import providers from dependency_injector import providers
@ -7,7 +8,6 @@ class Animal: ...
class Cat(Animal): class Cat(Animal):
@classmethod @classmethod
def create(cls) -> Animal: def create(cls) -> Animal:
return cls() return cls()
@ -15,11 +15,13 @@ class Cat(Animal):
# Test 1: to check the return type (class) # Test 1: to check the return type (class)
provider1 = providers.Callable(Cat) provider1 = providers.Callable(Cat)
animal1: Animal = provider1(1, 2, 3, b="1", c=2, e=0.0) cat1 = provider1(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat1, Cat)
# Test 2: to check the return type (class factory method) # Test 2: to check the return type (class factory method)
provider2 = providers.Callable(Cat.create) provider2 = providers.Callable(Cat.create)
animal2: Animal = provider2() animal2 = provider2()
assert_type(animal2, Animal)
# Test 3: to check the .override() method # Test 3: to check the .override() method
provider3 = providers.Callable(Animal) provider3 = providers.Callable(Animal)
@ -28,24 +30,32 @@ with provider3.override(providers.Callable(Cat)):
# Test 4: to check the .args & .kwargs attributes # Test 4: to check the .args & .kwargs attributes
provider4 = providers.Callable(Animal) provider4 = providers.Callable(Animal)
args4: Tuple[Any] = provider4.args args4 = provider4.args
kwargs4: Dict[str, Any] = provider4.kwargs kwargs4 = provider4.kwargs
assert_type(args4, Tuple[Any])
assert_type(kwargs4, Dict[str, Any])
# Test 5: to check the provided instance interface # Test 5: to check the provided instance interface
provider5 = providers.Callable(Animal) provider5 = providers.Callable(Animal)
provided5: Animal = provider5.provided() provided_val5 = provider5.provided()
attr_getter5: providers.AttributeGetter = provider5.provided.attr attr_getter5 = provider5.provided.attr
item_getter5: providers.ItemGetter = provider5.provided["item"] item_getter5 = provider5.provided["item"]
method_caller: providers.MethodCaller = provider5.provided.method.call(123, arg=324) method_caller5 = provider5.provided.method.call(123, arg=324)
assert_type(provided_val5, Any)
assert_type(attr_getter5, providers.AttributeGetter)
assert_type(item_getter5, providers.ItemGetter)
assert_type(method_caller5, providers.MethodCaller)
# Test 6: to check the DelegatedCallable # Test 6: to check the DelegatedCallable
provider6 = providers.DelegatedCallable(Cat) provider6 = providers.DelegatedCallable(Cat)
animal6: Animal = provider6(1, 2, 3, b="1", c=2, e=0.0) cat6 = provider6(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat6, Cat)
# Test 7: to check the AbstractCallable # Test 7: to check the AbstractCallable
provider7 = providers.AbstractCallable(Animal) provider7 = providers.AbstractCallable(Animal)
provider7.override(providers.Callable(Cat)) provider7.override(providers.Callable(Cat))
animal7: Animal = provider7(1, 2, 3, b="1", c=2, e=0.0) animal7 = provider7(1, 2, 3, b="1", c=2, e=0.0)
assert_type(animal7, Animal)
# Test 8: to check the CallableDelegate __init__ # Test 8: to check the CallableDelegate __init__
provider8 = providers.CallableDelegate(providers.Callable(lambda: None)) provider8 = providers.CallableDelegate(providers.Callable(lambda: None))
@ -55,20 +65,22 @@ provider9 = providers.Callable(Cat)
async def _async9() -> None: async def _async9() -> None:
animal1: Animal = await provider9(1, 2, 3, b="1", c=2, e=0.0) # type: ignore await provider9(1, 2, 3, b="1", c=2, e=0.0) # type: ignore[misc]
animal2: Animal = await provider9.async_(1, 2, 3, b="1", c=2, e=0.0) cat9 = await provider9.async_(1, 2, 3, b="1", c=2, e=0.0)
assert_type(cat9, Cat)
# Test 10: to check the .provides # Test 10: to check the .provides
provider10 = providers.Callable(Cat) provider10 = providers.Callable(Cat)
provides10: Optional[Callable[..., Cat]] = provider10.provides provides10 = provider10.provides
assert provides10 is Cat assert_type(provides10, Optional[Callable[..., Cat]])
# Test 11: to check the .provides for explicit typevar # Test 11: to check the .provides for explicit typevar
provider11 = providers.Callable[Animal](Cat) provider11 = providers.Callable[Animal](Cat)
provides11: Optional[Callable[..., Animal]] = provider11.provides provides11 = provider11.provides
assert provides11 is Cat assert_type(provides11, Optional[Callable[..., Animal]])
# Test 12: to check string imports # Test 12: to check string imports
provider12: providers.Callable[Dict[Any, Any]] = providers.Callable("builtins.dict") provider12 = providers.Callable("builtins.dict")
provider12.set_provides("builtins.dict") provider12.set_provides("builtins.dict")

View File

@ -1,3 +1,4 @@
from contextlib import contextmanager, asynccontextmanager
from typing import ( from typing import (
Any, Any,
AsyncGenerator, AsyncGenerator,
@ -7,6 +8,7 @@ from typing import (
Iterator, Iterator,
List, List,
Optional, Optional,
Self,
) )
from dependency_injector import providers, resources from dependency_injector import providers, resources
@ -109,3 +111,62 @@ async def _provide8() -> None:
# Test 9: to check string imports # Test 9: to check string imports
provider9: providers.Resource[Dict[Any, Any]] = providers.Resource("builtins.dict") provider9: providers.Resource[Dict[Any, Any]] = providers.Resource("builtins.dict")
provider9.set_provides("builtins.dict") provider9.set_provides("builtins.dict")
# Test 10: to check the return type with classes implementing AbstractContextManager protocol
class MyResource10:
def __init__(self) -> None:
pass
def __enter__(self) -> Self:
return self
def __exit__(self, *args: Any, **kwargs: Any) -> None:
return None
provider10 = providers.Resource(MyResource10)
var10: MyResource10 = provider10()
# Test 11: to check the return type with functions decorated with contextlib.contextmanager
@contextmanager
def init11() -> Iterator[int]:
yield 1
provider11 = providers.Resource(init11)
var11: int = provider11()
# Test 12: to check the return type with classes implementing AbstractAsyncContextManager protocol
class MyResource12:
def __init__(self) -> None:
pass
async def __aenter__(self) -> Self:
return self
async def __aexit__(self, *args: Any, **kwargs: Any) -> None:
return None
provider12 = providers.Resource(MyResource12)
async def _provide12() -> None:
var1: MyResource12 = await provider12() # type: ignore
var2: MyResource12 = await provider12.async_()
# Test 13: to check the return type with functions decorated with contextlib.asynccontextmanager
@asynccontextmanager
async def init13() -> AsyncIterator[int]:
yield 1
provider13 = providers.Resource(init13)
async def _provide13() -> None:
var1: int = await provider13() # type: ignore
var2: int = await provider13.async_()

View File

@ -1,4 +1,4 @@
from typing import Any from typing import Any, Callable, Optional, Dict
from dependency_injector import providers from dependency_injector import providers
@ -40,3 +40,36 @@ provider4 = providers.Selector(
async def _async4() -> None: async def _async4() -> None:
var1: Any = await provider4() var1: Any = await provider4()
var2: Any = await provider4.async_() var2: Any = await provider4.async_()
# Test 5: to check selector getter and setter
provider5 = providers.Selector(
lambda: "a",
a=providers.Factory(object),
b=providers.Factory(object),
)
selector5: Optional[Callable[..., Any]] = provider5.selector
provider5_after_set_selector: providers.Selector[Any] = provider5.set_selector(lambda: "a")
# Test 6: to check providers getter and setter
provider6 = providers.Selector(
lambda: "a",
a=providers.Factory(object),
b=providers.Factory(object),
)
providers6: Dict[str, providers.Provider[Any]] = provider6.providers
provider6_after_set_providers: providers.Selector[Any] = provider6.set_providers(c=providers.Factory(object))
# Test 7: to check explicit typing: return type, getattr, getter/setter of providers and selectors
provider7 = providers.Selector[bool](lambda: "a", a=providers.Factory(bool), b=providers.Factory(int))
var7: bool = provider7()
attr7: providers.Provider[bool] = provider7.a
selector7: Optional[Callable[..., Any]] = provider7.selector
provider7_after_set_selector: providers.Selector[bool] = provider7.set_selector(lambda: "a")
providers7: Dict[str, providers.Provider[bool]] = provider7.providers
provider7_after_set_providers: providers.Selector[bool] = provider7.set_providers(
c=providers.Factory(str)
) # We don't require Provider of subclass of bool yet since Provider is invariant

View File

@ -124,3 +124,10 @@ def test_class_decorator(service: Annotated[Service, Provide[Container.service]]
def test_container(container: Annotated[Container, Provide[Container]]): def test_container(container: Annotated[Container, Provide[Container]]):
return container.service() return container.service()
@inject
def test_annotated_with_non_di_metadata_first(
service: Annotated[Service, "some other annotated value", Provide[Container.service]],
):
return service

View File

@ -174,3 +174,14 @@ def test_class_decorator():
def test_container(): def test_container():
service = module.test_container() service = module.test_container()
assert isinstance(service, Service) assert isinstance(service, Service)
def test_annotated_with_non_di_metadata_first():
"""Test that Annotated works when DI marker is not the first metadata item.
This tests the case where Annotated has other metadata (like docstrings or
other annotations) before the Provide marker, e.g.:
Annotated[Service, "some doc", Provide[Container.service]]
"""
service = module.test_annotated_with_non_di_metadata_first()
assert isinstance(service, Service)