From 85182aeb027202e619754f6cd19776425eba6957 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Jul 2024 15:07:35 -0600 Subject: [PATCH 1/5] Fix test_slot_wrappers and test_static_types_inherited_slots. --- Lib/test/test_embed.py | 52 +++++++++++++++++------- Lib/test/test_types.py | 90 ++++++++++++++++++++++++++++++++++++------ Programs/_testembed.c | 14 +++++-- 3 files changed, 128 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index fb7995e05152d2..aa04716c8da5bd 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -417,29 +417,53 @@ def test_datetime_reset_strptime(self): self.assertEqual(out, '20000101\n' * INIT_LOOPS) def test_static_types_inherited_slots(self): - slots = [] - script = ['import sys'] - from test.test_types import iter_builtin_types, iter_own_slot_wrappers + script = textwrap.dedent(""" + import json + import sys + + results = {} + def add(cls, slot, own): + value = getattr(cls, slot) + try: + subresults = results[cls.__name__] + except KeyError: + subresults = results[cls.__name__] = {} + subresults[slot] = repr(value) + + {body} + + text = json.dumps(results) + print(text, file=sys.stderr) + """) + body = [] + from test.test_types import iter_builtin_types, iter_slot_wrappers for cls in iter_builtin_types(): - for slot in iter_own_slot_wrappers(cls): - slots.append((cls, slot)) - attr = f'{cls.__name__}.{slot}' - script.append(f'print("{attr}:", {attr}, file=sys.stderr)') - script.append('') - script = os.linesep.join(script) + body.append('') + body.append(f'cls = {cls.__name__}') + for slot, own in iter_slot_wrappers(cls): + body.append(f'add(cls, {slot!r}, {own})') + body.pop(0) + script = script.replace('{body}', os.linesep.join(body)) with contextlib.redirect_stderr(io.StringIO()) as stderr: - exec(script) - expected = stderr.getvalue().splitlines() + ns = {} + exec(script, ns, ns) + expected = json.loads(stderr.getvalue()) - out, err = self.run_embedded_interpreter("test_repeated_init_exec", script) + out, err = self.run_embedded_interpreter( + "test_repeated_init_exec", script, script) results = err.split('--- Loop #')[1:] results = [res.rpartition(' ---\n')[-1] for res in results] self.maxDiff = None - for i, result in enumerate(results, start=1): + for i, text in enumerate(results, start=1): + failed = True with self.subTest(loop=i): - self.assertEqual(result.splitlines(), expected) + result = json.loads(text) + self.assertEqual(result, expected) + failed = False + if failed: + break self.assertEqual(out, '') diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index a87bb275d296a0..044e5c3a4a546c 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -43,13 +43,49 @@ def iter_builtin_types(): @cpython_only -def iter_own_slot_wrappers(cls): - for name, value in vars(cls).items(): - if not name.startswith('__') or not name.endswith('__'): - continue - if 'slot wrapper' not in str(value): +def iter_slot_wrappers(cls): + assert cls.__module__ == 'builtins', cls + + def is_slot_wrapper(name, value): + if not isinstance(value, types.WrapperDescriptorType): + assert not repr(value).startswith(' 3 + ? main_argc - 2 + : INIT_LOOPS; - for (int i=1; i <= INIT_LOOPS; i++) { - fprintf(stderr, "--- Loop #%d ---\n", i); + for (int i=0; i < loops; i++) { + fprintf(stderr, "--- Loop #%d ---\n", i+1); fflush(stderr); + if (main_argc > 3) { + code = main_argv[i+2]; + } + _testembed_Py_InitializeFromConfig(); int err = PyRun_SimpleString(code); Py_Finalize(); From 8eb5645c91659af8a9b1c3e34e5c480762d8c39c Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Jul 2024 17:25:05 -0600 Subject: [PATCH 2/5] Skip test_static_types_inherited_slots temporarily. --- Lib/test/test_embed.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index aa04716c8da5bd..b5909e32ec578b 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -416,6 +416,7 @@ def test_datetime_reset_strptime(self): out, err = self.run_embedded_interpreter("test_repeated_init_exec", code) self.assertEqual(out, '20000101\n' * INIT_LOOPS) + @unittest.skip('inheritance across re-init is currently broken; see gh-117482') def test_static_types_inherited_slots(self): script = textwrap.dedent(""" import json From 777511f217ab89a3d9ff13d119085017db6e8866 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 26 Jul 2024 17:25:02 -0600 Subject: [PATCH 3/5] Fix the test name. --- Lib/test/test_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py index 044e5c3a4a546c..2d86a865fe9b7d 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2449,7 +2449,7 @@ def setUpClass(cls): @cpython_only @no_rerun('channels (and queues) might have a refleak; see gh-122199') @unittest.skipIf(is_apple_mobile, "Fails on iOS due to test ordering; see #121832.") - def test_slot_wrappers(self): + def test_static_types_inherited_slots(self): rch, sch = interpreters.channels.create() slots = [] From 560540c648a621118e32ac99ea950dafd9071df6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 26 Jul 2024 17:56:03 -0600 Subject: [PATCH 4/5] Move the helpers to test.support. --- Lib/test/support/__init__.py | 55 ++++++++++++++++++++++++++++++++++ Lib/test/test_embed.py | 5 ++-- Lib/test/test_types.py | 57 +----------------------------------- 3 files changed, 58 insertions(+), 59 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 37e3305036f499..f4dce793ff1acb 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2608,6 +2608,61 @@ def copy_python_src_ignore(path, names): return ignored +def iter_builtin_types(): + for obj in __builtins__.values(): + if not isinstance(obj, type): + continue + cls = obj + if cls.__module__ != 'builtins': + continue + yield cls + + +def iter_slot_wrappers(cls): + assert cls.__module__ == 'builtins', cls + + def is_slot_wrapper(name, value): + if not isinstance(value, types.WrapperDescriptorType): + assert not repr(value).startswith(' Date: Fri, 26 Jul 2024 17:25:46 -0600 Subject: [PATCH 5/5] Avoid excessively long commandline arguments. --- Lib/test/test_embed.py | 45 +++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py index fb9018508d6038..9602f1a92c37c8 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -419,8 +419,7 @@ def test_datetime_reset_strptime(self): @unittest.skip('inheritance across re-init is currently broken; see gh-117482') def test_static_types_inherited_slots(self): script = textwrap.dedent(""" - import json - import sys + import test.support results = {} def add(cls, slot, own): @@ -429,27 +428,24 @@ def add(cls, slot, own): subresults = results[cls.__name__] except KeyError: subresults = results[cls.__name__] = {} - subresults[slot] = repr(value) + subresults[slot] = [repr(value), own] + + for cls in test.support.iter_builtin_types(): + for slot, own in test.support.iter_slot_wrappers(cls): + add(cls, slot, own) + """) - {body} + ns = {} + exec(script, ns, ns) + all_expected = ns['results'] + del ns + script += textwrap.dedent(""" + import json + import sys text = json.dumps(results) print(text, file=sys.stderr) """) - body = [] - for cls in support.iter_builtin_types(): - body.append('') - body.append(f'cls = {cls.__name__}') - for slot, own in support.iter_slot_wrappers(cls): - body.append(f'add(cls, {slot!r}, {own})') - body.pop(0) - script = script.replace('{body}', os.linesep.join(body)) - - with contextlib.redirect_stderr(io.StringIO()) as stderr: - ns = {} - exec(script, ns, ns) - expected = json.loads(stderr.getvalue()) - out, err = self.run_embedded_interpreter( "test_repeated_init_exec", script, script) results = err.split('--- Loop #')[1:] @@ -457,13 +453,12 @@ def add(cls, slot, own): self.maxDiff = None for i, text in enumerate(results, start=1): - failed = True - with self.subTest(loop=i): - result = json.loads(text) - self.assertEqual(result, expected) - failed = False - if failed: - break + result = json.loads(text) + for classname, expected in all_expected.items(): + with self.subTest(loop=i, cls=classname): + slots = result.pop(classname) + self.assertEqual(slots, expected) + self.assertEqual(result, {}) self.assertEqual(out, '')