def _print_errored_task_report(session: Session, report: ExecutionReport) -> None: """Print the traceback and the exception of an errored report.""" task_name = format_task_id( task=report.task, editor_url_scheme=session.config["editor_url_scheme"], short_name=True, ) text = Text.assemble("Task ", task_name, " failed", style="failed") console.rule(text, style=report.outcome.style) console.print() if report.exc_info and isinstance(report.exc_info[1], Exit): console.print(format_exception_without_traceback(report.exc_info)) else: console.print( render_exc_info(*report.exc_info, session.config["show_locals"])) console.print() show_capture = session.config["show_capture"] for when, key, content in report.sections: if key in ("stdout", "stderr") and show_capture in ( ShowCapture[key.upper()], ShowCapture.ALL, ): console.rule(f"Captured {key} during {when}", style=None) console.print(content)
def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[Task] ) -> None: """Log collection.""" session.collection_end = time.time() console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.") failed_reports = [r for r in reports if r.outcome == CollectionOutcome.FAIL] if failed_reports: counts = count_outcomes(reports, CollectionOutcome) console.print() console.rule( Text("Failures during collection", style=CollectionOutcome.FAIL.style), style=CollectionOutcome.FAIL.style, ) for report in failed_reports: if report.node is None: header = "Error" else: if isinstance(report.node, Task): short_name = format_task_id( report.node, editor_url_scheme="no_link", short_name=True ) else: short_name = reduce_node_name(report.node, session.config["paths"]) header = f"Could not collect {short_name}" console.rule( Text(header, style=CollectionOutcome.FAIL.style), style=CollectionOutcome.FAIL.style, ) console.print() console.print( render_exc_info(*report.exc_info, session.config["show_locals"]) ) console.print() panel = create_summary_panel( counts, CollectionOutcome, "Collected errors and tasks" ) console.print(panel) session.hook.pytask_log_session_footer( session=session, duration=session.collection_end - session.collection_start, outcome=CollectionOutcome.FAIL if counts[CollectionOutcome.FAIL] else CollectionOutcome.SUCCESS, ) raise CollectionError
def profile(**config_from_cli: Any) -> NoReturn: """Show information about tasks like runtime and memory consumption of products.""" config_from_cli["command"] = "profile" try: # Duplication of the same mechanism in :func:`pytask.main.main`. pm = get_plugin_manager() from _pytask import cli pm.register(cli) pm.hook.pytask_add_hooks(pm=pm) config = pm.hook.pytask_configure(pm=pm, config_from_cli=config_from_cli) session = Session.from_config(config) except (ConfigurationError, Exception): # pragma: no cover session = Session({}, None) session.exit_code = ExitCode.CONFIGURATION_FAILED exc_info: tuple[ type[BaseException], BaseException, TracebackType | None ] = sys.exc_info() console.print(render_exc_info(*exc_info, show_locals=config["show_locals"])) else: try: session.hook.pytask_log_session_header(session=session) session.hook.pytask_collect(session=session) session.hook.pytask_resolve_dependencies(session=session) profile: dict[str, dict[str, Any]] = { task.name: {} for task in session.tasks } session.hook.pytask_profile_add_info_on_task( session=session, tasks=session.tasks, profile=profile ) profile = _process_profile(profile) _print_profile_table(profile, session.tasks, session.config) session.hook.pytask_profile_export_profile(session=session, profile=profile) console.rule(style="neutral") except CollectionError: # pragma: no cover session.exit_code = ExitCode.COLLECTION_FAILED except Exception: # pragma: no cover session.exit_code = ExitCode.FAILED console.print_exception() console.rule(style="failed") sys.exit(session.exit_code)
def pytask_resolve_dependencies_log( session: Session, report: ResolvingDependenciesReport) -> None: """Log errors which happened while resolving dependencies.""" console.print() console.rule( Text("Failures during resolving dependencies", style="failed"), style="failed", ) console.print() console.print( render_exc_info(*report.exc_info, session.config["show_locals"])) console.print() console.rule(style="failed")
def wrapper(*args: Any, **kwargs: Any) -> None: capman = session.config["pm"].get_plugin("capturemanager") live_manager = session.config["pm"].get_plugin("live_manager") try: task_function(*args, **kwargs) except Exception: # Order is important! Pausing the live object before the capturemanager # would flush the table to stdout and it will be visible in the captured # output. capman.suspend(in_=True) out, err = capman.read() live_manager.pause() if out or err: console.print() if out: console.rule("Captured stdout", style=None) console.print(out) if err: console.rule("Captured stderr", style=None) console.print(err) exc_info = remove_internal_traceback_frames_from_exc_info( sys.exc_info()) console.print() console.rule("Traceback", characters=">", style=None) console.print( render_exc_info(*exc_info, session.config["show_locals"])) post_mortem(exc_info[2]) live_manager.resume() capman.resume() raise
def clean(**config_from_cli: Any) -> NoReturn: """Clean the provided paths by removing files unknown to pytask.""" config_from_cli["command"] = "clean" try: # Duplication of the same mechanism in :func:`pytask.main.main`. pm = get_plugin_manager() from _pytask import cli pm.register(cli) pm.hook.pytask_add_hooks(pm=pm) config = pm.hook.pytask_configure(pm=pm, config_from_cli=config_from_cli) session = Session.from_config(config) except Exception: session = Session({}, None) session.exit_code = ExitCode.CONFIGURATION_FAILED exc_info: tuple[type[BaseException], BaseException, TracebackType | None] = sys.exc_info() console.print(render_exc_info(*exc_info)) else: try: session.hook.pytask_log_session_header(session=session) session.hook.pytask_collect(session=session) known_paths = _collect_all_paths_known_to_pytask(session) exclude = session.config["exclude"] include_directories = session.config["directories"] unknown_paths = _find_all_unknown_paths(session, known_paths, exclude, include_directories) common_ancestor = find_common_ancestor(*unknown_paths, *session.config["paths"]) if unknown_paths: targets = "Files" if session.config["directories"]: targets += " and directories" console.print(f"\n{targets} which can be removed:\n") for path in unknown_paths: short_path = relative_to(path, common_ancestor) if session.config["mode"] == "dry-run": console.print(f"Would remove {short_path}") else: should_be_deleted = session.config[ "mode"] == "force" or click.confirm( f"Would you like to remove {short_path}?") if should_be_deleted: if not session.config["quiet"]: console.print(f"Remove {short_path}") if path.is_dir(): shutil.rmtree(path) else: path.unlink() else: console.print() console.print( "There are no files and directories which can be deleted.") console.print() console.rule(style=None) except CollectionError: session.exit_code = ExitCode.COLLECTION_FAILED console.rule(style="failed") except Exception: exc_info = sys.exc_info() console.print( render_exc_info(*exc_info, show_locals=config["show_locals"])) console.rule(style="failed") session.exit_code = ExitCode.FAILED sys.exit(session.exit_code)