Capturing output#

What is capturing? Some of your tasks may use print() statements, have progress bars, require user input, or the libraries you are using show information during execution.

Since the output would pollute the terminal and the information shown by pytask, it captures all the output during execution and attaches it to the report of this task by default.

If the task fails, the output is shown along with the traceback to help you track down the error.

Default stdout/stderr/stdin capturing behavior#

Any output sent to stdout and stderr is captured during task execution. pytask displays it only if the task fails in addition to the traceback.

In addition, stdin is set to a “null” object which will fail on attempts to read from it because it is rarely desired to wait for interactive input when running automated tasks.

By default, capturing is done by intercepting writes to low-level file descriptors. This allows capturing output from simple print() statements as well as output from a subprocess started by a task.

Setting capturing methods or disabling capturing#

There are three ways in which pytask can perform capturing:

  • fd (file descriptor) level capturing (default): All writes going to the operating system file descriptors 1 and 2 will be captured.

  • sys level capturing: Only writes to Python files sys.stdout and sys.stderr will be captured. No capturing of writes to file descriptors is performed.

  • tee-sys capturing: Python writes to sys.stdout and sys.stderr will be captured. However, the writes will also be passed through to the actual sys.stdout and sys.stderr.

You can influence output-capturing mechanisms from the command line:

$ pytask -s                  # disable all capturing
$ pytask --capture=sys       # replace sys.stdout/stderr with in-mem files
$ pytask --capture=fd        # also point filedescriptors 1 and 2 to temp file
$ pytask --capture=tee-sys   # combines 'sys' and '-s', capturing sys.stdout/stderr
                             # and passing it along to the actual sys.stdout/stderr

Using print statements for debugging#

One primary benefit of the default capturing of stdout/stderr output is that you can use print statements for debugging:

# content of task_capture.py


def task_func1():
    assert True


def task_func2():
    print("Debug statement")
    assert False

And running this module will show you precisely the output of the failing function and hide the other one:

$ pytask
──────────────────────────── Start pytask session ────────────────────────────
Platform: win32 -- Python <span style="color: var(--termynal-blue)">3.10.0</span>, pytask <span style="color: var(--termynal-blue)">0.4.0</span>, pluggy <span style="color: var(--termynal-blue)">1.0.0</span>
Root: C:\Users\pytask-dev\git\my_project
Collected <span style="color: var(--termynal-blue)">2</span> tasks.

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
┃ Task                         ┃ Outcome ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
│ <span class="termynal-dim">task_capture.py::</span>task_func1  │ <span class="termynal-success">.      </span> │
│ <span class="termynal-dim">task_capture.py::</span>task_func2  │ <span class="termynal-failed">F      </span> │
└──────────────────────────────┴─────────┘

<span style="color: #bf2d2d">────────────────────────────────── Failures ──────────────────────────────────</span>

<span style="color: #bf2d2d">─────────────────── Task </span><span style="color: #6c1e1e; font-weight: bold">task_capture.py::</span><span style="color: #bf2d2d">task_func2</span><span style="color: #bf2d2d"> failed ──────────────────</span>

<span style="color: #f14c4c">╭─────────────────────</span><span style="color: #f14c4c; font-weight: bold;"> Traceback </span><span style="color: #6c1e1e; font-weight: bold">(most recent call last)</span><span style="color: #f14c4c"> ────────────────────╮</span>
<span style="color: #cd3131">│</span>                                                                            <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span> <span style="color: #e5e510">...\git\pytask-examples\task_capture.py</span>:<span style="color: #3b8eea">13</span> in <span style="color: #23d18b">task_func2</span>                   <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>                                                                            <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>   10                                                                       <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>   11 <span style="color: #3b8eea">def</span> <span style="color: #23d18b">task_func2</span>():                                                     <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>   12 │   <span style="color: #29b8db">print</span>(<span style="color: #e5e510">&quot;Debug statement&quot;</span>)                                          <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span> <span style="color: #cd3131">❱ </span>13 <span style="font-size: .2em;">&thinsp;</span>│   <span style="color: #3b8eea">assert</span> <span style="color: #3b8eea">False</span>                                                      <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>   14                                                                       <span style="color: #cd3131">│</span>
<span style="color: #cd3131">│</span>   15                                                                       <span style="color: #cd3131">│</span>
<span style="color: #cd3131">╰────────────────────────────────────────────────────────────────────────────╯</span>
<span style="color: #f14c4c; font-weight: bold;">AssertionError</span>

──────────────────────── Captured stdout during call ─────────────────────────
Debug Statement

<span class="termynal-dim">──────────────────────────────────────────────────────────────────────────────</span>
<span style="color: #bf2d2d">╭─────────── </span><span style="font-weight: bold;">Summary</span><span style="color: #bf2d2d"> ───────────╮</span>
<span style="color: #bf2d2d">│</span> <span style="font-weight: bold"> 2  Collected tasks          </span> <span style="color: #bf2d2d">│</span>
<span style="color: #bf2d2d">│</span> <span class="termynal-success-textonly"> 1  Succeeded        (50.0%) </span> <span style="color: #bf2d2d">│</span>
<span style="color: #bf2d2d">│</span> <span class="termynal-failed-textonly"> 1  Failed           (50.0%) </span> <span style="color: #bf2d2d">│</span>
<span style="color: #bf2d2d">╰───────────────────────────────╯</span>
<span style="color: #bf2d2d">─────────────────────────── Failed in 0.03 seconds ───────────────────────────</span>