def _enforce_nested_string_type()

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)}.")