Skip to content

Commit 60820d7

Browse files
committed
refactor: Polymorphism instead of inspection
1 parent 3229e0d commit 60820d7

File tree

1 file changed

+39
-23
lines changed

1 file changed

+39
-23
lines changed

injector/__init__.py

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,18 @@ 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 multbind(self, interface: type, to: Any, scope: Union['ScopeDecorator', Type['Scope'], None]) -> None:
357+
raise NotImplementedError
358+
353359
def append(self, provider: Provider[T], scope: Type['Scope']) -> None:
354360
# HACK: generate a pseudo-type for this element in the list.
355361
# This is needed for scopes to work properly. Some, like the Singleton scope,
@@ -372,6 +378,21 @@ class MultiBindProvider(MultiBinder[List[T]]):
372378
"""Used by :meth:`Binder.multibind` to flatten results of providers that
373379
return sequences."""
374380

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

407+
def multibind(
408+
self, interface: type, to: Any, scope: Union['ScopeDecorator', Type['Scope'], None]
409+
) -> None:
410+
try:
411+
value_type = get_args(_punch_through_alias(interface))[1]
412+
except IndexError:
413+
raise InvalidInterface(
414+
f"Use typing.Dict[K, V] or dict[K, V] to specify the value type of the dict"
415+
)
416+
if isinstance(to, dict):
417+
for key, value in to.items():
418+
element_binding = self._binder.create_binding(value_type, value, scope)
419+
self.append(KeyValueProvider(key, element_binding.provider), element_binding.scope)
420+
else:
421+
element_binding = self._binder.create_binding(interface, to, scope)
422+
self.append(element_binding.provider, element_binding.scope)
423+
386424
def get(self, injector: 'Injector') -> Dict[str, T]:
387425
map: Dict[str, T] = {}
388426
for provider in self.get_scoped_providers(injector):
@@ -549,29 +587,7 @@ def multibind(
549587
:param scope: Optional Scope in which to bind.
550588
"""
551589
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)
590+
multi_binder.multibind(interface, to, scope)
575591

576592
def _get_multi_binder(self, interface: type) -> MultiBinder:
577593
multi_binder: MultiBinder

0 commit comments

Comments
 (0)