Beispiel #1
0
def pytask_execute_task(task: Task) -> bool:
    """Execute task."""
    kwargs = {**task.kwargs}

    func_arg_names = set(inspect.signature(task.function).parameters)
    for arg_name in ("depends_on", "produces"):
        if arg_name in func_arg_names:
            attribute = getattr(task, arg_name)
            kwargs[arg_name] = tree_map(lambda x: x.value, attribute)

    task.execute(**kwargs)
    return True
Beispiel #2
0
    def task_capture(self, when: str,
                     task: Task) -> Generator[None, None, None]:
        """Pipe captured stdout and stderr into report sections."""
        self.resume()

        try:
            yield
        finally:
            self.suspend(in_=False)

        out, err = self.read()
        task.add_report_section(when, "stdout", out)
        task.add_report_section(when, "stderr", err)
Beispiel #3
0
def pytask_collect_task(
    session: Session, path: Path, name: str, obj: Any
) -> Task | None:
    """Collect a task which is a function.

    There is some discussion on how to detect functions in this `thread
    <https://stackoverflow.com/q/624926/7523785>`_. :class:`types.FunctionType` does not
    detect built-ins which is not possible anyway.

    """
    if (name.startswith("task_") or has_mark(obj, "task")) and callable(obj):
        dependencies = parse_nodes(session, path, name, obj, depends_on)
        products = parse_nodes(session, path, name, obj, produces)

        markers = obj.pytask_meta.markers if hasattr(obj, "pytask_meta") else []
        kwargs = obj.pytask_meta.kwargs if hasattr(obj, "pytask_meta") else {}

        # Get the underlying function to avoid having different states of the function,
        # e.g. due to pytask_meta, in different layers of the wrapping.
        unwrapped = inspect.unwrap(obj)

        return Task(
            base_name=name,
            path=path,
            function=unwrapped,
            depends_on=dependencies,
            produces=products,
            markers=markers,
            kwargs=kwargs,
        )
    else:
        return None
Beispiel #4
0
def wrap_function_for_post_mortem_debugging(session: Session,
                                            task: Task) -> None:
    """Wrap the function for post-mortem debugging."""

    task_function = task.function

    @functools.wraps(task_function)
    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

    task.function = wrapper
Beispiel #5
0
def pytask_collect_task_protocol(
    session: Session, path: Path, name: str, obj: Any
) -> CollectionReport | None:
    """Start protocol for collecting a task."""
    try:
        session.hook.pytask_collect_task_setup(
            session=session, path=path, name=name, obj=obj
        )
        task = session.hook.pytask_collect_task(
            session=session, path=path, name=name, obj=obj
        )
        if task is not None:
            session.hook.pytask_collect_task_teardown(session=session, task=task)
            return CollectionReport(outcome=CollectionOutcome.SUCCESS, node=task)

    except Exception:
        task = Task(base_name=name, path=path, function=None)
        return CollectionReport.from_exception(
            outcome=CollectionOutcome.FAIL, exc_info=sys.exc_info(), node=task
        )

    else:
        return None
Beispiel #6
0
def wrap_function_for_tracing(session: Session, task: Task) -> None:
    """Wrap the task function for tracing."""

    _pdb = PytaskPDB._init_pdb("runcall")
    task_function = task.function

    # We can't just return `partial(pdb.runcall, task_function)` because (on python <
    # 3.7.4) runcall's first param is `func`, which means we'd get an exception if one
    # of the kwargs to task_function was called `func`.
    @functools.wraps(task_function)
    def wrapper(*args: Any, **kwargs: Any) -> None:
        capman = session.config["pm"].get_plugin("capturemanager")
        live_manager = session.config["pm"].get_plugin("live_manager")

        # 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.stop()

        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)

        _pdb.runcall(task_function, *args, **kwargs)

        live_manager.resume()
        capman.resume()

    task.function = wrapper
Beispiel #7
0
def pytask_execute_task(task: Task) -> Generator[None, None, None]:
    """Attach the duration of the execution to the task."""
    start = time.time()
    yield
    end = time.time()
    task.attributes["duration"] = (start, end)