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 schema_type_for_attribute(attribute: Any) -> str: # Race and ethnicity fields are the only ones that support list form. These # are converted to comma-separated lists stored as strings in BigQuery. if is_enum(attribute) or is_list(attribute) or is_str(attribute): return bigquery.enums.SqlTypeNames.STRING.value if is_int(attribute): return bigquery.enums.SqlTypeNames.INTEGER.value if is_float(attribute): return bigquery.enums.SqlTypeNames.FLOAT.value if is_date(attribute): return bigquery.enums.SqlTypeNames.DATE.value if is_bool(attribute): return bigquery.enums.SqlTypeNames.BOOLEAN.value raise ValueError(f"Unhandled attribute type for attribute: {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}")