Skip to content

KeyboardInterrupt full-trace should have option to ignore pytest frames #9201

@beasteers

Description

@beasteers

What's the problem this feature will solve?

Currently, pytest is difficult to use when testing bugs that cause your program to hang. By default, interrupting will mark the test as successful and no traceback is shown (related: #7640). So if it hangs you'll need to re-run your tests with the --full-trace flag (which can be annoying if the tests take a while or the problem is not consistently reproducible).

But when you use --full-trace it includes a bunch of frames from internal pytest and related libraries. i.e.:

anaconda3/envs/s/lib/python3.7/site-packages/pluggy/hooks.py
anaconda3/envs/s/lib/python3.7/site-packages/pluggy/manager.py
anaconda3/envs/s/lib/python3.7/site-packages/_pytest/python.py
anaconda3/envs/s/lib/python3.7/site-packages/_pytest/runner.py
... etc.

and makes the output SUUUUUPER LONG (like obscenely).

But 90% of the time, I don't care about all of those frames and it just makes the problem really hard and tedious to parse. I just want the frames related to my application.

I understand that those might be useful for debugging pytest, but I have personally used ctrl-c countless times to debug hanging programs and nearly every time I want to see the trace for my application and nothing else.

(I have also tried --full-trace --tb=native and --full-trace --tb=short with no change in behaviour).

Describe the solution you'd like

I would like a way to tell pytest to enable stack traces for keyboard interrupt, only including the frames that are relevant to my application.

The clearest solution that I can think of would be to add a --ctrlc-trace CLI flag

Basically, I'm suggesting decoupling --full-trace with showing the ctrl-c output because --full-trace has the additional connotation of "show me every possible frame including everything in pytest" which is something I have never wanted.

Alternatives

  1. Setting a global variable in your test_something.py file (__keyboardinterrupt_trace__ = True)
  2. Setting an attribute in pytest (e.g. pytest.__keyboardinterrupt_trace__ = True) in your test_something.py
  3. Have a list of paths to filter from tracebacks (e.g. pytest.ignore_stack_trace_matching.append('ignored1', 'ignored2')

Path to a solution

Doing a quick look thru the source, the logic already partially exists

def filter_traceback(entry: TracebackEntry) -> bool:

And maybe it just involves adding another option and checking it here

if self.config.option.fulltrace:

i.e.

if self.config.option.fulltrace or self.config.option.ctrlctrace:
    ...

since it looks like the full unfiltered trace is being enforced here, so by adding the second option, the kb interrupt output can be shown without being forced to use style == 'long'

if option and getattr(option, "fulltrace", False):
style: _TracebackStyle = "long"
else:
style = "native"

(I am not familiar with the pytest source and I didn't do a deep dive so I'm sure I'm missing a thing or two)


Additional context

pytest 6.2.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: reportingrelated to terminal output and user-facing messages and errorstype: enhancementnew feature or API change, should be merged into features branch

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions