Skip to content

Baseline

pytest 8.0.0 - 8.0.2 - A plain test suite with no conftest and no plugins.

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 reference shape of a pytest run: parametrised tests, a yield fixture, a finalizer fixture, a skip, and one intentional failure. Every other scenario should be read as a diff against this one.

How this was produced

  • Source: scenarios/baseline/ - 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: 287 hook calls, 39 distinct hooks

The project is test_dummy.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_runtest THE RUN-TEST PROTOCOL cluster_runtest_n1 pytest_runtest_protocol firstresult · 8x in run cluster_phase_finish SESSION FINISH cluster_finish_n1 pytest_sessionfinish startup_n2 pytest_plugin_registered historic · 81x in run startup_n4 pytest_plugin_registered historic · x39 startup_n2->startup_n4 startup_n6 pytest_plugin_registered historic · x39 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 x8 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 collection_n13 pytest_warning_recorded historic · 2x in run collection_n12->collection_n13 runtest_n2 pytest_runtest_logstart 8x in run runtest_n3 pytest_runtest_setup 8x in run runtest_n2->runtest_n3 runtest_n4 pytest_runtest_makereport firstresult · 23x in run runtest_n3->runtest_n4 runtest_n5 pytest_runtest_logreport 23x in run runtest_n4->runtest_n5 runtest_n6 pytest_runtest_call 7x in run runtest_n5->runtest_n6 runtest_n7 pytest_runtest_makereport firstresult · 23x in run runtest_n6->runtest_n7 runtest_n8 pytest_runtest_logreport 23x in run runtest_n7->runtest_n8 runtest_n9 pytest_runtest_teardown 8x in run runtest_n8->runtest_n9 runtest_n10 pytest_runtest_makereport firstresult · 23x in run runtest_n9->runtest_n10 runtest_n11 pytest_runtest_logreport 23x in run runtest_n10->runtest_n11 runtest_n12 pytest_runtest_logfinish 8x in run runtest_n11->runtest_n12 finish_n2 pytest_terminal_summary finish_n3 pytest_unconfigure finish_n2->finish_n3

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.

The run-test protocol

pytest_runtestloop runs this once per collected test. Note the rhythm: setup, call and teardown are each followed by their own makereport and logreport pair - three reports per test, not one.

The path 5 of 8 took.

The others differed:

  • 1 test also called pytest_exception_interact
  • 1 test skipped pytest_fixture_post_finalizer, pytest_fixture_setup, pytest_pyfunc_call, pytest_runtest_call
  • 1 test also called pytest_warning_recorded and skipped pytest_fixture_post_finalizer, pytest_fixture_setup

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 3 _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)
_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_exception_interact 1 _pytest.faulthandler [tryfirst]
pytest_fixture_post_finalizer 11 _pytest.setuponly
pytest_fixture_setup 11 firstresult _pytest.setuponly [wrapper]
_pytest.setupplan [tryfirst]
_pytest.fixtures
pytest_generate_tests 4 _pytest.fixtures.FixtureManager (funcmanage)
_pytest.python
pytest_ignore_collect 3 firstresult _pytest.main
pytest_itemcollected 8 -
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_make_parametrize_id 5 firstresult -
pytest_plugin_registered 81 historic _pytest.legacypath
_pytest.terminal.TerminalReporter
_pytest.fixtures.FixtureManager (funcmanage)
pytest_pycollect_makeitem 10 firstresult _pytest.unittest
_pytest.python [trylast]
pytest_pycollect_makemodule 1 firstresult _pytest.python
pytest_pyfunc_call 7 firstresult _pytest.python [trylast]
pytest_report_collectionfinish 1 -
pytest_report_teststatus 24 firstresult _pytest.skipping
_pytest.runner
_pytest.terminal [trylast]
pytest_runtest_call 7 _pytest.threadexception [wrapper, tryfirst]
_pytest.unraisableexception [wrapper, tryfirst]
_pytest.logging.LoggingPlugin (logging-plugin) [wrapper]
_pytest.capture.CaptureManager [wrapper]
_pytest.skipping [wrapper]
_pytest.runner
pytest_runtest_logfinish 8 _pytest.logging.LoggingPlugin (logging-plugin)
_pytest.terminal.TerminalReporter
pytest_runtest_logreport 23 _pytest.main.Session [tryfirst]
_pytest.logging.LoggingPlugin (logging-plugin)
_pytest.terminal.TerminalReporter
pytest_runtest_logstart 8 _pytest.logging.LoggingPlugin (logging-plugin)
_pytest.terminal.TerminalReporter
pytest_runtest_makereport 23 firstresult _pytest.tmpdir [wrapper, tryfirst]
_pytest.skipping [wrapper]
_pytest.unittest [tryfirst]
_pytest.runner
pytest_runtest_protocol 8 firstresult _pytest.warnings [wrapper, tryfirst]
_pytest.assertion [wrapper, tryfirst]
_pytest.unittest [wrapper]
_pytest.faulthandler [wrapper, trylast]
_pytest.runner
pytest_runtest_setup 8 _pytest.unraisableexception [wrapper, tryfirst]
_pytest.logging.LoggingPlugin (logging-plugin) [wrapper]
_pytest.capture.CaptureManager [wrapper]
_pytest.threadexception [wrapper, trylast]
_pytest.skipping [tryfirst]
_pytest.runner
_pytest.nose [trylast]
pytest_runtest_teardown 8 _pytest.threadexception [wrapper, tryfirst]
_pytest.unraisableexception [wrapper, tryfirst]
_pytest.logging.LoggingPlugin (logging-plugin) [wrapper]
_pytest.capture.CaptureManager [wrapper]
_pytest.runner
pytest_runtestloop 1 firstresult _pytest.logging.LoggingPlugin (logging-plugin) [wrapper]
_pytest.main
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_terminal_summary 1 _pytest.terminal.TerminalReporter [wrapper]
_pytest.warnings [wrapper]
_pytest.pastebin
_pytest.runner
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]
pytest_warning_recorded 2 historic _pytest.terminal.TerminalReporter