Skip to content

Commit a8e54b3

Browse files
authored
fix: include stacktrace in signal eval error message (#4143)
1 parent d1c34ce commit a8e54b3

4 files changed

Lines changed: 25 additions & 11 deletions

File tree

sqlmesh/core/snapshot/definition.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@
3939
yesterday,
4040
)
4141
from sqlmesh.utils.errors import SQLMeshError, SignalEvalError
42-
from sqlmesh.utils.metaprogramming import prepare_env, print_exception
42+
from sqlmesh.utils.metaprogramming import (
43+
prepare_env,
44+
print_exception,
45+
format_evaluated_code_exception,
46+
Executable,
47+
)
4348
from sqlmesh.utils.hashing import hash_data
4449
from sqlmesh.utils.pydantic import PydanticModel, field_validator
4550

@@ -962,6 +967,7 @@ def check_ready_intervals(self, intervals: Intervals, context: ExecutionContext)
962967
env[signal_name],
963968
intervals,
964969
context,
970+
python_env=python_env,
965971
dialect=self.model.dialect,
966972
path=self.model._path,
967973
kwargs=kwargs,
@@ -2153,6 +2159,7 @@ def _check_ready_intervals(
21532159
check: t.Callable,
21542160
intervals: Intervals,
21552161
context: ExecutionContext,
2162+
python_env: t.Dict[str, Executable],
21562163
dialect: DialectType = None,
21572164
path: Path = Path(),
21582165
kwargs: t.Optional[t.Dict] = None,
@@ -2172,7 +2179,7 @@ def _check_ready_intervals(
21722179
context=context,
21732180
)
21742181
except Exception as ex:
2175-
raise SignalEvalError("Error evaluating signal") from ex
2182+
raise SignalEvalError(format_evaluated_code_exception(ex, python_env))
21762183

21772184
if isinstance(ready_intervals, bool):
21782185
if not ready_intervals:

sqlmesh/utils/errors.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from __future__ import annotations
22

3+
import traceback
34
import typing as t
45
from enum import auto
56
from pathlib import Path

sqlmesh/utils/metaprogramming.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,9 @@ def format_evaluated_code_exception(
539539
for error_line in format_exception(exception):
540540
traceback_match = error_line.startswith("Traceback (most recent call last):")
541541
model_def_match = re.search('File ".*?core/model/definition.py', error_line)
542-
if traceback_match or model_def_match:
542+
snapshot_def_match = re.search('File ".*?core/snapshot/definition.py', error_line)
543+
core_macros_match = re.search('File ".*?core/macros.py', error_line)
544+
if traceback_match or model_def_match or snapshot_def_match or core_macros_match:
543545
continue
544546

545547
error_match = re.search("^.*?Error: ", error_line)

tests/core/test_snapshot.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2499,23 +2499,28 @@ def test_contiguous_intervals():
24992499

25002500
def test_check_ready_intervals(mocker: MockerFixture):
25012501
def assert_always_signal(intervals):
2502-
assert _check_ready_intervals(lambda _: True, intervals, mocker.Mock()) == intervals
2502+
assert (
2503+
_check_ready_intervals(lambda _: True, intervals, mocker.Mock(), mocker.Mock())
2504+
== intervals
2505+
)
25032506

25042507
assert_always_signal([])
25052508
assert_always_signal([(0, 1)])
25062509
assert_always_signal([(0, 1), (1, 2)])
25072510
assert_always_signal([(0, 1), (2, 3)])
25082511

25092512
def assert_never_signal(intervals):
2510-
assert _check_ready_intervals(lambda _: False, intervals, mocker.Mock()) == []
2513+
assert (
2514+
_check_ready_intervals(lambda _: False, intervals, mocker.Mock(), mocker.Mock()) == []
2515+
)
25112516

25122517
assert_never_signal([])
25132518
assert_never_signal([(0, 1)])
25142519
assert_never_signal([(0, 1), (1, 2)])
25152520
assert_never_signal([(0, 1), (2, 3)])
25162521

25172522
def assert_empty_signal(intervals):
2518-
assert _check_ready_intervals(lambda _: [], intervals, mocker.Mock()) == []
2523+
assert _check_ready_intervals(lambda _: [], intervals, mocker.Mock(), mocker.Mock()) == []
25192524

25202525
assert_empty_signal([])
25212526
assert_empty_signal([(0, 1)])
@@ -2532,7 +2537,7 @@ def assert_check_intervals(
25322537
):
25332538
mock = mocker.Mock()
25342539
mock.side_effect = [to_intervals(r) for r in ready]
2535-
_check_ready_intervals(mock, intervals, mocker.Mock()) == expected
2540+
_check_ready_intervals(mock, intervals, mocker.Mock(), mocker.Mock()) == expected
25362541

25372542
assert_check_intervals([], [], [])
25382543
assert_check_intervals([(0, 1)], [[]], [])
@@ -2571,16 +2576,15 @@ def assert_check_intervals(
25712576
[[(0, 1)], [(3, 4)]],
25722577
[(0, 1), (3, 4)],
25732578
)
2574-
with pytest.raises(SignalEvalError) as excinfo:
2579+
2580+
with pytest.raises(SignalEvalError):
25752581
_check_ready_intervals(
25762582
lambda _: (_ for _ in ()).throw(MemoryError("Some exception")),
25772583
[(0, 1), (1, 2)],
25782584
mocker.Mock(),
2585+
mocker.Mock(),
25792586
)
25802587

2581-
assert isinstance(excinfo.value.__cause__, MemoryError)
2582-
assert str(excinfo.value.__cause__) == "Some exception"
2583-
25842588

25852589
@pytest.mark.parametrize(
25862590
"auto_restatement_intervals,expected_auto_restatement_start",

0 commit comments

Comments
 (0)