From 30904e7e7c6172f8adc6300b44a4a7f13807ef24 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 24 Jul 2024 15:07:35 -0600 Subject: [PATCH 1/4] Fix test_slot_wrappers and test_static_types_inherited_slots. --- Lib/test/test_embed.py | 52 +++++++++++++++++++++++++++---------- Lib/test/test_types.py | 58 ++++++++++++++++++++++++++++++++++-------- Objects/typeobject.c | 23 ++++++++++++++--- Programs/_testembed.c | 14 +++++++--- 4 files changed, 115 insertions(+), 32 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 a754a5ca981479..971320fe3d340c 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -41,13 +41,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 be2536270d8d1b73eaaffa14b1b79da50d6ed145 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 26 Jul 2024 17:25:02 -0600 Subject: [PATCH 2/4] 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 971320fe3d340c..963b9c7065baa4 100644 --- a/Lib/test/test_types.py +++ b/Lib/test/test_types.py @@ -2417,7 +2417,7 @@ def setUpClass(cls): @cpython_only @unittest.skipIf(is_apple_mobile, "Fails on iOS due to test ordering; see #121832.") @no_rerun('channels (and queues) might have a refleak; see gh-122199') - def test_slot_wrappers(self): + def test_static_types_inherited_slots(self): rch, sch = interpreters.channels.create() slots = [] From 31fc15881b318ec99b0ad002e118bac425957679 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 26 Jul 2024 17:56:03 -0600 Subject: [PATCH 3/4] Move the helpers to test.support. --- Lib/test/support/__init__.py | 55 ++++++++++++++++++++++++++++++++ Lib/test/test_embed.py | 5 ++- Lib/test/test_types.py | 62 +++--------------------------------- 3 files changed, 62 insertions(+), 60 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 03950bf63bf4b9..a6fe8f5f2b2d50 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -2589,6 +2589,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 4/4] 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 177254e4418252..9a63dbc3c6af37 100644 --- a/Lib/test/test_embed.py +++ b/Lib/test/test_embed.py @@ -418,8 +418,7 @@ def test_datetime_reset_strptime(self): def test_static_types_inherited_slots(self): script = textwrap.dedent(""" - import json - import sys + import test.support results = {} def add(cls, slot, own): @@ -428,27 +427,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:] @@ -456,13 +452,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, '')