From d570585d09ed27c7274d576660fa4f8ca4d693f5 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 29 Jun 2024 13:39:45 +0300 Subject: [PATCH 1/2] Use `Self` type for `Container` --- rodi/__init__.py | 87 +++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/rodi/__init__.py b/rodi/__init__.py index d5f72b7..c2c3044 100644 --- a/rodi/__init__.py +++ b/rodi/__init__.py @@ -10,6 +10,7 @@ Callable, ClassVar, DefaultDict, + Iterator, Mapping, Protocol, Type, @@ -46,8 +47,8 @@ def __contains__(self, item) -> bool: def inject( - globalsns: Optional[Dict[str, Any]] = None, - localns: Optional[Dict[str, Any]] = None, + globalsns: dict[str, Any] | None = None, + localns: dict[str, Any] | None = None, ) -> Callable[[T], T]: """ Marks a class or a function as injected. This method is only necessary if the class @@ -860,6 +861,9 @@ def __call__(self, context, activating_type): return self.factory(context) +_ContainerSelf = TypeVar("_ContainerSelf", bound="Container") + + class Container(ContainerProtocol): """ Configuration class for a collection of services. @@ -872,7 +876,7 @@ def __init__( *, strict: bool = False, scope_cls: Type[ActivationScope] | None = None, - ): + ) -> None: self._map: dict[Type, Callable] = {} self._aliases: DefaultDict[str, set[Type]] = defaultdict(set) self._exact_aliases: dict[str, Type] = {} @@ -886,18 +890,18 @@ def provider(self) -> Services: self._provider = self.build_provider() return self._provider - def __iter__(self): + def __iter__(self) -> Iterator[tuple[Type, Callable]]: yield from self._map.items() - def __contains__(self, key): + def __contains__(self, key: object) -> bool: return key in self._map def bind_types( - self, + self: _ContainerSelf, obj_type: Any, concrete_type: Any = None, life_style: ServiceLifeStyle = ServiceLifeStyle.TRANSIENT, - ): + ) -> _ContainerSelf: try: assert issubclass(concrete_type, obj_type), ( f"Cannot register {class_name(obj_type)} for abstract class " @@ -910,13 +914,13 @@ def bind_types( return self def register( - self, + self: _ContainerSelf, obj_type: Any, sub_type: Any = None, instance: Any = None, *args, **kwargs, - ) -> "Container": + ) -> _ContainerSelf: """ Registers a type in this container. """ @@ -942,7 +946,11 @@ def resolve( """ return self.provider.get(obj_type, scope=scope) - def add_alias(self, name: str, desired_type: Type): + def add_alias( + self: _ContainerSelf, + name: str, + desired_type: Type, + ) -> _ContainerSelf: """ Adds an alias to the set of inferred aliases. @@ -957,7 +965,7 @@ def add_alias(self, name: str, desired_type: Type): self._aliases[name].add(desired_type) return self - def add_aliases(self, values: AliasesTypeHint): + def add_aliases(self: _ContainerSelf, values: AliasesTypeHint) -> _ContainerSelf: """ Adds aliases to the set of inferred aliases. @@ -968,7 +976,12 @@ def add_aliases(self, values: AliasesTypeHint): self.add_alias(key, value) return self - def set_alias(self, name: str, desired_type: Type, override: bool = False): + def set_alias( + self: _ContainerSelf, + name: str, + desired_type: Type, + override: bool = False, + ) -> _ContainerSelf: """ Sets an exact alias for a desired type. @@ -984,7 +997,11 @@ def set_alias(self, name: str, desired_type: Type, override: bool = False): self._exact_aliases[name] = desired_type return self - def set_aliases(self, values: AliasesTypeHint, override: bool = False): + def set_aliases( + self: _ContainerSelf, + values: AliasesTypeHint, + override: bool = False, + ) -> _ContainerSelf: """Sets many exact aliases for desired types. :param values: mapping object (parameter name: class) @@ -1013,8 +1030,8 @@ def _bind(self, key: Type, value: Any) -> None: self._aliases[to_standard_param_name(key_name)].add(key) def add_instance( - self, instance: Any, declared_class: Type | None = None - ) -> "Container": + self: _ContainerSelf, instance: Any, declared_class: Type | None = None + ) -> _ContainerSelf: """ Registers an exact instance, optionally by declared class. @@ -1030,8 +1047,8 @@ def add_instance( return self def add_singleton( - self, base_type: Type, concrete_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, base_type: Type, concrete_type: Type | None = None + ) -> _ContainerSelf: """ Registers a type by base type, to be instantiated with singleton lifetime. If a single type is given, the method `add_exact_singleton` is used. @@ -1047,8 +1064,10 @@ def add_singleton( return self.bind_types(base_type, concrete_type, ServiceLifeStyle.SINGLETON) def add_scoped( - self, base_type: Type, concrete_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, + base_type: Type, + concrete_type: Type | None = None, + ) -> _ContainerSelf: """ Registers a type by base type, to be instantiated with scoped lifetime. If a single type is given, the method `add_exact_scoped` is used. @@ -1064,8 +1083,10 @@ def add_scoped( return self.bind_types(base_type, concrete_type, ServiceLifeStyle.SCOPED) def add_transient( - self, base_type: Type, concrete_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, + base_type: Type, + concrete_type: Type | None = None, + ) -> _ContainerSelf: """ Registers a type by base type, to be instantiated with transient lifetime. If a single type is given, the method `add_exact_transient` is used. @@ -1080,7 +1101,7 @@ def add_transient( return self.bind_types(base_type, concrete_type, ServiceLifeStyle.TRANSIENT) - def _add_exact_singleton(self, concrete_type: Type) -> "Container": + def _add_exact_singleton(self: _ContainerSelf, concrete_type: Type) -> _ContainerSelf: """ Registers an exact type, to be instantiated with singleton lifetime. @@ -1094,7 +1115,7 @@ def _add_exact_singleton(self, concrete_type: Type) -> "Container": ) return self - def _add_exact_scoped(self, concrete_type: Type) -> "Container": + def _add_exact_scoped(self: _ContainerSelf, concrete_type: Type) -> _ContainerSelf: """ Registers an exact type, to be instantiated with scoped lifetime. @@ -1107,7 +1128,7 @@ def _add_exact_scoped(self, concrete_type: Type) -> "Container": ) return self - def _add_exact_transient(self, concrete_type: Type) -> "Container": + def _add_exact_transient(self: _ContainerSelf, concrete_type: Type) -> _ContainerSelf: """ Registers an exact type, to be instantiated with transient lifetime. @@ -1122,20 +1143,26 @@ def _add_exact_transient(self, concrete_type: Type) -> "Container": return self def add_singleton_by_factory( - self, factory: FactoryCallableType, return_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, + factory: FactoryCallableType, + return_type: Type | None = None, + ) -> _ContainerSelf: self.register_factory(factory, return_type, ServiceLifeStyle.SINGLETON) return self def add_transient_by_factory( - self, factory: FactoryCallableType, return_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, + factory: FactoryCallableType, + return_type: Type | None = None, + ) -> _ContainerSelf: self.register_factory(factory, return_type, ServiceLifeStyle.TRANSIENT) return self def add_scoped_by_factory( - self, factory: FactoryCallableType, return_type: Type | None = None - ) -> "Container": + self: _ContainerSelf, + factory: FactoryCallableType, + return_type: Type | None = None, + ) -> _ContainerSelf: self.register_factory(factory, return_type, ServiceLifeStyle.SCOPED) return self From 21f257d0f6313fe17406e044d6511f028caa98da Mon Sep 17 00:00:00 2001 From: Roberto Prevato Date: Sun, 8 Mar 2026 11:46:35 +0100 Subject: [PATCH 2/2] Fix typos and formatting --- rodi/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rodi/__init__.py b/rodi/__init__.py index c2c3044..622b48e 100644 --- a/rodi/__init__.py +++ b/rodi/__init__.py @@ -1101,7 +1101,9 @@ def add_transient( return self.bind_types(base_type, concrete_type, ServiceLifeStyle.TRANSIENT) - def _add_exact_singleton(self: _ContainerSelf, concrete_type: Type) -> _ContainerSelf: + def _add_exact_singleton( + self: _ContainerSelf, concrete_type: Type + ) -> _ContainerSelf: """ Registers an exact type, to be instantiated with singleton lifetime. @@ -1128,7 +1130,9 @@ def _add_exact_scoped(self: _ContainerSelf, concrete_type: Type) -> _ContainerSe ) return self - def _add_exact_transient(self: _ContainerSelf, concrete_type: Type) -> _ContainerSelf: + def _add_exact_transient( + self: _ContainerSelf, concrete_type: Type + ) -> _ContainerSelf: """ Registers an exact type, to be instantiated with transient lifetime.