Skip to content

Commit 700b515

Browse files
committed
Enhance CSV validation error handling and normalization in Spanish translations
1 parent d651019 commit 700b515

File tree

3 files changed

+61
-50
lines changed

3 files changed

+61
-50
lines changed

ckanext/iati_generator/helpers.py

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -750,13 +750,63 @@ def _deduplicate_errors(normalized: List[Dict[str, Any]]) -> List[Dict[str, Any]
750750
return deduped
751751

752752

753+
def _normalize_validation_issues(error_list: List[Any]) -> List[Dict[str, Any]]:
754+
"""Helper to process list of errors (ValidationIssue objects)."""
755+
normalized = []
756+
for err in error_list:
757+
if hasattr(err, 'message'):
758+
row = getattr(err, 'row_number', getattr(err, 'line', None))
759+
col = getattr(err, 'column_name', getattr(err, 'column', None))
760+
761+
item = {
762+
"severity": "error",
763+
"category": "csv-content",
764+
"title": toolkit._(f"Error in {err.file_name}") if hasattr(err, 'file_name')
765+
else toolkit._("Validation error"),
766+
"details": err.message,
767+
"csv_file": getattr(err, 'file_name', None),
768+
"location": {"line": row, "col": col} if row else None,
769+
"suggestion": toolkit._("Check the format of the uploaded file."),
770+
"raw": str(err)
771+
}
772+
normalized.append(item)
773+
else:
774+
# Fallback for simple strings inside a list
775+
parsed = _parse_schema_error_line(str(err))
776+
normalized.append(_normalize_single_error(str(err), parsed))
777+
return normalized
778+
779+
780+
def _format_raw_errors_as_json(error_dict: Any) -> str:
781+
"""Helper to dump errors to a pretty JSON string."""
782+
def _json_default(obj):
783+
"""Converts complex objects (ValidationIssue, Enums) to dictionaries/strings."""
784+
if isinstance(obj, ValidationIssue):
785+
return {
786+
"level": getattr(obj.level, 'value', str(obj.level)) if hasattr(obj, 'level') else None,
787+
"code": getattr(obj.code, 'value', str(obj.code)) if hasattr(obj, 'code') else None,
788+
"message": obj.message,
789+
"file_name": getattr(obj, 'file_name', None),
790+
"row": getattr(obj, 'row_number', None),
791+
"column": getattr(obj, 'column_name', None),
792+
"value": getattr(obj, 'value', None)
793+
}
794+
if hasattr(obj, 'value'):
795+
return obj.value
796+
return str(obj)
797+
798+
try:
799+
return json.dumps(error_dict, default=_json_default, indent=4, ensure_ascii=False)
800+
except Exception:
801+
return str(error_dict)
802+
803+
753804
def normalize_iati_errors(error_dict: Any, package_id: Optional[str] = None) -> Dict[str, Any]:
754805
"""
755806
It normalizes converter errors (XSD / latest_errors) into a user-friendly structure.
756807
757808
It also supports pre-normalized structures (e.g., the output of validate_required_csv_folder()).
758809
"""
759-
760810
if isinstance(error_dict, dict) and "items" in error_dict and "raw" in error_dict:
761811
if "summary" not in error_dict or error_dict["summary"] is None:
762812
error_dict["summary"] = toolkit._(
@@ -767,54 +817,15 @@ def normalize_iati_errors(error_dict: Any, package_id: Optional[str] = None) ->
767817
normalized = []
768818

769819
if isinstance(error_dict, list):
770-
for err in error_dict:
771-
if hasattr(err, 'message'):
772-
row = getattr(err, 'row_number', getattr(err, 'line', None))
773-
col = getattr(err, 'column_name', getattr(err, 'column', None))
774-
775-
item = {
776-
"severity": "error",
777-
"category": "csv-content",
778-
"title": toolkit._(f"Error in {err.file_name}") if hasattr(err, 'file_name') else toolkit._("Validation error"),
779-
"details": err.message,
780-
"csv_file": getattr(err, 'file_name', None),
781-
"location": {"line": row, "col": col} if row else None,
782-
"suggestion": toolkit._("Check the format of the uploaded file."),
783-
"raw": str(err)
784-
}
785-
normalized.append(item)
786-
else:
787-
parsed = _parse_schema_error_line(str(err))
788-
normalized.append(_normalize_single_error(str(err), parsed))
789-
820+
normalized = _normalize_validation_issues(error_dict)
790821
elif isinstance(error_dict, dict):
791822
raw_lines = _flatten_error_dict(error_dict)
792823
for raw in raw_lines:
793824
parsed = _parse_schema_error_line(raw)
794825
normalized.append(_normalize_single_error(raw, parsed))
795826

796827
deduped = _deduplicate_errors(normalized)
797-
798-
def _json_default(obj):
799-
"""Converts complex objects (ValidationIssue, Enums) to dictionaries/strings."""
800-
if isinstance(obj, ValidationIssue):
801-
return {
802-
"level": getattr(obj.level, 'value', str(obj.level)) if hasattr(obj, 'level') else None,
803-
"code": getattr(obj.code, 'value', str(obj.code)) if hasattr(obj, 'code') else None,
804-
"message": obj.message,
805-
"file_name": getattr(obj, 'file_name', None),
806-
"row": getattr(obj, 'row_number', None),
807-
"column": getattr(obj, 'column_name', None),
808-
"value": getattr(obj, 'value', None)
809-
}
810-
if hasattr(obj, 'value'):
811-
return obj.value
812-
return str(obj)
813-
814-
try:
815-
raw_formatted = json.dumps(error_dict, default=_json_default, indent=4, ensure_ascii=False)
816-
except Exception:
817-
raw_formatted = str(error_dict)
828+
raw_formatted = _format_raw_errors_as_json(error_dict)
818829

819830
return {
820831
"summary": toolkit._("Validation errors were found in the source CSV files.") if deduped else None,
Binary file not shown.

ckanext/iati_generator/i18n/es/LC_MESSAGES/ckanext-iati-generator.po

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,31 +126,31 @@ msgstr "Tipo de dato inválido"
126126
msgid "The value '%(value)s' is not of the correct type for '%(element)s'."
127127
msgstr "El valor '%(value)s' no es del tipo correcto para '%(element)s'."
128128

129-
#: ckanext/iati_generator/helpers.py:716
130-
#, fuzzy
129+
#: ckanext/iati_generator/helpers.py:718
131130
msgid "Validation error"
132131
msgstr "Errores al compilar IATI"
133-
#: ckanext/iati_generator/helpers.py:718
132+
133+
#: ckanext/iati_generator/helpers.py:720
134134
msgid "Check the required CSV files and their format."
135135
msgstr "Verifica los archivos CSV requeridos y su formato."
136136

137-
#: ckanext/iati_generator/helpers.py:763
137+
#: ckanext/iati_generator/helpers.py:813
138138
msgid "The XML could not be generated due to errors in the source CSV files."
139139
msgstr "No se pudo generar el XML debido a errores en los archivos CSV fuente."
140140

141-
#: ckanext/iati_generator/helpers.py:778
141+
#: ckanext/iati_generator/helpers.py:764
142142
msgid "Error in %(file_name)s"
143143
msgstr "Error en %(file_name)s"
144144

145-
#: ckanext/iati_generator/helpers.py:778
145+
#: ckanext/iati_generator/helpers.py:764
146146
msgid "Validation error"
147147
msgstr "Error de validación"
148148

149-
#: ckanext/iati_generator/helpers.py:782
149+
#: ckanext/iati_generator/helpers.py:769
150150
msgid "Check the format of the uploaded file."
151151
msgstr "Verifica el formato del archivo subido."
152152

153-
#: ckanext/iati_generator/helpers.py:820
153+
#: ckanext/iati_generator/helpers.py:831
154154
msgid "Validation errors were found in the source CSV files."
155155
msgstr "Se encontraron errores de validación en los archivos CSV fuente."
156156

0 commit comments

Comments
 (0)