Skip to content

A run that dies during collection

pytest 8.0.0 - 8.0.2 - What pytest does when a hook implementation raises.

These 3 releases produced an identical flow, so they share one page. Identical as far as this scenario can measure - a scenario exercising more hooks may tell them apart.

The conftest.py here raises from pytest_collection_modifyitems. Nothing catches it, so pytest abandons the session and reports an internal error.

No test ever runs, so the whole run-test phase is missing from this diagram - which is the point. It shows how little of a session happens when a hook implementation fails early, and which hooks still get their chance to clean up.

How this was produced

  • Source: scenarios/internal-error/ - the project this diagram was traced from
  • Invocation: pytest . -q
  • Traced against: pytest 8.0.2, pluggy 1.6.0, Python 3.12.3
  • Covers: 3 releases - pytest 8.0.0 - 8.0.2, which produced an identical flow
  • Observed: 120 hook calls, 23 distinct hooks

The project is conftest.py, test_never_runs.py. Browse it in the repository rather than inline here - scenarios grow directory trees, and GitHub renders them better than a collapsed block can.

The whole run

Phases left to right, steps top to bottom. Colour says which phase a hook belongs to; how dark a step is says how often it was called. Click a column heading to jump to that phase in full detail, or any hook to open its pytest documentation. Why it looks like this

%3 cluster_phase_startup STARTUP AND CONFIGURATION cluster_startup_n1 pytest_load_initial_conftests cluster_startup_n3 pytest_configure historic cluster_startup_n5 pytest_sessionstart cluster_phase_collection COLLECTION cluster_collection_n1 pytest_collection firstresult cluster_phase_finish SESSION FINISH startup_n2 pytest_plugin_registered historic · x2 startup_n4 pytest_plugin_registered historic · x40 startup_n2->startup_n4 startup_n6 pytest_plugin_registered historic · x40 startup_n4->startup_n6 collection_n2 pytest_collectstart 3x in run collection_n3 pytest_make_collect_report firstresult · 3x in run collection_n2->collection_n3 collection_n4 pytest_collectreport 3x in run collection_n3->collection_n4 collection_n5 pytest_collectstart 3x in run collection_n4->collection_n5 collection_n6 pytest_make_collect_report firstresult · 3x in run collection_n5->collection_n6 collection_n7 pytest_collectstart 3x in run collection_n6->collection_n7 collection_n8 pytest_make_collect_report firstresult · 3x in run collection_n7->collection_n8 collection_n9 pytest_itemcollected collection_n8->collection_n9 collection_n10 pytest_collectreport x2 collection_n9->collection_n10 collection_n11 pytest_collection_modifyitems collection_n10->collection_n11 collection_n12 pytest_collection_finish collection_n11->collection_n12 finish_n1 pytest_sessionfinish finish_n2 pytest_unconfigure finish_n1->finish_n2

Startup and configuration

Everything before collection begins: initial conftests are loaded, plugins register, and the session is configured.

Collection

Finding tests. Note that pytest_make_collect_report recurses - directories contain directories contain files.

Session finish

Summary reporting and teardown of the session.

Every hook observed

Hook Calls Semantics Implemented by, in call order
pytest_cmdline_main 1 firstresult _pytest.setupplan [tryfirst]
_pytest.setuponly [tryfirst]
_pytest.mark [tryfirst]
_pytest.python
_pytest.helpconfig
_pytest.main
pytest_cmdline_preparse 1 -
pytest_collect_directory 1 firstresult _pytest.python
_pytest.main
pytest_collect_file 4 _pytest.doctest
_pytest.python
pytest_collection 1 firstresult _pytest.logging.LoggingPlugin (logging-plugin) [wrapper, tryfirst]
_pytest.warnings [wrapper, tryfirst]
_pytest.config.Config (pytestconfig) [wrapper]
_pytest.terminal.TerminalReporter
_pytest.assertion
_pytest.main
pytest_collection_finish 1 _pytest.terminal.TerminalReporter
pytest_collection_modifyitems 1 _pytest.fixtures.FixtureManager (funcmanage)
conftest.py
_pytest.main
_pytest.mark
pytest_collectreport 3 _pytest.main.Session.pytest_runtest_logreport (session) [tryfirst]
_pytest.terminal.TerminalReporter
pytest_collectstart 3 _pytest.main.Session [tryfirst]
pytest_configure 1 historic _pytest.faulthandler
_pytest.warnings
_pytest.junitxml
_pytest.tmpdir
_pytest.legacypath
_pytest.skipping
_pytest.debugging
_pytest.terminal
_pytest.python
_pytest.mark
_pytest.config.PytestPluginManager (<anonymous>)
_pytest.pastebin [trylast]
_pytest.logging [trylast]
pytest_generate_tests 1 _pytest.fixtures.FixtureManager (funcmanage)
_pytest.python
pytest_ignore_collect 4 firstresult _pytest.main
pytest_internalerror 1 _pytest.capture.CaptureManager [tryfirst]
_pytest.terminal.TerminalReporter
pytest_itemcollected 1 -
pytest_load_initial_conftests 1 _pytest.warnings [wrapper]
_pytest.capture [wrapper]
_pytest.python_path [tryfirst]
_pytest.legacypath [tryfirst]
_pytest.config.Config (pytestconfig) [trylast]
pytest_make_collect_report 3 firstresult _pytest.capture.CaptureManager [wrapper]
_pytest.runner
pytest_plugin_registered 84 historic _pytest.legacypath
_pytest.terminal.TerminalReporter
_pytest.fixtures.FixtureManager (funcmanage)
pytest_pycollect_makeitem 3 firstresult _pytest.unittest
_pytest.python [trylast]
pytest_pycollect_makemodule 1 firstresult _pytest.python
pytest_report_collectionfinish 1 -
pytest_sessionfinish 1 _pytest.logging.LoggingPlugin (logging-plugin) [wrapper, tryfirst]
_pytest.terminal.TerminalReporter [wrapper]
_pytest.warnings [wrapper]
_pytest.assertion
_pytest.tmpdir
_pytest.runner
pytest_sessionstart 1 _pytest.logging.LoggingPlugin (logging-plugin) [wrapper, tryfirst]
_pytest.fixtures
_pytest.runner
_pytest.terminal.TerminalReporter [trylast]
pytest_unconfigure 1 _pytest.logging.LoggingPlugin (logging-plugin)
_pytest.terminal.TerminalReporter
_pytest.faulthandler
_pytest.doctest
_pytest.junitxml
_pytest.pastebin
_pytest.mark
_pytest.python_path [trylast]