Skip to content

--doctest-modules uses GBs of memory on modules importing unittest.mock.call when the recursion limit is raised #15333

Open

Description

@RonnyPfannschmidt

🤖 Written by Claude Opus 5.5 via Claude Code for the pytest maintainers; I prompted it, it did the work, I read it.

Found while working on #15281 / #15283. This is a separate problem that already exists in 9.1.1, not the 9.2.0 regression.

Reproducer

conftest.py:

import sys

sys.setrecursionlimit(30_000)

mod_c.py:

"""
>>> 1
1
"""
from unittest.mock import call
pytest -q -p no:cacheprovider --doctest-modules

Measured on Python 3.13, Linux:

pytest wall peak RSS
9.1.1 4.7 s 5.2 GB
main (with #15283) 6.2 s 5.2 GB

At a limit of 100 000 the process is OOM-killed.

Cause

On Python 3.10+, the stdlib DocTestFinder._is_routine calls inspect.unwrap(obj) on every module attribute and only catches ValueError. mock.call.__wrapped__ keeps returning a new _Call with a longer name, so unwrapping runs until sys.getrecursionlimit(). Memory grows roughly quadratically with the limit.

pytest used to guard against this. MockAwareDocTestFinder._find skipped _is_mocked objects and ran the stdlib _find under _patch_unwrap_mock_aware() (#3456, python/cpython#69718). That override was limited to Python < 3.10 and was removed along with 3.9 support in bb712f1. _patch_unwrap_mock_aware itself is now only used by its own test.

Possible fix

Restore the _find override for all Python versions (about 14 lines in src/_pytest/doctest.py). I prototyped it locally: the reproducer drops to 0.09 s / 33 MB and the full test suite passes. A regression test is still needed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions