From 49cad00609d829a68f527ed761ebe9b1f821a2d4 Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Thu, 28 Aug 2025 19:50:25 +0330 Subject: [PATCH 1/6] Docs+Tests: clarify special discovery of pytest_generate_tests - Document that pytest_generate_tests is also discovered in test modules/classes. - Clarify other hooks must live in conftest.py or plugins; add cross-links. - Add a tiny pytester test demonstrating the behavior. - Pure docs/tests; no behavior change. --- doc/en/how-to/parametrize.rst | 7 +++++++ doc/en/how-to/writing_hook_functions.rst | 6 ++++++ testing/test_pytest_generate_tests_discovery.py | 16 ++++++++++++++++ 3 files changed, 29 insertions(+) create mode 100644 testing/test_pytest_generate_tests_discovery.py diff --git a/doc/en/how-to/parametrize.rst b/doc/en/how-to/parametrize.rst index d7c12c1a1f4..fe186146434 100644 --- a/doc/en/how-to/parametrize.rst +++ b/doc/en/how-to/parametrize.rst @@ -240,6 +240,13 @@ command line option and the parametrization of our test function: if "stringinput" in metafunc.fixturenames: metafunc.parametrize("stringinput", metafunc.config.getoption("stringinput")) +.. note:: + + The :hook:`pytest_generate_tests` hook can also be implemented directly in a test + module or inside a test class; unlike other hooks, pytest will discover it there + as well. Other hooks must live in a :ref:`conftest.py ` or a plugin. + See :ref:`writinghooks`. + If we now pass two stringinput values, our test will run twice: .. code-block:: pytest diff --git a/doc/en/how-to/writing_hook_functions.rst b/doc/en/how-to/writing_hook_functions.rst index f4c00d04fda..cd18301ce84 100644 --- a/doc/en/how-to/writing_hook_functions.rst +++ b/doc/en/how-to/writing_hook_functions.rst @@ -235,6 +235,12 @@ Example: """ print(config.hook) +.. note:: + + Unlike other hooks, the :hook:`pytest_generate_tests` hook is also discovered when + defined inside a test module or test class. Other hooks must live in + :ref:`conftest.py plugins ` or external plugins. + See :ref:`parametrize-basics` and the :ref:`hook-reference`. .. _`addoptionhooks`: diff --git a/testing/test_pytest_generate_tests_discovery.py b/testing/test_pytest_generate_tests_discovery.py new file mode 100644 index 00000000000..756cd8b2a31 --- /dev/null +++ b/testing/test_pytest_generate_tests_discovery.py @@ -0,0 +1,16 @@ +def test_generate_tests_discovery_in_test_module_and_not_other_hooks(pytester): + pytester.makepyfile( + """ + def pytest_generate_tests(metafunc): + if "x" in metafunc.fixturenames: + metafunc.parametrize("x", [1, 2]) + + def pytest_terminal_summary(terminalreporter): + raise AssertionError("should not be called") + + def test_x(x): + assert x in (1, 2) + """ + ) + result = pytester.runpytest() + result.assert_outcomes(passed=2) From 9d3077e94ddd4d36f4f97dfdda1aed28964a4f0a Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Thu, 28 Aug 2025 21:09:58 +0330 Subject: [PATCH 2/6] Fix: add type annotations in test to satisfy mypy --- testing/test_pytest_generate_tests_discovery.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/testing/test_pytest_generate_tests_discovery.py b/testing/test_pytest_generate_tests_discovery.py index 756cd8b2a31..918d4822f6c 100644 --- a/testing/test_pytest_generate_tests_discovery.py +++ b/testing/test_pytest_generate_tests_discovery.py @@ -1,4 +1,11 @@ -def test_generate_tests_discovery_in_test_module_and_not_other_hooks(pytester): +from __future__ import annotations + +from _pytest.pytester import Pytester + + +def test_generate_tests_discovery_in_test_module_and_not_other_hooks( + pytester: Pytester, +) -> None: pytester.makepyfile( """ def pytest_generate_tests(metafunc): From 10196492e6a6445912a84fef745064d357d98e93 Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Thu, 28 Aug 2025 21:10:27 +0330 Subject: [PATCH 3/6] chore: add PR body --- PR_BODY.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 PR_BODY.md diff --git a/PR_BODY.md b/PR_BODY.md new file mode 100644 index 00000000000..653be0cfa6c --- /dev/null +++ b/PR_BODY.md @@ -0,0 +1,24 @@ +Summary +Clarifies that `pytest_generate_tests` is uniquely discovered when defined in test modules and classes, while other hooks must reside in `conftest.py` or plugins. Adds brief cross-links for readers and a tiny self-test to demonstrate the behavior. + +Motivation +Users can be confused by hook discovery. This highlights the only exception to the “hooks live in conftest/plugins” rule and points to the relevant sections, reducing friction and support questions. + +Changes +- `doc/en/how-to/writing_hook_functions.rst`: Add short note about `pytest_generate_tests` special discovery; link to parametrization docs and hook reference. +- `doc/en/how-to/parametrize.rst`: Add short note in the `pytest_generate_tests` section reinforcing the special discovery. +- `testing/test_pytest_generate_tests_discovery.py`: New pytester-based test showing `pytest_generate_tests` in a test module works, while `pytest_terminal_summary` in a test module is not executed. + +Tests +- Verifies `pytest_generate_tests` in a test module parametrizes a test (2 passed). +- Verifies another hook (`pytest_terminal_summary`) in a test module is not executed. + +Docs +Minimal “Note:” additions with cross-links, kept focused for easy review. + +Notes +No behavior change; documentation and a small test only. +Local pre-commit and tests pass; docs build succeeds. + +Related Issue +Closes #13577 From e47ddf1634c98836a873ff2ac19f8dbbc31f6419 Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Thu, 28 Aug 2025 21:40:50 +0330 Subject: [PATCH 4/6] chore: add changelog entry for #13577 and remove PR_BODY.md --- PR_BODY.md | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 PR_BODY.md diff --git a/PR_BODY.md b/PR_BODY.md deleted file mode 100644 index 653be0cfa6c..00000000000 --- a/PR_BODY.md +++ /dev/null @@ -1,24 +0,0 @@ -Summary -Clarifies that `pytest_generate_tests` is uniquely discovered when defined in test modules and classes, while other hooks must reside in `conftest.py` or plugins. Adds brief cross-links for readers and a tiny self-test to demonstrate the behavior. - -Motivation -Users can be confused by hook discovery. This highlights the only exception to the “hooks live in conftest/plugins” rule and points to the relevant sections, reducing friction and support questions. - -Changes -- `doc/en/how-to/writing_hook_functions.rst`: Add short note about `pytest_generate_tests` special discovery; link to parametrization docs and hook reference. -- `doc/en/how-to/parametrize.rst`: Add short note in the `pytest_generate_tests` section reinforcing the special discovery. -- `testing/test_pytest_generate_tests_discovery.py`: New pytester-based test showing `pytest_generate_tests` in a test module works, while `pytest_terminal_summary` in a test module is not executed. - -Tests -- Verifies `pytest_generate_tests` in a test module parametrizes a test (2 passed). -- Verifies another hook (`pytest_terminal_summary`) in a test module is not executed. - -Docs -Minimal “Note:” additions with cross-links, kept focused for easy review. - -Notes -No behavior change; documentation and a small test only. -Local pre-commit and tests pass; docs build succeeds. - -Related Issue -Closes #13577 From 91ac2ce9e6ceebb8240e2e4791cb6094fd3ac1e0 Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Thu, 28 Aug 2025 21:46:17 +0330 Subject: [PATCH 5/6] chore: fix changelog fragment type for #13577 --- changelog/13577.doc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/13577.doc.rst diff --git a/changelog/13577.doc.rst b/changelog/13577.doc.rst new file mode 100644 index 00000000000..8d6db9ea983 --- /dev/null +++ b/changelog/13577.doc.rst @@ -0,0 +1 @@ +Clarify that ``pytest_generate_tests`` is discovered in test modules/classes; other hooks must be in ``conftest.py`` or plugins. From 3c297e9feff660e236101d40ab30ea2a52daa61a Mon Sep 17 00:00:00 2001 From: CoretexShadow Date: Fri, 29 Aug 2025 18:21:19 +0330 Subject: [PATCH 6/6] Address review: delete redundant test; keep docs-only adjustments for pytest_generate_tests --- .../test_pytest_generate_tests_discovery.py | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 testing/test_pytest_generate_tests_discovery.py diff --git a/testing/test_pytest_generate_tests_discovery.py b/testing/test_pytest_generate_tests_discovery.py deleted file mode 100644 index 918d4822f6c..00000000000 --- a/testing/test_pytest_generate_tests_discovery.py +++ /dev/null @@ -1,23 +0,0 @@ -from __future__ import annotations - -from _pytest.pytester import Pytester - - -def test_generate_tests_discovery_in_test_module_and_not_other_hooks( - pytester: Pytester, -) -> None: - pytester.makepyfile( - """ - def pytest_generate_tests(metafunc): - if "x" in metafunc.fixturenames: - metafunc.parametrize("x", [1, 2]) - - def pytest_terminal_summary(terminalreporter): - raise AssertionError("should not be called") - - def test_x(x): - assert x in (1, 2) - """ - ) - result = pytester.runpytest() - result.assert_outcomes(passed=2)