in src/evaluate/module.py [0:0]
def _enforce_nested_string_type(self, schema, obj):
"""
Recursively checks if there is any Value feature of type string and throws TypeError if corresponding object is not a string.
Since any Python object can be cast to string this avoids implicitly casting wrong input types (e.g. lists) to string without error.
"""
# Nested structures: we allow dict, list, tuples, sequences
if isinstance(schema, dict):
return [self._enforce_nested_string_type(sub_schema, o) for k, (sub_schema, o) in zip_dict(schema, obj)]
elif isinstance(schema, (list, tuple)):
sub_schema = schema[0]
return [self._enforce_nested_string_type(sub_schema, o) for o in obj]
elif isinstance(schema, Sequence):
# We allow to reverse list of dict => dict of list for compatiblity with tfds
if isinstance(schema.feature, dict):
if isinstance(obj, (list, tuple)):
# obj is a list of dict
for k, dict_tuples in zip_dict(schema.feature, *obj):
for sub_obj in dict_tuples[1:]:
if _check_non_null_non_empty_recursive(sub_obj, dict_tuples[0]):
self._enforce_nested_string_type(dict_tuples[0], sub_obj)
break
return None
else:
# obj is a single dict
for k, (sub_schema, sub_objs) in zip_dict(schema.feature, obj):
for sub_obj in sub_objs:
if _check_non_null_non_empty_recursive(sub_obj, sub_schema):
self._enforce_nested_string_type(sub_schema, sub_obj)
break
return None
# schema.feature is not a dict
if isinstance(obj, str): # don't interpret a string as a list
raise ValueError(f"Got a string but expected a list instead: '{obj}'")
if obj is None:
return None
else:
if len(obj) > 0:
for first_elmt in obj:
if _check_non_null_non_empty_recursive(first_elmt, schema.feature):
break
if not isinstance(first_elmt, list):
return self._enforce_nested_string_type(schema.feature, first_elmt)
elif isinstance(schema, Value):
if pa.types.is_string(schema.pa_type) and not isinstance(obj, str):
raise TypeError(f"Expected type str but got {type(obj)}.")