Skip to content

Enable rendering of exceptions and tracebacks raised in subprocesses. #130

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jul 20, 2021
8 changes: 0 additions & 8 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,6 @@ projects. Its features include:
.. end-features


New Features
------------

- Create a visualization of the DAG with ``pytask dag``. (`Tutorial
<https://pytask-dev.readthedocs.io/en/latest/tutorials/how_to_visualize_the_dag.html>`_)
- Show a profile of all tasks (duration, size of products) with ``pytask profile``.


Installation
------------

Expand Down
3 changes: 2 additions & 1 deletion docs/source/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ all releases are available on `PyPI <https://pypi.org/project/pytask>`_ and
`Anaconda.org <https://anaconda.org/conda-forge/pytask>`_.


0.1.0 - 2021-xx-xx
0.1.0 - 2021-07-20
------------------

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


0.0.16 - 2021-06-25
Expand Down
6 changes: 3 additions & 3 deletions src/_pytask/clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from _pytask.pluginmanager import get_plugin_manager
from _pytask.session import Session
from _pytask.shared import get_first_non_none_value
from rich.traceback import Traceback
from _pytask.traceback import render_exc_info


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

else:
try:
Expand Down Expand Up @@ -136,7 +136,7 @@ def clean(**config_from_cli):
console.rule(style=ColorCode.FAILED)

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

Expand Down
6 changes: 2 additions & 4 deletions src/_pytask/collect.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from _pytask.path import find_case_sensitive_path
from _pytask.report import CollectionReport
from _pytask.shared import reduce_node_name
from rich.traceback import Traceback
from _pytask.traceback import render_exc_info


@hookimpl
Expand Down Expand Up @@ -252,9 +252,7 @@ def pytask_collect_log(session, reports, tasks):
console.print()

console.print(
Traceback.from_exception(
*report.exc_info, show_locals=session.config["show_locals"]
)
render_exc_info(*report.exc_info, session.config["show_locals"])
)

console.print()
Expand Down
4 changes: 2 additions & 2 deletions src/_pytask/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from _pytask.shared import convert_truthy_or_falsy_to_bool
from _pytask.shared import get_first_non_none_value
from _pytask.traceback import remove_internal_traceback_frames_from_exc_info
from rich.traceback import Traceback
from _pytask.traceback import render_exc_info


@hookimpl
Expand Down Expand Up @@ -364,7 +364,7 @@ def wrapper(*args, **kwargs):

console.print()
console.rule("Traceback", characters=">", style=None)
console.print(Traceback.from_exception(*exc_info))
console.print(render_exc_info(*exc_info, session.config["show_locals"]))

post_mortem(exc_info[2])

Expand Down
6 changes: 2 additions & 4 deletions src/_pytask/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from _pytask.report import ExecutionReport
from _pytask.shared import reduce_node_name
from _pytask.traceback import remove_traceback_from_exc_info
from rich.traceback import Traceback
from _pytask.traceback import render_exc_info


@hookimpl
Expand Down Expand Up @@ -198,9 +198,7 @@ def pytask_execute_log_end(session, reports):

console.print()

console.print(
Traceback.from_exception(*report.exc_info, show_locals=show_locals)
)
console.print(render_exc_info(*report.exc_info, show_locals))

console.print()
show_capture = session.config["show_capture"]
Expand Down
4 changes: 2 additions & 2 deletions src/_pytask/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
from _pytask.session import Session
from _pytask.shared import get_first_non_none_value
from _pytask.shared import reduce_node_name
from _pytask.traceback import render_exc_info
from pony import orm
from rich.table import Table
from rich.traceback import Traceback


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

else:
try:
Expand Down
6 changes: 3 additions & 3 deletions src/_pytask/resolve_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from _pytask.report import ResolvingDependenciesReport
from _pytask.shared import reduce_names_of_multiple_nodes
from _pytask.shared import reduce_node_name
from _pytask.traceback import render_exc_info
from pony import orm
from rich.traceback import Traceback
from rich.tree import Tree


Expand Down Expand Up @@ -297,7 +297,7 @@ def _check_if_tasks_have_the_same_products(dag):


@hookimpl
def pytask_resolve_dependencies_log(report):
def pytask_resolve_dependencies_log(session, report):
"""Log errors which happened while resolving dependencies."""
console.print()
console.rule(
Expand All @@ -306,7 +306,7 @@ def pytask_resolve_dependencies_log(report):
)

console.print()
console.print(Traceback.from_exception(*report.exc_info))
console.print(render_exc_info(*report.exc_info, session.config["show_locals"]))

console.print()
console.rule(style=ColorCode.FAILED)
18 changes: 16 additions & 2 deletions src/_pytask/traceback.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
"""Process tracebacks."""
from pathlib import Path
from types import TracebackType

import _pytask
import pluggy
from rich.traceback import Traceback

_PLUGGY_DIRECTORY = Path(pluggy.__file__).parent
_PYTASK_DIRECTORY = Path(_pytask.__file__).parent


def render_exc_info(exc_type, exc_value, traceback, show_locals=False):
if isinstance(traceback, str):
renderable = traceback
else:
renderable = Traceback.from_exception(
exc_type, exc_value, traceback, show_locals=show_locals
)

return renderable


def remove_traceback_from_exc_info(exc_info):
"""Remove traceback from exception."""
return (*exc_info[:2], None)
Expand All @@ -21,8 +34,9 @@ def remove_internal_traceback_frames_from_exc_info(exc_info):

"""
if exc_info is not None:
filtered_traceback = _filter_internal_traceback_frames(exc_info[2])
exc_info = (*exc_info[:2], filtered_traceback)
if isinstance(exc_info[2], TracebackType):
filtered_traceback = _filter_internal_traceback_frames(exc_info[2])
exc_info = (*exc_info[:2], filtered_traceback)

return exc_info

Expand Down