diff --git a/README.rst b/README.rst index c7043e7c..b01c5faa 100644 --- a/README.rst +++ b/README.rst @@ -79,14 +79,6 @@ projects. Its features include: .. end-features -New Features ------------- - -- Create a visualization of the DAG with ``pytask dag``. (`Tutorial - `_) -- Show a profile of all tasks (duration, size of products) with ``pytask profile``. - - Installation ------------ diff --git a/docs/source/changes.rst b/docs/source/changes.rst index 2c7b513e..a2e05d85 100644 --- a/docs/source/changes.rst +++ b/docs/source/changes.rst @@ -7,7 +7,7 @@ all releases are available on `PyPI `_ and `Anaconda.org `_. -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 @@ -25,6 +25,7 @@ all releases are available on `PyPI `_ 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 diff --git a/src/_pytask/clean.py b/src/_pytask/clean.py index 856d37d6..df6f6798 100644 --- a/src/_pytask/clean.py +++ b/src/_pytask/clean.py @@ -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 = ( @@ -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: @@ -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 diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index d78c5d75..b7bc3882 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -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 @@ -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() diff --git a/src/_pytask/debugging.py b/src/_pytask/debugging.py index a9abba1a..b6f999ce 100644 --- a/src/_pytask/debugging.py +++ b/src/_pytask/debugging.py @@ -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 @@ -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]) diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index 357df24d..08d2d735 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -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 @@ -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"] diff --git a/src/_pytask/profile.py b/src/_pytask/profile.py index 679b9440..4aebbb05 100644 --- a/src/_pytask/profile.py +++ b/src/_pytask/profile.py @@ -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): @@ -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: diff --git a/src/_pytask/resolve_dependencies.py b/src/_pytask/resolve_dependencies.py index 4c9e9af5..d97f8245 100644 --- a/src/_pytask/resolve_dependencies.py +++ b/src/_pytask/resolve_dependencies.py @@ -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 @@ -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( @@ -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) diff --git a/src/_pytask/traceback.py b/src/_pytask/traceback.py index e7a1ba64..22321736 100644 --- a/src/_pytask/traceback.py +++ b/src/_pytask/traceback.py @@ -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) @@ -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