Skip to content

Commit 0cc80d0

Browse files
committed
Refactored _parse.py even more
1 parent 01ca4b4 commit 0cc80d0

2 files changed

Lines changed: 56 additions & 52 deletions

File tree

exasol/error/_parse.py

Lines changed: 44 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from dataclasses import dataclass
55
from pathlib import Path
66
from typing import (
7-
Any,
87
Dict,
98
Generator,
109
Iterable,
@@ -49,7 +48,7 @@ def __iter__(self) -> Generator[ast.Call, None, None]:
4948

5049

5150
def _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

test/unit/parse_test.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33

44
import pytest
55

6-
from exasol.error._parse import parse_file, Validator
6+
from exasol.error._parse import (
7+
Validator,
8+
parse_file,
9+
)
710
from exasol.error._report import ErrorCodeDetails
811

912

@@ -12,7 +15,7 @@
1215
[
1316
("'str mitigation'", ["str mitigation"]),
1417
("42", [42]),
15-
("""['mitigation a', 42.5]""",['mitigation a', 42.5]),
18+
("""['mitigation a', 42.5]""", ["mitigation a", 42.5]),
1619
],
1720
)
1821
def test_mitigation_values(mitigation_str, mitigation):
@@ -80,7 +83,13 @@ def test_mitigation_none_constant_fails():
8083

8184
expected_definitions = []
8285
expected_warnings = []
83-
expected_errors = [Validator.Error(message="mitigations only can contain constant values, details: <class 'ast.BinOp'>", file='<StringIO>', line_number=10)]
86+
expected_errors = [
87+
Validator.Error(
88+
message="mitigations only can contain constant values, details: <class 'ast.BinOp'>",
89+
file="<StringIO>",
90+
line_number=10,
91+
)
92+
]
8493

8594
definitions, warnings, errors = parse_file(f)
8695

0 commit comments

Comments
 (0)