Skip to content

Commit c2fdced

Browse files
authored
fallback catch all exceptions (#148)
1 parent 86d7544 commit c2fdced

File tree

2 files changed

+78
-22
lines changed

2 files changed

+78
-22
lines changed

src/pdl/pdl_interpreter.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,20 @@ def step_advanced_block(
318318
result, background, scope, trace = yield from step_block_body(
319319
state, scope, block, loc
320320
)
321-
except PDLRuntimeError as exc:
321+
trace = trace.model_copy(update={"result": result})
322+
if block.parser is not None:
323+
result = parse_result(block.parser, result)
324+
if block.spec is not None and not isinstance(block, FunctionBlock):
325+
errors = type_check_spec(result, block.spec, block.location)
326+
if len(errors) > 0:
327+
message = "Type errors during spec checking:\n" + "\n".join(errors)
328+
raise PDLRuntimeError(
329+
message,
330+
loc=loc,
331+
trace=ErrorBlock(msg=message, program=trace),
332+
fallback=result,
333+
)
334+
except Exception as exc:
322335
if block.fallback is None:
323336
raise exc from exc
324337
(
@@ -334,29 +347,19 @@ def step_advanced_block(
334347
scope,
335348
loc=loc,
336349
)
337-
trace = trace.model_copy(update={"result": result})
338-
if block.parser is not None:
339-
try:
340-
result = parse_result(block.parser, result)
341-
except PDLRuntimeParserError as exc:
342-
raise PDLRuntimeError(
343-
exc.message,
344-
loc=exc.loc or loc,
345-
trace=ErrorBlock(msg=exc.message, program=trace, fallback=result),
346-
) from exc
350+
if block.spec is not None and not isinstance(block, FunctionBlock):
351+
errors = type_check_spec(result, block.spec, block.location)
352+
if len(errors) > 0:
353+
message = "Type errors during spec checking:\n" + "\n".join(errors)
354+
raise PDLRuntimeError( # pylint: disable=raise-missing-from
355+
message,
356+
loc=append(loc, "fallback"),
357+
trace=ErrorBlock(msg=message, program=trace),
358+
fallback=result,
359+
)
347360
if block.assign is not None:
348361
var = block.assign
349362
scope = scope | {var: result}
350-
if block.spec is not None and not isinstance(block, FunctionBlock):
351-
errors = type_check_spec(result, block.spec, block.location)
352-
if len(errors) > 0:
353-
message = "Type errors during spec checking:\n" + "\n".join(errors)
354-
raise PDLRuntimeError(
355-
message,
356-
loc=loc,
357-
trace=ErrorBlock(msg=message, program=trace),
358-
fallback=result,
359-
)
360363
if ContributeTarget.RESULT not in block.contribute:
361364
result = ""
362365
if ContributeTarget.CONTEXT not in block.contribute:

tests/test_fallback.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
import pytest
2+
3+
from pdl.pdl import exec_str
14
from pdl.pdl_ast import Program
2-
from pdl.pdl_interpreter import InterpreterState, empty_scope, process_prog
5+
from pdl.pdl_interpreter import (
6+
InterpreterState,
7+
PDLRuntimeError,
8+
empty_scope,
9+
process_prog,
10+
)
311

412
direct_fallback_data = {"model": "raise an error", "fallback": "The error was caught"}
513

@@ -35,3 +43,48 @@ def test_error_in_sequence():
3543
data = Program.model_validate(error_in_sequence_data)
3644
text, _, _, _ = process_prog(state, empty_scope, data)
3745
assert text == "The error was caught"
46+
47+
48+
def test_python_exception():
49+
prog_str = """
50+
code: "raise Exception()"
51+
lang: python
52+
fallback: "Exception caught"
53+
"""
54+
result = exec_str(prog_str)
55+
assert result == "Exception caught"
56+
57+
58+
def test_parse_regex_error():
59+
prog_str = """
60+
text: "Hello"
61+
parser:
62+
regex: "(e"
63+
fallback: "Exception caught"
64+
"""
65+
result = exec_str(prog_str)
66+
assert result == "Exception caught"
67+
68+
69+
def test_type_checking():
70+
prog_str = """
71+
text: "Hello"
72+
spec: int
73+
fallback: 4012
74+
"""
75+
result = exec_str(prog_str)
76+
assert result == 4012
77+
78+
79+
def test_type_checking_in_fallback():
80+
prog_str = """
81+
model: "raise an error"
82+
spec: int
83+
fallback: "Error"
84+
"""
85+
with pytest.raises(PDLRuntimeError) as exc:
86+
_ = exec_str(prog_str)
87+
assert (
88+
str(exc.value.message)
89+
== "Type errors during spec checking:\nline 0 - Error should be of type <class 'int'>" # TODO: check line number
90+
)

0 commit comments

Comments
 (0)