Skip to content

Commit b96f052

Browse files
acoleman2000mr-c
authored andcommitted
Improve error messages for Python codegen
Squashed merge from pull request #687
1 parent ff3f82b commit b96f052

18 files changed

+2892
-615
lines changed

.flake8

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ extend-select = B9
88
per-file-ignores =
99
schema_salad/metaschema.py:B950
1010
schema_salad/tests/*.py:B011
11+
schema_salad/tests/test_codegen_errors.py:B950
12+
schema_salad/tests/util.py:B950

schema_salad/metaschema.py

Lines changed: 2326 additions & 517 deletions
Large diffs are not rendered by default.

schema_salad/python_codegen.py

Lines changed: 55 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def safe_name(name: str) -> str:
101101
avn = avn[5:]
102102
elif avn[0].isdigit():
103103
avn = f"_{avn}"
104-
elif avn in ("class", "in"):
104+
elif avn in ("class", "in", "type"):
105105
# reserved words
106106
avn = f"{avn}_"
107107
return avn.replace(".", "_")
@@ -192,8 +192,7 @@ def begin_class(
192192
+ "\n extension_fields: Optional[Dict[str, Any]] = None,"
193193
+ "\n loadingOptions: Optional[LoadingOptions] = None,"
194194
+ "\n ) -> None:\n"
195-
+ """
196-
if extension_fields:
195+
+ """ if extension_fields:
197196
self.extension_fields = extension_fields
198197
else:
199198
self.extension_fields = CommentedMap()
@@ -257,9 +256,10 @@ def fromDoc(
257256
doc: Any,
258257
baseuri: str,
259258
loadingOptions: LoadingOptions,
260-
docRoot: Optional[str] = None,
259+
docRoot: Optional[str] = None
261260
) -> "{classname}":
262261
_doc = copy.copy(doc)
262+
263263
if hasattr(doc, "lc"):
264264
_doc.lc.data = doc.lc.data
265265
_doc.lc.filename = doc.lc.filename
@@ -288,8 +288,10 @@ def save(
288288
if "class" in field_names:
289289
self.out.write(
290290
"""
291+
if "class" not in _doc:
292+
raise ValidationException("Missing 'class' field")
291293
if _doc.get("class") != "{class_}":
292-
raise ValidationException("Not a {class_}")
294+
raise ValidationException("tried `{class_}` but")
293295
294296
""".format(
295297
class_=classname
@@ -315,7 +317,11 @@ def end_class(self, classname: str, field_names: List[str]) -> None:
315317
extension_fields: Dict[str, Any] = {{}}
316318
for k in _doc.keys():
317319
if k not in cls.attrs:
318-
if ":" in k:
320+
if not k:
321+
_errors__.append(
322+
ValidationException("mapping with implicit null key")
323+
)
324+
elif ":" in k:
319325
ex = expand_url(
320326
k, "", loadingOptions, scoped_id=False, vocab_term=False
321327
)
@@ -329,13 +335,11 @@ def end_class(self, classname: str, field_names: List[str]) -> None:
329335
SourceLine(_doc, k, str),
330336
)
331337
)
332-
break
333338
334339
if _errors__:
335-
raise ValidationException(\"Trying '{class_}'\", None, _errors__)
340+
raise ValidationException("", None, _errors__, "*")
336341
""".format(
337342
attrstr=", ".join([f"`{f}`" for f in field_names]),
338-
class_=self.safe_name(classname),
339343
),
340344
8,
341345
)
@@ -474,7 +478,7 @@ def declare_id_field(
474478
safename=self.safe_name(name)
475479
)
476480
else:
477-
opt = """raise ValidationException("Missing {fieldname}")""".format(
481+
opt = """_errors__.append(ValidationException("missing {fieldname}"))""".format(
478482
fieldname=shortname(name)
479483
)
480484

@@ -527,19 +531,15 @@ def declare_field(
527531

528532
self.out.write(
529533
"""{spc} try:
534+
{spc} if _doc.get("{fieldname}") is None:
535+
{spc} raise ValidationException("missing required field `{fieldname}`", None, [])
536+
530537
{spc} {safename} = load_field(
531538
{spc} _doc.get("{fieldname}"),
532539
{spc} {fieldtype},
533540
{spc} {baseurivar},
534541
{spc} loadingOptions,
535-
{spc} )
536-
{spc} except ValidationException as e:
537-
{spc} _errors__.append(
538-
{spc} ValidationException(
539-
{spc} \"the {fieldname!r} field is not valid because:\",
540-
{spc} SourceLine(_doc, "{fieldname}", str),
541-
{spc} [e],
542-
{spc} )
542+
{spc} lc=_doc.get("{fieldname}")
543543
{spc} )
544544
""".format(
545545
safename=self.safe_name(name),
@@ -549,6 +549,43 @@ def declare_field(
549549
spc=spc,
550550
)
551551
)
552+
self.out.write(
553+
"""
554+
{spc} except ValidationException as e:
555+
{spc} error_message, to_print, verb_tensage = parse_errors(str(e))
556+
557+
{spc} if str(e) == "missing required field `{fieldname}`":
558+
{spc} _errors__.append(
559+
{spc} ValidationException(
560+
{spc} str(e),
561+
{spc} None
562+
{spc} )
563+
{spc} )
564+
{spc} else:
565+
{spc} if error_message != str(e):
566+
{spc} val_type = convert_typing(extract_type(type(_doc.get("{fieldname}"))))
567+
{spc} _errors__.append(
568+
{spc} ValidationException(
569+
{spc} \"the `{fieldname}` field is not valid because:\",
570+
{spc} SourceLine(_doc, "{fieldname}", str),
571+
{spc} [ValidationException(f"Value is a {{val_type}}, "
572+
{spc} f"but valid {{to_print}} for this field "
573+
{spc} f"{{verb_tensage}} {{error_message}}")],
574+
{spc} )
575+
{spc} )
576+
{spc} else:
577+
{spc} _errors__.append(
578+
{spc} ValidationException(
579+
{spc} \"the `{fieldname}` field is not valid because:\",
580+
{spc} SourceLine(_doc, "{fieldname}", str),
581+
{spc} [e],
582+
{spc} )
583+
{spc} )
584+
""".format(
585+
fieldname=shortname(name),
586+
spc=spc,
587+
)
588+
)
552589
if optional:
553590
self.out.write(
554591
""" else:

0 commit comments

Comments
 (0)