|
17 | 17 | import warnings
|
18 | 18 |
|
19 | 19 |
|
20 |
| -try: |
21 |
| - from _testcapi import unicode_legacy_string |
22 |
| -except ImportError: |
23 |
| - unicode_legacy_string = None |
24 |
| - |
25 | 20 | __all__ = [
|
26 | 21 | # globals
|
27 | 22 | "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast",
|
@@ -507,11 +502,18 @@ def has_no_debug_ranges():
|
507 | 502 | def requires_debug_ranges(reason='requires co_positions / debug_ranges'):
|
508 | 503 | return unittest.skipIf(has_no_debug_ranges(), reason)
|
509 | 504 |
|
510 |
| -requires_legacy_unicode_capi = unittest.skipUnless(unicode_legacy_string, |
511 |
| - 'requires legacy Unicode C API') |
| 505 | +def requires_legacy_unicode_capi(): |
| 506 | + try: |
| 507 | + from _testcapi import unicode_legacy_string |
| 508 | + except ImportError: |
| 509 | + unicode_legacy_string = None |
| 510 | + |
| 511 | + return unittest.skipUnless(unicode_legacy_string, |
| 512 | + 'requires legacy Unicode C API') |
512 | 513 |
|
513 | 514 | MS_WINDOWS = (sys.platform == 'win32')
|
514 | 515 |
|
| 516 | +# Is not actually used in tests, but is kept for compatibility. |
515 | 517 | is_jython = sys.platform.startswith('java')
|
516 | 518 |
|
517 | 519 | is_android = hasattr(sys, 'getandroidapilevel')
|
@@ -587,7 +589,8 @@ def darwin_malloc_err_warning(test_name):
|
587 | 589 | msg = ' NOTICE '
|
588 | 590 | detail = (f'{test_name} may generate "malloc can\'t allocate region"\n'
|
589 | 591 | 'warnings on macOS systems. This behavior is known. Do not\n'
|
590 |
| - 'report a bug unless tests are also failing. See bpo-40928.') |
| 592 | + 'report a bug unless tests are also failing.\n' |
| 593 | + 'See https://github.com/python/cpython/issues/85100') |
591 | 594 |
|
592 | 595 | padding, _ = shutil.get_terminal_size()
|
593 | 596 | print(msg.center(padding, '-'))
|
@@ -743,8 +746,6 @@ def gc_collect():
|
743 | 746 | """
|
744 | 747 | import gc
|
745 | 748 | gc.collect()
|
746 |
| - if is_jython: |
747 |
| - time.sleep(0.1) |
748 | 749 | gc.collect()
|
749 | 750 | gc.collect()
|
750 | 751 |
|
@@ -795,10 +796,20 @@ def check_cflags_pgo():
|
795 | 796 | _align = '0P'
|
796 | 797 | _vheader = _header + 'n'
|
797 | 798 |
|
| 799 | +def check_bolt_optimized(): |
| 800 | + # Always return false, if the platform is WASI, |
| 801 | + # because BOLT optimization does not support WASM binary. |
| 802 | + if is_wasi: |
| 803 | + return False |
| 804 | + config_args = sysconfig.get_config_var('CONFIG_ARGS') or '' |
| 805 | + return '--enable-bolt' in config_args |
| 806 | + |
| 807 | + |
798 | 808 | def calcobjsize(fmt):
|
799 | 809 | import struct
|
800 | 810 | return struct.calcsize(_header + fmt + _align)
|
801 | 811 |
|
| 812 | + |
802 | 813 | def calcvobjsize(fmt):
|
803 | 814 | import struct
|
804 | 815 | return struct.calcsize(_vheader + fmt + _align)
|
@@ -1099,6 +1110,19 @@ def refcount_test(test):
|
1099 | 1110 | return no_tracing(cpython_only(test))
|
1100 | 1111 |
|
1101 | 1112 |
|
| 1113 | +def requires_limited_api(test): |
| 1114 | + try: |
| 1115 | + import _testcapi |
| 1116 | + except ImportError: |
| 1117 | + return unittest.skip('needs _testcapi module')(test) |
| 1118 | + return unittest.skipUnless( |
| 1119 | + _testcapi.LIMITED_API_AVAILABLE, 'needs Limited API support')(test) |
| 1120 | + |
| 1121 | +def requires_specialization(test): |
| 1122 | + return unittest.skipUnless( |
| 1123 | + opcode.ENABLE_SPECIALIZATION, "requires specialization")(test) |
| 1124 | + |
| 1125 | + |
1102 | 1126 | #=======================================================================
|
1103 | 1127 | # Check for the presence of docstrings.
|
1104 | 1128 |
|
@@ -1722,6 +1746,18 @@ def setswitchinterval(interval):
|
1722 | 1746 | return sys.setswitchinterval(interval)
|
1723 | 1747 |
|
1724 | 1748 |
|
| 1749 | +def get_pagesize(): |
| 1750 | + """Get size of a page in bytes.""" |
| 1751 | + try: |
| 1752 | + page_size = os.sysconf('SC_PAGESIZE') |
| 1753 | + except (ValueError, AttributeError): |
| 1754 | + try: |
| 1755 | + page_size = os.sysconf('SC_PAGE_SIZE') |
| 1756 | + except (ValueError, AttributeError): |
| 1757 | + page_size = 4096 |
| 1758 | + return page_size |
| 1759 | + |
| 1760 | + |
1725 | 1761 | @contextlib.contextmanager
|
1726 | 1762 | def disable_faulthandler():
|
1727 | 1763 | import faulthandler
|
@@ -2041,16 +2077,7 @@ def get_recursion_available():
|
2041 | 2077 | """
|
2042 | 2078 | limit = sys.getrecursionlimit()
|
2043 | 2079 | depth = get_recursion_depth()
|
2044 |
| - |
2045 |
| - try: |
2046 |
| - from _testcapi import USE_STACKCHECK |
2047 |
| - except ImportError: |
2048 |
| - USE_STACKCHECK = False |
2049 |
| - |
2050 |
| - if USE_STACKCHECK: |
2051 |
| - return max(limit - depth - 1, 0) |
2052 |
| - else: |
2053 |
| - return limit - depth |
| 2080 | + return limit - depth |
2054 | 2081 |
|
2055 | 2082 | @contextlib.contextmanager
|
2056 | 2083 | def set_recursion_limit(limit):
|
@@ -2127,6 +2154,43 @@ def requires_venv_with_pip():
|
2127 | 2154 | Py_DEBUG = hasattr(sys, 'gettotalrefcount')
|
2128 | 2155 |
|
2129 | 2156 |
|
| 2157 | +def late_deletion(obj): |
| 2158 | + """ |
| 2159 | + Keep a Python alive as long as possible. |
| 2160 | +
|
| 2161 | + Create a reference cycle and store the cycle in an object deleted late in |
| 2162 | + Python finalization. Try to keep the object alive until the very last |
| 2163 | + garbage collection. |
| 2164 | +
|
| 2165 | + The function keeps a strong reference by design. It should be called in a |
| 2166 | + subprocess to not mark a test as "leaking a reference". |
| 2167 | + """ |
| 2168 | + |
| 2169 | + # Late CPython finalization: |
| 2170 | + # - finalize_interp_clear() |
| 2171 | + # - _PyInterpreterState_Clear(): Clear PyInterpreterState members |
| 2172 | + # (ex: codec_search_path, before_forkers) |
| 2173 | + # - clear os.register_at_fork() callbacks |
| 2174 | + # - clear codecs.register() callbacks |
| 2175 | + |
| 2176 | + ref_cycle = [obj] |
| 2177 | + ref_cycle.append(ref_cycle) |
| 2178 | + |
| 2179 | + # Store a reference in PyInterpreterState.codec_search_path |
| 2180 | + import codecs |
| 2181 | + def search_func(encoding): |
| 2182 | + return None |
| 2183 | + search_func.reference = ref_cycle |
| 2184 | + codecs.register(search_func) |
| 2185 | + |
| 2186 | + if hasattr(os, 'register_at_fork'): |
| 2187 | + # Store a reference in PyInterpreterState.before_forkers |
| 2188 | + def atfork_func(): |
| 2189 | + pass |
| 2190 | + atfork_func.reference = ref_cycle |
| 2191 | + os.register_at_fork(before=atfork_func) |
| 2192 | + |
| 2193 | + |
2130 | 2194 | def busy_retry(timeout, err_msg=None, /, *, error=True):
|
2131 | 2195 | """
|
2132 | 2196 | Run the loop body until "break" stops the loop.
|
@@ -2238,3 +2302,75 @@ def copy_python_src_ignore(path, names):
|
2238 | 2302 | 'build',
|
2239 | 2303 | }
|
2240 | 2304 | return ignored
|
| 2305 | + |
| 2306 | + |
| 2307 | +def iter_builtin_types(): |
| 2308 | + for obj in __builtins__.values(): |
| 2309 | + if not isinstance(obj, type): |
| 2310 | + continue |
| 2311 | + cls = obj |
| 2312 | + if cls.__module__ != 'builtins': |
| 2313 | + continue |
| 2314 | + yield cls |
| 2315 | + |
| 2316 | + |
| 2317 | +def iter_slot_wrappers(cls): |
| 2318 | + assert cls.__module__ == 'builtins', cls |
| 2319 | + |
| 2320 | + def is_slot_wrapper(name, value): |
| 2321 | + if not isinstance(value, types.WrapperDescriptorType): |
| 2322 | + assert not repr(value).startswith('<slot wrapper '), (cls, name, value) |
| 2323 | + return False |
| 2324 | + assert repr(value).startswith('<slot wrapper '), (cls, name, value) |
| 2325 | + assert callable(value), (cls, name, value) |
| 2326 | + assert name.startswith('__') and name.endswith('__'), (cls, name, value) |
| 2327 | + return True |
| 2328 | + |
| 2329 | + ns = vars(cls) |
| 2330 | + unused = set(ns) |
| 2331 | + for name in dir(cls): |
| 2332 | + if name in ns: |
| 2333 | + unused.remove(name) |
| 2334 | + |
| 2335 | + try: |
| 2336 | + value = getattr(cls, name) |
| 2337 | + except AttributeError: |
| 2338 | + # It's as though it weren't in __dir__. |
| 2339 | + assert name in ('__annotate__', '__annotations__', '__abstractmethods__'), (cls, name) |
| 2340 | + if name in ns and is_slot_wrapper(name, ns[name]): |
| 2341 | + unused.add(name) |
| 2342 | + continue |
| 2343 | + |
| 2344 | + if not name.startswith('__') or not name.endswith('__'): |
| 2345 | + assert not is_slot_wrapper(name, value), (cls, name, value) |
| 2346 | + if not is_slot_wrapper(name, value): |
| 2347 | + if name in ns: |
| 2348 | + assert not is_slot_wrapper(name, ns[name]), (cls, name, value, ns[name]) |
| 2349 | + else: |
| 2350 | + if name in ns: |
| 2351 | + assert ns[name] is value, (cls, name, value, ns[name]) |
| 2352 | + yield name, True |
| 2353 | + else: |
| 2354 | + yield name, False |
| 2355 | + |
| 2356 | + for name in unused: |
| 2357 | + value = ns[name] |
| 2358 | + if is_slot_wrapper(cls, name, value): |
| 2359 | + yield name, True |
| 2360 | + |
| 2361 | + |
| 2362 | +class BrokenIter: |
| 2363 | + def __init__(self, init_raises=False, next_raises=False, iter_raises=False): |
| 2364 | + if init_raises: |
| 2365 | + 1/0 |
| 2366 | + self.next_raises = next_raises |
| 2367 | + self.iter_raises = iter_raises |
| 2368 | + |
| 2369 | + def __next__(self): |
| 2370 | + if self.next_raises: |
| 2371 | + 1/0 |
| 2372 | + |
| 2373 | + def __iter__(self): |
| 2374 | + if self.iter_raises: |
| 2375 | + 1/0 |
| 2376 | + return self |
0 commit comments