def _map_attr_to_type_for_class( cls: Type, ) -> Dict[attr.Attribute, Tuple[BuildableAttrFieldType, Optional[Type[Enum]]]]: """Helper function for _attribute_field_type_reference_for_class to map attributes to their BuildableAttrFieldType for a class if the attributes of the class aren't yet in the cached _class_structure_reference. """ attr_field_types: Dict[ attr.Attribute, Tuple[BuildableAttrFieldType, Optional[Type[Enum]]] ] = {} for attribute in attr.fields_dict(cls).values(): if is_forward_ref(attribute): attr_field_types[attribute] = (BuildableAttrFieldType.FORWARD_REF, None) elif is_enum(attribute): enum_cls = get_enum_cls(attribute) if not enum_cls: raise ValueError( f"Did not find enum class for enum attribute [{attribute}]" ) attr_field_types[attribute] = (BuildableAttrFieldType.ENUM, enum_cls) elif is_date(attribute): attr_field_types[attribute] = (BuildableAttrFieldType.DATE, None) else: attr_field_types[attribute] = (BuildableAttrFieldType.OTHER, None) return attr_field_types
def is_property_flat_field(obj: Union[list, Entity], property_name: str) -> bool: """Returns true if the attribute corresponding to |property_name| on the given object is a flat field (not a List, attr class, or ForwardRef).""" if not isinstance(obj, Entity) and not isinstance(obj, list): raise TypeError(f'Unexpected type [{type(obj)}]') attribute = attr.fields_dict(obj.__class__).get(property_name) if not attribute: raise ValueError(f'Unexpected None attribute for property_name [{property_name}] on obj [{obj}]') return not is_list(attribute) and not is_forward_ref(attribute)
def build_from_dictionary(cls, build_dict: Dict[str, Any]) -> \ Optional['BuildableAttr']: """Builds a BuildableAttr with values from the given build_dict. Given build_dict must contain all required fields, and cannot contain any fields with attribute types of List or ForwardRef. Any date values must be in the format 'YYYY-MM-DD' if they are present. """ if not attr.has(cls): raise Exception("Parent class must be an attr class") if not build_dict: raise ValueError("build_dict cannot be empty") cls_builder = cls.builder() for field, attribute in attr.fields_dict(cls).items(): if field in build_dict: if is_list(attribute): raise ValueError("build_dict should be a dictionary of " "flat values. Should not contain any " f"lists: {build_dict}.") if is_forward_ref(attribute): # TODO(1886): Implement detection of non-ForwardRefs # ForwardRef fields are expected to be references to other # BuildableAttrs raise ValueError("build_dict should be a dictionary of " "flat values. Should not contain any " f"ForwardRef fields: {build_dict}") if is_enum(attribute): value = cls.extract_enum_value(build_dict, field, attribute) elif is_date(attribute): value = cls.extract_date_value(build_dict, field) else: value = build_dict.get(field) setattr(cls_builder, field, value) return cls_builder.build()
def convert_field_value(field: attr.Attribute, field_value: Union[str, EnumParser]) -> Any: if field_value is None: return None if is_forward_ref(field) or is_list(field): return field_value if isinstance(field_value, str): if not field_value or not field_value.strip(): return None if field.name in converter_overrides: converter = converter_overrides[field.name] if not isinstance(field_value, converter.field_type): raise ValueError( f"Found converter for field [{field.name}] in the converter_overrides, but expected " f"field type [{converter.field_type}] does not match actual field type " f"[{type(field_value)}]") return converter.convert(field_value) if isinstance(field_value, EnumParser): if is_enum(field): return field_value.parse() raise ValueError( f"Found field value [{field_value}] for field that is not an enum [{field}]." ) if isinstance(field_value, str): if is_str(field): return normalize(field_value) if is_date(field): return parse_date(field_value) if is_int(field): return parse_int(field_value) if field.type in {bool, Union[bool, None]}: return parse_bool(field_value) raise ValueError(f"Unsupported field {field.name}")