Skip to content

Commit 2500a34

Browse files
committed
reformat validator errors
1 parent f7cf7c3 commit 2500a34

27 files changed

Lines changed: 54 additions & 52 deletions

sdks/python/src/lqp/proto_validator.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,14 @@ def get_original_name(self, rid: logic_pb2.RelationId) -> str:
427427
key = relation_id_key(rid)
428428
return self.original_names.get(key, relation_id_hex(rid))
429429

430-
def _location_str(self, node: Message) -> str:
431-
"""Return ' at file:line:col' for the given node, or '' if unavailable."""
430+
def _location_prefix(self, node: Message) -> str:
431+
"""Return 'file:line:col: ' for the given node, or '' if unavailable."""
432432
span = self._provenance.get(id(node))
433433
if span is not None:
434434
loc = span.start
435435
if self._filename:
436-
return f" at {self._filename}:{loc.line}:{loc.column}"
437-
return f" at {loc.line}:{loc.column}"
436+
return f"{self._filename}:{loc.line}:{loc.column}: "
437+
return f"{loc.line}:{loc.column}: "
438438
return ""
439439

440440
def _resolve_visitor(self, type_name: str):
@@ -491,7 +491,7 @@ def _mark_var_used(self, var_name: str, node: Message):
491491
used.add(var_name)
492492
return
493493
raise ValidationError(
494-
f"Undeclared variable used{self._location_str(node)}: '{var_name}'"
494+
f"ERROR: {self._location_prefix(node)}Undeclared variable used: '{var_name}'"
495495
)
496496

497497
def visit_Abstraction(self, node: logic_pb2.Abstraction, *args: Any):
@@ -509,7 +509,7 @@ def visit_Abstraction(self, node: logic_pb2.Abstraction, *args: Any):
509509
continue
510510
b = binding_map[var_name]
511511
raise ValidationError(
512-
f"Unused variable declared{self._location_str(b)}: '{var_name}'"
512+
f"ERROR: {self._location_prefix(b)}Unused variable declared: '{var_name}'"
513513
)
514514

515515
def visit_Var(self, node: logic_pb2.Var, *args: Any):
@@ -532,7 +532,7 @@ def visit_Abstraction(self, node: logic_pb2.Abstraction, *args: Any):
532532
name = binding.var.name
533533
if name in in_scope_names:
534534
raise ValidationError(
535-
f"Shadowed variable{self._location_str(binding)}: '{name}'"
535+
f"ERROR: {self._location_prefix(binding)}Shadowed variable: '{name}'"
536536
)
537537
new_scope = in_scope_names | {b.var.name for b in node.vars}
538538
self.visit(node.value, new_scope)
@@ -556,12 +556,12 @@ def _check_relation_id(self, rid: logic_pb2.RelationId, node: Message):
556556
if self.curr_fragment != seen_frag:
557557
original_name = self.get_original_name(rid)
558558
raise ValidationError(
559-
f"Duplicate declaration across fragments{self._location_str(node)}: '{original_name}'"
559+
f"ERROR: {self._location_prefix(node)}Duplicate declaration across fragments: '{original_name}'"
560560
)
561561
elif self.curr_epoch == seen_epoch:
562562
original_name = self.get_original_name(rid)
563563
raise ValidationError(
564-
f"Duplicate declaration within fragment in epoch{self._location_str(node)}: '{original_name}'"
564+
f"ERROR: {self._location_prefix(node)}Duplicate declaration within fragment in epoch: '{original_name}'"
565565
)
566566
self.seen_ids[key] = (self.curr_epoch, self.curr_fragment)
567567

@@ -579,7 +579,7 @@ def visit_Algorithm(self, node: logic_pb2.Algorithm, *args: Any):
579579
if key in self.seen_ids:
580580
original_name = self.get_original_name(rid)
581581
raise ValidationError(
582-
f"Duplicate declaration{self._location_str(rid)}: '{original_name}'"
582+
f"ERROR: {self._location_prefix(rid)}Duplicate declaration: '{original_name}'"
583583
)
584584
else:
585585
self.seen_ids[key] = (self.curr_epoch, self.curr_fragment)
@@ -600,7 +600,7 @@ def visit_Define(self, node: transactions_pb2.Define, *args: Any):
600600
if frag_id in self.seen_ids:
601601
id_str = frag_id.decode("utf-8")
602602
raise ValidationError(
603-
f"Duplicate fragment within an epoch{self._location_str(node)}: '{id_str}'"
603+
f"ERROR: {self._location_prefix(node)}Duplicate fragment within an epoch: '{id_str}'"
604604
)
605605
else:
606606
self.seen_ids.add(frag_id)
@@ -724,7 +724,8 @@ def visit_Atom(self, node: logic_pb2.Atom, *args: Any):
724724
if atom_arity != relation_arity:
725725
original_name = self.get_original_name(node.name)
726726
raise ValidationError(
727-
f"Incorrect arity for '{original_name}' atom{self._location_str(node)}: "
727+
f"ERROR: {self._location_prefix(node)}"
728+
f"Incorrect arity for '{original_name}' atom: "
728729
f"expected {relation_arity} term{'' if relation_arity == 1 else 's'}, got {atom_arity}"
729730
)
730731

