diff options
author | Victor Stinner <vstinner@python.org> | 2023-09-06 15:34:31 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-06 15:34:31 (GMT) |
commit | 8ff11425783806f8cb78e99f667546b1f7f3428e (patch) | |
tree | 0c4d2006d833d74a59a809fd2447fc6a91ceabd7 /Lib/test/support | |
parent | 2cd170db40ffba357848672ff3d2f8c1e0e74f2c (diff) | |
download | cpython-8ff11425783806f8cb78e99f667546b1f7f3428e.zip cpython-8ff11425783806f8cb78e99f667546b1f7f3428e.tar.gz cpython-8ff11425783806f8cb78e99f667546b1f7f3428e.tar.bz2 |
gh-108851: Fix tomllib recursion tests (#108853)
* Add get_recursion_available() and get_recursion_depth() functions
to the test.support module.
* Change infinite_recursion() default max_depth from 75 to 100.
* Fix test_tomllib recursion tests for WASI buildbots: reduce the
recursion limit and compute the maximum nested array/dict depending
on the current available recursion limit.
* test.pythoninfo logs sys.getrecursionlimit().
* Enhance test_sys tests on sys.getrecursionlimit()
and sys.setrecursionlimit().
Diffstat (limited to 'Lib/test/support')
-rw-r--r-- | Lib/test/support/__init__.py | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 7bac116..d39f529 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2241,6 +2241,39 @@ def check_disallow_instantiation(testcase, tp, *args, **kwds): msg = f"cannot create '{re.escape(qualname)}' instances" testcase.assertRaisesRegex(TypeError, msg, tp, *args, **kwds) +def get_recursion_depth(): + """Get the recursion depth of the caller function. + + In the __main__ module, at the module level, it should be 1. + """ + try: + import _testinternalcapi + depth = _testinternalcapi.get_recursion_depth() + except (ImportError, RecursionError) as exc: + # sys._getframe() + frame.f_back implementation. + try: + depth = 0 + frame = sys._getframe() + while frame is not None: + depth += 1 + frame = frame.f_back + finally: + # Break any reference cycles. + frame = None + + # Ignore get_recursion_depth() frame. + return max(depth - 1, 1) + +def get_recursion_available(): + """Get the number of available frames before RecursionError. + + It depends on the current recursion depth of the caller function and + sys.getrecursionlimit(). + """ + limit = sys.getrecursionlimit() + depth = get_recursion_depth() + return limit - depth + @contextlib.contextmanager def set_recursion_limit(limit): """Temporarily change the recursion limit.""" @@ -2251,14 +2284,18 @@ def set_recursion_limit(limit): finally: sys.setrecursionlimit(original_limit) -def infinite_recursion(max_depth=75): +def infinite_recursion(max_depth=100): """Set a lower limit for tests that interact with infinite recursions (e.g test_ast.ASTHelpers_Test.test_recursion_direct) since on some debug windows builds, due to not enough functions being inlined the stack size might not handle the default recursion limit (1000). See bpo-11105 for details.""" - return set_recursion_limit(max_depth) - + if max_depth < 3: + raise ValueError("max_depth must be at least 3, got {max_depth}") + depth = get_recursion_depth() + depth = max(depth - 1, 1) # Ignore infinite_recursion() frame. + limit = depth + max_depth + return set_recursion_limit(limit) def ignore_deprecations_from(module: str, *, like: str) -> object: token = object() |