def _build_value_for_collection(collection: Type, data: Any, config: Config) -> Any: if is_instance(data, Mapping): return data.__class__( (key, _build_value(type_=extract_generic(collection)[1], data=value, config=config)) for key, value in data.items() ) return data.__class__(_build_value(type_=extract_generic(collection)[0], data=item, config=config) for item in data)
def _build_value_for_collection(collection: Type, data: Any, config: Config) -> Any: data_type = data.__class__ if is_instance(data, Mapping): item_type = extract_generic(collection, defaults=(Any, Any))[1] return data_type((key, _build_value(type_=item_type, data=value, config=config)) for key, value in data.items()) elif is_instance(data, tuple): types = extract_generic(collection) if len(types) == 2 and types[1] == Ellipsis: return data_type(_build_value(type_=types[0], data=item, config=config) for item in data) return data_type( _build_value(type_=type_, data=item, config=config) for item, type_ in zip_longest(data, types) ) item_type = extract_generic(collection, defaults=(Any,))[0] return data_type(_build_value(type_=item_type, data=item, config=config) for item in data)
def _build_value_for_union(union: Type, data: Any, config: Config) -> Any: types = extract_generic(union) if is_optional(union) and len(types) == 2: return _build_value(type_=types[0], data=data, config=config) union_matches = {} for inner_type in types: try: # noinspection PyBroadException try: data = transform_value(type_hooks=config.type_hooks, cast=config.cast, target_type=inner_type, value=data) except Exception: # pylint: disable=broad-except continue value = _build_value(type_=inner_type, data=data, config=config) if is_instance(value, inner_type): if config.strict_unions_match: union_matches[inner_type] = value else: return value except DaciteError: pass if config.strict_unions_match: if len(union_matches) > 1: raise StrictUnionMatchError(union_matches) return union_matches.popitem()[1] if not config.check_types: return data raise UnionMatchError(field_type=union, value=data)
def _build_value_for_union(union: Type, data: Any, config: Config) -> Any: types = [ type_ for type_ in extract_generic(union) if type_ is not type(None) ] if is_optional(union) and len(extract_generic(union)) == 2: return _build_value(type_=types[0], data=data, config=config) for inner_type in types: try: value = _build_value(type_=inner_type, data=data, config=config) if is_instance(value, inner_type): return value except DaciteError: pass if not config.check_types: return data raise UnionMatchError(field_type=union, value=data)
def load_from_template(template, cfg_value): if isinstance(cfg_value, dict): cfg_obj = SimpleNamespace() for key, value in cfg_value.items(): nest_template = getattr(template, key, None) if nest_template is not None: # it is a nested class which means subsection of config result = load_from_template(nest_template, value) setattr(cfg_obj, key, result) else: # it should be either raw type or a Union anno = template.__annotations__[key] if typing_utils.is_union(anno): nest_templates = typing_utils.extract_generic(anno) result = load_from_matching_template( nest_templates, value) setattr(cfg_obj, key, result) else: setattr(cfg_obj, key, value) return cfg_obj elif isinstance(cfg_value, list): if typing_utils.is_generic_collection(template): item_template = typing_utils.extract_generic(template)[0] if typing_utils.is_union(item_template): item_templates = typing_utils.extract_generic( item_template) else: item_templates = [item_template] return [ load_from_matching_template(item_templates, item) for item in cfg_value ] else: return cfg_value else: return cfg_value
def _build_value_for_union(union: Type, data: Any, config: Config) -> Any: types = extract_generic(union) if is_optional(union) and len(types) == 2: return _build_value(type_=types[0], data=data, config=config) for inner_type in types: try: value = _build_value(type_=inner_type, data=data, config=config) if is_instance(value, inner_type): return transform_value( type_hooks=config.type_hooks, cast=config.cast, target_type=inner_type, value=value ) except DaciteError: pass if not config.check_types: return data raise UnionMatchError(field_type=union, value=data)
def _build_value_for_collection(collection: Type, data: Any, config: Config) -> Any: generic = extract_generic(collection) if is_instance(data, Mapping): return data.__class__( (key, _build_value(type_=generic[1], data=value, config=config)) for key, value in data.items()) collection_type = extract_origin_collection(collection) if collection_type == tuple and not (len(generic) == 2 and generic[1] == Ellipsis): return data.__class__( _build_value(type_=item_type, data=item, config=config) for item, item_type in zip(data, generic)) return data.__class__( _build_value(type_=generic[0], data=item, config=config) for item in data)
def test_extract_generic(): assert extract_generic(List[int]) == (int,)
def test_extract_generic_with_defaults(): assert extract_generic(List, defaults=(Any, )) == (Any, )