1010 from hyperbase .hyperedge import Atom , Hyperedge
1111
1212
13+ def _safe_mtype (edge : Hyperedge ) -> str :
14+ """Main type of ``edge``, or the sentinel ``'?'`` when it cannot be determined.
15+
16+ A malformed-but-parseable subedge (e.g. a concept used as a connector) makes
17+ :meth:`Hyperedge.type` raise. The correctness checker must *report* that as a
18+ bad-type error rather than crash, so an undeterminable type is returned as
19+ ``'?'`` — a value no valid-type set accepts, so it surfaces as a bad-type
20+ error at whichever connector/argument slot it occupies.
21+ """
22+ try :
23+ return edge .mtype ()
24+ except (RuntimeError , IndexError ):
25+ return "?"
26+
27+
1328def check_correctness (
1429 edge : Hyperedge , strict : bool = False
1530) -> dict [Hyperedge , list [tuple [str , str , int ]]]:
@@ -31,7 +46,7 @@ def _check_atom(atom: Atom) -> dict[Hyperedge, list[tuple[str, str, int]]]:
3146 output : dict [Hyperedge , list [tuple [str , str , int ]]] = {}
3247 errors : list [tuple [str , str ]] = []
3348
34- at = atom . mtype ( )
49+ at = _safe_mtype ( atom )
3550 if at not in {
3651 EdgeType .CONCEPT ,
3752 EdgeType .PREDICATE ,
@@ -54,7 +69,7 @@ def _check_edge(
5469 output : dict [Hyperedge , list [tuple [str , str , int ]]] = {}
5570 errors : list [tuple [str , str ]] = []
5671
57- ct = edge [0 ]. mtype ( )
72+ ct = _safe_mtype ( edge [0 ])
5873 # check if connector has valid type
5974 if ct not in {
6075 EdgeType .PREDICATE ,
@@ -82,7 +97,7 @@ def _check_edge(
8297 ("build-2-args" , f"builder edge '{ edge } ' can only have two arguments" )
8398 )
8499 for arg in edge [1 :]:
85- at = arg . mtype ( )
100+ at = _safe_mtype ( arg )
86101 if at != EdgeType .CONCEPT :
87102 e = f"builder argument '{ arg } ' of '{ edge } ' has incorrect type: { at } "
88103 errors .append (("build-arg-bad-type" , e ))
@@ -93,14 +108,14 @@ def _check_edge(
93108 ("trig-1-arg" , f"trigger edge '{ edge } ' can only have one argument" )
94109 )
95110 for arg in edge [1 :]:
96- at = arg . mtype ( )
111+ at = _safe_mtype ( arg )
97112 if at not in {EdgeType .CONCEPT , EdgeType .RELATION }:
98113 e = f"trigger argument '{ arg } ' of '{ edge } ' has incorrect type: { at } "
99114 errors .append (("trig-bad-arg-type" , e ))
100115 # check if predicate structure is correct
101116 elif ct == EdgeType .PREDICATE :
102117 for arg in edge [1 :]:
103- at = arg . mtype ( )
118+ at = _safe_mtype ( arg )
104119 if at not in {EdgeType .CONCEPT , EdgeType .RELATION , EdgeType .SPECIFIER }:
105120 e = f"predicate argument '{ arg } ' of '{ edge } ' has incorrect type: { at } "
106121 errors .append (("pred-arg-bad-type" , e ))
@@ -111,17 +126,18 @@ def _check_edge(
111126 except RuntimeError :
112127 ars = ""
113128 for i , arg in enumerate (edge [1 :]):
129+ am = _safe_mtype (arg )
114130 if (
115131 i < len (ars )
116132 and ars [i ] == const .ArgRole .SPECIFICATION
117- and arg . mtype () != EdgeType .SPECIFIER
133+ and am != EdgeType .SPECIFIER
118134 ):
119135 errors .append (
120136 (
121137 "spec-arg-not-specifier" ,
122138 f"specification argument '{ arg } ' of '{ edge } ' must "
123139 f"be a specifier (type 'S'), but has type "
124- f"{ arg . mtype () } . Wrap it in a trigger (e.g. a "
140+ f"{ am } . Wrap it in a trigger (e.g. a "
125141 f"special trigger atom like _/Tt/.)." ,
126142 )
127143 )
0 commit comments