44from dataclasses import dataclass
55from pathlib import Path
66from typing import (
7- Any ,
87 Dict ,
98 Generator ,
109 Iterable ,
@@ -49,7 +48,7 @@ def __iter__(self) -> Generator[ast.Call, None, None]:
4948
5049
5150def _extract_attributes (node : ast .Call ) -> _ExaErrorAttributes :
52- kwargs : Dict [str , Any ] = {}
51+ kwargs : Dict [str , ast . expr ] = {}
5352 params = ["code" , "message" , "mitigations" , "parameters" ]
5453
5554 for arg in node .args :
@@ -82,10 +81,10 @@ class Warning:
8281
8382 @dataclass (frozen = True )
8483 class ExaValidatedNode :
85- code : ast . Constant
86- message : ast . Constant
87- mitigations : Union [ ast . Constant , ast . List ]
88- parameters : ast . Dict
84+ code : str
85+ message : str
86+ mitigations : List [ str ]
87+ parameters : List [ Tuple [ str , str ]]
8988 lineno : int
9089
9190 @dataclass (frozen = True )
@@ -126,10 +125,19 @@ def validate(self, node: ast.Call, file: str) -> Result:
126125 # make sure all parameters have the valid type
127126 code_validated = self ._validate_code (error_attributes .code , file )
128127 message_validated = self ._validate_message (error_attributes .message , file )
129- mitigations_validated = self ._validate_mitigations (error_attributes .mitigations , file )
130- parameters_validated = self ._validate_parameters (error_attributes .parameters , file )
128+ mitigations_validated = self ._validate_mitigations (
129+ error_attributes .mitigations , file
130+ )
131+ parameters_validated = self ._validate_parameters (
132+ error_attributes .parameters , file
133+ )
131134 validated_node = None
132- if code_validated and message_validated and mitigations_validated and parameters_validated :
135+ if (
136+ code_validated is not None
137+ and message_validated is not None
138+ and mitigations_validated is not None
139+ and parameters_validated is not None
140+ ):
133141 validated_node = Validator .ExaValidatedNode (
134142 code = code_validated ,
135143 message = message_validated ,
@@ -144,7 +152,7 @@ def validate(self, node: ast.Call, file: str) -> Result:
144152 node = validated_node ,
145153 )
146154
147- def _validate_code (self , code : ast .expr , file : str ) -> Optional [ast . Constant ]:
155+ def _validate_code (self , code : ast .expr , file : str ) -> Optional [str ]:
148156 if not isinstance (code , ast .Constant ):
149157 self ._errors .append (
150158 self .Error (
@@ -157,9 +165,9 @@ def _validate_code(self, code: ast.expr, file: str) -> Optional[ast.Constant]:
157165 )
158166 return None
159167 else :
160- return code
168+ return code . value
161169
162- def _validate_message (self , node : ast .expr , file : str ) -> Optional [ast . Constant ]:
170+ def _validate_message (self , node : ast .expr , file : str ) -> Optional [str ]:
163171 if not isinstance (node , ast .Constant ):
164172 self ._errors .append (
165173 self .Error (
@@ -170,11 +178,9 @@ def _validate_message(self, node: ast.expr, file: str) -> Optional[ast.Constant]
170178 )
171179 return None
172180 else :
173- return node
181+ return node . value
174182
175- def _validate_mitigations (
176- self , node : ast .expr , file : str
177- ) -> Union [ast .Constant , ast .List , None ]:
183+ def _validate_mitigations (self , node : ast .expr , file : str ) -> Optional [List [str ]]:
178184 if not isinstance (node , ast .List ) and not isinstance (node , ast .Constant ):
179185 self ._errors .append (
180186 self .Error (
@@ -203,12 +209,21 @@ def _validate_mitigations(
203209 if invalid :
204210 return None
205211 else :
206- return node
212+ return [ e . value for e in node . elts if isinstance ( e , ast . Constant )]
207213 elif isinstance (node , ast .Constant ):
208- return node
214+ return [ node . value ]
209215 return None
210216
211- def _validate_parameters (self , node : ast .expr , file : str ) -> Optional [ast .Dict ]:
217+ def _validate_parameters (
218+ self , node : ast .expr , file : str
219+ ) -> Optional [List [Tuple [str , str ]]]:
220+ def normalize (params ):
221+ for k , v in zip (params .keys , params .keys ):
222+ if isinstance (v , ast .Call ):
223+ yield k .value , v [1 ]
224+ else :
225+ yield k .value , ""
226+
212227 if not isinstance (node , ast .Dict ):
213228 self ._errors .append (
214229 self .Error (
@@ -246,7 +261,7 @@ def _validate_parameters(self, node: ast.expr, file: str) -> Optional[ast.Dict]:
246261 )
247262 is_ok = False
248263 if is_ok :
249- return node
264+ return list ( normalize ( node ))
250265 else :
251266 return None
252267
@@ -270,56 +285,36 @@ def errors(self) -> Iterable["Validator.Error"]:
270285 def warnings (self ) -> Iterable ["Validator.Warning" ]:
271286 return self ._validator .warnings
272287
273- def _construct_mitigations (self , code : ast .Constant , mitigations : Union [ast .Constant , ast .List ]):
274- if isinstance (mitigations , ast .Constant ):
275- return [mitigations .value ]
276- if isinstance (mitigations , ast .List ):
277- mitigation_values = [m .value for m in mitigations .elts if isinstance (m , ast .Constant )]
278- if len (mitigation_values ) != len (mitigations .elts ):
279- raise Exception (f"Internal error: validation not correct for '{ code } '. Not all elements in list are constants." )
280- return mitigation_values
281- else :
282- raise Exception (f"Internal error: validation not correct for '{ code } ' Invalid type." )
283-
284288 def _make_error (
285289 self , validated_node : Validator .ExaValidatedNode
286290 ) -> ErrorCodeDetails :
287291
288- def normalize (params ):
289- for k , v in zip (params .keys , params .keys ):
290- if isinstance (v , ast .Call ):
291- yield k .value , v [1 ]
292- else :
293- yield k .value , ""
294-
295292 return ErrorCodeDetails (
296- identifier = validated_node .code . value ,
297- message = validated_node .message . value ,
293+ identifier = validated_node .code ,
294+ message = validated_node .message ,
298295 messagePlaceholders = [
299296 Placeholder (name , description )
300- for name , description in normalize (
301- validated_node .parameters
302- )
297+ for name , description in validated_node .parameters
303298 ],
304299 description = None ,
305300 internalDescription = None ,
306301 potentialCauses = None ,
307- mitigations = self . _construct_mitigations ( validated_node .code , validated_node . mitigations ) ,
302+ mitigations = validated_node .mitigations ,
308303 sourceFile = self ._filename ,
309304 sourceLine = validated_node .lineno ,
310305 contextHash = None ,
311306 )
312307
313308 def collect (self ) -> None :
314309 for node in _ExaErrorNodeWalker (self ._root ):
315- validatation_result = self ._validator .validate (
316- node , self ._filename
317- )
310+ validatation_result = self ._validator .validate (node , self ._filename )
318311 if validatation_result .errors :
319312 # stop if we encountered any error
320313 return
321- if validatation_result .node is None :
322- raise Exception ("Validation finished with invalid result, but no error was set" )
314+ if validatation_result .node is None :
315+ raise Exception (
316+ "Validation finished with invalid result, but no error was set"
317+ )
323318 error_definition = self ._make_error (validatation_result .node )
324319 self ._error_definitions .append (error_definition )
325320
0 commit comments