Example #1
0
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)
Example #2
0
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
Example #3
0
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")
Example #5
0
    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
Example #6
0
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)