mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
gh-116303: Skip tests if C recursion limit is unavailable (GH-117368)
The test suite fetches the C recursion limit from the _testcapi extension module. Test extension modules can be disabled using the --disable-test-modules configure option.
This commit is contained in:
parent
9a12f5d1c1
commit
ca62ffd1a5
14 changed files with 32 additions and 35 deletions
|
@ -6,7 +6,7 @@ import sys
|
||||||
from functools import cmp_to_key
|
from functools import cmp_to_key
|
||||||
|
|
||||||
from test import seq_tests
|
from test import seq_tests
|
||||||
from test.support import ALWAYS_EQ, NEVER_EQ, Py_C_RECURSION_LIMIT
|
from test.support import ALWAYS_EQ, NEVER_EQ, get_c_recursion_limit
|
||||||
|
|
||||||
|
|
||||||
class CommonTest(seq_tests.CommonTest):
|
class CommonTest(seq_tests.CommonTest):
|
||||||
|
@ -61,7 +61,7 @@ class CommonTest(seq_tests.CommonTest):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
a = self.type2test([])
|
a = self.type2test([])
|
||||||
for i in range(Py_C_RECURSION_LIMIT + 1):
|
for i in range(get_c_recursion_limit() + 1):
|
||||||
a = self.type2test([a])
|
a = self.type2test([a])
|
||||||
self.assertRaises(RecursionError, repr, a)
|
self.assertRaises(RecursionError, repr, a)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# tests common to dict and UserDict
|
# tests common to dict and UserDict
|
||||||
import unittest
|
import unittest
|
||||||
import collections
|
import collections
|
||||||
from test.support import Py_C_RECURSION_LIMIT
|
from test.support import get_c_recursion_limit
|
||||||
|
|
||||||
|
|
||||||
class BasicTestMappingProtocol(unittest.TestCase):
|
class BasicTestMappingProtocol(unittest.TestCase):
|
||||||
|
@ -624,7 +624,7 @@ class TestHashMappingProtocol(TestMappingProtocol):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
d = self._empty_mapping()
|
d = self._empty_mapping()
|
||||||
for i in range(Py_C_RECURSION_LIMIT + 1):
|
for i in range(get_c_recursion_limit() + 1):
|
||||||
d0 = d
|
d0 = d
|
||||||
d = self._empty_mapping()
|
d = self._empty_mapping()
|
||||||
d[1] = d0
|
d[1] = d0
|
||||||
|
|
|
@ -56,7 +56,7 @@ __all__ = [
|
||||||
"run_with_tz", "PGO", "missing_compiler_executable",
|
"run_with_tz", "PGO", "missing_compiler_executable",
|
||||||
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
|
"ALWAYS_EQ", "NEVER_EQ", "LARGEST", "SMALLEST",
|
||||||
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
|
"LOOPBACK_TIMEOUT", "INTERNET_TIMEOUT", "SHORT_TIMEOUT", "LONG_TIMEOUT",
|
||||||
"Py_DEBUG", "EXCEEDS_RECURSION_LIMIT", "Py_C_RECURSION_LIMIT",
|
"Py_DEBUG", "exceeds_recursion_limit", "get_c_recursion_limit",
|
||||||
"skip_on_s390x",
|
"skip_on_s390x",
|
||||||
"without_optimizer",
|
"without_optimizer",
|
||||||
]
|
]
|
||||||
|
@ -2490,22 +2490,18 @@ def adjust_int_max_str_digits(max_digits):
|
||||||
sys.set_int_max_str_digits(current)
|
sys.set_int_max_str_digits(current)
|
||||||
|
|
||||||
|
|
||||||
def _get_c_recursion_limit():
|
def get_c_recursion_limit():
|
||||||
try:
|
try:
|
||||||
import _testcapi
|
import _testcapi
|
||||||
return _testcapi.Py_C_RECURSION_LIMIT
|
return _testcapi.Py_C_RECURSION_LIMIT
|
||||||
except (ImportError, AttributeError):
|
except ImportError:
|
||||||
# Originally taken from Include/cpython/pystate.h .
|
raise unittest.SkipTest('requires _testcapi')
|
||||||
if sys.platform == 'win32':
|
|
||||||
return 4000
|
|
||||||
else:
|
|
||||||
return 10000
|
|
||||||
|
|
||||||
# The default C recursion limit.
|
|
||||||
Py_C_RECURSION_LIMIT = _get_c_recursion_limit()
|
|
||||||
|
|
||||||
#For recursion tests, easily exceeds default recursion limit
|
def exceeds_recursion_limit():
|
||||||
EXCEEDS_RECURSION_LIMIT = Py_C_RECURSION_LIMIT * 3
|
"""For recursion tests, easily exceeds default recursion limit."""
|
||||||
|
return get_c_recursion_limit() * 3
|
||||||
|
|
||||||
|
|
||||||
#Windows doesn't have os.uname() but it doesn't support s390x.
|
#Windows doesn't have os.uname() but it doesn't support s390x.
|
||||||
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
|
skip_on_s390x = unittest.skipIf(hasattr(os, 'uname') and os.uname().machine == 's390x',
|
||||||
|
|
|
@ -1153,9 +1153,9 @@ class AST_Tests(unittest.TestCase):
|
||||||
|
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
def test_ast_recursion_limit(self):
|
def test_ast_recursion_limit(self):
|
||||||
fail_depth = support.EXCEEDS_RECURSION_LIMIT
|
fail_depth = support.exceeds_recursion_limit()
|
||||||
crash_depth = 100_000
|
crash_depth = 100_000
|
||||||
success_depth = int(support.Py_C_RECURSION_LIMIT * 0.8)
|
success_depth = int(support.get_c_recursion_limit() * 0.8)
|
||||||
if _testinternalcapi is not None:
|
if _testinternalcapi is not None:
|
||||||
remaining = _testinternalcapi.get_c_recursion_remaining()
|
remaining = _testinternalcapi.get_c_recursion_remaining()
|
||||||
success_depth = min(success_depth, remaining)
|
success_depth = min(success_depth, remaining)
|
||||||
|
|
|
@ -542,7 +542,7 @@ class TestNamedTuple(unittest.TestCase):
|
||||||
self.assertEqual(Dot(1)._replace(d=999), (999,))
|
self.assertEqual(Dot(1)._replace(d=999), (999,))
|
||||||
self.assertEqual(Dot(1)._fields, ('d',))
|
self.assertEqual(Dot(1)._fields, ('d',))
|
||||||
|
|
||||||
n = support.EXCEEDS_RECURSION_LIMIT
|
n = support.exceeds_recursion_limit()
|
||||||
names = list(set(''.join([choice(string.ascii_letters)
|
names = list(set(''.join([choice(string.ascii_letters)
|
||||||
for j in range(10)]) for i in range(n)))
|
for j in range(10)]) for i in range(n)))
|
||||||
n = len(names)
|
n = len(names)
|
||||||
|
|
|
@ -13,7 +13,7 @@ import textwrap
|
||||||
import warnings
|
import warnings
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import (script_helper, requires_debug_ranges,
|
from test.support import (script_helper, requires_debug_ranges,
|
||||||
requires_specialization, Py_C_RECURSION_LIMIT)
|
requires_specialization, get_c_recursion_limit)
|
||||||
from test.support.bytecode_helper import instructions_with_positions
|
from test.support.bytecode_helper import instructions_with_positions
|
||||||
from test.support.os_helper import FakePath
|
from test.support.os_helper import FakePath
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ class TestSpecifics(unittest.TestCase):
|
||||||
|
|
||||||
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
||||||
def test_extended_arg(self):
|
def test_extended_arg(self):
|
||||||
repeat = int(Py_C_RECURSION_LIMIT * 0.9)
|
repeat = int(get_c_recursion_limit() * 0.9)
|
||||||
longexpr = 'x = x or ' + '-x' * repeat
|
longexpr = 'x = x or ' + '-x' * repeat
|
||||||
g = {}
|
g = {}
|
||||||
code = textwrap.dedent('''
|
code = textwrap.dedent('''
|
||||||
|
@ -634,9 +634,10 @@ class TestSpecifics(unittest.TestCase):
|
||||||
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
||||||
def test_compiler_recursion_limit(self):
|
def test_compiler_recursion_limit(self):
|
||||||
# Expected limit is Py_C_RECURSION_LIMIT
|
# Expected limit is Py_C_RECURSION_LIMIT
|
||||||
fail_depth = Py_C_RECURSION_LIMIT + 1
|
limit = get_c_recursion_limit()
|
||||||
crash_depth = Py_C_RECURSION_LIMIT * 100
|
fail_depth = limit + 1
|
||||||
success_depth = int(Py_C_RECURSION_LIMIT * 0.8)
|
crash_depth = limit * 100
|
||||||
|
success_depth = int(limit * 0.8)
|
||||||
|
|
||||||
def check_limit(prefix, repeated, mode="single"):
|
def check_limit(prefix, repeated, mode="single"):
|
||||||
expect_ok = prefix + repeated * success_depth
|
expect_ok = prefix + repeated * success_depth
|
||||||
|
|
|
@ -8,7 +8,7 @@ import sys
|
||||||
import unittest
|
import unittest
|
||||||
import weakref
|
import weakref
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import import_helper, Py_C_RECURSION_LIMIT
|
from test.support import import_helper, get_c_recursion_limit
|
||||||
|
|
||||||
|
|
||||||
class DictTest(unittest.TestCase):
|
class DictTest(unittest.TestCase):
|
||||||
|
@ -596,7 +596,7 @@ class DictTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_repr_deep(self):
|
def test_repr_deep(self):
|
||||||
d = {}
|
d = {}
|
||||||
for i in range(Py_C_RECURSION_LIMIT + 1):
|
for i in range(get_c_recursion_limit() + 1):
|
||||||
d = {1: d}
|
d = {1: d}
|
||||||
self.assertRaises(RecursionError, repr, d)
|
self.assertRaises(RecursionError, repr, d)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import collections.abc
|
||||||
import copy
|
import copy
|
||||||
import pickle
|
import pickle
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import Py_C_RECURSION_LIMIT
|
from test.support import get_c_recursion_limit
|
||||||
|
|
||||||
class DictSetTest(unittest.TestCase):
|
class DictSetTest(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ class DictSetTest(unittest.TestCase):
|
||||||
|
|
||||||
def test_deeply_nested_repr(self):
|
def test_deeply_nested_repr(self):
|
||||||
d = {}
|
d = {}
|
||||||
for i in range(Py_C_RECURSION_LIMIT//2 + 100):
|
for i in range(get_c_recursion_limit()//2 + 100):
|
||||||
d = {42: d.values()}
|
d = {42: d.values()}
|
||||||
self.assertRaises(RecursionError, repr, d)
|
self.assertRaises(RecursionError, repr, d)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import collections.abc
|
import collections.abc
|
||||||
import types
|
import types
|
||||||
import unittest
|
import unittest
|
||||||
from test.support import Py_C_RECURSION_LIMIT
|
from test.support import get_c_recursion_limit
|
||||||
|
|
||||||
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
class TestExceptionGroupTypeHierarchy(unittest.TestCase):
|
||||||
def test_exception_group_types(self):
|
def test_exception_group_types(self):
|
||||||
|
@ -460,7 +460,7 @@ class ExceptionGroupSplitTests(ExceptionGroupTestBase):
|
||||||
class DeepRecursionInSplitAndSubgroup(unittest.TestCase):
|
class DeepRecursionInSplitAndSubgroup(unittest.TestCase):
|
||||||
def make_deep_eg(self):
|
def make_deep_eg(self):
|
||||||
e = TypeError(1)
|
e = TypeError(1)
|
||||||
for i in range(Py_C_RECURSION_LIMIT + 1):
|
for i in range(get_c_recursion_limit() + 1):
|
||||||
e = ExceptionGroup('eg', [e])
|
e = ExceptionGroup('eg', [e])
|
||||||
return e
|
return e
|
||||||
|
|
||||||
|
|
|
@ -1424,7 +1424,7 @@ class ExceptionTests(unittest.TestCase):
|
||||||
next(generator)
|
next(generator)
|
||||||
recursionlimit = sys.getrecursionlimit()
|
recursionlimit = sys.getrecursionlimit()
|
||||||
try:
|
try:
|
||||||
recurse(support.EXCEEDS_RECURSION_LIMIT)
|
recurse(support.exceeds_recursion_limit())
|
||||||
finally:
|
finally:
|
||||||
sys.setrecursionlimit(recursionlimit)
|
sys.setrecursionlimit(recursionlimit)
|
||||||
print('Done.')
|
print('Done.')
|
||||||
|
|
|
@ -1867,7 +1867,7 @@ class TestLRU:
|
||||||
return fib(n-1) + fib(n-2)
|
return fib(n-1) + fib(n-2)
|
||||||
|
|
||||||
if not support.Py_DEBUG:
|
if not support.Py_DEBUG:
|
||||||
depth = support.Py_C_RECURSION_LIMIT*2//7
|
depth = support.get_c_recursion_limit()*2//7
|
||||||
with support.infinite_recursion():
|
with support.infinite_recursion():
|
||||||
fib(depth)
|
fib(depth)
|
||||||
if self.module == c_functools:
|
if self.module == c_functools:
|
||||||
|
|
|
@ -352,7 +352,7 @@ def blowstack(fxn, arg, compare_to):
|
||||||
# Make sure that calling isinstance with a deeply nested tuple for its
|
# Make sure that calling isinstance with a deeply nested tuple for its
|
||||||
# argument will raise RecursionError eventually.
|
# argument will raise RecursionError eventually.
|
||||||
tuple_arg = (compare_to,)
|
tuple_arg = (compare_to,)
|
||||||
for cnt in range(support.EXCEEDS_RECURSION_LIMIT):
|
for cnt in range(support.exceeds_recursion_limit()):
|
||||||
tuple_arg = (tuple_arg,)
|
tuple_arg = (tuple_arg,)
|
||||||
fxn(arg, tuple_arg)
|
fxn(arg, tuple_arg)
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ class CodeTestCase(unittest.TestCase):
|
||||||
def test_many_codeobjects(self):
|
def test_many_codeobjects(self):
|
||||||
# Issue2957: bad recursion count on code objects
|
# Issue2957: bad recursion count on code objects
|
||||||
# more than MAX_MARSHAL_STACK_DEPTH
|
# more than MAX_MARSHAL_STACK_DEPTH
|
||||||
count = support.EXCEEDS_RECURSION_LIMIT
|
count = support.exceeds_recursion_limit()
|
||||||
codes = (ExceptionTestCase.test_exceptions.__code__,) * count
|
codes = (ExceptionTestCase.test_exceptions.__code__,) * count
|
||||||
marshal.loads(marshal.dumps(codes))
|
marshal.loads(marshal.dumps(codes))
|
||||||
|
|
||||||
|
|
|
@ -3039,7 +3039,7 @@ class TestExtendedArgs(unittest.TestCase):
|
||||||
|
|
||||||
def test_trace_lots_of_globals(self):
|
def test_trace_lots_of_globals(self):
|
||||||
|
|
||||||
count = min(1000, int(support.Py_C_RECURSION_LIMIT * 0.8))
|
count = min(1000, int(support.get_c_recursion_limit() * 0.8))
|
||||||
|
|
||||||
code = """if 1:
|
code = """if 1:
|
||||||
def f():
|
def f():
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue