From 11042c7db725d96eded9ad2aa7305b407d830127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 09:22:32 +0000 Subject: [PATCH 01/10] add tests, format test file --- injector_test.py | 74 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/injector_test.py b/injector_test.py index 6260033..8e1ddbc 100644 --- a/injector_test.py +++ b/injector_test.py @@ -10,14 +10,14 @@ """Functional tests for the "Injector" dependency injection framework.""" -from contextlib import contextmanager -from dataclasses import dataclass -from typing import Any, NewType, Optional, Union import abc import sys import threading import traceback import warnings +from contextlib import contextmanager +from dataclasses import dataclass +from typing import Any, NewType, Optional, Union if sys.version_info >= (3, 9): from typing import Annotated @@ -29,32 +29,32 @@ import pytest from injector import ( + AssistedBuilder, Binder, CallError, + CircularDependency, + ClassAssistedBuilder, + ClassProvider, + Error, Inject, Injector, + InstanceProvider, + InvalidInterface, + Module, NoInject, + ProviderOf, Scope, - InstanceProvider, - ClassProvider, + ScopeDecorator, + SingletonScope, + UnknownArgument, + UnsatisfiedRequirement, get_bindings, inject, multiprovider, noninjectable, + provider, singleton, threadlocal, - UnsatisfiedRequirement, - CircularDependency, - Module, - SingletonScope, - ScopeDecorator, - AssistedBuilder, - provider, - ProviderOf, - ClassAssistedBuilder, - Error, - UnknownArgument, - InvalidInterface, ) @@ -723,6 +723,46 @@ def configure_dict(binder: Binder): Injector([configure_dict]) +def test_multibind_types_respect_the_bound_type_scope() -> None: + def configure(binder: Binder) -> None: + binder.bind(PluginA, to=PluginA, scope=singleton) + binder.multibind(List[Plugin], to=PluginA) + + injector = Injector([configure]) + first_list = injector.get(List[Plugin]) + second_list = injector.get(List[Plugin]) + + assert first_list[0] is second_list[0] + + +def test_multibind_scopes_applies_to_the_bound_items() -> None: + def configure(binder: Binder) -> None: + binder.multibind(List[Plugin], to=PluginA, scope=singleton) + binder.multibind(List[Plugin], to=PluginB) + binder.multibind(List[Plugin], to=PluginC, scope=singleton) + + injector = Injector([configure]) + first_list = injector.get(List[Plugin]) + second_list = injector.get(List[Plugin]) + + assert first_list is not second_list + assert first_list[0] is second_list[0] + assert first_list[1] is not second_list[1] + assert first_list[2] is second_list[2] + + +def test_multibind_scopes_does_not_apply_to_the_type_globally() -> None: + def configure(binder: Binder) -> None: + binder.multibind(List[Plugin], to=PluginA, scope=singleton) + + injector = Injector([configure]) + plugins = injector.get(List[Plugin]) + + assert plugins[0] is not injector.get(PluginA) + assert plugins[0] is not injector.get(Plugin) + assert injector.get(PluginA) is not injector.get(PluginA) + + def test_regular_bind_and_provider_dont_work_with_multibind(): # We only want multibind and multiprovider to work to avoid confusion From bdbf66ce9516a2a31095a1fd48f60d1182b6ceae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 21:59:47 +0000 Subject: [PATCH 02/10] Slightly tweak one test --- injector_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/injector_test.py b/injector_test.py index 8e1ddbc..0a39c92 100644 --- a/injector_test.py +++ b/injector_test.py @@ -739,7 +739,7 @@ def test_multibind_scopes_applies_to_the_bound_items() -> None: def configure(binder: Binder) -> None: binder.multibind(List[Plugin], to=PluginA, scope=singleton) binder.multibind(List[Plugin], to=PluginB) - binder.multibind(List[Plugin], to=PluginC, scope=singleton) + binder.multibind(List[Plugin], to=[PluginC], scope=singleton) injector = Injector([configure]) first_list = injector.get(List[Plugin]) From 1032e805fc997046ae8a5f5947748438688171af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 22:02:06 +0000 Subject: [PATCH 03/10] Get scopes working for list binder --- injector/__init__.py | 74 ++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index 9b52729..6d11cb7 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -22,24 +22,24 @@ import threading import types from abc import ABCMeta, abstractmethod -from collections import namedtuple +from dataclasses import dataclass from typing import ( + TYPE_CHECKING, Any, Callable, - cast, Dict, Generic, - get_args, Iterable, List, Optional, - overload, Set, Tuple, Type, TypeVar, - TYPE_CHECKING, Union, + cast, + get_args, + overload, ) try: @@ -52,13 +52,13 @@ # canonical. Since this typing_extensions import is only for mypy it'll work even without # typing_extensions actually installed so all's good. if TYPE_CHECKING: - from typing_extensions import _AnnotatedAlias, Annotated, get_type_hints + from typing_extensions import Annotated, _AnnotatedAlias, get_type_hints else: # Ignoring errors here as typing_extensions stub doesn't know about those things yet try: - from typing import _AnnotatedAlias, Annotated, get_type_hints + from typing import Annotated, _AnnotatedAlias, get_type_hints except ImportError: - from typing_extensions import _AnnotatedAlias, Annotated, get_type_hints + from typing_extensions import Annotated, _AnnotatedAlias, get_type_hints __author__ = 'Alec Thomas ' @@ -343,16 +343,19 @@ def __repr__(self) -> str: class ListOfProviders(Provider, Generic[T]): """Provide a list of instances via other Providers.""" - _providers: List[Provider[T]] + _multi_bindings: List['Binding'] - def __init__(self) -> None: - self._providers = [] + def __init__(self, parent: 'Binder') -> None: + self._multi_bindings = [] + self._binder = Binder(parent.injector, auto_bind=False, parent=parent) - def append(self, provider: Provider[T]) -> None: - self._providers.append(provider) + def append(self, provider: Provider[T], scope: Type['Scope']) -> None: + # HACK: generate a pseudo-type for this element in the list + pseudo_type = type(f"pseudo-type-{id(provider)}", (provider.__class__,), {}) + self._multi_bindings.append(Binding(pseudo_type, provider, scope)) def __repr__(self) -> str: - return '%s(%r)' % (type(self).__name__, self._providers) + return '%s(%r)' % (type(self).__name__, self._multi_bindings) class MultiBindProvider(ListOfProviders[List[T]]): @@ -361,8 +364,11 @@ class MultiBindProvider(ListOfProviders[List[T]]): def get(self, injector: 'Injector') -> List[T]: result: List[T] = [] - for provider in self._providers: - instances: List[T] = _ensure_iterable(provider.get(injector)) + for binding in self._multi_bindings: + scope_binding, _ = self._binder.get_binding(binding.scope) + scope_instance: Scope = scope_binding.provider.get(injector) + provider_instance = scope_instance.get(binding.interface, binding.provider) + instances: List[T] = _ensure_iterable(provider_instance.get(injector)) result.extend(instances) return result @@ -372,8 +378,9 @@ class MapBindProvider(ListOfProviders[Dict[str, T]]): def get(self, injector: 'Injector') -> Dict[str, T]: map: Dict[str, T] = {} - for provider in self._providers: - map.update(provider.get(injector)) + for binding in self._multi_bindings: + # TODO: support scope + map.update(binding.provider.get(injector)) return map @@ -387,7 +394,11 @@ def get(self, injector: 'Injector') -> Dict[str, T]: return {self._key: self._provider.get(injector)} -_BindingBase = namedtuple('_BindingBase', 'interface provider scope') +@dataclass +class _BindingBase: + interface: type + provider: Provider + scope: Type['Scope'] @private @@ -539,15 +550,15 @@ def multibind( and issubclass(interface, dict) or _get_origin(_punch_through_alias(interface)) is dict ): - provider = MapBindProvider() + provider = MapBindProvider(self) else: - provider = MultiBindProvider() - binding = self.create_binding(interface, provider, scope) + provider = MultiBindProvider(self) + binding = self.create_binding(interface, provider) self._bindings[interface] = binding else: binding = self._bindings[interface] + assert isinstance(binding.provider, ListOfProviders) provider = binding.provider - assert isinstance(provider, ListOfProviders) if isinstance(provider, MultiBindProvider) and isinstance(to, list): try: @@ -557,7 +568,8 @@ def multibind( f"Use typing.List[T] or list[T] to specify the element type of the list" ) for element in to: - provider.append(self.provider_for(element_type, element)) + element_binding = self.create_binding(element_type, element, scope) + provider.append(element_binding.provider, element_binding.scope) elif isinstance(provider, MapBindProvider) and isinstance(to, dict): try: value_type = get_args(_punch_through_alias(interface))[1] @@ -566,9 +578,11 @@ def multibind( f"Use typing.Dict[K, V] or dict[K, V] to specify the value type of the dict" ) for key, value in to.items(): - provider.append(KeyValueProvider(key, self.provider_for(value_type, value))) + element_binding = self.create_binding(value_type, value, scope) + provider.append(KeyValueProvider(key, element_binding.provider), element_binding.scope) else: - provider.append(self.provider_for(interface, to)) + element_binding = self.create_binding(interface, to, scope) + provider.append(element_binding.provider, element_binding.scope) def install(self, module: _InstallableModuleType) -> None: """Install a module into this binder. @@ -611,10 +625,10 @@ def create_binding( self, interface: type, to: Any = None, scope: Union['ScopeDecorator', Type['Scope'], None] = None ) -> Binding: provider = self.provider_for(interface, to) - scope = scope or getattr(to or interface, '__scope__', NoScope) + scope = scope or getattr(to or interface, '__scope__', None) if isinstance(scope, ScopeDecorator): scope = scope.scope - return Binding(interface, provider, scope) + return Binding(interface, provider, scope or NoScope) def provider_for(self, interface: Any, to: Any = None) -> Provider: base_type = _punch_through_alias(interface) @@ -696,7 +710,7 @@ def get_binding(self, interface: type) -> Tuple[Binding, 'Binder']: # The special interface is added here so that requesting a special # interface with auto_bind disabled works if self._auto_bind or self._is_special_interface(interface): - binding = ImplicitBinding(*self.create_binding(interface)) + binding = ImplicitBinding(**self.create_binding(interface).__dict__) self._bindings[interface] = binding return binding, self @@ -817,7 +831,7 @@ def __repr__(self) -> str: class NoScope(Scope): """An unscoped provider.""" - def get(self, unused_key: Type[T], provider: Provider[T]) -> Provider[T]: + def get(self, key: Type[T], provider: Provider[T]) -> Provider[T]: return provider From efc62e174604036fe8aca8ada587f8089cf6d1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 22:42:31 +0000 Subject: [PATCH 04/10] Defer to parent binder if it has an explicit binding --- injector/__init__.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index 6d11cb7..e296da8 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -365,10 +365,19 @@ class MultiBindProvider(ListOfProviders[List[T]]): def get(self, injector: 'Injector') -> List[T]: result: List[T] = [] for binding in self._multi_bindings: - scope_binding, _ = self._binder.get_binding(binding.scope) + if ( + isinstance(binding.provider, ClassProvider) + and binding.scope is NoScope + and self._binder.parent + and self._binder.parent.has_explicit_binding_for(binding.provider._cls) + ): + parent_binding, _ = self._binder.parent.get_binding(binding.provider._cls) + scope_binding, _ = self._binder.parent.get_binding(parent_binding.scope) + else: + scope_binding, _ = self._binder.get_binding(binding.scope) scope_instance: Scope = scope_binding.provider.get(injector) provider_instance = scope_instance.get(binding.interface, binding.provider) - instances: List[T] = _ensure_iterable(provider_instance.get(injector)) + instances = _ensure_iterable(provider_instance.get(injector)) result.extend(instances) return result From 4d57f119ff82f2dc67861755d21547a3f8f24404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 22:53:02 +0000 Subject: [PATCH 05/10] Make test a bit harder --- injector_test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/injector_test.py b/injector_test.py index 0a39c92..47a646c 100644 --- a/injector_test.py +++ b/injector_test.py @@ -731,8 +731,11 @@ def configure(binder: Binder) -> None: injector = Injector([configure]) first_list = injector.get(List[Plugin]) second_list = injector.get(List[Plugin]) + child_injector = injector.create_child_injector() + third_list = child_injector.get(List[Plugin]) assert first_list[0] is second_list[0] + assert third_list[0] is second_list[0] def test_multibind_scopes_applies_to_the_bound_items() -> None: From b4d9fcb504205e694e9b68724c77624294b8b463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 23:11:42 +0000 Subject: [PATCH 06/10] add scope support to dicts --- injector/__init__.py | 40 ++++++++++++++++++++++------------------ injector_test.py | 16 ++++++++++++++++ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index e296da8..cef3689 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -28,6 +28,7 @@ Any, Callable, Dict, + Generator, Generic, Iterable, List, @@ -340,7 +341,7 @@ def __repr__(self) -> str: @private -class ListOfProviders(Provider, Generic[T]): +class Multibinder(Provider, Generic[T]): """Provide a list of instances via other Providers.""" _multi_bindings: List['Binding'] @@ -354,16 +355,7 @@ def append(self, provider: Provider[T], scope: Type['Scope']) -> None: pseudo_type = type(f"pseudo-type-{id(provider)}", (provider.__class__,), {}) self._multi_bindings.append(Binding(pseudo_type, provider, scope)) - def __repr__(self) -> str: - return '%s(%r)' % (type(self).__name__, self._multi_bindings) - - -class MultiBindProvider(ListOfProviders[List[T]]): - """Used by :meth:`Binder.multibind` to flatten results of providers that - return sequences.""" - - def get(self, injector: 'Injector') -> List[T]: - result: List[T] = [] + def get_scoped_providers(self, injector: 'Injector') -> Generator[Provider[T], None, None]: for binding in self._multi_bindings: if ( isinstance(binding.provider, ClassProvider) @@ -377,19 +369,31 @@ def get(self, injector: 'Injector') -> List[T]: scope_binding, _ = self._binder.get_binding(binding.scope) scope_instance: Scope = scope_binding.provider.get(injector) provider_instance = scope_instance.get(binding.interface, binding.provider) - instances = _ensure_iterable(provider_instance.get(injector)) + yield provider_instance + + def __repr__(self) -> str: + return '%s(%r)' % (type(self).__name__, self._multi_bindings) + + +class MultiBindProvider(Multibinder[List[T]]): + """Used by :meth:`Binder.multibind` to flatten results of providers that + return sequences.""" + + def get(self, injector: 'Injector') -> List[T]: + result: List[T] = [] + for provider in self.get_scoped_providers(injector): + instances: List[T] = _ensure_iterable(provider.get(injector)) result.extend(instances) return result -class MapBindProvider(ListOfProviders[Dict[str, T]]): +class MapBindProvider(Multibinder[Dict[str, T]]): """A provider for map bindings.""" def get(self, injector: 'Injector') -> Dict[str, T]: map: Dict[str, T] = {} - for binding in self._multi_bindings: - # TODO: support scope - map.update(binding.provider.get(injector)) + for provider in self.get_scoped_providers(injector): + map.update(provider.get(injector)) return map @@ -552,7 +556,7 @@ def multibind( :param scope: Optional Scope in which to bind. """ if interface not in self._bindings: - provider: ListOfProviders + provider: Multibinder if ( isinstance(interface, dict) or isinstance(interface, type) @@ -566,7 +570,7 @@ def multibind( self._bindings[interface] = binding else: binding = self._bindings[interface] - assert isinstance(binding.provider, ListOfProviders) + assert isinstance(binding.provider, Multibinder) provider = binding.provider if isinstance(provider, MultiBindProvider) and isinstance(to, list): diff --git a/injector_test.py b/injector_test.py index 47a646c..0bb2c25 100644 --- a/injector_test.py +++ b/injector_test.py @@ -754,6 +754,22 @@ def configure(binder: Binder) -> None: assert first_list[2] is second_list[2] +def test_multibind_dict_scopes_applies_to_the_bound_items() -> None: + def configure(binder: Binder) -> None: + binder.multibind(Dict[str, Plugin], to={'a': PluginA}, scope=singleton) + binder.multibind(Dict[str, Plugin], to={'b': PluginB}) + binder.multibind(Dict[str, Plugin], to={'c': PluginC}, scope=singleton) + + injector = Injector([configure]) + first_dict = injector.get(Dict[str, Plugin]) + second_dict = injector.get(Dict[str, Plugin]) + + assert first_dict is not second_dict + assert first_dict['a'] is second_dict['a'] + assert first_dict['b'] is not second_dict['b'] + assert first_dict['c'] is second_dict['c'] + + def test_multibind_scopes_does_not_apply_to_the_type_globally() -> None: def configure(binder: Binder) -> None: binder.multibind(List[Plugin], to=PluginA, scope=singleton) From 37e071e0f8a42af83e2e05984ad3076f27379645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Sun, 12 Oct 2025 23:12:49 +0000 Subject: [PATCH 07/10] rename test --- injector_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/injector_test.py b/injector_test.py index 0bb2c25..9df43eb 100644 --- a/injector_test.py +++ b/injector_test.py @@ -738,7 +738,7 @@ def configure(binder: Binder) -> None: assert third_list[0] is second_list[0] -def test_multibind_scopes_applies_to_the_bound_items() -> None: +def test_multibind_list_scopes_applies_to_the_bound_items() -> None: def configure(binder: Binder) -> None: binder.multibind(List[Plugin], to=PluginA, scope=singleton) binder.multibind(List[Plugin], to=PluginB) From 11b52e2f0d7f3232914a0530ac63bdb46989660e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Mon, 13 Oct 2025 22:35:30 +0000 Subject: [PATCH 08/10] Add more information to a comment --- injector/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index cef3689..b2f06e4 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -351,8 +351,10 @@ def __init__(self, parent: 'Binder') -> None: self._binder = Binder(parent.injector, auto_bind=False, parent=parent) def append(self, provider: Provider[T], scope: Type['Scope']) -> None: - # HACK: generate a pseudo-type for this element in the list - pseudo_type = type(f"pseudo-type-{id(provider)}", (provider.__class__,), {}) + # HACK: generate a pseudo-type for this element in the list. + # This is needed for scopes to work properly. Some, like the Singleton scope, + # key instances by type, so we need one that is unique to this binding. + pseudo_type = type(f"multibind-type-{id(provider)}", (provider.__class__,), {}) self._multi_bindings.append(Binding(pseudo_type, provider, scope)) def get_scoped_providers(self, injector: 'Injector') -> Generator[Provider[T], None, None]: From 2d45015c394947d9a7f2350f0bd01e150d5da38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Mon, 13 Oct 2025 22:49:07 +0000 Subject: [PATCH 09/10] Extract method --- injector/__init__.py | 56 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index b2f06e4..2c4661e 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -341,7 +341,7 @@ def __repr__(self) -> str: @private -class Multibinder(Provider, Generic[T]): +class MultiBinder(Provider, Generic[T]): """Provide a list of instances via other Providers.""" _multi_bindings: List['Binding'] @@ -377,7 +377,7 @@ def __repr__(self) -> str: return '%s(%r)' % (type(self).__name__, self._multi_bindings) -class MultiBindProvider(Multibinder[List[T]]): +class MultiBindProvider(MultiBinder[List[T]]): """Used by :meth:`Binder.multibind` to flatten results of providers that return sequences.""" @@ -389,7 +389,7 @@ def get(self, injector: 'Injector') -> List[T]: return result -class MapBindProvider(Multibinder[Dict[str, T]]): +class MapBindProvider(MultiBinder[Dict[str, T]]): """A provider for map bindings.""" def get(self, injector: 'Injector') -> Dict[str, T]: @@ -557,25 +557,8 @@ def multibind( :param scope: Optional Scope in which to bind. """ - if interface not in self._bindings: - provider: Multibinder - if ( - isinstance(interface, dict) - or isinstance(interface, type) - and issubclass(interface, dict) - or _get_origin(_punch_through_alias(interface)) is dict - ): - provider = MapBindProvider(self) - else: - provider = MultiBindProvider(self) - binding = self.create_binding(interface, provider) - self._bindings[interface] = binding - else: - binding = self._bindings[interface] - assert isinstance(binding.provider, Multibinder) - provider = binding.provider - - if isinstance(provider, MultiBindProvider) and isinstance(to, list): + multi_binder = self._get_multi_binder(interface) + if isinstance(multi_binder, MultiBindProvider) and isinstance(to, list): try: element_type = get_args(_punch_through_alias(interface))[0] except IndexError: @@ -584,8 +567,8 @@ def multibind( ) for element in to: element_binding = self.create_binding(element_type, element, scope) - provider.append(element_binding.provider, element_binding.scope) - elif isinstance(provider, MapBindProvider) and isinstance(to, dict): + multi_binder.append(element_binding.provider, element_binding.scope) + elif isinstance(multi_binder, MapBindProvider) and isinstance(to, dict): try: value_type = get_args(_punch_through_alias(interface))[1] except IndexError: @@ -594,10 +577,31 @@ def multibind( ) for key, value in to.items(): element_binding = self.create_binding(value_type, value, scope) - provider.append(KeyValueProvider(key, element_binding.provider), element_binding.scope) + multi_binder.append(KeyValueProvider(key, element_binding.provider), element_binding.scope) else: element_binding = self.create_binding(interface, to, scope) - provider.append(element_binding.provider, element_binding.scope) + multi_binder.append(element_binding.provider, element_binding.scope) + + def _get_multi_binder(self, interface: type) -> MultiBinder: + multi_binder: MultiBinder + if interface not in self._bindings: + if ( + isinstance(interface, dict) + or isinstance(interface, type) + and issubclass(interface, dict) + or _get_origin(_punch_through_alias(interface)) is dict + ): + multi_binder = MapBindProvider(self) + else: + multi_binder = MultiBindProvider(self) + binding = self.create_binding(interface, multi_binder) + self._bindings[interface] = binding + else: + binding = self._bindings[interface] + assert isinstance(binding.provider, MultiBinder) + multi_binder = binding.provider + + return multi_binder def install(self, module: _InstallableModuleType) -> None: """Install a module into this binder. From 9faa32a32f591802b4d8e93e7f5acb8489eb360e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eir=C3=ADkur=20Torfason?= Date: Mon, 13 Oct 2025 22:52:39 +0000 Subject: [PATCH 10/10] format --- injector/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/injector/__init__.py b/injector/__init__.py index 2c4661e..d231ff3 100644 --- a/injector/__init__.py +++ b/injector/__init__.py @@ -352,7 +352,7 @@ def __init__(self, parent: 'Binder') -> None: def append(self, provider: Provider[T], scope: Type['Scope']) -> None: # HACK: generate a pseudo-type for this element in the list. - # This is needed for scopes to work properly. Some, like the Singleton scope, + # This is needed for scopes to work properly. Some, like the Singleton scope, # key instances by type, so we need one that is unique to this binding. pseudo_type = type(f"multibind-type-{id(provider)}", (provider.__class__,), {}) self._multi_bindings.append(Binding(pseudo_type, provider, scope)) @@ -581,7 +581,7 @@ def multibind( else: element_binding = self.create_binding(interface, to, scope) multi_binder.append(element_binding.provider, element_binding.scope) - + def _get_multi_binder(self, interface: type) -> MultiBinder: multi_binder: MultiBinder if interface not in self._bindings: @@ -600,7 +600,7 @@ def _get_multi_binder(self, interface: type) -> MultiBinder: binding = self._bindings[interface] assert isinstance(binding.provider, MultiBinder) multi_binder = binding.provider - + return multi_binder def install(self, module: _InstallableModuleType) -> None: