Closed andresi closed 1 year ago
Ok, I don't know if this was already supported by one of the existing providers, but I built one:
class ListSelectorProvider(providers.Provider):
def __init__(self, selectors, **providers):
"""Initialize provider."""
self.__selectors = None
self.set_selectors(selectors)
self.__providers = {}
self.set_providers(**providers)
super(ListSelectorProvider, self).__init__()
def __deepcopy__(self, memo):
"""Create and return full copy of provider."""
copied = memo.get(id(self))
if copied is not None:
return copied
copied = self.__class__(
providers.deepcopy(self.__selectors, memo),
**providers.deepcopy(self.__providers, memo)
)
self._copy_overridings(copied, memo)
return copied
def __getattr__(self, name):
"""Return provider."""
if name.startswith("__") and name.endswith("__"):
raise AttributeError(
"'{cls}' object has no attribute "
"'{attribute_name}'".format(cls=self.__class__.__name__, attribute_name=name))
if name not in self.__providers:
raise AttributeError("ListSelectorProvider has no \"{0}\" provider".format(name))
return self.__providers[name]
def __str__(self):
"""Return string representation of provider.
:rtype: str
"""
return "<{provider}({selectors}, {providers}) at {address}>".format(
provider=".".join((self.__class__.__module__, self.__class__.__name__)),
selector=self.__selectors,
providers=", ".join((
"{0}={1}".format(name, provider)
for name, provider in self.__providers.items()
)),
address=hex(id(self)),
)
@property
def selectors(self):
"""Return selectors."""
return self.__selectors
def set_selectors(self, selectors):
"""Set selectors."""
self.__selectors = selectors
return self
@property
def providers(self):
"""Return providers."""
return dict(self.__providers)
def set_providers(self, **providers):
"""Set providers."""
self.__providers = providers
return self
@property
def related(self):
"""Return related providers generator."""
yield from filter(providers.is_provider, [self.__selectors])
yield from self.providers.values()
yield from super().related
def _provide(self, args, kwargs):
"""Return single instance."""
selectors_value = self.__selectors()
if selectors_value is None or len(selectors_value) == 0:
raise providers.Error("ListSelectorProvider value is undefined")
provides = []
for selector_value in selectors_value:
if selector_value not in self.__providers:
raise providers.Error("ListSelectorProvider has no \"{0}\" provider".format(selector_value))
provides.append(self.__providers[selector_value](*args, **kwargs))
return provides
@andresi can you share an implementation of ListSelectorProvider
? I just found this after posting https://github.com/ets-labs/python-dependency-injector/issues/762 which seems similar.
Let's say your config looks like this:
items:
- itemA
- itemB
- itemC
Then you use like this:
items = ListSelectorProvider(
config.items,
itemA=providers.Factory(ItemA),
itemB=providers.Factory(ItemB),
itemC=providers.Factory(ItemC)
)
A lot simpler than I was imagining ;) Thanks!
I have a class that takes a list of items in it's constructor. Each item can be a different class, and I want to define the items in a configuration yaml file, like this:
I can use Selector to map itemA to ClassA, etc. But I can't find a way to then map this into a List provider. Is there some other Provider that does this?