From 6fb2b45c6fd95b999262cf925426c7d94f0f4a32 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 29 Jan 2022 02:13:44 +0100 Subject: [PATCH 1/2] Allow __tracebackhide__ to be a callable. --- docs/source/changes.rst | 10 ++++++++++ src/_pytask/traceback.py | 16 +++++++++++----- tests/test_traceback.py | 14 +++++++++++--- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/docs/source/changes.rst b/docs/source/changes.rst index 3401e93f..42a92864 100644 --- a/docs/source/changes.rst +++ b/docs/source/changes.rst @@ -7,6 +7,16 @@ all releases are available on `PyPI `_ and `Anaconda.org `_. +0.1.7 - 2022-01-28 +------------------ + +- :gh:`153` adds support for Python 3.10 which requires pony >= 0.7.15. +- :gh:`192` deprecates Python 3.6. +- :gh:`209` cancels previous CI jobs when a new job is started. +- :gh:`210` allows ``__tracebackhide__`` to be a callable which accepts the current + exception as an input. Closes :gh:`145`. + + 0.1.6 - 2022-01-27 ------------------ diff --git a/src/_pytask/traceback.py b/src/_pytask/traceback.py index e384cec1..8f6ef3c0 100644 --- a/src/_pytask/traceback.py +++ b/src/_pytask/traceback.py @@ -57,13 +57,15 @@ def remove_internal_traceback_frames_from_exc_info( """ if exc_info is not None: if isinstance(exc_info[2], TracebackType): - filtered_traceback = _filter_internal_traceback_frames(exc_info[2]) + filtered_traceback = _filter_internal_traceback_frames(exc_info) exc_info = (*exc_info[:2], filtered_traceback) return exc_info -def _is_internal_or_hidden_traceback_frame(frame: TracebackType) -> bool: +def _is_internal_or_hidden_traceback_frame( + frame: TracebackType, exc_info: ExceptionInfo +) -> bool: """Returns ``True`` if traceback frame belongs to internal packages or is hidden. Internal packages are ``_pytask`` and ``pluggy``. A hidden frame is indicated by a @@ -71,7 +73,10 @@ def _is_internal_or_hidden_traceback_frame(frame: TracebackType) -> bool: """ is_hidden = frame.tb_frame.f_locals.get("__tracebackhide__", False) - if is_hidden: + + if callable(is_hidden): + return is_hidden(exc_info) + elif is_hidden: return True path = Path(frame.tb_frame.f_code.co_filename) @@ -79,15 +84,16 @@ def _is_internal_or_hidden_traceback_frame(frame: TracebackType) -> bool: def _filter_internal_traceback_frames( - frame: TracebackType, + exc_info: ExceptionInfo, ) -> TracebackType: """Filter internal traceback frames from traceback. If the first external frame is visited, return the frame. Else return ``None``. """ + frame = exc_info[2] for frame in _yield_traceback_frames(frame): - if frame is None or not _is_internal_or_hidden_traceback_frame(frame): + if frame is None or not _is_internal_or_hidden_traceback_frame(frame, exc_info): break return frame diff --git a/tests/test_traceback.py b/tests/test_traceback.py index 5d02dcc9..07ab683e 100644 --- a/tests/test_traceback.py +++ b/tests/test_traceback.py @@ -8,12 +8,20 @@ @pytest.mark.end_to_end -@pytest.mark.parametrize("is_hidden", [True, False]) -def test_hide_traceback_from_error_report(runner, tmp_path, is_hidden): +@pytest.mark.parametrize( + "value, is_hidden", + [ + (True, True), + (False, False), + ("lambda exc_info: True", True), + ("lambda exc_info: False", False), + ], +) +def test_hide_traceback_from_error_report(runner, tmp_path, value, is_hidden): source = f""" def task_main(): a = "This variable should not be shown." - __tracebackhide__ = {is_hidden} + __tracebackhide__ = {value} helper() From 4ed2e1ddd070c5de90e2453afa7e4681907a2c52 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Sat, 29 Jan 2022 02:25:28 +0100 Subject: [PATCH 2/2] one more test case using exception in callable. --- tests/test_traceback.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/test_traceback.py b/tests/test_traceback.py index 07ab683e..acf550f9 100644 --- a/tests/test_traceback.py +++ b/tests/test_traceback.py @@ -9,15 +9,19 @@ @pytest.mark.end_to_end @pytest.mark.parametrize( - "value, is_hidden", + "value, exception, is_hidden", [ - (True, True), - (False, False), - ("lambda exc_info: True", True), - ("lambda exc_info: False", False), + ("True", "Exception", True), + ("False", "Exception", False), + ("lambda exc_info: True", "Exception", True), + ("lambda exc_info: False", "Exception", False), + ("lambda exc_info: isinstance(exc_info[1], ValueError)", "ValueError", True), + ("lambda exc_info: isinstance(exc_info[1], ValueError)", "TypeError", False), ], ) -def test_hide_traceback_from_error_report(runner, tmp_path, value, is_hidden): +def test_hide_traceback_from_error_report( + runner, tmp_path, value, exception, is_hidden +): source = f""" def task_main(): a = "This variable should not be shown." @@ -28,7 +32,7 @@ def task_main(): def helper(): - raise Exception + raise {exception} """ tmp_path.joinpath("task_main.py").write_text(textwrap.dedent(source))