-
-
Save spzm/edc5b53aa79e2080cdfdd040043dad61 to your computer and use it in GitHub Desktop.
Typehints-based deserializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def _create_config_hierarchy(config_cls: Type[TConfig], config_data: Mapping) -> TConfig: | |
sig = signature(config_cls) | |
cls_data_attributes = getmembers(config_cls, lambda a: isinstance(a, GenericDescriptor)) | |
if len(cls_data_attributes) != len(sig.parameters): | |
raise TypeError( | |
'Type {type_name} has invalid __init__.\n' | |
'Init parameters count should equal to data descriptors count.\n' | |
'Init parameters: [{init_params}], data descriptors: [{data_descriptors}]'.format( | |
type_name=config_cls, | |
init_params=', '.join(sig.parameters.keys()), | |
data_descriptors=', '.join(attr_name for attr_name, _ in cls_data_attributes), | |
) | |
) | |
config_cls_kwargs: MutableMapping = OrderedDict() | |
for kwarg_name, kwarg in sig.parameters.items(): | |
if kwarg_name == 'self': | |
continue | |
kwarg_type = kwarg.annotation | |
if kwarg_type in (bool, float, int, str, list, tuple) or issubclass(kwarg_type, Enum): | |
config_cls_kwargs[kwarg_name] = kwarg_type(config_data[kwarg_name]) | |
elif kwarg_type in (datetime, date): | |
if isinstance(config_data[kwarg_name], kwarg_type): | |
# Some parsers will parse dates to objects, not strings | |
config_cls_kwargs[kwarg_name] = config_data[kwarg_name] | |
else: | |
if ( | |
(isinstance(config_data[kwarg_name], date) and kwarg_type is datetime) or | |
(isinstance(config_data[kwarg_name], datetime) and kwarg_type is date) | |
): | |
raise TypeError( | |
'Invalid kwarg type while constructing {target_type}. ' | |
'Expected {expected_type}, got {got_type}'.format( | |
target_type=config_cls, | |
expected_type=kwarg_type, | |
got_type=type(config_data[kwarg_name]) | |
)) | |
else: | |
raise NotImplementedError('Dates parsing is not supported') | |
elif isinstance(kwarg_type, GenericMeta) and isinstance(config_data[kwarg_name], (list, tuple)): | |
# Iterables and Mappings have annotation of type GenericMeta | |
# In this case we use actual data type to construct config kwarg | |
# Used for kwargs of type List[T], Mapping[KK, KV], etc | |
actual_data_type = type(config_data[kwarg_name]) | |
config_cls_kwargs[kwarg_name] = actual_data_type(config_data[kwarg_name]) | |
else: | |
config_cls_kwargs[kwarg_name] = _create_config_hierarchy(kwarg_type, config_data[kwarg_name]) | |
return config_cls(**config_cls_kwargs) # type: ignore | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment