Update config resolving

This commit is contained in:
Roman Mogylatov 2020-09-18 21:40:37 -04:00
parent 96dbd0f6bb
commit dd3aa32c53
7 changed files with 4176 additions and 3072 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -93,6 +93,10 @@ cdef class ConfigurationOption(Provider):
cdef object __cache
cdef class TypedConfigurationOption(Callable):
pass
cdef class Configuration(Object):
cdef str __name
cdef dict __children

View File

@ -128,9 +128,9 @@ class ConfigurationOption(Provider):
def __getitem__(self, item: str) -> ConfigurationOption: ...
def get_name(self) -> str: ...
def get_option_provider(self, selector: str) -> ConfigurationOption: ...
def as_int(self) -> Callable[int]: ...
def as_float(self) -> Callable[float]: ...
def as_(self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection) -> Callable[T]: ...
def as_int(self) -> TypedConfigurationOption[int]: ...
def as_float(self) -> TypedConfigurationOption[float]: ...
def as_(self, callback: _Callable[..., T], *args: Injection, **kwargs: Injection) -> TypedConfigurationOption[T]: ...
def update(self, value: Any) -> None: ...
def from_ini(self, filepath: str) -> None: ...
def from_yaml(self, filepath: str) -> None: ...
@ -138,6 +138,11 @@ class ConfigurationOption(Provider):
def from_env(self, name: str, default: Optional[Any] = None) -> None: ...
class TypedConfigurationOption(Callable[T]):
@property
def option(self) -> ConfigurationOption: ...
class Configuration(Object):
DEFAULT_NAME: str = 'config'
def __init__(self, name: str = DEFAULT_NAME, default: Optional[Any] = None) -> None: ...

View File

@ -1161,13 +1161,13 @@ cdef class ConfigurationOption(Provider):
return child
def as_int(self):
return Callable(int, self)
return TypedConfigurationOption(int, self)
def as_float(self):
return Callable(float, self)
return TypedConfigurationOption(float, self)
def as_(self, callback, *args, **kwargs):
return Callable(callback, self, *args, **kwargs)
return TypedConfigurationOption(callback, self, *args, **kwargs)
def override(self, value):
if isinstance(value, Provider):
@ -1279,6 +1279,13 @@ cdef class ConfigurationOption(Provider):
self.override(value)
cdef class TypedConfigurationOption(Callable):
@property
def option(self):
return self.args[0]
cdef class Configuration(Object):
"""Configuration provider provides configuration options to the other providers.

View File

@ -50,10 +50,7 @@ def _patch_cls(
return
init_method = getattr(cls, '__init__')
try:
injections = _resolve_injections(init_method, container)
except Exception:
raise Exception(cls)
injections = _resolve_injections(init_method, container)
if not injections:
return
@ -84,11 +81,19 @@ def _resolve_injections(fn: Callable[..., Any], container: AnyContainer) -> Dict
continue
marker = parameter.default
provider_name = container.resolve_provider_name(marker.provider)
if provider_name:
if config and isinstance(marker.provider, providers.ConfigurationOption):
provider = _prepare_config_injection(marker.provider.get_name(), config)
elif config and isinstance(marker.provider, providers.TypedConfigurationOption):
provider = _prepare_config_injection(
marker.provider.option.get_name(),
config,
marker.provider.provides,
)
elif isinstance(marker.provider, providers.Provider):
provider_name = container.resolve_provider_name(marker.provider)
if not provider_name:
continue
provider = container.providers[provider_name]
elif config and isinstance(marker.provider, providers.ConfigurationOption):
provider = _prepare_config_injection(marker.provider, parameter, config)
else:
continue
@ -101,24 +106,15 @@ def _resolve_injections(fn: Callable[..., Any], container: AnyContainer) -> Dict
def _prepare_config_injection(
option: providers.ConfigurationOption,
parameter: inspect.Parameter,
option_name: str,
config: providers.Configuration,
as_: Any = None,
) -> providers.Provider:
full_option_name = option.get_name()
_, *parts = full_option_name.split('.')
_, *parts = option_name.split('.')
relative_option_name = '.'.join(parts)
provider = config.get_option_provider(relative_option_name)
if parameter.annotation is int:
provider = provider.as_int()
elif parameter.annotation is float:
provider = provider.as_float()
elif parameter.annotation is not inspect.Parameter.empty:
try:
provider = provider.as_(parameter.annotation)
except Exception:
raise Exception(option, parameter, parameter.annotation)
if as_:
return provider.as_(as_)
return provider

View File

@ -25,8 +25,8 @@ def test_function_provider(service_provider: Callable[..., Service] = Provider[C
def test_config_value(
some_value_int: int = Provide[Container.config.a.b.c],
some_value_str: str = Provide[Container.config.a.b.c],
some_value_decimal: Decimal = Provide[Container.config.a.b.c],
some_value_int: int = Provide[Container.config.a.b.c.as_int()],
some_value_str: str = Provide[Container.config.a.b.c.as_(str)],
some_value_decimal: Decimal = Provide[Container.config.a.b.c.as_(Decimal)],
):
return some_value_int, some_value_str, some_value_decimal