Skip to content

Doc/library/test.rst still says regrtest calls test_main() #158681

Closed

Description

@bazhil

Documentation

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.

Linked PRs

Activity

  1. added
    docsDocumentation in the Doc dir
    on Oct 3, 2026
  2. ryan-duve commented on Oct 6, 2026

    @ryan-duve
    Contributor

    @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?

  3. bazhil commented on Oct 7, 2026

    @bazhil
    ContributorAuthor

    @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.

  4. ryan-duve commented on Oct 7, 2026

    @ryan-duve
    Contributor

    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
    ...
    
  5. bazhil commented on Oct 7, 2026

    @bazhil
    ContributorAuthor

    @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.

    Image

    The success screenshot is the same module without test_main(). The TestCase method runs (test_passes ran) and the result is OK (run=1).

    Image

    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.

  6. ryan-duve commented on Oct 7, 2026

    @ryan-duve
    Contributor

    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.

  7. StanFromIreland commented on Oct 7, 2026

    @StanFromIreland
    Member

    This issue seems fine IMO.

  8. ryan-duve commented on Oct 8, 2026

    @ryan-duve
    Contributor

    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!

  9. added 3 commits that reference this issue on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docsDocumentation in the Doc dir

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions