You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Doc/library/test.rst still says regrtest calls test_main() #158681
Doc/library/test.rst describes how python -m test runs the regression suite. It says the runner imports each test_* module and executes test_main() when that function exists, otherwise loading tests with unittest.TestLoader.loadTestsFromModule. The same page tells readers to call test.support.reap_children() at the end of test_main.
That has not been true since test_main was removed as a regrtest entry point (#89392). Lib/test/libregrtest/single.py never calls test_main(). If the imported module defines it, the runner raises Exception. The module is then reported as failed with an uncaught exception (test <name> crashed on stderr, failed (uncaught exception) in the summary). Tests are always loaded with loadTestsFromModule. That collects unittest.TestCase classes and, when the module defines load_tests, runs the suite that function returns. Test packages add submodule tests through load_tests, usually via test.support.load_package_tests.
reap_children() is not called from test_main. Tests call it from setUp(), tearDown(), or tearDownModule() (for example test_subprocess and test_pty). The docstring of test.support.reap_children still says to call it at the end of test_main().
The runner itself does not need to change. The documentation and the reap_children docstring should describe the current behavior.
@bazhil One thing I don't understand is what benefits from this change. I don't really understand the motivation; could you help me wrap my head around that so I have context to read the proposed change?
@ryan-duve The change does not alter how tests run. The page currently describes a runner that no longer exists, and following it breaks a test.
Doc/library/test.rst says python -m test calls a module-level test_main() when that function exists, and otherwise loads tests with unittest.TestLoader.loadTestsFromModule. It also says to call test.support.reap_children() at the end of test_main. The docstring of reap_children() says the same thing.
Since #89392, Lib/test/libregrtest/single.py does not call test_main(). If the imported module defines it, the runner raises Exception and reports the module as failed with an uncaught exception (test crashed on stderr, failed (uncaught exception) in the summary). Tests are always loaded with loadTestsFromModule. That collects TestCase classes and, when the module defines load_tests, runs the suite that function returns. Packages add submodule tests through load_tests, usually via test.support.load_package_tests. reap_children() is called from setUp(), tearDown(), and tearDownModule(), not from test_main.
So a reader who follows the current page probably add a test_main() and fail the module, and will look for a hook that regrtest rejects. This updates the library page and the reap_children() docstring to match the runner.
Ok, great, thanks for reporting this fix. Can you provide a minimum working example to show the failure? I gave it a shot and see a difference between 3.12 and 3.14 but I don't know whether I'm demonstrating what you describe. My goal is to help make the update to the docs as clear as we can for the next user that tries to follow them.
My MWE attempt
ryan@host:/tmp/testing$ tree .
.
├── app.py
├── __init__.py
└── test
└── test_app.py
1 directory, 3 files
ryan@host:/tmp/testing$ head $(find . -name "*.py")
==> ./__init__.py <==
==> ./app.py <==
def my_adder(a, b):
return a + b
==> ./test/test_app.py <==
import app
def test_main():
assert app.my_adder(1,2) == 3
ryan@host:/tmp/testing$ python3.14 -m test
/home/ryan/.local/bin/python3.14: No module named test.__main__; 'test' is a package and cannot be directly executed
ryan@host:/tmp/testing$ python3.12 -m test
== CPython 3.12.1 (main, Dec 25 2023, 21:02:37) [GCC 11.4.0]
== Linux-6.4.6-76060406-generic-x86_64-with-glibc2.35 little-endian
== Python build: release shared
== cwd: /tmp/test_python_worker_2914988æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources: all test resources are disabled, use -u option to unskip tests
Using random seed: 816464377
0:00:00 load avg: 0.32 Run 469 tests sequentially
0:00:00 load avg: 0.32 [ 1/469] test.test_asyncio.test_base_events
0:00:00 load avg: 0.32 [ 2/469] test.test_asyncio.test_buffered_proto
0:00:00 load avg: 0.32 [ 3/469] test.test_asyncio.test_context
0:00:01 load avg: 0.29 [ 4/469] test.test_asyncio.test_eager_task_factory
0:00:01 load avg: 0.29 [ 5/469] test.test_asyncio.test_events
...
@ryan-duve
python -m test only runs CPython's own regression tests. To run one module the way the docs describe, point regrtest at that directory with --testdir.
The failure screenshot is that case: a test_main() plus a TestCase. test_main() is not called (test_main ran is absent), no test method runs (Total tests: run=0), and the module fails with defines test_main() which is no longer supported by regrtest.
The success screenshot is the same module without test_main(). The TestCase method runs (test_passes ran) and the result is OK (run=1).
The reap_children() sentence points at that same removed hook. Tests call it from setUp(), tearDown(), or tearDownModule(). The runner is unchanged. This only updates the docs to match it.
Thank you for the clarification; you're clearly more familiar with the tool than me :-)
If a core dev that's already familiar with the tool and docs chimes in and approves then this is good. Otherwise, I'll take some time later to reproduce what you shared and let you know if I have any thoughts from the docs perspective and then I can try to help find the right core developer to review/merge.
@bazhil It looks like you've got a core developer working with you on the PR to finish it up. Let me know if you hit any docs-specific snags but the path forward looks clear. Thanks for helping improve the docs!
Activity
ryan-duve commentedon Oct 6, 2026
@bazhil One thing I don't understand is what benefits from this change. I don't really understand the motivation; could you help me wrap my head around that so I have context to read the proposed change?
bazhil commentedon Oct 7, 2026
@ryan-duve The change does not alter how tests run. The page currently describes a runner that no longer exists, and following it breaks a test.
Doc/library/test.rst says python -m test calls a module-level test_main() when that function exists, and otherwise loads tests with unittest.TestLoader.loadTestsFromModule. It also says to call test.support.reap_children() at the end of test_main. The docstring of reap_children() says the same thing.
Since #89392, Lib/test/libregrtest/single.py does not call test_main(). If the imported module defines it, the runner raises Exception and reports the module as failed with an uncaught exception (test crashed on stderr, failed (uncaught exception) in the summary). Tests are always loaded with loadTestsFromModule. That collects TestCase classes and, when the module defines load_tests, runs the suite that function returns. Packages add submodule tests through load_tests, usually via test.support.load_package_tests. reap_children() is called from setUp(), tearDown(), and tearDownModule(), not from test_main.
So a reader who follows the current page probably add a test_main() and fail the module, and will look for a hook that regrtest rejects. This updates the library page and the reap_children() docstring to match the runner.
ryan-duve commentedon Oct 7, 2026
Ok, great, thanks for reporting this fix. Can you provide a minimum working example to show the failure? I gave it a shot and see a difference between 3.12 and 3.14 but I don't know whether I'm demonstrating what you describe. My goal is to help make the update to the docs as clear as we can for the next user that tries to follow them.
My MWE attempt
bazhil commentedon Oct 7, 2026
@ryan-duve
python -m test only runs CPython's own regression tests. To run one module the way the docs describe, point regrtest at that directory with --testdir.
The failure screenshot is that case: a test_main() plus a TestCase. test_main() is not called (test_main ran is absent), no test method runs (Total tests: run=0), and the module fails with defines test_main() which is no longer supported by regrtest.
The success screenshot is the same module without test_main(). The TestCase method runs (test_passes ran) and the result is OK (run=1).
The reap_children() sentence points at that same removed hook. Tests call it from setUp(), tearDown(), or tearDownModule(). The runner is unchanged. This only updates the docs to match it.
ryan-duve commentedon Oct 7, 2026
Thank you for the clarification; you're clearly more familiar with the tool than me :-)
If a core dev that's already familiar with the tool and docs chimes in and approves then this is good. Otherwise, I'll take some time later to reproduce what you shared and let you know if I have any thoughts from the docs perspective and then I can try to help find the right core developer to review/merge.
StanFromIreland commentedon Oct 7, 2026
This issue seems fine IMO.
ryan-duve commentedon Oct 8, 2026
Agreed, Stan! I was able to reproduce.
@bazhil It looks like you've got a core developer working with you on the PR to finish it up. Let me know if you hit any docs-specific snags but the path forward looks clear. Thanks for helping improve the docs!
gh-158681: Document that regrtest no longer supports `test_main()` (#…
[3.14] gh-158681: Document that regrtest no longer supports `test_mai…
[3.15] gh-158681: Document that regrtest no longer supports `test_mai…