Skip to content

Commit 0d95c51

Browse files
authored
Merge pull request #293 from python-injector/refactor-polymorphism
refactor: Polymorphism instead of inspection
2 parents 3229e0d + fc84c46 commit 0d95c51

File tree

1 file changed

+41
-23
lines changed

1 file changed

+41
-23
lines changed

injector/__init__.py

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,20 @@ def __repr__(self) -> str:
344344
class MultiBinder(Provider, Generic[T]):
345345
"""Provide a list of instances via other Providers."""
346346

347+
__metaclass__ = ABCMeta
348+
347349
_multi_bindings: List['Binding']
348350

349351
def __init__(self, parent: 'Binder') -> None:
350352
self._multi_bindings = []
351353
self._binder = Binder(parent.injector, auto_bind=False, parent=parent)
352354

355+
@abstractmethod
356+
def multibind(
357+
self, interface: type, to: Any, scope: Union['ScopeDecorator', Type['Scope'], None]
358+
) -> None:
359+
raise NotImplementedError
360+
353361
def append(self, provider: Provider[T], scope: Type['Scope']) -> None:
354362
# HACK: generate a pseudo-type for this element in the list.
355363
# This is needed for scopes to work properly. Some, like the Singleton scope,
@@ -372,6 +380,21 @@ class MultiBindProvider(MultiBinder[List[T]]):
372380
"""Used by :meth:`Binder.multibind` to flatten results of providers that
373381
return sequences."""
374382

383+
def multibind(
384+
self, interface: type, to: Any, scope: Union['ScopeDecorator', Type['Scope'], None]
385+
) -> None:
386+
try:
387+
element_type = get_args(_punch_through_alias(interface))[0]
388+
except IndexError:
389+
raise InvalidInterface(f"Use typing.List[T] or list[T] to specify the element type of the list")
390+
if isinstance(to, list):
391+
for element in to:
392+
element_binding = self._binder.create_binding(element_type, element, scope)
393+
self.append(element_binding.provider, element_binding.scope)
394+
else:
395+
element_binding = self._binder.create_binding(interface, to, scope)
396+
self.append(element_binding.provider, element_binding.scope)
397+
375398
def get(self, injector: 'Injector') -> List[T]:
376399
result: List[T] = []
377400
for provider in self.get_scoped_providers(injector):
@@ -383,6 +406,23 @@ def get(self, injector: 'Injector') -> List[T]:
383406
class MapBindProvider(MultiBinder[Dict[str, T]]):
384407
"""A provider for map bindings."""
385408

409+
def multibind(
410+
self, interface: type, to: Any, scope: Union['ScopeDecorator', Type['Scope'], None]
411+
) -> None:
412+
try:
413+
value_type = get_args(_punch_through_alias(interface))[1]
414+
except IndexError:
415+
raise InvalidInterface(
416+
f"Use typing.Dict[K, V] or dict[K, V] to specify the value type of the dict"
417+
)
418+
if isinstance(to, dict):
419+
for key, value in to.items():
420+
element_binding = self._binder.create_binding(value_type, value, scope)
421+
self.append(KeyValueProvider(key, element_binding.provider), element_binding.scope)
422+
else:
423+
element_binding = self._binder.create_binding(interface, to, scope)
424+
self.append(element_binding.provider, element_binding.scope)
425+
386426
def get(self, injector: 'Injector') -> Dict[str, T]:
387427
map: Dict[str, T] = {}
388428
for provider in self.get_scoped_providers(injector):
@@ -549,29 +589,7 @@ def multibind(
549589
:param scope: Optional Scope in which to bind.
550590
"""
551591
multi_binder = self._get_multi_binder(interface)
552-
if isinstance(multi_binder, MultiBindProvider) and isinstance(to, list):
553-
try:
554-
element_type = get_args(_punch_through_alias(interface))[0]
555-
except IndexError:
556-
raise InvalidInterface(
557-
f"Use typing.List[T] or list[T] to specify the element type of the list"
558-
)
559-
for element in to:
560-
element_binding = self.create_binding(element_type, element, scope)
561-
multi_binder.append(element_binding.provider, element_binding.scope)
562-
elif isinstance(multi_binder, MapBindProvider) and isinstance(to, dict):
563-
try:
564-
value_type = get_args(_punch_through_alias(interface))[1]
565-
except IndexError:
566-
raise InvalidInterface(
567-
f"Use typing.Dict[K, V] or dict[K, V] to specify the value type of the dict"
568-
)
569-
for key, value in to.items():
570-
element_binding = self.create_binding(value_type, value, scope)
571-
multi_binder.append(KeyValueProvider(key, element_binding.provider), element_binding.scope)
572-
else:
573-
element_binding = self.create_binding(interface, to, scope)
574-
multi_binder.append(element_binding.provider, element_binding.scope)
592+
multi_binder.multibind(interface, to, scope)
575593

576594
def _get_multi_binder(self, interface: type) -> MultiBinder:
577595
multi_binder: MultiBinder

0 commit comments

Comments
 (0)