Skip to content

Commit 9b1d7ce

Browse files
authored
Enable rendering of exceptions and tracebacks raised in subprocesses. (#130)
1 parent 21b98fb commit 9b1d7ce

9 files changed

+32
-29
lines changed

README.rst

-8
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,6 @@ projects. Its features include:
7979
.. end-features
8080
8181
82-
New Features
83-
------------
84-
85-
- Create a visualization of the DAG with ``pytask dag``. (`Tutorial
86-
<https://pytask-dev.readthedocs.io/en/latest/tutorials/how_to_visualize_the_dag.html>`_)
87-
- Show a profile of all tasks (duration, size of products) with ``pytask profile``.
88-
89-
9082
Installation
9183
------------
9284

docs/source/changes.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ all releases are available on `PyPI <https://pypi.org/project/pytask>`_ and
77
`Anaconda.org <https://anaconda.org/conda-forge/pytask>`_.
88

99

10-
0.1.0 - 2021-xx-xx
10+
0.1.0 - 2021-07-20
1111
------------------
1212

1313
- :gh:`106` implements a verbose mode for the execution which is available with ``pytask
@@ -25,6 +25,7 @@ all releases are available on `PyPI <https://pypi.org/project/pytask>`_ and
2525
verbose mode integers and increase verbosity with positive ones.
2626
- :gh:`129` allows to hide frames from the traceback by using ``__tracebackhide__ =
2727
True``.
28+
- :gh:`130` enables rendering of tracebacks from subprocesses with rich.
2829

2930

3031
0.0.16 - 2021-06-25

src/_pytask/clean.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from _pytask.pluginmanager import get_plugin_manager
1818
from _pytask.session import Session
1919
from _pytask.shared import get_first_non_none_value
20-
from rich.traceback import Traceback
20+
from _pytask.traceback import render_exc_info
2121

2222

2323
_HELP_TEXT_MODE = (
@@ -84,7 +84,7 @@ def clean(**config_from_cli):
8484
except Exception:
8585
session = Session({}, None)
8686
session.exit_code = ExitCode.CONFIGURATION_FAILED
87-
console.print(Traceback.from_exception(*sys.exc_info()))
87+
console.print(render_exc_info(*sys.exc_info(), config["show_locals"]))
8888

8989
else:
9090
try:
@@ -136,7 +136,7 @@ def clean(**config_from_cli):
136136
console.rule(style=ColorCode.FAILED)
137137

138138
except Exception:
139-
console.print(Traceback.from_exception(*sys.exc_info()))
139+
console.print(render_exc_info(*sys.exc_info(), config["show_locals"]))
140140
console.rule(style=ColorCode.FAILED)
141141
session.exit_code = ExitCode.FAILED
142142

src/_pytask/collect.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from _pytask.path import find_case_sensitive_path
2121
from _pytask.report import CollectionReport
2222
from _pytask.shared import reduce_node_name
23-
from rich.traceback import Traceback
23+
from _pytask.traceback import render_exc_info
2424

2525

2626
@hookimpl
@@ -252,9 +252,7 @@ def pytask_collect_log(session, reports, tasks):
252252
console.print()
253253

254254
console.print(
255-
Traceback.from_exception(
256-
*report.exc_info, show_locals=session.config["show_locals"]
257-
)
255+
render_exc_info(*report.exc_info, session.config["show_locals"])
258256
)
259257

260258
console.print()

src/_pytask/debugging.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from _pytask.shared import convert_truthy_or_falsy_to_bool
1111
from _pytask.shared import get_first_non_none_value
1212
from _pytask.traceback import remove_internal_traceback_frames_from_exc_info
13-
from rich.traceback import Traceback
13+
from _pytask.traceback import render_exc_info
1414

1515

1616
@hookimpl
@@ -364,7 +364,7 @@ def wrapper(*args, **kwargs):
364364

365365
console.print()
366366
console.rule("Traceback", characters=">", style=None)
367-
console.print(Traceback.from_exception(*exc_info))
367+
console.print(render_exc_info(*exc_info, session.config["show_locals"]))
368368

369369
post_mortem(exc_info[2])
370370

src/_pytask/execute.py

+2-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from _pytask.report import ExecutionReport
1818
from _pytask.shared import reduce_node_name
1919
from _pytask.traceback import remove_traceback_from_exc_info
20-
from rich.traceback import Traceback
20+
from _pytask.traceback import render_exc_info
2121

2222

2323
@hookimpl
@@ -198,9 +198,7 @@ def pytask_execute_log_end(session, reports):
198198

199199
console.print()
200200

201-
console.print(
202-
Traceback.from_exception(*report.exc_info, show_locals=show_locals)
203-
)
201+
console.print(render_exc_info(*report.exc_info, show_locals))
204202

205203
console.print()
206204
show_capture = session.config["show_capture"]

src/_pytask/profile.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
from _pytask.session import Session
1919
from _pytask.shared import get_first_non_none_value
2020
from _pytask.shared import reduce_node_name
21+
from _pytask.traceback import render_exc_info
2122
from pony import orm
2223
from rich.table import Table
23-
from rich.traceback import Traceback
2424

2525

2626
class Runtime(db.Entity):
@@ -108,7 +108,7 @@ def profile(**config_from_cli):
108108
except (ConfigurationError, Exception):
109109
session = Session({}, None)
110110
session.exit_code = ExitCode.CONFIGURATION_FAILED
111-
console.print(Traceback.from_exception(*sys.exc_info()))
111+
console.print(render_exc_info(*sys.exc_info(), config["show_locals"]))
112112

113113
else:
114114
try:

src/_pytask/resolve_dependencies.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
from _pytask.report import ResolvingDependenciesReport
2525
from _pytask.shared import reduce_names_of_multiple_nodes
2626
from _pytask.shared import reduce_node_name
27+
from _pytask.traceback import render_exc_info
2728
from pony import orm
28-
from rich.traceback import Traceback
2929
from rich.tree import Tree
3030

3131

@@ -297,7 +297,7 @@ def _check_if_tasks_have_the_same_products(dag):
297297

298298

299299
@hookimpl
300-
def pytask_resolve_dependencies_log(report):
300+
def pytask_resolve_dependencies_log(session, report):
301301
"""Log errors which happened while resolving dependencies."""
302302
console.print()
303303
console.rule(
@@ -306,7 +306,7 @@ def pytask_resolve_dependencies_log(report):
306306
)
307307

308308
console.print()
309-
console.print(Traceback.from_exception(*report.exc_info))
309+
console.print(render_exc_info(*report.exc_info, session.config["show_locals"]))
310310

311311
console.print()
312312
console.rule(style=ColorCode.FAILED)

src/_pytask/traceback.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
11
"""Process tracebacks."""
22
from pathlib import Path
3+
from types import TracebackType
34

45
import _pytask
56
import pluggy
7+
from rich.traceback import Traceback
68

79
_PLUGGY_DIRECTORY = Path(pluggy.__file__).parent
810
_PYTASK_DIRECTORY = Path(_pytask.__file__).parent
911

1012

13+
def render_exc_info(exc_type, exc_value, traceback, show_locals=False):
14+
if isinstance(traceback, str):
15+
renderable = traceback
16+
else:
17+
renderable = Traceback.from_exception(
18+
exc_type, exc_value, traceback, show_locals=show_locals
19+
)
20+
21+
return renderable
22+
23+
1124
def remove_traceback_from_exc_info(exc_info):
1225
"""Remove traceback from exception."""
1326
return (*exc_info[:2], None)
@@ -21,8 +34,9 @@ def remove_internal_traceback_frames_from_exc_info(exc_info):
2134
2235
"""
2336
if exc_info is not None:
24-
filtered_traceback = _filter_internal_traceback_frames(exc_info[2])
25-
exc_info = (*exc_info[:2], filtered_traceback)
37+
if isinstance(exc_info[2], TracebackType):
38+
filtered_traceback = _filter_internal_traceback_frames(exc_info[2])
39+
exc_info = (*exc_info[:2], filtered_traceback)
2640

2741
return exc_info
2842

0 commit comments

Comments
 (0)