From db2af30320022e9323729ee737b7c9f643680806 Mon Sep 17 00:00:00 2001 From: Aliipou Date: Sun, 22 Mar 2026 21:03:53 +0200 Subject: [PATCH 1/2] docs: move collection hooks from reporting to collection section Fixes #12658. The hooks `pytest_collectstart`, `pytest_make_collect_report`, `pytest_itemcollected`, `pytest_collectreport`, and `pytest_deselected` were listed under the "Reporting hooks" section in the reference docs. These hooks are collection-related and belong in the "Collection hooks" section. This commit moves them to the end of the Collection hooks section with a brief description, and removes them from the Reporting hooks section. Co-Authored-By: Claude Sonnet 4.6 --- doc/en/reference/reference.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index 4e5c7cfd644..3ed429f70a8 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -760,6 +760,19 @@ items, delete or otherwise amend the test items: .. hook:: pytest_collection_finish .. autofunction:: pytest_collection_finish +During collection, the following hooks are called to track collection progress: + +.. hook:: pytest_collectstart +.. autofunction:: pytest_collectstart +.. hook:: pytest_make_collect_report +.. autofunction:: pytest_make_collect_report +.. hook:: pytest_itemcollected +.. autofunction:: pytest_itemcollected +.. hook:: pytest_collectreport +.. autofunction:: pytest_collectreport +.. hook:: pytest_deselected +.. autofunction:: pytest_deselected + Test running (runtest) hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -796,16 +809,6 @@ Reporting hooks Session related reporting hooks: -.. hook:: pytest_collectstart -.. autofunction:: pytest_collectstart -.. hook:: pytest_make_collect_report -.. autofunction:: pytest_make_collect_report -.. hook:: pytest_itemcollected -.. autofunction:: pytest_itemcollected -.. hook:: pytest_collectreport -.. autofunction:: pytest_collectreport -.. hook:: pytest_deselected -.. autofunction:: pytest_deselected .. hook:: pytest_report_header .. autofunction:: pytest_report_header .. hook:: pytest_report_collectionfinish From ffeb09ab4591c5274e5668ffbd2c3938f4f65e03 Mon Sep 17 00:00:00 2001 From: Aliipou Date: Sun, 22 Mar 2026 21:08:10 +0200 Subject: [PATCH 2/2] docs: add docstrings to public functions in _pytest/main.py Closes #12979. Adds Sphinx-compatible docstrings to several functions in `src/_pytest/main.py` (lines 245-490) that were missing them: - `validate_basetemp`: documents the validation logic, parameters, return value, and the exception it raises. - `pytest_cmdline_main`: describes its role as the default hook implementation that runs the test session. - `pytest_collection`: documents that it triggers test collection via `Session.perform_collect()`. - `pytest_runtestloop`: describes the iteration over test items and the early-exit conditions. - `pytest_ignore_collect`: enumerates all conditions under which a path is skipped. - `pytest_collect_directory`: describes the `Dir` node it creates. - `pytest_collection_modifyitems`: documents the `--deselect` filtering logic. Co-Authored-By: Claude Sonnet 4.6 --- src/_pytest/main.py | 70 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 02c7fb373fd..6c8afd9af26 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -277,6 +277,16 @@ def pytest_addoption(parser: Parser) -> None: def validate_basetemp(path: str) -> str: + """Validate the ``--basetemp`` option value. + + Raises :class:`argparse.ArgumentTypeError` if ``path`` is empty or is + an ancestor of (or equal to) the current working directory, to prevent + accidental deletion of the working tree. + + :param path: The path string provided by the user for the base temp directory. + :returns: The validated path string unchanged. + :raises argparse.ArgumentTypeError: If the path is empty or an ancestor of cwd. + """ # GH 7119 msg = "basetemp must not be empty, the current working directory or any parent directory of it" @@ -361,6 +371,14 @@ def wrap_session( def pytest_cmdline_main(config: Config) -> int | ExitCode: + """Default implementation of the :hook:`pytest_cmdline_main` hook. + + Runs the full test session by calling :func:`wrap_session` with the + default ``_main`` implementation. + + :param config: The pytest :class:`~pytest.Config` object. + :returns: The session exit code. + """ return wrap_session(config, _main) @@ -378,10 +396,27 @@ def _main(config: Config, session: Session) -> int | ExitCode | None: def pytest_collection(session: Session) -> None: + """Default implementation of the :hook:`pytest_collection` hook. + + Triggers test collection by calling :meth:`~pytest.Session.perform_collect` + on the active session. + + :param session: The active :class:`~pytest.Session`. + """ session.perform_collect() def pytest_runtestloop(session: Session) -> bool: + """Default implementation of the :hook:`pytest_runtestloop` hook. + + Iterates over all collected test items and runs each one via + :hook:`pytest_runtest_protocol`. Raises :class:`~pytest.Session.Failed` + or :class:`~pytest.Session.Interrupted` if the session signals that + testing should stop early. + + :param session: The active :class:`~pytest.Session`. + :returns: ``True`` when the loop completes normally. + """ if session.testsfailed and not session.config.option.continue_on_collection_errors: raise session.Interrupted( f"{session.testsfailed} error{'s' if session.testsfailed != 1 else ''} during collection" @@ -422,6 +457,24 @@ def _in_venv(path: Path) -> bool: def pytest_ignore_collect(collection_path: Path, config: Config) -> bool | None: + """Default implementation of the :hook:`pytest_ignore_collect` hook. + + Returns ``True`` to skip collection of *collection_path* when any of the + following conditions hold: + + * The path is a ``__pycache__`` directory. + * The path matches an entry in ``collect_ignore`` or ``--ignore``. + * The path matches a glob in ``collect_ignore_glob`` or ``--ignore-glob``. + * The path is a virtual environment root and ``--collect-in-virtualenv`` + is not set. + * The path is a directory matching a pattern in ``norecursedirs``. + + Returns ``None`` to allow collection to proceed normally. + + :param collection_path: The filesystem path being considered for collection. + :param config: The pytest :class:`~pytest.Config` object. + :returns: ``True`` to skip the path, ``None`` to allow collection. + """ if collection_path.name == "__pycache__": return True @@ -462,10 +515,27 @@ def pytest_ignore_collect(collection_path: Path, config: Config) -> bool | None: def pytest_collect_directory( path: Path, parent: nodes.Collector ) -> nodes.Collector | None: + """Default implementation of the :hook:`pytest_collect_directory` hook. + + Creates a :class:`~pytest.Dir` collector node for the given directory. + + :param path: The directory path to collect. + :param parent: The parent collector node. + :returns: A :class:`~pytest.Dir` node for the directory. + """ return Dir.from_parent(parent, path=path) def pytest_collection_modifyitems(items: list[nodes.Item], config: Config) -> None: + """Default implementation of the :hook:`pytest_collection_modifyitems` hook. + + Removes test items whose node IDs start with any of the prefixes supplied + via the ``--deselect`` command-line option, firing the + :hook:`pytest_deselected` hook for the removed items. + + :param items: The list of collected test items (modified in place). + :param config: The pytest :class:`~pytest.Config` object. + """ deselect_prefixes = tuple(config.getoption("deselect") or []) if not deselect_prefixes: return