Update some tests to 3.14.5 (#7990)

* Update `test_embed.py` to 3.14.5

* Update `test_cmd_line*` to 3.14.5

* Update unicode related tests

* Update `test_script_helper.py`

* Update `test_gc.py`
This commit is contained in:
Shahar Naveh authored and GitHub committed 2026-05-30 20:16:10 +09:00
1 parent 024201c050
commit 620faab734
13 files changed
+2672 -222

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
import sys
import types
import unittest
# bpo-46417: Test that structseq types used by the sys module are still
# valid when Py_Finalize()/Py_Initialize() are called multiple times.
class TestStructSeq(unittest.TestCase):
# test PyTypeObject members
def check_structseq(self, obj_type):
# ob_refcnt
self.assertGreaterEqual(sys.getrefcount(obj_type), 1)
# tp_base
self.assertIsSubclass(obj_type, tuple)
# tp_bases
self.assertEqual(obj_type.__bases__, (tuple,))
# tp_dict
self.assertIsInstance(obj_type.__dict__, types.MappingProxyType)
# tp_mro
self.assertEqual(obj_type.__mro__, (obj_type, tuple, object))
# tp_name
self.assertIsInstance(type.__name__, str)
# tp_subclasses
self.assertEqual(obj_type.__subclasses__(), [])
def test_sys_attrs(self):
for attr_name in (
'flags', # FlagsType
'float_info', # FloatInfoType
'hash_info', # Hash_InfoType
'int_info', # Int_InfoType
'thread_info', # ThreadInfoType
'version_info', # VersionInfoType
):
with self.subTest(attr=attr_name):
attr = getattr(sys, attr_name)
self.check_structseq(type(attr))
def test_sys_funcs(self):
func_names = ['get_asyncgen_hooks'] # AsyncGenHooksType
if hasattr(sys, 'getwindowsversion'):
func_names.append('getwindowsversion') # WindowsVersionType
for func_name in func_names:
with self.subTest(func=func_name):
func = getattr(sys, func_name)
obj = func()
self.check_structseq(type(obj))
try:
unittest.main(
module=(
'__main__'
if __name__ == '__main__'
# Avoiding a circular import:
else sys.modules['test._test_embed_structseq']
)
)
except SystemExit as exc:
if exc.args[0] != 0:
raise
print("Tests passed")
+408 -65
View File
@@ -3,17 +3,23 @@
# See test_cmd_line_script.py for testing of script execution
import os
import re
import subprocess
import sys
import sysconfig
import tempfile
import textwrap
import unittest
from test import support
from test.support import os_helper
from test.support import force_not_colorized
from test.support import threading_helper
from test.support.script_helper import (
spawn_python, kill_python, assert_python_ok, assert_python_failure,
interpreter_requires_environment
)
from textwrap import dedent
if not support.has_subprocess_support:
raise unittest.SkipTest("test module requires subprocess")
@@ -33,11 +39,13 @@ class CmdLineTest(unittest.TestCase):
def verify_valid_flag(self, cmd_line):
rc, out, err = assert_python_ok(cmd_line)
self.assertTrue(out == b'' or out.endswith(b'\n'))
if out != b'':
self.assertEndsWith(out, b'\n')
self.assertNotIn(b'Traceback', out)
self.assertNotIn(b'Traceback', err)
return out
@support.cpython_only
def test_help(self):
self.verify_valid_flag('-h')
self.verify_valid_flag('-?')
@@ -48,20 +56,28 @@ class CmdLineTest(unittest.TestCase):
self.assertNotIn(b'-X dev', out)
self.assertLess(len(lines), 50)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_help_env(self):
out = self.verify_valid_flag('--help-env')
self.assertIn(b'PYTHONHOME', out)
# Env vars in each section should be sorted alphabetically
# (ignoring underscores so PYTHON_FOO and PYTHONFOO intermix naturally)
sort_key = lambda name: name.replace(b'_', b'').lower()
sections = out.split(b'These variables have equivalent')
for section in sections:
envvars = re.findall(rb'^(PYTHON\w+)', section, re.MULTILINE)
self.assertEqual(envvars, sorted(envvars, key=sort_key),
"env vars should be sorted alphabetically")
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_help_xoptions(self):
out = self.verify_valid_flag('--help-xoptions')
self.assertIn(b'-X dev', out)
options = re.findall(rb'^-X (\w+)', out, re.MULTILINE)
self.assertEqual(options, sorted(options),
"options should be sorted alphabetically")
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_help_all(self):
out = self.verify_valid_flag('--help-all')
lines = out.splitlines()
@@ -80,12 +96,13 @@ class CmdLineTest(unittest.TestCase):
def test_site_flag(self):
self.verify_valid_flag('-S')
@support.cpython_only
def test_version(self):
version = ('Python %d.%d' % sys.version_info[:2]).encode("ascii")
for switch in '-V', '--version', '-VV':
rc, out, err = assert_python_ok(switch)
self.assertFalse(err.startswith(version))
self.assertTrue(out.startswith(version))
self.assertNotStartsWith(err, version)
self.assertStartsWith(out, version)
def test_verbose(self):
# -v causes imports to write to stderr. If the write to
@@ -145,8 +162,7 @@ class CmdLineTest(unittest.TestCase):
else:
self.assertEqual(err, b'')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_xoption_frozen_modules(self):
tests = {
('=on', 'FrozenImporter'),
@@ -161,6 +177,18 @@ class CmdLineTest(unittest.TestCase):
res = assert_python_ok(*cmd)
self.assertRegex(res.out.decode('utf-8'), expected)
@support.cpython_only
def test_env_var_frozen_modules(self):
tests = {
('on', 'FrozenImporter'),
('off', 'SourceFileLoader'),
}
for raw, expected in tests:
cmd = ['-c', 'import os; print(os.__spec__.loader, end="")']
with self.subTest(raw):
res = assert_python_ok(*cmd, PYTHON_FROZEN_MODULES=raw)
self.assertRegex(res.out.decode('utf-8'), expected)
def test_run_module(self):
# Test expected operation of the '-m' switch
# Switch needs an argument
@@ -173,6 +201,7 @@ class CmdLineTest(unittest.TestCase):
# All good if module is located and run successfully
assert_python_ok('-m', 'timeit', '-n', '1')
@unittest.expectedFailureIf(support.is_android, "TODO: RUSTPYTHON")
def test_run_module_bug1764407(self):
# -m and -i need to play well together
# Runs the timeit module and checks the __main__
@@ -184,6 +213,14 @@ class CmdLineTest(unittest.TestCase):
self.assertTrue(data.find(b'1 loop') != -1)
self.assertTrue(data.find(b'__main__.Timer') != -1)
@support.cpython_only
def test_null_byte_in_interactive_mode(self):
# gh-140594: Fix an out of bounds read when a single NUL character
# is read from the standard input in interactive mode.
proc = spawn_python('-i')
proc.communicate(b'\x00', timeout=support.SHORT_TIMEOUT)
self.assertEqual(proc.returncode, 0)
def test_relativedir_bug46421(self):
# Test `python -m unittest` with a relative directory beginning with ./
# Note: We have to switch to the project's top module's directory, as per
@@ -222,8 +259,7 @@ class CmdLineTest(unittest.TestCase):
# command line, but how subprocess does decode bytes to unicode. Python
# doesn't decode the command line because Windows provides directly the
# arguments as unicode (using wmain() instead of main()).
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf(sys.platform == 'win32',
'Windows has a native unicode API')
def test_undecodable_code(self):
@@ -259,8 +295,7 @@ class CmdLineTest(unittest.TestCase):
if not stdout.startswith(pattern):
raise AssertionError("%a doesn't start with %a" % (stdout, pattern))
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf(sys.platform == 'win32',
'Windows has a native unicode API')
def test_invalid_utf8_arg(self):
@@ -272,12 +307,10 @@ class CmdLineTest(unittest.TestCase):
# Test with default config, in the C locale, in the Python UTF-8 Mode.
code = 'import sys, os; s=os.fsencode(sys.argv[1]); print(ascii(s))'
# TODO: RUSTPYTHON
def run_default(arg):
cmd = [sys.executable, '-c', code, arg]
return subprocess.run(cmd, stdout=subprocess.PIPE, text=True)
# TODO: RUSTPYTHON
def run_c_locale(arg):
cmd = [sys.executable, '-c', code, arg]
env = dict(os.environ)
@@ -285,7 +318,6 @@ class CmdLineTest(unittest.TestCase):
return subprocess.run(cmd, stdout=subprocess.PIPE,
text=True, env=env)
# TODO: RUSTPYTHON
def run_utf8_mode(arg):
cmd = [sys.executable, '-X', 'utf8', '-c', code, arg]
return subprocess.run(cmd, stdout=subprocess.PIPE, text=True)
@@ -330,6 +362,8 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(stdout, expected)
self.assertEqual(p.returncode, 0)
@unittest.skipIf(os.environ.get("PYTHONUNBUFFERED", "0") != "0",
"Python stdio buffering is disabled.")
def test_non_interactive_output_buffering(self):
code = textwrap.dedent("""
import sys
@@ -369,7 +403,7 @@ class CmdLineTest(unittest.TestCase):
p.stdin.flush()
data, rc = _kill_python_and_exit_code(p)
self.assertEqual(rc, 0)
self.assertTrue(data.startswith(b'x'), data)
self.assertStartsWith(data, b'x')
def test_large_PYTHONPATH(self):
path1 = "ABCDE" * 100
@@ -406,8 +440,7 @@ class CmdLineTest(unittest.TestCase):
# for empty and unset PYTHONPATH
self.assertEqual(out1, out2)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_displayhook_unencodable(self):
for encoding in ('ascii', 'latin-1', 'utf-8'):
env = os.environ.copy()
@@ -475,6 +508,7 @@ class CmdLineTest(unittest.TestCase):
self.assertRegex(err.decode('ascii', 'ignore'), 'SyntaxError')
self.assertEqual(b'', out)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_stdout_flush_at_shutdown(self):
# Issue #5319: if stdout.flush() fails at shutdown, an error should
# be printed out.
@@ -486,8 +520,9 @@ class CmdLineTest(unittest.TestCase):
rc, out, err = assert_python_failure('-c', code)
self.assertEqual(b'', out)
self.assertEqual(120, rc)
self.assertRegex(err.decode('ascii', 'ignore'),
'Exception ignored in.*\nOSError: .*')
self.assertIn(b'Exception ignored while flushing sys.stdout:\n'
b'OSError: '.replace(b'\n', os.linesep.encode()),
err)
def test_closed_stdout(self):
# Issue #13444: if stdout has been explicitly closed, we should
@@ -525,23 +560,19 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(err, b'')
self.assertEqual(p.returncode, 42)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_no_stdin(self):
self._test_no_stdio(['stdin'])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_no_stdout(self):
self._test_no_stdio(['stdout'])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_no_stderr(self):
self._test_no_stdio(['stderr'])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_no_std_streams(self):
self._test_no_stdio(['stdin', 'stdout', 'stderr'])
@@ -593,8 +624,7 @@ class CmdLineTest(unittest.TestCase):
print("del sys.modules['__main__']", file=script)
assert_python_ok(filename)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_unknown_options(self):
rc, out, err = assert_python_failure('-E', '-z')
self.assertIn(b'Unknown option: -z', err)
@@ -641,6 +671,7 @@ class CmdLineTest(unittest.TestCase):
cwd=tmpdir)
self.assertEqual(out.strip(), b"ok")
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_sys_flags_set(self):
# Issue 31845: a startup refactoring broke reading flags from env vars
for value, expected in (("", 0), ("1", 1), ("text", 1), ("2", 2)):
@@ -650,22 +681,19 @@ class CmdLineTest(unittest.TestCase):
PYTHONDONTWRITEBYTECODE=value,
PYTHONVERBOSE=value,
)
dont_write_bytecode = int(bool(value))
expected_bool = int(bool(value))
code = (
"import sys; "
"sys.stderr.write(str(sys.flags)); "
f"""sys.exit(not (
sys.flags.debug == sys.flags.optimize ==
sys.flags.verbose ==
{expected}
and sys.flags.dont_write_bytecode == {dont_write_bytecode}
sys.flags.optimize == sys.flags.verbose == {expected}
and sys.flags.debug == sys.flags.dont_write_bytecode == {expected_bool}
))"""
)
with self.subTest(envar_value=value):
assert_python_ok('-c', code, **env_vars)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_set_pycache_prefix(self):
# sys.pycache_prefix can be set from either -X pycache_prefix or
# PYTHONPYCACHEPREFIX env var, with the former taking precedence.
@@ -711,6 +739,7 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.returncode, 0, proc)
return proc.stdout.rstrip()
@support.cpython_only
def test_xdev(self):
# sys.flags.dev_mode
code = "import sys; print(sys.flags.dev_mode)"
@@ -747,22 +776,24 @@ class CmdLineTest(unittest.TestCase):
# Memory allocator debug hooks
try:
import _testcapi
import _testinternalcapi # noqa: F401
except ImportError:
pass
else:
code = "import _testcapi; print(_testcapi.pymem_getallocatorsname())"
code = "import _testinternalcapi; print(_testinternalcapi.pymem_getallocatorsname())"
with support.SuppressCrashReport():
out = self.run_xdev("-c", code, check_exitcode=False)
if support.with_pymalloc():
alloc_name = "pymalloc_debug"
elif support.Py_GIL_DISABLED:
alloc_name = "mimalloc_debug"
else:
alloc_name = "malloc_debug"
self.assertEqual(out, alloc_name)
# Faulthandler
try:
import faulthandler
import faulthandler # noqa: F401
except ImportError:
pass
else:
@@ -791,8 +822,7 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.returncode, 0, proc)
return proc.stdout.rstrip()
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_warnings_filter_precedence(self):
expected_filters = ("error::BytesWarning "
"once::UserWarning "
@@ -815,7 +845,7 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(out, expected_filters)
def check_pythonmalloc(self, env_var, name):
code = 'import _testcapi; print(_testcapi.pymem_getallocatorsname())'
code = 'import _testinternalcapi; print(_testinternalcapi.pymem_getallocatorsname())'
env = dict(os.environ)
env.pop('PYTHONDEVMODE', None)
if env_var is not None:
@@ -831,12 +861,16 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.stdout.rstrip(), name)
self.assertEqual(proc.returncode, 0)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_pythonmalloc(self):
# Test the PYTHONMALLOC environment variable
malloc = not support.Py_GIL_DISABLED
pymalloc = support.with_pymalloc()
if pymalloc:
mimalloc = support.with_mimalloc()
if support.Py_GIL_DISABLED:
default_name = 'mimalloc_debug' if support.Py_DEBUG else 'mimalloc'
default_name_debug = 'mimalloc_debug'
elif pymalloc:
default_name = 'pymalloc_debug' if support.Py_DEBUG else 'pymalloc'
default_name_debug = 'pymalloc_debug'
else:
@@ -846,21 +880,28 @@ class CmdLineTest(unittest.TestCase):
tests = [
(None, default_name),
('debug', default_name_debug),
('malloc', 'malloc'),
('malloc_debug', 'malloc_debug'),
]
if malloc:
tests.extend([
('malloc', 'malloc'),
('malloc_debug', 'malloc_debug'),
])
if pymalloc:
tests.extend((
('pymalloc', 'pymalloc'),
('pymalloc_debug', 'pymalloc_debug'),
))
if mimalloc:
tests.extend((
('mimalloc', 'mimalloc'),
('mimalloc_debug', 'mimalloc_debug'),
))
for env_var, name in tests:
with self.subTest(env_var=env_var, name=name):
self.check_pythonmalloc(env_var, name)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_pythondevmode_env(self):
# Test the PYTHONDEVMODE environment variable
code = "import sys; print(sys.flags.dev_mode)"
@@ -879,6 +920,138 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.stdout.rstrip(), 'True')
self.assertEqual(proc.returncode, 0, proc)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_python_gil(self):
cases = [
# (env, opt, expected, msg)
('1', None, '1', "PYTHON_GIL=1"),
(None, '1', '1', "-X gil=1"),
]
if support.Py_GIL_DISABLED:
cases.extend(
[
(None, None, 'None', "no options set"),
('0', None, '0', "PYTHON_GIL=0"),
('1', '0', '0', "-X gil=0 overrides PYTHON_GIL=1"),
(None, '0', '0', "-X gil=0"),
]
)
else:
cases.extend(
[
(None, None, '1', '-X gil=0 (unsupported by this build)'),
('1', None, '1', 'PYTHON_GIL=0 (unsupported by this build)'),
]
)
code = "import sys; print(sys.flags.gil)"
environ = dict(os.environ)
for env, opt, expected, msg in cases:
with self.subTest(msg, env=env, opt=opt):
environ.pop('PYTHON_GIL', None)
if env is not None:
environ['PYTHON_GIL'] = env
extra_args = []
if opt is not None:
extra_args = ['-X', f'gil={opt}']
proc = subprocess.run([sys.executable, *extra_args, '-c', code],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True, env=environ)
self.assertEqual(proc.returncode, 0, proc)
self.assertEqual(proc.stdout.rstrip(), expected)
self.assertEqual(proc.stderr, '')
def test_python_asyncio_debug(self):
code = "import asyncio; print(asyncio.new_event_loop().get_debug())"
rc, out, err = assert_python_ok('-c', code, PYTHONASYNCIODEBUG='1')
self.assertIn(b'True', out)
@unittest.skipUnless(sysconfig.get_config_var('Py_TRACE_REFS'), "Requires --with-trace-refs build option")
def test_python_dump_refs(self):
code = 'import sys; sys._clear_internal_caches()'
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFS='1')
self.assertEqual(rc, 0)
@unittest.skipUnless(sysconfig.get_config_var('Py_TRACE_REFS'), "Requires --with-trace-refs build option")
def test_python_dump_refs_file(self):
with tempfile.NamedTemporaryFile() as dump_file:
code = 'import sys; sys._clear_internal_caches()'
rc, out, err = assert_python_ok('-c', code, PYTHONDUMPREFSFILE=dump_file.name)
self.assertEqual(rc, 0)
with open(dump_file.name, 'r') as file:
contents = file.read()
self.assertIn('Remaining objects', contents)
@unittest.expectedFailureIf(sys.platform == "darwin", "TODO: RUSTPYTHON")
@unittest.skipUnless(sys.platform == 'darwin', 'PYTHONEXECUTABLE only works on macOS')
def test_python_executable(self):
code = 'import sys; print(sys.executable)'
expected = "/busr/bbin/bpython"
rc, out, err = assert_python_ok('-c', code, PYTHONEXECUTABLE=expected)
self.assertIn(expected.encode(), out)
@unittest.expectedFailureIf(support.MS_WINDOWS, "TODO: RUSTPYTHON")
@unittest.skipUnless(support.MS_WINDOWS, 'Test only applicable on Windows')
def test_python_legacy_windows_fs_encoding(self):
code = "import sys; print(sys.getfilesystemencoding())"
expected = 'mbcs'
rc, out, err = assert_python_ok('-c', code, PYTHONLEGACYWINDOWSFSENCODING='1')
self.assertIn(expected.encode(), out)
@unittest.expectedFailureIf(support.MS_WINDOWS, "TODO: RUSTPYTHON")
@unittest.skipUnless(support.MS_WINDOWS, 'Test only applicable on Windows')
def test_python_legacy_windows_stdio(self):
# Test that _WindowsConsoleIO is used when PYTHONLEGACYWINDOWSSTDIO
# is not set.
# We cannot use PIPE becase it prevents creating new console.
# So we use exit code.
code = "import sys; sys.exit(type(sys.stdout.buffer.raw).__name__ != '_WindowsConsoleIO')"
env = os.environ.copy()
env["PYTHONLEGACYWINDOWSSTDIO"] = ""
p = subprocess.run([sys.executable, "-c", code],
creationflags=subprocess.CREATE_NEW_CONSOLE,
env=env)
self.assertEqual(p.returncode, 0)
# Then test that FIleIO is used when PYTHONLEGACYWINDOWSSTDIO is set.
code = "import sys; sys.exit(type(sys.stdout.buffer.raw).__name__ != 'FileIO')"
env["PYTHONLEGACYWINDOWSSTDIO"] = "1"
p = subprocess.run([sys.executable, "-c", code],
creationflags=subprocess.CREATE_NEW_CONSOLE,
env=env)
self.assertEqual(p.returncode, 0)
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipIf("-fsanitize" in sysconfig.get_config_vars().get('PY_CFLAGS', ()),
"PYTHONMALLOCSTATS doesn't work with ASAN")
def test_python_malloc_stats(self):
code = "pass"
rc, out, err = assert_python_ok('-c', code, PYTHONMALLOCSTATS='1')
self.assertIn(b'Small block threshold', err)
def test_python_user_base(self):
code = "import site; print(site.USER_BASE)"
expected = "/custom/userbase"
rc, out, err = assert_python_ok('-c', code, PYTHONUSERBASE=expected)
self.assertIn(expected.encode(), out)
def test_python_basic_repl(self):
# Currently this only tests that the env var is set. See test_pyrepl.test_python_basic_repl.
code = "import os; print('PYTHON_BASIC_REPL' in os.environ)"
expected = "True"
rc, out, err = assert_python_ok('-c', code, PYTHON_BASIC_REPL='1')
self.assertIn(expected.encode(), out)
@unittest.skipUnless(sysconfig.get_config_var('HAVE_PERF_TRAMPOLINE'), "Requires HAVE_PERF_TRAMPOLINE support")
def test_python_perf_jit_support(self):
code = "import sys; print(sys.is_stack_trampoline_active())"
expected = "True"
rc, out, err = assert_python_ok('-c', code, PYTHON_PERF_JIT_SUPPORT='1')
self.assertIn(expected.encode(), out)
@unittest.skipUnless(sys.platform == 'win32',
'bpo-32457 only applies on Windows')
def test_argv0_normalization(self):
@@ -891,16 +1064,15 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(proc.returncode, 0, proc)
self.assertEqual(proc.stdout.strip(), b'0')
# TODO: RUSTPYTHON
@unittest.expectedFailure
@support.cpython_only
def test_parsing_error(self):
args = [sys.executable, '-I', '--unknown-option']
proc = subprocess.run(args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
err_msg = "unknown option --unknown-option\nusage: "
self.assertTrue(proc.stderr.startswith(err_msg), proc.stderr)
err_msg = "Unknown option: --unknown-option\nusage: "
self.assertStartsWith(proc.stderr, err_msg)
self.assertNotEqual(proc.returncode, 0)
def test_int_max_str_digits(self):
@@ -915,11 +1087,8 @@ class CmdLineTest(unittest.TestCase):
assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='foo')
assert_python_failure('-c', code, PYTHONINTMAXSTRDIGITS='100')
def res2int(res):
out = res.out.strip().decode("utf-8")
return tuple(int(i) for i in out.split())
res = assert_python_ok('-c', code)
res2int = self.res2int
current_max = sys.get_int_max_str_digits()
self.assertEqual(res2int(res), (current_max, current_max))
res = assert_python_ok('-X', 'int_max_str_digits=0', '-c', code)
@@ -939,6 +1108,181 @@ class CmdLineTest(unittest.TestCase):
)
self.assertEqual(res2int(res), (6000, 6000))
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_cmd_dedent(self):
# test that -c auto-dedents its arguments
test_cases = [
(
"""
print('space-auto-dedent')
""",
"space-auto-dedent",
),
(
dedent(
"""
^^^print('tab-auto-dedent')
"""
).replace("^", "\t"),
"tab-auto-dedent",
),
(
dedent(
"""
^^if 1:
^^^^print('mixed-auto-dedent-1')
^^print('mixed-auto-dedent-2')
"""
).replace("^", "\t \t"),
"mixed-auto-dedent-1\nmixed-auto-dedent-2",
),
(
'''
data = """$
this data has an empty newline above and a newline with spaces below $
$
"""$
if 1: $
print(repr(data))$
'''.replace(
"$", ""
),
# Note: entirely blank lines are normalized to \n, even if they
# are part of a data string. This is consistent with
# textwrap.dedent behavior, but might not be intuitive.
"'\\n\\nthis data has an empty newline above and a newline with spaces below \\n\\n'",
),
(
'',
'',
),
(
' \t\n\t\n \t\t\t \t\t \t\n\t\t \n\n\n\t\t\t ',
'',
),
]
for code, expected in test_cases:
# Run the auto-dedent case
args1 = sys.executable, '-c', code
proc1 = subprocess.run(args1, stdout=subprocess.PIPE)
self.assertEqual(proc1.returncode, 0, proc1)
output1 = proc1.stdout.strip().decode(encoding='utf-8')
# Manually dedent beforehand, check the result is the same.
args2 = sys.executable, '-c', dedent(code)
proc2 = subprocess.run(args2, stdout=subprocess.PIPE)
self.assertEqual(proc2.returncode, 0, proc2)
output2 = proc2.stdout.strip().decode(encoding='utf-8')
self.assertEqual(output1, output2)
self.assertEqual(output1.replace('\r\n', '\n'), expected)
def test_cmd_dedent_failcase(self):
# Mixing tabs and spaces is not allowed
from textwrap import dedent
template = dedent(
'''
-+if 1:
+-++ print('will fail')
''')
code = template.replace('-', ' ').replace('+', '\t')
assert_python_failure('-c', code)
code = template.replace('-', '\t').replace('+', ' ')
assert_python_failure('-c', code)
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_cpu_count(self):
code = "import os; print(os.cpu_count(), os.process_cpu_count())"
res = assert_python_ok('-X', 'cpu_count=4321', '-c', code)
self.assertEqual(self.res2int(res), (4321, 4321))
res = assert_python_ok('-c', code, PYTHON_CPU_COUNT='1234')
self.assertEqual(self.res2int(res), (1234, 1234))
def test_cpu_count_default(self):
code = "import os; print(os.cpu_count(), os.process_cpu_count())"
res = assert_python_ok('-X', 'cpu_count=default', '-c', code)
self.assertEqual(self.res2int(res), (os.cpu_count(), os.process_cpu_count()))
res = assert_python_ok('-X', 'cpu_count=default', '-c', code, PYTHON_CPU_COUNT='1234')
self.assertEqual(self.res2int(res), (os.cpu_count(), os.process_cpu_count()))
res = assert_python_ok('-c', code, PYTHON_CPU_COUNT='default')
self.assertEqual(self.res2int(res), (os.cpu_count(), os.process_cpu_count()))
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_import_time(self):
# os is not imported at startup
code = 'import os; import os'
for case in 'importtime', 'importtime=1', 'importtime=true':
res = assert_python_ok('-X', case, '-c', code)
res_err = res.err.decode('utf-8')
self.assertRegex(res_err, r'import time: \s*\d+ \| \s*\d+ \| \s*os')
self.assertNotRegex(res_err, r'import time: cached\s* \| cached\s* \| os')
res = assert_python_ok('-X', 'importtime=2', '-c', code)
res_err = res.err.decode('utf-8')
self.assertRegex(res_err, r'import time: \s*\d+ \| \s*\d+ \| \s*os')
self.assertRegex(res_err, r'import time: cached\s* \| cached\s* \| os')
assert_python_failure('-X', 'importtime=-1', '-c', code)
assert_python_failure('-X', 'importtime=3', '-c', code)
def res2int(self, res):
out = res.out.strip().decode("utf-8")
return tuple(int(i) for i in out.split())
@unittest.skipUnless(support.Py_GIL_DISABLED,
"PYTHON_TLBC and -X tlbc"
" only supported in Py_GIL_DISABLED builds")
@threading_helper.requires_working_threading()
def test_disable_thread_local_bytecode(self):
code = """if 1:
import threading
def test(x, y):
return x + y
t = threading.Thread(target=test, args=(1,2))
t.start()
t.join()"""
assert_python_ok("-W", "always", "-X", "tlbc=0", "-c", code)
assert_python_ok("-W", "always", "-c", code, PYTHON_TLBC="0")
@unittest.skipUnless(support.Py_GIL_DISABLED,
"PYTHON_TLBC and -X tlbc"
" only supported in Py_GIL_DISABLED builds")
@threading_helper.requires_working_threading()
def test_enable_thread_local_bytecode(self):
code = """if 1:
import threading
def test(x, y):
return x + y
t = threading.Thread(target=test, args=(1,2))
t.start()
t.join()"""
# The functionality of thread-local bytecode is tested more extensively
# in test_thread_local_bytecode
assert_python_ok("-W", "always", "-X", "tlbc=1", "-c", code)
assert_python_ok("-W", "always", "-c", code, PYTHON_TLBC="1")
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.skipUnless(support.Py_GIL_DISABLED,
"PYTHON_TLBC and -X tlbc"
" only supported in Py_GIL_DISABLED builds")
def test_invalid_thread_local_bytecode(self):
rc, out, err = assert_python_failure("-X", "tlbc")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=foo")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=-1")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=2")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="foo")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="-1")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="2")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)
@unittest.skipIf(interpreter_requires_environment(),
'Cannot run -I tests when PYTHON env vars are required.')
@@ -979,6 +1323,7 @@ class IgnoreEnvironmentTest(unittest.TestCase):
class SyntaxErrorTests(unittest.TestCase):
@force_not_colorized
def check_string(self, code):
proc = subprocess.run([sys.executable, "-"], input=code,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
@@ -986,13 +1331,11 @@ class SyntaxErrorTests(unittest.TestCase):
self.assertNotEqual(proc.stderr, None)
self.assertIn(b"\nSyntaxError", proc.stderr)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailureIf(not support.is_android, "TODO: RUSTPYTHON")
def test_tokenizer_error_with_stdin(self):
self.check_string(b"(1+2+3")
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailureIf(not support.is_android, "TODO: RUSTPYTHON")
def test_decoding_error_at_the_end_of_the_line(self):
self.check_string(br"'\u1f'")
+56 -36
View File
@@ -14,8 +14,7 @@ import io
import textwrap
from test import support
from test.support import import_helper
from test.support import os_helper
from test.support import import_helper, is_apple, os_helper
from test.support.script_helper import (
make_pkg, make_script, make_zip_pkg, make_zip_script,
assert_python_ok, assert_python_failure, spawn_python, kill_python)
@@ -89,6 +88,8 @@ def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename,
importlib.invalidate_caches()
return to_return
@support.force_not_colorized_test_class
class CmdLineTest(unittest.TestCase):
def _check_output(self, script_name, exit_code, data,
expected_file, expected_argv0,
@@ -152,15 +153,13 @@ class CmdLineTest(unittest.TestCase):
print('Expected output: %r' % expected_msg)
self.assertIn(expected_msg.encode('utf-8'), err)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_dash_c_loader(self):
rc, out, err = assert_python_ok("-c", "print(__loader__)")
expected = repr(importlib.machinery.BuiltinImporter).encode("utf-8")
self.assertIn(expected, out)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_stdin_loader(self):
# Unfortunately, there's no way to automatically test the fully
# interactive REPL, since that code path only gets executed when
@@ -207,21 +206,23 @@ class CmdLineTest(unittest.TestCase):
stderr = p.stderr if separate_stderr else p.stdout
self.assertIn(b'Traceback ', stderr.readline())
self.assertIn(b'File "<stdin>"', stderr.readline())
self.assertIn(b'1/0', stderr.readline())
self.assertIn(b' ~^~', stderr.readline())
self.assertIn(b'ZeroDivisionError', stderr.readline())
@unittest.skip("TODO: RUSTPYTHON, test hang in middle")
@unittest.skip("TODO: RUSTPYTHON; test hang in middle")
def test_repl_stdout_flush(self):
self.check_repl_stdout_flush()
@unittest.skip("TODO: RUSTPYTHON, test hang in middle")
@unittest.skip("TODO: RUSTPYTHON; test hang in middle")
def test_repl_stdout_flush_separate_stderr(self):
self.check_repl_stdout_flush(True)
@unittest.skip("TODO: RUSTPYTHON, test hang in middle")
@unittest.skip("TODO: RUSTPYTHON; test hang in middle")
def test_repl_stderr_flush(self):
self.check_repl_stderr_flush()
@unittest.skip("TODO: RUSTPYTHON, test hang in middle")
@unittest.skip("TODO: RUSTPYTHON; test hang in middle")
def test_repl_stderr_flush_separate_stderr(self):
self.check_repl_stderr_flush(True)
@@ -233,8 +234,7 @@ class CmdLineTest(unittest.TestCase):
importlib.machinery.SourceFileLoader,
expected_cwd=script_dir)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_script_abspath(self):
# pass the script using the relative path, expect the absolute path
# in __file__
@@ -390,8 +390,7 @@ class CmdLineTest(unittest.TestCase):
"be directly executed")
self._check_import_error(["-m", "test_pkg"], msg, cwd=script_dir)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_issue8202(self):
# Make sure package __init__ modules see "-m" in sys.argv0 while
# searching for the module to execute
@@ -554,7 +553,7 @@ class CmdLineTest(unittest.TestCase):
script = textwrap.dedent("""\
try:
raise ValueError
except:
except ValueError:
raise NameError from None
""")
with os_helper.temp_dir() as script_dir:
@@ -562,18 +561,23 @@ class CmdLineTest(unittest.TestCase):
exitcode, stdout, stderr = assert_python_failure(script_name)
text = stderr.decode('ascii').split('\n')
self.assertEqual(len(text), 5)
self.assertTrue(text[0].startswith('Traceback'))
self.assertTrue(text[1].startswith(' File '))
self.assertTrue(text[3].startswith('NameError'))
self.assertStartsWith(text[0], 'Traceback')
self.assertStartsWith(text[1], ' File ')
self.assertStartsWith(text[3], 'NameError')
@unittest.expectedFailureIf(sys.platform == "linux", "TODO: RUSTPYTHON")
@unittest.expectedFailureIf(sys.platform in ("android", "linux"), "TODO: RUSTPYTHON")
def test_non_ascii(self):
# Mac OS X denies the creation of a file with an invalid UTF-8 name.
# Apple platforms deny the creation of a file with an invalid UTF-8 name.
# Windows allows creating a name with an arbitrary bytes name, but
# Python cannot a undecodable bytes argument to a subprocess.
# WASI does not permit invalid UTF-8 names.
if (os_helper.TESTFN_UNDECODABLE
and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')):
# Emscripten/WASI does not permit invalid UTF-8 names.
if (
os_helper.TESTFN_UNDECODABLE
and sys.platform not in {
"win32", "emscripten", "wasi"
}
and not is_apple
):
name = os.fsdecode(os_helper.TESTFN_UNDECODABLE)
elif os_helper.TESTFN_NONASCII:
name = os_helper.TESTFN_NONASCII
@@ -641,8 +645,7 @@ class CmdLineTest(unittest.TestCase):
self.assertNotIn("\f", text)
self.assertIn("\n 1 + 1 = 2\n ^^^^^\n", text)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_syntaxerror_multi_line_fstring(self):
script = 'foo = f"""{}\nfoo"""\n'
with os_helper.temp_dir() as script_dir:
@@ -657,8 +660,7 @@ class CmdLineTest(unittest.TestCase):
],
)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_syntaxerror_invalid_escape_sequence_multi_line(self):
script = 'foo = """\\q"""\n'
with os_helper.temp_dir() as script_dir:
@@ -669,13 +671,13 @@ class CmdLineTest(unittest.TestCase):
self.assertEqual(
stderr.splitlines()[-3:],
[ b' foo = """\\q"""',
b' ^^^^^^^^',
b'SyntaxError: invalid escape sequence \'\\q\''
b' ^^',
b'SyntaxError: "\\q" is an invalid escape sequence. '
b'Did you mean "\\\\q"? A raw string is also an option.'
],
)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_syntaxerror_null_bytes(self):
script = "x = '\0' nothing to see here\n';import os;os.system('echo pwnd')\n"
with os_helper.temp_dir() as script_dir:
@@ -688,8 +690,7 @@ class CmdLineTest(unittest.TestCase):
],
)
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_syntaxerror_null_bytes_in_multiline_string(self):
scripts = ["\n'''\nmultilinestring\0\n'''", "\nf'''\nmultilinestring\0\n'''"] # Both normal and f-strings
with os_helper.temp_dir() as script_dir:
@@ -703,6 +704,26 @@ class CmdLineTest(unittest.TestCase):
]
)
def test_source_lines_are_shown_when_running_source(self):
_, _, stderr = assert_python_failure("-c", "1/0")
expected_lines = [
b'Traceback (most recent call last):',
b' File "<string>", line 1, in <module>',
b' 1/0',
b' ~^~',
b'ZeroDivisionError: division by zero']
self.assertEqual(stderr.splitlines(), expected_lines)
def test_syntaxerror_does_not_crash(self):
script = "nonlocal x\n"
with os_helper.temp_dir() as script_dir:
script_name = _make_test_script(script_dir, 'script', script)
exitcode, stdout, stderr = assert_python_failure(script_name)
text = io.TextIOWrapper(io.BytesIO(stderr), 'ascii').read()
# It used to crash in https://github.com/python/cpython/issues/111132
self.assertEndsWith(text,
'SyntaxError: nonlocal declaration not allowed at module level\n')
def test_consistent_sys_path_for_direct_execution(self):
# This test case ensures that the following all give the same
# sys.path configuration:
@@ -771,8 +792,7 @@ class CmdLineTest(unittest.TestCase):
traceback_lines = stderr.decode().splitlines()
self.assertIn("No module named script_pkg", traceback_lines[-1])
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_nonexisting_script(self):
# bpo-34783: "./python script.py" must not crash
# if the script file doesn't exist.
@@ -788,11 +808,11 @@ class CmdLineTest(unittest.TestCase):
self.assertIn(": can't open file ", err)
self.assertNotEqual(proc.returncode, 0)
@unittest.skipIf(sys.platform.startswith("darwin"), "TODO: RUSTPYTHON; Problems with Mac os descriptor")
@unittest.skipUnless(os.path.exists('/dev/fd/0'), 'requires /dev/fd platform')
@unittest.skipIf(sys.platform.startswith("freebsd") and
os.stat("/dev").st_dev == os.stat("/dev/fd").st_dev,
"Requires fdescfs mounted on /dev/fd on FreeBSD")
@unittest.skipIf(sys.platform.startswith("darwin"), "TODO: RUSTPYTHON Problems with Mac os descriptor")
def test_script_as_dev_fd(self):
# GH-87235: On macOS passing a non-trivial script to /dev/fd/N can cause
# problems because all open /dev/fd/N file descriptors share the same
+2032
View File
File diff suppressed because it is too large. Load diff
+71 -106
View File
@@ -7,7 +7,7 @@ from test.support import (verbose, refcount_test,
Py_GIL_DISABLED)
from test.support.import_helper import import_module
from test.support.os_helper import temp_dir, TESTFN, unlink
from test.support.script_helper import assert_python_ok, make_script, run_test_script
from test.support.script_helper import assert_python_ok, make_script
from test.support import threading_helper, gc_threshold
import gc
@@ -236,8 +236,7 @@ class GCTests(unittest.TestCase):
# is 3 because it includes f's code object.
self.assertIn(gc.collect(), (2, 3))
# TODO: RUSTPYTHON - weakref clear ordering differs from 3.15+
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON; - weakref clear ordering differs from 3.15+
def test_function_tp_clear_leaves_consistent_state(self):
# https://github.com/python/cpython/issues/91636
code = """if 1:
@@ -311,28 +310,6 @@ class GCTests(unittest.TestCase):
self.assertRegex(stdout, rb"""\A\s*func=None""")
self.assertFalse(stderr)
# TODO: RUSTPYTHON - _datetime module not available
@unittest.expectedFailure
def test_datetime_weakref_cycle(self):
# https://github.com/python/cpython/issues/132413
# If the weakref used by the datetime extension gets cleared by the GC (due to being
# in an unreachable cycle) then datetime functions would crash (get_module_state()
# was returning a NULL pointer). This bug is fixed by clearing weakrefs without
# callbacks *after* running finalizers.
code = """if 1:
import _datetime
class C:
def __del__(self):
print('__del__ called')
_datetime.timedelta(days=1) # crash?
l = [C()]
l.append(l)
"""
rc, stdout, stderr = assert_python_ok("-c", code)
self.assertEqual(rc, 0)
self.assertEqual(stdout.strip(), b'__del__ called')
@refcount_test
def test_frame(self):
def f():
@@ -423,11 +400,19 @@ class GCTests(unittest.TestCase):
# each call to collect(N)
x = []
gc.collect(0)
# x is now in the old gen
# x is now in gen 1
a, b, c = gc.get_count()
# We don't check a since its exact values depends on
gc.collect(1)
# x is now in gen 2
d, e, f = gc.get_count()
gc.collect(2)
# x is now in gen 3
g, h, i = gc.get_count()
# We don't check a, d, g since their exact values depends on
# internal implementation details of the interpreter.
self.assertEqual((b, c), (1, 0))
self.assertEqual((e, f), (0, 1))
self.assertEqual((h, i), (0, 0))
def test_trashcan(self):
class Ouch:
@@ -682,8 +667,9 @@ class GCTests(unittest.TestCase):
gc.collect()
self.assertEqual(len(ouch), 2) # else the callbacks didn't run
for x in ouch:
# The weakref should be cleared before executing the callback.
self.assertIsNone(x)
# If the callback resurrected one of these guys, the instance
# would be damaged, with an empty __dict__.
self.assertEqual(x, None)
def test_bug21435(self):
# This is a poor test - its only virtue is that it happened to
@@ -845,20 +831,17 @@ class GCTests(unittest.TestCase):
rc, out, err = assert_python_ok(TESTFN)
self.assertEqual(out.strip(), b'__del__ called')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_get_stats(self):
stats = gc.get_stats()
self.assertEqual(len(stats), 3)
for st in stats:
self.assertIsInstance(st, dict)
self.assertEqual(
set(st),
{"collected", "collections", "uncollectable", "candidates", "duration"}
)
self.assertEqual(set(st),
{"collected", "collections", "uncollectable"})
self.assertGreaterEqual(st["collected"], 0)
self.assertGreaterEqual(st["collections"], 0)
self.assertGreaterEqual(st["uncollectable"], 0)
self.assertGreaterEqual(st["candidates"], 0)
self.assertGreaterEqual(st["duration"], 0)
# Check that collection counts are incremented correctly
if gc.isenabled():
self.addCleanup(gc.enable)
@@ -869,25 +852,11 @@ class GCTests(unittest.TestCase):
self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
self.assertEqual(new[1]["collections"], old[1]["collections"])
self.assertEqual(new[2]["collections"], old[2]["collections"])
self.assertGreater(new[0]["duration"], old[0]["duration"])
self.assertEqual(new[1]["duration"], old[1]["duration"])
self.assertEqual(new[2]["duration"], old[2]["duration"])
for stat in ["collected", "uncollectable", "candidates"]:
self.assertGreaterEqual(new[0][stat], old[0][stat])
self.assertEqual(new[1][stat], old[1][stat])
self.assertEqual(new[2][stat], old[2][stat])
gc.collect(2)
old, new = new, gc.get_stats()
self.assertEqual(new[0]["collections"], old[0]["collections"])
new = gc.get_stats()
self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
self.assertEqual(new[1]["collections"], old[1]["collections"])
self.assertEqual(new[2]["collections"], old[2]["collections"] + 1)
self.assertEqual(new[0]["duration"], old[0]["duration"])
self.assertEqual(new[1]["duration"], old[1]["duration"])
self.assertGreater(new[2]["duration"], old[2]["duration"])
for stat in ["collected", "uncollectable", "candidates"]:
self.assertEqual(new[0][stat], old[0][stat])
self.assertEqual(new[1][stat], old[1][stat])
self.assertGreaterEqual(new[2][stat], old[2][stat])
def test_freeze(self):
gc.freeze()
@@ -911,10 +880,42 @@ class GCTests(unittest.TestCase):
self.assertTrue(
any(l is element for element in gc.get_objects(generation=0))
)
gc.collect()
self.assertFalse(
any(l is element for element in gc.get_objects(generation=1))
)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=2))
)
gc.collect(generation=0)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=0))
)
self.assertTrue(
any(l is element for element in gc.get_objects(generation=1))
)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=2))
)
gc.collect(generation=1)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=0))
)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=1))
)
self.assertTrue(
any(l is element for element in gc.get_objects(generation=2))
)
gc.collect(generation=2)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=0))
)
self.assertFalse(
any(l is element for element in gc.get_objects(generation=1))
)
self.assertTrue(
any(l is element for element in gc.get_objects(generation=2))
)
del l
gc.collect()
@@ -1203,37 +1204,6 @@ class GCTests(unittest.TestCase):
""")
assert_python_ok("-c", source)
def test_do_not_cleanup_type_subclasses_before_finalization(self):
# See https://github.com/python/cpython/issues/135552
# If we cleanup weakrefs for tp_subclasses before calling
# the finalizer (__del__) then the line `fail = BaseNode.next.next`
# should fail because we are trying to access a subclass
# attribute. But subclass type cache was not properly invalidated.
code = """
class BaseNode:
def __del__(self):
BaseNode.next = BaseNode.next.next
fail = BaseNode.next.next
class Node(BaseNode):
pass
BaseNode.next = Node()
BaseNode.next.next = Node()
"""
# this test checks garbage collection while interp
# finalization
assert_python_ok("-c", textwrap.dedent(code))
code_inside_function = textwrap.dedent(F"""
def test():
{textwrap.indent(code, ' ')}
test()
""")
# this test checks regular garbage collection
assert_python_ok("-c", code_inside_function)
@unittest.skipUnless(Py_GIL_DISABLED, "requires free-threaded GC")
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
@@ -1252,16 +1222,14 @@ class GCTests(unittest.TestCase):
# Use n // 2 just in case some other objects were collected.
self.assertTrue(new_count - count > (n // 2))
class IncrementalGCTests(unittest.TestCase):
@requires_gil_enabled('need generational GC')
@unittest.skipIf(_testinternalcapi is None, "requires _testinternalcapi")
@requires_gil_enabled("Free threading does not support incremental GC")
def test_incremental_gc_handles_fast_cycle_creation(self):
# Run this test in a fresh process. The number of alive objects (which can
# be from unit tests run before this one) can influence how quickly cyclic
# garbage is found.
script = support.findfile("_test_gc_fast_cycles.py")
run_test_script(script)
def test_heap_size(self):
count = _testinternalcapi.get_tracked_heap_size()
l = []
self.assertEqual(count + 1, _testinternalcapi.get_tracked_heap_size())
del l
self.assertEqual(count, _testinternalcapi.get_tracked_heap_size())
class GCCallbackTests(unittest.TestCase):
@@ -1338,11 +1306,9 @@ class GCCallbackTests(unittest.TestCase):
# Check that we got the right info dict for all callbacks
for v in self.visit:
info = v[2]
self.assertIn("generation", info)
self.assertIn("collected", info)
self.assertIn("uncollectable", info)
self.assertIn("candidates", info)
self.assertIn("duration", info)
self.assertTrue("generation" in info)
self.assertTrue("collected" in info)
self.assertTrue("uncollectable" in info)
def test_collect_generation(self):
self.preclean()
@@ -1518,8 +1484,8 @@ class GCTogglingTests(unittest.TestCase):
assert not detector.gc_happened
while not detector.gc_happened:
i += 1
if i > 100000:
self.fail("gc didn't happen after 100000 iterations")
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
self.assertEqual(len(ouch), 0)
junk.append([]) # this will eventually trigger gc
@@ -1530,7 +1496,6 @@ class GCTogglingTests(unittest.TestCase):
self.assertEqual(x, None)
@gc_threshold(1000, 0, 0)
@unittest.skipIf(Py_GIL_DISABLED, "requires GC generations or increments")
def test_bug1055820d(self):
# Corresponds to temp2d.py in the bug report. This is very much like
# test_bug1055820c, but uses a __del__ method instead of a weakref
@@ -1591,8 +1556,8 @@ class GCTogglingTests(unittest.TestCase):
gc.collect()
while not detector.gc_happened:
i += 1
if i > 50000:
self.fail("gc didn't happen after 50000 iterations")
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
self.assertEqual(len(ouch), 0)
junk.append([]) # this will eventually trigger gc
@@ -1609,8 +1574,8 @@ class GCTogglingTests(unittest.TestCase):
detector = GC_Detector()
while not detector.gc_happened:
i += 1
if i > 100000:
self.fail("gc didn't happen after 100000 iterations")
if i > 10000:
self.fail("gc didn't happen after 10000 iterations")
junk.append([]) # this will eventually trigger gc
try:
@@ -1620,11 +1585,11 @@ class GCTogglingTests(unittest.TestCase):
detector = GC_Detector()
while not detector.gc_happened:
i += 1
if i > 100000:
if i > 10000:
break
junk.append([]) # this may eventually trigger gc (if it is enabled)
self.assertEqual(i, 100001)
self.assertEqual(i, 10001)
finally:
gc.enable()
@@ -1 +0,0 @@
-1
View File
@@ -1 +0,0 @@
-1
View File
@@ -1 +0,0 @@
-1
View File
@@ -1 +0,0 @@
+3 -3
View File
@@ -3,7 +3,7 @@
import subprocess
import sys
import os
from test.support import script_helper
from test.support import script_helper, requires_subprocess
import unittest
from unittest import mock
@@ -69,12 +69,12 @@ class TestScriptHelper(unittest.TestCase):
self.assertNotIn('-E', popen_command)
@requires_subprocess()
class TestScriptHelperEnvironment(unittest.TestCase):
"""Code coverage for interpreter_requires_environment()."""
def setUp(self):
self.assertTrue(
hasattr(script_helper, '__cached_interp_requires_environment'))
self.assertHasAttr(script_helper, '__cached_interp_requires_environment')
# Reset the private cached state.
script_helper.__dict__['__cached_interp_requires_environment'] = None
+36 -3
View File
@@ -88,6 +88,9 @@ class UnicodeNamesTest(unittest.TestCase):
self.checkletter("HANGUL SYLLABLE HWEOK", "\ud6f8")
self.checkletter("HANGUL SYLLABLE HIH", "\ud7a3")
self.checkletter("haNGul SYllABle WAe", '\uc65c')
self.checkletter("HAngUL syLLabLE waE", '\uc65c')
self.assertRaises(ValueError, unicodedata.name, "\ud7a4")
def test_cjk_unified_ideographs(self):
@@ -103,6 +106,36 @@ class UnicodeNamesTest(unittest.TestCase):
self.checkletter("CJK UNIFIED IDEOGRAPH-2B81D", "\U0002B81D")
self.checkletter("CJK UNIFIED IDEOGRAPH-3134A", "\U0003134A")
self.checkletter("cjK UniFIeD idEogRAph-3aBc", "\u3abc")
self.checkletter("CJk uNIfiEd IDeOGraPH-3AbC", "\u3abc")
self.checkletter("cjK UniFIeD idEogRAph-2aBcD", "\U0002abcd")
self.checkletter("CJk uNIfiEd IDeOGraPH-2AbCd", "\U0002abcd")
@unittest.expectedFailure # TODO: RUSTPYTHON; SyntaxError: got unexpected unicode
def test_tangut_ideographs(self):
self.checkletter("TANGUT IDEOGRAPH-17000", "\U00017000")
self.checkletter("TANGUT IDEOGRAPH-187F7", "\U000187f7")
self.checkletter("TANGUT IDEOGRAPH-18D00", "\U00018D00")
self.checkletter("TANGUT IDEOGRAPH-18D08", "\U00018d08")
self.checkletter("tangut ideograph-18d08", "\U00018d08")
def test_egyptian_hieroglyphs(self):
self.checkletter("EGYPTIAN HIEROGLYPH-13460", "\U00013460")
self.checkletter("EGYPTIAN HIEROGLYPH-143FA", "\U000143fa")
self.checkletter("egyptian hieroglyph-143fa", "\U000143fa")
def test_khitan_small_script_characters(self):
self.checkletter("KHITAN SMALL SCRIPT CHARACTER-18B00", "\U00018b00")
self.checkletter("KHITAN SMALL SCRIPT CHARACTER-18CD5", "\U00018cd5")
self.checkletter("KHITAN SMALL SCRIPT CHARACTER-18CFF", "\U00018cff")
self.checkletter("KHITAN SMALL SCRIPT CHARACTER-18CFF", "\U00018cff")
self.checkletter("khitan small script character-18cff", "\U00018cff")
def test_nushu_characters(self):
self.checkletter("NUSHU CHARACTER-1B170", "\U0001b170")
self.checkletter("NUSHU CHARACTER-1B2FB", "\U0001b2fb")
self.checkletter("nushu character-1b2fb", "\U0001b2fb")
def test_bmp_characters(self):
for code in range(0x10000):
char = chr(code)
@@ -116,7 +149,7 @@ class UnicodeNamesTest(unittest.TestCase):
self.checkletter("HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK", "\uFF9F")
self.checkletter("FULLWIDTH LATIN SMALL LETTER A", "\uFF41")
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_aliases(self):
# Check that the aliases defined in the NameAliases.txt file work.
# This should be updated when new aliases are added or the file
@@ -157,7 +190,7 @@ class UnicodeNamesTest(unittest.TestCase):
unicodedata.name(chr(cp))
self.assertEqual(str(cm.exception), 'no such name')
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_named_sequences_sample(self):
# Check a few named sequences. See #12753.
sequences = [
@@ -174,7 +207,7 @@ class UnicodeNamesTest(unittest.TestCase):
with self.assertRaises(KeyError):
unicodedata.ucd_3_2_0.lookup(seqname)
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_named_sequences_full(self):
# Check all the named sequences
def check_version(testfile):
+2 -2
View File
@@ -125,8 +125,8 @@ class UnicodeFileTests(unittest.TestCase):
# open(), os.stat(), etc. don't raise any exception.
@unittest.skipIf(is_apple, 'irrelevant test on Apple platforms')
@unittest.skipIf(
support.is_emscripten or support.is_wasi,
"test fails on Emscripten/WASI when host platform is macOS."
support.is_wasi,
"test fails on WASI when host platform is macOS."
)
def test_normalize(self):
files = set(self.files)
+2 -3
View File
@@ -17,11 +17,10 @@ class PEP3131Test(unittest.TestCase):
𝔘𝔫𝔦𝔠𝔬𝔡𝔢 = 1
self.assertIn("Unicode", dir())
# TODO: RUSTPYTHON
@unittest.expectedFailure
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_invalid(self):
try:
from test.tokenizedata import badsyntax_3131
from test.tokenizedata import badsyntax_3131 # noqa: F401
except SyntaxError as err:
self.assertEqual(str(err),
"invalid character '€' (U+20AC) (badsyntax_3131.py, line 2)")