@@ -742,7 +743,8 @@ def visit_Atom(self, node: logic_pb2.Atom, *args: Any):
742743
original_name = self.get_original_name(node.name)
743744
pretty_term = proto_term_str(term)
744745
raise ValidationError(
745-
f"Incorrect type for '{original_name}' atom at index {i} ('{pretty_term}'){self._location_str(node)}: "
746+
f"ERROR: {self._location_prefix(node)}"
747+
f"Incorrect type for '{original_name}' atom at index {i} ('{pretty_term}'): "
746748
f"expected {expected_type} term, got {term_type}"
747749
)
748750

@@ -758,7 +760,7 @@ def visit_Loop(self, node: logic_pb2.Loop, *args: Any):
758760
brk = getattr(instr_wrapper, "break")
759761
original_name = self.get_original_name(brk.name)
760762
raise ValidationError(
761-
f"Break rule found outside of body{self._location_str(brk)}: '{original_name}'"
763+
f"ERROR: {self._location_prefix(brk)}Break rule found outside of body: '{original_name}'"
762764
)
763765

764766

@@ -811,7 +813,7 @@ def visit_Loop(self, node: logic_pb2.Loop, *args: Any):
811813
if key in self.globals and key not in self.init:
812814
original_name = self.get_original_name(actual.name) # type: ignore[union-attr]
813815
raise ValidationError(
814-
f"Global rule found in body{self._location_str(actual)}: '{original_name}'"
816+
f"ERROR: {self._location_prefix(actual)}Global rule found in body: '{original_name}'"
815817
)
816818

817819

@@ -825,7 +827,7 @@ def _check_atom_body(self, node: Message, instr_type_name: str):
825827
which = formula.WhichOneof("formula_type")
826828
if which != "atom":
827829
raise ValidationError(
828-
f"{instr_type_name}{self._location_str(node)} must have an Atom as its value"
830+
f"ERROR: {self._location_prefix(node)}{instr_type_name} must have an Atom as its value"
829831
)
830832

831833
def visit_Upsert(self, node: logic_pb2.Upsert, *args: Any):
@@ -851,24 +853,24 @@ def __init__(self, txn: transactions_pb2.Transaction, **kwargs: Any):
851853
self.visit(txn)
852854

853855
def visit_ExportCSVConfig(self, node: transactions_pb2.ExportCSVConfig, *args: Any):
854-
loc = self._location_str(node)
856+
loc = self._location_prefix(node)
855857
if node.HasField("syntax_delim") and len(node.syntax_delim) != 1:
856858
raise ValidationError(
857-
f"CSV delimiter should be a single character{loc}, got '{node.syntax_delim}'"
859+
f"ERROR: {loc}CSV delimiter should be a single character, got '{node.syntax_delim}'"
858860
)
859861
if node.HasField("syntax_quotechar") and len(node.syntax_quotechar) != 1:
860862
raise ValidationError(
861-
f"CSV quotechar should be a single character{loc}, got '{node.syntax_quotechar}'"
863+
f"ERROR: {loc}CSV quotechar should be a single character, got '{node.syntax_quotechar}'"
862864
)
863865
if node.HasField("syntax_escapechar") and len(node.syntax_escapechar) != 1:
864866
raise ValidationError(
865-
f"CSV escapechar should be a single character{loc}, got '{node.syntax_escapechar}'"
867+
f"ERROR: {loc}CSV escapechar should be a single character, got '{node.syntax_escapechar}'"
866868
)
867869

868870
valid_compressions = {"", "gzip"}
869871
if node.HasField("compression") and node.compression not in valid_compressions:
870872
raise ValidationError(
871-
f"CSV compression should be one of {valid_compressions}{loc}, got '{node.compression}'"
873+
f"ERROR: {loc}CSV compression should be one of {valid_compressions}, got '{node.compression}'"
872874
)
873875

874876
column_0_key_types: list[str] | None = None
@@ -881,7 +883,7 @@ def visit_ExportCSVConfig(self, node: transactions_pb2.ExportCSVConfig, *args: A
881883
column_types = self.relation_types[key]
882884
if len(column_types) < 1:
883885
raise ValidationError(
884-
f"Data column relation must have at least one column{loc}, "
886+
f"ERROR: {loc}Data column relation must have at least one column, "
885887
f"got zero columns in '{self.get_original_name(column.column_data)}'"
886888
)
887889
key_types = column_types[:-1]
@@ -891,7 +893,7 @@ def visit_ExportCSVConfig(self, node: transactions_pb2.ExportCSVConfig, *args: A
891893
else:
892894
if column_0_key_types != key_types:
893895
raise ValidationError(
894-
f"All data columns in ExportCSVConfig{loc} must have the same key types. "
896+
f"ERROR: {loc}All data columns in ExportCSVConfig must have the same key types. "
895897
f"Got '{column_0_name}' with key types {[str(t) for t in column_0_key_types]} "
896898
f"and '{self.get_original_name(column.column_data)}' with key types {[str(t) for t in key_types]}."
897899
)
@@ -909,12 +911,12 @@ def visit_FunctionalDependency(
909911
for var in node.keys:
910912
if var.name not in guard_var_names:
911913
raise ValidationError(
912-
f"Key variable '{var.name}' not declared in guard{self._location_str(var)}"
914+
f"ERROR: {self._location_prefix(var)}Key variable '{var.name}' not declared in guard"
913915
)
914916
for var in node.values:
915917
if var.name not in guard_var_names:
916918
raise ValidationError(
917-
f"Value variable '{var.name}' not declared in guard{self._location_str(var)}"
919+
f"ERROR: {self._location_prefix(var)}Value variable '{var.name}' not declared in guard"
918920
)
919921

920922

sdks/python/tests/test_proto_validator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def test_proto_validator_error_has_location(validator_file):
6666
pytest.skip(f"No expected error comment found in {validator_file}")
6767
return
6868
# Skip files whose expected error doesn't include a location.
69-
if not re.search(r"at\s+\S+:\d+:\d+", expected_error):
69+
if not re.search(r"\S+:\d+:\d+:", expected_error):
7070
pytest.skip(f"Expected error has no location: {validator_file}")
7171
return
7272
with open(file_path) as f:
@@ -75,6 +75,6 @@ def test_proto_validator_error_has_location(validator_file):
7575
with pytest.raises(ValidationError) as exc_info:
7676
validate_proto(txn_proto, provenance=provenance, filename=validator_file)
7777
error_message = str(exc_info.value)
78-
assert re.search(r"at\s+\S+:\d+:\d+", error_message), (
78+
assert re.search(r"\S+:\d+:\d+:", error_message), (
7979
f"Error message missing location: '{error_message}'"
8080
)

sdks/python/tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def extract_expected_error(file_path) -> str | None:
3434
"""Extract the expected error from a ;; ERROR: comment in the file."""
3535
with open(file_path) as f:
3636
content = f.read()
37-
error_match = re.search(r";;\s*ERROR:\s*(.+)(?:\n|\r\n?)", content)
37+
error_match = re.search(r";;\s*(.+?)(?:\n|\r\n?|\Z)", content)
3838
if error_match:
3939
return error_match.group(1).strip()
4040
return None

sdks/python/tests/validator/fail_atom_arity_1.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect arity for 'foo' atom at fail_atom_arity_1.lqp:8:25: expected 0 terms, got 1
1+
;; ERROR: fail_atom_arity_1.lqp:8:25: Incorrect arity for 'foo' atom: expected 0 terms, got 1
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_arity_2.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect arity for 'foo' atom at fail_atom_arity_2.lqp:8:25: expected 2 terms, got 1
1+
;; ERROR: fail_atom_arity_2.lqp:8:25: Incorrect arity for 'foo' atom: expected 2 terms, got 1
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_arity_3.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect arity for 'foo2' atom at fail_atom_arity_3.lqp:15:26: expected 0 terms, got 1
1+
;; ERROR: fail_atom_arity_3.lqp:15:26: Incorrect arity for 'foo2' atom: expected 0 terms, got 1
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_type_1.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect type for 'foo' atom at index 1 ('2') at fail_atom_type_1.lqp:8:25: expected STRING term, got INT
1+
;; ERROR: fail_atom_type_1.lqp:8:25: Incorrect type for 'foo' atom at index 1 ('2'): expected STRING term, got INT
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_type_2.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect type for 'foo' atom at index 0 ('z') at fail_atom_type_2.lqp:8:31: expected FLOAT term, got INT
1+
;; ERROR: fail_atom_type_2.lqp:8:31: Incorrect type for 'foo' atom at index 0 ('z'): expected FLOAT term, got INT
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_type_3.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect type for 'foo' atom at index 0 ('1') at fail_atom_type_3.lqp:8:25: expected STRING term, got INT
1+
;; ERROR: fail_atom_type_3.lqp:8:25: Incorrect type for 'foo' atom at index 0 ('1'): expected STRING term, got INT
22
(transaction
33
(epoch
44
(writes

sdks/python/tests/validator/fail_atom_type_4.lqp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
;; ERROR: Incorrect type for 'foo' atom at index 1 ('1') at fail_atom_type_4.lqp:15:26: expected STRING term, got INT
1+
;; ERROR: fail_atom_type_4.lqp:15:26: Incorrect type for 'foo' atom at index 1 ('1'): expected STRING term, got INT
22
(transaction
33
(epoch
44
(writes

0 commit comments

Comments
 (0)