From fe28cbc59b05a486ce387fac328df4759c78c4fb Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 13:25:20 +0300 Subject: [PATCH 1/7] Align patches for `test_class.py` --- Lib/test/test_class.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_class.py b/Lib/test/test_class.py index 1aee6fb73d2..f2f99d366d9 100644 --- a/Lib/test/test_class.py +++ b/Lib/test/test_class.py @@ -887,14 +887,14 @@ class VarSizedSubclass(tuple): class TestInlineValues(unittest.TestCase): - @unittest.expectedFailure # TODO: RUSTPYTHON; NameError: name 'has_inline_values' is not defined. + @unittest.expectedFailure # TODO: RUSTPYTHON; NameError: name 'has_inline_values' is not defined. def test_no_flags_for_slots_class(self): flags = NoManagedDict.__flags__ self.assertEqual(flags & Py_TPFLAGS_MANAGED_DICT, 0) self.assertEqual(flags & Py_TPFLAGS_INLINE_VALUES, 0) self.assertFalse(has_inline_values(NoManagedDict())) - @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 4 + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 4 def test_both_flags_for_regular_class(self): for cls in (Plain, WithAttrs): with self.subTest(cls=cls.__name__): @@ -903,7 +903,7 @@ def test_both_flags_for_regular_class(self): self.assertEqual(flags & Py_TPFLAGS_INLINE_VALUES, Py_TPFLAGS_INLINE_VALUES) self.assertTrue(has_inline_values(cls())) - @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 4 + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 0 != 4 def test_managed_dict_only_for_varsized_subclass(self): flags = VarSizedSubclass.__flags__ self.assertEqual(flags & Py_TPFLAGS_MANAGED_DICT, Py_TPFLAGS_MANAGED_DICT) @@ -1056,6 +1056,5 @@ def __init__(self): self.assertFalse(out, msg=out.decode('utf-8')) self.assertFalse(err, msg=err.decode('utf-8')) - if __name__ == '__main__': unittest.main() From f7c75b805d3885ca05060d1c140bf069fac5c308 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 13:43:56 +0300 Subject: [PATCH 2/7] Update more tests to 3.14.5 --- Lib/test/test_import/__init__.py | 30 ++++++++++++++++++++++++++++-- Lib/test/test_memoryview.py | 22 ++++++++++++++++++++++ Lib/test/test_pep646_syntax.py | 14 +++----------- Lib/test/test_pkg.py | 5 ++--- Lib/test/test_sort.py | 2 +- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 6920cf45533..60413aa7629 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -43,6 +43,7 @@ Py_GIL_DISABLED, no_rerun, force_not_colorized_test_class, + catch_unraisable_exception ) from test.support.import_helper import ( forget, make_legacy_pyc, unlink, unload, ready_to_import, @@ -1238,8 +1239,7 @@ def test_script_shadowing_stdlib_sys_path_modification(self): stdout, stderr = popen.communicate() self.assertRegex(stdout, expected_error) - # TODO: RUSTPYTHON: _imp.create_dynamic is for C extensions, not applicable - @unittest.skip("TODO: RustPython _imp.create_dynamic not implemented") + @unittest.expectedFailure # TODO: RUSTPYTHON; _imp.create_dynamic not implemented def test_create_dynamic_null(self): with self.assertRaisesRegex(ValueError, 'embedded null character'): class Spec: @@ -2544,6 +2544,32 @@ def test_disallowed_reimport(self): excsnap = _interpreters.run_string(interpid, script) self.assertIsNot(excsnap, None) + @requires_subinterpreters + def test_pyinit_function_raises_exception(self): + # gh-144601: PyInit functions that raised exceptions would cause a + # crash when imported from a subinterpreter. + import _testsinglephase + filename = _testsinglephase.__file__ + script = f"""if True: + from test.test_import import import_extension_from_file + + import_extension_from_file('_testsinglephase_raise_exception', {filename!r})""" + + interp = _interpreters.create() + try: + with catch_unraisable_exception() as cm: + exception = _interpreters.run_string(interp, script) + unraisable = cm.unraisable + finally: + _interpreters.destroy(interp) + + self.assertIsNotNone(exception) + self.assertIsNotNone(exception.type.__name__, "ImportError") + self.assertIsNotNone(exception.msg, "failed to import from subinterpreter due to exception") + self.assertIsNotNone(unraisable) + self.assertIs(unraisable.exc_type, RuntimeError) + self.assertEqual(str(unraisable.exc_value), "evil") + class TestSinglePhaseSnapshot(ModuleSnapshot): """A representation of a single-phase init module for testing. diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index 891c4d76745..7889fa88d00 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -581,6 +581,28 @@ def test_array_assign(self): m[:] = new_a self.assertEqual(a, new_a) + def test_boolean_format(self): + # Test '?' format (keep all the checks below for UBSan) + # See github.com/python/cpython/issues/148390. + + # m1a and m1b are equivalent to [False, True, False] + m1a = memoryview(b'\0\2\0').cast('?') + self.assertEqual(m1a.tolist(), [False, True, False]) + m1b = memoryview(b'\0\4\0').cast('?') + self.assertEqual(m1b.tolist(), [False, True, False]) + self.assertEqual(m1a, m1b) + + # m2a and m2b are equivalent to [True, True, True] + m2a = memoryview(b'\1\3\5').cast('?') + self.assertEqual(m2a.tolist(), [True, True, True]) + m2b = memoryview(b'\2\4\6').cast('?') + self.assertEqual(m2b.tolist(), [True, True, True]) + self.assertEqual(m2a, m2b) + + allbytes = bytes(range(256)) + allbytes = memoryview(allbytes).cast('?') + self.assertEqual(allbytes.tolist(), [False] + [True] * 255) + class BytesMemorySliceTest(unittest.TestCase, BaseMemorySliceTests, BaseBytesMemoryTests): diff --git a/Lib/test/test_pep646_syntax.py b/Lib/test/test_pep646_syntax.py index ca8e7d62057..8034bb9e935 100644 --- a/Lib/test/test_pep646_syntax.py +++ b/Lib/test/test_pep646_syntax.py @@ -312,7 +312,7 @@ >>> f4.__annotations__ {'args': StarredB, 'arg1': } - >>> def f5(*args: *b = (1,)): pass # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE + >>> def f5(*args: *b = (1,)): pass # TODO: RUSTPYTHON # doctest: +EXPECTED_FAILURE Traceback (most recent call last): ... SyntaxError: invalid syntax @@ -320,17 +320,9 @@ __test__ = {'doctests' : doctests} -EXPECTED_FAILURE = doctest.register_optionflag('EXPECTED_FAILURE') # TODO: RUSTPYTHON -class CustomOutputChecker(doctest.OutputChecker): # TODO: RUSTPYTHON - def check_output(self, want, got, optionflags): # TODO: RUSTPYTHON - if optionflags & EXPECTED_FAILURE: # TODO: RUSTPYTHON - if want == got: # TODO: RUSTPYTHON - return False # TODO: RUSTPYTHON - return True # TODO: RUSTPYTHON - return super().check_output(want, got, optionflags) # TODO: RUSTPYTHON - def load_tests(loader, tests, pattern): - tests.addTest(doctest.DocTestSuite(checker=CustomOutputChecker())) # TODO: RUSTPYTHON + from test.support.rustpython import DocTestChecker # TODO: RUSTPYTHON + tests.addTest(doctest.DocTestSuite(checker=DocTestChecker())) # TODO: RUSTPYTHON return tests diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index eed0fd1c6b7..d2b724db40d 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -94,7 +94,7 @@ def mkhier(self, descr): def test_1(self): hier = [("t1", None), ("t1 __init__.py", "")] self.mkhier(hier) - import t1 + import t1 # noqa: F401 def test_2(self): hier = [ @@ -124,7 +124,7 @@ def test_2(self): from t2 import sub from t2.sub import subsub - from t2.sub.subsub import spam + from t2.sub.subsub import spam # noqa: F401 self.assertEqual(sub.__name__, "t2.sub") self.assertEqual(subsub.__name__, "t2.sub.subsub") self.assertEqual(sub.subsub.__name__, "t2.sub.subsub") @@ -190,7 +190,6 @@ def test_5(self): ] self.mkhier(hier) - import t5 s = """ from t5 import * self.assertEqual(dir(), ['foo', 'self', 'string', 't5']) diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py index dfb050a34ec..3a6f4f1c05b 100644 --- a/Lib/test/test_sort.py +++ b/Lib/test/test_sort.py @@ -326,7 +326,7 @@ def test_safe_object_compare(self): for L in float_int_lists: check_against_PyObject_RichCompareBool(self, L) - @support.cpython_only # XXX RUSTPYTHON: added by us but it seems like an implementation detail + @unittest.skip("TODO: RUSTPYTHON; not really a todo, it seems like an implementation detail") def test_unsafe_object_compare(self): # This test is by ppperry. It ensures that unsafe_object_compare is From 3582a6a28e1e9ba9b375bee3465a7e4c3957c2d8 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 13:44:20 +0300 Subject: [PATCH 3/7] Update `test_math` --- Lib/test/test_math.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index d8a5eb27501..5678536ff18 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -324,6 +324,8 @@ def testAtanh(self): self.assertRaises(ValueError, math.atanh, NINF) self.assertTrue(math.isnan(math.atanh(NAN))) + @unittest.skipIf(sys.platform.startswith("sunos"), + "skipping, see gh-138573") def testAtan2(self): self.assertRaises(TypeError, math.atan2) self.ftest('atan2(-1, 0)', math.atan2(-1, 0), -math.pi/2) From 93f79bc672f343d2bb2f25847e0a738cf94b8444 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 13:46:23 +0300 Subject: [PATCH 4/7] `test_hash.py` --- Lib/test/test_hash.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_hash.py b/Lib/test/test_hash.py index 9fae17db7b1..11c43ccee19 100644 --- a/Lib/test/test_hash.py +++ b/Lib/test/test_hash.py @@ -263,8 +263,7 @@ def get_expected_hash(self, position, length): platform = 3 if IS_64BIT else 2 return self.known_hashes[algorithm][position][platform] - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.expectedFailure # TODO: RUSTPYTHON def test_null_hash(self): # PYTHONHASHSEED=0 disables the randomized hash known_hash_of_obj = self.get_expected_hash(0, 3) @@ -275,8 +274,7 @@ def test_null_hash(self): # It can also be disabled by setting the seed to 0: self.assertEqual(self.get_hash(self.repr_, seed=0), known_hash_of_obj) - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.expectedFailure # TODO: RUSTPYTHON @skip_unless_internalhash def test_fixed_hash(self): # test a fixed seed for the randomized hash @@ -284,8 +282,7 @@ def test_fixed_hash(self): h = self.get_expected_hash(1, 3) self.assertEqual(self.get_hash(self.repr_, seed=42), h) - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.expectedFailure # TODO: RUSTPYTHON @skip_unless_internalhash def test_long_fixed_hash(self): if self.repr_long is None: @@ -304,8 +301,7 @@ class StrHashRandomizationTests(StringlikeHashRandomizationTests, def test_empty_string(self): self.assertEqual(hash(""), 0) - # TODO: RUSTPYTHON - @unittest.expectedFailure + @unittest.expectedFailure # TODO: RUSTPYTHON @skip_unless_internalhash def test_ucs2_string(self): h = self.get_expected_hash(3, 6) From 98fc50bef3ae968d6be34822869b0733724d48d5 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 14:02:11 +0300 Subject: [PATCH 5/7] Update `test_grammar.py` --- Lib/test/test_grammar.py | 568 ++++++++++++++++++++++----------------- 1 file changed, 327 insertions(+), 241 deletions(-) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 91eb6cc58f3..4d63656a53c 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1,11 +1,13 @@ # Python test set -- part 1, grammar. # This just tests whether the parser accepts them all. -from test.support import check_syntax_error +from test.support import check_syntax_error, skip_wasi_stack_overflow from test.support import import_helper +import annotationlib import inspect import unittest import sys +import textwrap import warnings # testing import * from sys import * @@ -112,7 +114,7 @@ def test_underscore_literals(self): # Sanity check: no literal begins with an underscore self.assertRaises(NameError, eval, "_0") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_bad_numerical_literals(self): check = self.check_syntax_error check("0b12", "invalid digit '2' in binary literal") @@ -135,7 +137,7 @@ def test_bad_numerical_literals(self): check("1e2_", "invalid decimal literal") check("1e+", "invalid decimal literal") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_end_of_numerical_literals(self): def check(test, error=False): with self.subTest(expr=test): @@ -216,6 +218,27 @@ def test_string_literals(self): ' self.assertEqual(x, y) + def test_string_prefixes(self): + def check(s): + parsed = eval(s) + self.assertIs(type(parsed), str) + self.assertGreater(len(parsed), 0) + + check("u'abc'") + check("r'abc\t'") + check("rf'abc\a {1 + 1}'") + check("fr'abc\a {1 + 1}'") + + def test_bytes_prefixes(self): + def check(s): + parsed = eval(s) + self.assertIs(type(parsed), bytes) + self.assertGreater(len(parsed), 0) + + check("b'abc'") + check("br'abc\t'") + check("rb'abc\a'") + def test_ellipsis(self): x = ... self.assertTrue(x is Ellipsis) @@ -228,17 +251,20 @@ def test_eof_error(self): compile(s, "", "exec") self.assertIn("was never closed", str(cm.exception)) -var_annot_global: int # a global annotated is necessary for test_var_annot + @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: SyntaxError not raised + @skip_wasi_stack_overflow() + def test_max_level(self): + # Macro defined in Parser/lexer/state.h + MAXLEVEL = 200 + + result = eval("(" * MAXLEVEL + ")" * MAXLEVEL) + self.assertEqual(result, ()) -# custom namespace for testing __annotations__ + with self.assertRaises(SyntaxError) as cm: + eval("(" * (MAXLEVEL + 1) + ")" * (MAXLEVEL + 1)) + self.assertStartsWith(str(cm.exception), 'too many nested parentheses') -class CNS: - def __init__(self): - self._dct = {} - def __setitem__(self, item, value): - self._dct[item.lower()] = value - def __getitem__(self, item): - return self._dct[item] +var_annot_global: int # a global annotated is necessary for test_var_annot class GrammarTests(unittest.TestCase): @@ -272,7 +298,7 @@ def one(): my_lst[one()-1]: int = 5 self.assertEqual(my_lst, [5]) - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_syntax_errors(self): # parser pass check_syntax_error(self, "def f: int") @@ -371,24 +397,12 @@ class F(C, A): self.assertEqual(E.__annotations__, {}) self.assertEqual(F.__annotations__, {}) - - @unittest.expectedFailure # TODO: RUSTPYTHON - def test_var_annot_metaclass_semantics(self): - class CMeta(type): - @classmethod - def __prepare__(metacls, name, bases, **kwds): - return {'__annotations__': CNS()} - class CC(metaclass=CMeta): - XX: 'ANNOT' - self.assertEqual(CC.__annotations__['xx'], 'ANNOT') - - @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_module_semantics(self): self.assertEqual(test.__annotations__, {}) self.assertEqual(ann_module.__annotations__, - {1: 2, 'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float}) + {'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float}) self.assertEqual(ann_module.M.__annotations__, - {'123': 123, 'o': type}) + {'o': type}) self.assertEqual(ann_module2.__annotations__, {}) def test_var_annot_in_module(self): @@ -402,55 +416,14 @@ def test_var_annot_in_module(self): with self.assertRaises(NameError): ann_module3.D_bad_ann(5) - @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_simple_exec(self): - gns = {}; lns= {} + gns = {}; lns = {} exec("'docstring'\n" - "__annotations__[1] = 2\n" "x: int = 5\n", gns, lns) - self.assertEqual(lns["__annotations__"], {1: 2, 'x': int}) - with self.assertRaises(KeyError): - gns['__annotations__'] - - @unittest.expectedFailure # TODO: RUSTPYTHON - def test_var_annot_custom_maps(self): - # tests with custom locals() and __annotations__ - ns = {'__annotations__': CNS()} - exec('X: int; Z: str = "Z"; (w): complex = 1j', ns) - self.assertEqual(ns['__annotations__']['x'], int) - self.assertEqual(ns['__annotations__']['z'], str) - with self.assertRaises(KeyError): - ns['__annotations__']['w'] - nonloc_ns = {} - class CNS2: - def __init__(self): - self._dct = {} - def __setitem__(self, item, value): - nonlocal nonloc_ns - self._dct[item] = value - nonloc_ns[item] = value - def __getitem__(self, item): - return self._dct[item] - exec('x: int = 1', {}, CNS2()) - self.assertEqual(nonloc_ns['__annotations__']['x'], int) - - @unittest.expectedFailure # TODO: RUSTPYTHON - def test_var_annot_refleak(self): - # complex case: custom locals plus custom __annotations__ - # this was causing refleak - cns = CNS() - nonloc_ns = {'__annotations__': cns} - class CNS2: - def __init__(self): - self._dct = {'__annotations__': cns} - def __setitem__(self, item, value): - nonlocal nonloc_ns - self._dct[item] = value - nonloc_ns[item] = value - def __getitem__(self, item): - return self._dct[item] - exec('X: str', {}, CNS2()) - self.assertEqual(nonloc_ns['__annotations__']['x'], str) + self.assertNotIn('__annotate__', gns) + + gns.update(lns) # __annotate__ looks at globals + self.assertEqual(lns["__annotate__"](annotationlib.Format.VALUE), {'x': int}) def test_var_annot_rhs(self): ns = {} @@ -778,7 +751,7 @@ def test_expr_stmt(self): # Check the heuristic for print & exec covers significant cases # As well as placing some limits on false positives - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_former_statements_refer_to_builtins(self): keywords = "print", "exec" # Cases where we want the custom error @@ -905,188 +878,294 @@ def g3(): self.assertEqual(y, (1, 2, 3), "unparenthesized star expr return") check_syntax_error(self, "class foo:return 1") - def test_break_in_finally(self): - count = 0 - while count < 2: - count += 1 - try: - pass - finally: - break - self.assertEqual(count, 1) + def test_control_flow_in_finally(self): - count = 0 - while count < 2: - count += 1 - try: - continue - finally: - break - self.assertEqual(count, 1) + def run_case(self, src, expected): + with warnings.catch_warnings(): + warnings.simplefilter('ignore', SyntaxWarning) + g, l = {}, { 'self': self } + exec(textwrap.dedent(src), g, l) + self.assertEqual(expected, l['result']) - count = 0 - while count < 2: - count += 1 - try: - 1/0 - finally: - break - self.assertEqual(count, 1) - for count in [0, 1]: - self.assertEqual(count, 0) - try: - pass - finally: - break - self.assertEqual(count, 0) + # *********** Break in finally *********** - for count in [0, 1]: - self.assertEqual(count, 0) - try: - continue - finally: - break - self.assertEqual(count, 0) + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + pass + finally: + break + """, + 1) + + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + continue + finally: + break + """, + 1) + + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + 1/0 + finally: + break + """, + 1) + + run_case( + self, + """ + for result in [0, 1]: + self.assertEqual(result, 0) + try: + pass + finally: + break + """, + 0) + + run_case( + self, + """ + for result in [0, 1]: + self.assertEqual(result, 0) + try: + continue + finally: + break + """, + 0) + + run_case( + self, + """ + for result in [0, 1]: + self.assertEqual(result, 0) + try: + 1/0 + finally: + break + """, + 0) - for count in [0, 1]: - self.assertEqual(count, 0) - try: - 1/0 - finally: + + # *********** Continue in finally *********** + + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + pass + finally: + continue break - self.assertEqual(count, 0) + """, + 2) - def test_continue_in_finally(self): - count = 0 - while count < 2: - count += 1 - try: - pass - finally: - continue - break - self.assertEqual(count, 2) - count = 0 - while count < 2: - count += 1 - try: + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + break + finally: + continue + """, + 2) + + run_case( + self, + """ + result = 0 + while result < 2: + result += 1 + try: + 1/0 + finally: + continue break - finally: - continue - self.assertEqual(count, 2) + """, + 2) - count = 0 - while count < 2: - count += 1 - try: - 1/0 - finally: - continue - break - self.assertEqual(count, 2) + run_case( + self, + """ + for result in [0, 1]: + try: + pass + finally: + continue + break + """, + 1) - for count in [0, 1]: - try: - pass - finally: - continue - break - self.assertEqual(count, 1) + run_case( + self, + """ + for result in [0, 1]: + try: + break + finally: + continue + """, + 1) - for count in [0, 1]: - try: + run_case( + self, + """ + for result in [0, 1]: + try: + 1/0 + finally: + continue break - finally: - continue - self.assertEqual(count, 1) + """, + 1) - for count in [0, 1]: - try: - 1/0 - finally: - continue - break - self.assertEqual(count, 1) - def test_return_in_finally(self): - def g1(): - try: - pass - finally: - return 1 - self.assertEqual(g1(), 1) + # *********** Return in finally *********** - def g2(): - try: - return 2 - finally: - return 3 - self.assertEqual(g2(), 3) + run_case( + self, + """ + def f(): + try: + pass + finally: + return 1 + result = f() + """, + 1) + + run_case( + self, + """ + def f(): + try: + return 2 + finally: + return 3 + result = f() + """, + 3) + + run_case( + self, + """ + def f(): + try: + 1/0 + finally: + return 4 + result = f() + """, + 4) - def g3(): - try: - 1/0 - finally: - return 4 - self.assertEqual(g3(), 4) + # See issue #37830 + run_case( + self, + """ + def break_in_finally_after_return1(x): + for count in [0, 1]: + count2 = 0 + while count2 < 20: + count2 += 10 + try: + return count + count2 + finally: + if x: + break + return 'end', count, count2 + + self.assertEqual(break_in_finally_after_return1(False), 10) + self.assertEqual(break_in_finally_after_return1(True), ('end', 1, 10)) + result = True + """, + True) + + + run_case( + self, + """ + def break_in_finally_after_return2(x): + for count in [0, 1]: + for count2 in [10, 20]: + try: + return count + count2 + finally: + if x: + break + return 'end', count, count2 + + self.assertEqual(break_in_finally_after_return2(False), 10) + self.assertEqual(break_in_finally_after_return2(True), ('end', 1, 10)) + result = True + """, + True) - def test_break_in_finally_after_return(self): # See issue #37830 - def g1(x): - for count in [0, 1]: - count2 = 0 - while count2 < 20: - count2 += 10 + run_case( + self, + """ + def continue_in_finally_after_return1(x): + count = 0 + while count < 100: + count += 1 try: - return count + count2 + return count finally: if x: - break - return 'end', count, count2 - self.assertEqual(g1(False), 10) - self.assertEqual(g1(True), ('end', 1, 10)) - - def g2(x): - for count in [0, 1]: - for count2 in [10, 20]: + continue + return 'end', count + + self.assertEqual(continue_in_finally_after_return1(False), 1) + self.assertEqual(continue_in_finally_after_return1(True), ('end', 100)) + result = True + """, + True) + + run_case( + self, + """ + def continue_in_finally_after_return2(x): + for count in [0, 1]: try: - return count + count2 + return count finally: if x: - break - return 'end', count, count2 - self.assertEqual(g2(False), 10) - self.assertEqual(g2(True), ('end', 1, 10)) - - def test_continue_in_finally_after_return(self): - # See issue #37830 - def g1(x): - count = 0 - while count < 100: - count += 1 - try: - return count - finally: - if x: - continue - return 'end', count - self.assertEqual(g1(False), 1) - self.assertEqual(g1(True), ('end', 100)) + continue + return 'end', count - def g2(x): - for count in [0, 1]: - try: - return count - finally: - if x: - continue - return 'end', count - self.assertEqual(g2(False), 0) - self.assertEqual(g2(True), ('end', 1)) + self.assertEqual(continue_in_finally_after_return2(False), 0) + self.assertEqual(continue_in_finally_after_return2(True), ('end', 1)) + result = True + """, + True) - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_yield(self): # Allowed as standalone statement def g(): yield 1 @@ -1126,7 +1205,7 @@ def g(): rest = 4, 5, 6; yield 1, 2, 3, *rest # Check annotation refleak on SyntaxError check_syntax_error(self, "def g(a:(yield)): pass") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_yield_in_comprehensions(self): # Check yield in comprehensions def g(): [x for x in [(yield 1)]] @@ -1223,7 +1302,7 @@ def test_assert_failures(self): else: self.fail("AssertionError not raised by 'assert False'") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_assert_syntax_warnings(self): # Ensure that we warn users if they provide a non-zero length tuple as # the assertion test. @@ -1238,7 +1317,7 @@ def test_assert_syntax_warnings(self): compile('assert x, "msg"', '', 'exec') compile('assert False, "msg"', '', 'exec') - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_assert_warning_promotes_to_syntax_error(self): # If SyntaxWarning is configured to be an error, it actually raises a # SyntaxError. @@ -1339,6 +1418,8 @@ def test_try(self): try: 1/0 except (EOFError, TypeError, ZeroDivisionError): pass try: 1/0 + except EOFError, TypeError, ZeroDivisionError: pass + try: 1/0 except (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass finally: pass @@ -1346,8 +1427,6 @@ def test_try(self): compile("try:\n pass\nexcept Exception as a.b:\n pass", "?", "exec") compile("try:\n pass\nexcept Exception as a[b]:\n pass", "?", "exec") - # TODO: RUSTPYTHON - ''' def test_try_star(self): ### try_stmt: 'try': suite (except_star_clause : suite) + ['else' ':' suite] ### except_star_clause: 'except*' expr ['as' NAME] @@ -1363,6 +1442,9 @@ def test_try_star(self): else: pass try: 1/0 except* (EOFError, TypeError, ZeroDivisionError): pass + # TODO: RUSTPYTHON; SyntaxError: multiple exception types must be parenthesized + # try: 1/0 + # except* EOFError, TypeError, ZeroDivisionError: pass try: 1/0 except* (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass @@ -1371,7 +1453,6 @@ def test_try_star(self): compile("try:\n pass\nexcept* Exception as a.b:\n pass", "?", "exec") compile("try:\n pass\nexcept* Exception as a[b]:\n pass", "?", "exec") compile("try:\n pass\nexcept*:\n pass", "?", "exec") - ''' def test_suite(self): # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT @@ -1416,7 +1497,7 @@ def test_comparison(self): if 1 not in (): pass if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in x is x is not x: pass - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_comparison_is_literal(self): def check(test, msg): self.check_syntax_warning(test, msg) @@ -1446,7 +1527,7 @@ def check(test, msg): compile('True is x', '', 'exec') compile('... is x', '', 'exec') - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_warn_missed_comma(self): def check(test): self.check_syntax_warning(test, msg) @@ -1471,6 +1552,8 @@ def check(test): check('[None (3, 4)]') check('[True (3, 4)]') check('[... (3, 4)]') + check('[t"{x}" (3, 4)]') + check('[t"x={x}" (3, 4)]') msg=r'is not subscriptable; perhaps you missed a comma\?' check('[{1, 2} [i, j]]') @@ -1483,6 +1566,8 @@ def check(test): check('[None [i, j]]') check('[True [i, j]]') check('[... [i, j]]') + check('[t"{x}" [i, j]]') + check('[t"x={x}" [i, j]]') msg=r'indices must be integers or slices, not tuple; perhaps you missed a comma\?' check('[(1, 2) [i, j]]') @@ -1513,6 +1598,9 @@ def check(test): check('[[1, 2] [f"{x}"]]') check('[[1, 2] [f"x={x}"]]') check('[[1, 2] ["abc"]]') + msg=r'indices must be integers or slices, not string.templatelib.Template;' + check('[[1, 2] [t"{x}"]]') + check('[[1, 2] [t"x={x}"]]') msg=r'indices must be integers or slices, not' check('[[1, 2] [b"abc"]]') check('[[1, 2] [12.3]]') @@ -1623,8 +1711,6 @@ def test_atoms(self): ### testlist: test (',' test)* [','] # These have been exercised enough above - # TODO: RUSTPYTHON - ''' def test_classdef(self): # 'class' NAME ['(' [testlist] ')'] ':' suite class B: pass @@ -1649,7 +1735,8 @@ class G: pass class H: pass @d := class_decorator class I: pass - @lambda c: class_decorator(c) + # TODO: RUSTPYTHON; SyntaxError: the symbol 'class_decorator' must be present in the symbol table + # @lambda c: class_decorator(c) class J: pass @[..., class_decorator, ...][1] class K: pass @@ -1657,7 +1744,6 @@ class K: pass class L: pass @[class_decorator][0].__call__.__call__ class M: pass - ''' def test_dictcomps(self): # dictorsetmaker: ( (test ':' test (comp_for | From a8faa90dcc1bcc2ecb70aa15cbf0d57d54cdb150 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 15:33:17 +0300 Subject: [PATCH 6/7] Fix failing test --- Lib/test/test_grammar.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index 4d63656a53c..d16c626010c 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1417,8 +1417,9 @@ def test_try(self): else: pass try: 1/0 except (EOFError, TypeError, ZeroDivisionError): pass - try: 1/0 - except EOFError, TypeError, ZeroDivisionError: pass + # TODO: RUSTPYTHON; SyntaxError: multiple exception types must be parenthesized + # try: 1/0 + # except EOFError, TypeError, ZeroDivisionError: pass try: 1/0 except (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass From f201397e20ae8389d11281d1567f013420f21d19 Mon Sep 17 00:00:00 2001 From: ShaharNaveh <50263213+ShaharNaveh@users.noreply.github.com> Date: Mon, 18 May 2026 16:40:14 +0300 Subject: [PATCH 7/7] Restore `test_grammar.py` --- Lib/test/test_grammar.py | 569 +++++++++++++++++---------------------- 1 file changed, 241 insertions(+), 328 deletions(-) diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py index d16c626010c..91eb6cc58f3 100644 --- a/Lib/test/test_grammar.py +++ b/Lib/test/test_grammar.py @@ -1,13 +1,11 @@ # Python test set -- part 1, grammar. # This just tests whether the parser accepts them all. -from test.support import check_syntax_error, skip_wasi_stack_overflow +from test.support import check_syntax_error from test.support import import_helper -import annotationlib import inspect import unittest import sys -import textwrap import warnings # testing import * from sys import * @@ -114,7 +112,7 @@ def test_underscore_literals(self): # Sanity check: no literal begins with an underscore self.assertRaises(NameError, eval, "_0") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_bad_numerical_literals(self): check = self.check_syntax_error check("0b12", "invalid digit '2' in binary literal") @@ -137,7 +135,7 @@ def test_bad_numerical_literals(self): check("1e2_", "invalid decimal literal") check("1e+", "invalid decimal literal") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_end_of_numerical_literals(self): def check(test, error=False): with self.subTest(expr=test): @@ -218,27 +216,6 @@ def test_string_literals(self): ' self.assertEqual(x, y) - def test_string_prefixes(self): - def check(s): - parsed = eval(s) - self.assertIs(type(parsed), str) - self.assertGreater(len(parsed), 0) - - check("u'abc'") - check("r'abc\t'") - check("rf'abc\a {1 + 1}'") - check("fr'abc\a {1 + 1}'") - - def test_bytes_prefixes(self): - def check(s): - parsed = eval(s) - self.assertIs(type(parsed), bytes) - self.assertGreater(len(parsed), 0) - - check("b'abc'") - check("br'abc\t'") - check("rb'abc\a'") - def test_ellipsis(self): x = ... self.assertTrue(x is Ellipsis) @@ -251,20 +228,17 @@ def test_eof_error(self): compile(s, "", "exec") self.assertIn("was never closed", str(cm.exception)) - @unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: SyntaxError not raised - @skip_wasi_stack_overflow() - def test_max_level(self): - # Macro defined in Parser/lexer/state.h - MAXLEVEL = 200 - - result = eval("(" * MAXLEVEL + ")" * MAXLEVEL) - self.assertEqual(result, ()) +var_annot_global: int # a global annotated is necessary for test_var_annot - with self.assertRaises(SyntaxError) as cm: - eval("(" * (MAXLEVEL + 1) + ")" * (MAXLEVEL + 1)) - self.assertStartsWith(str(cm.exception), 'too many nested parentheses') +# custom namespace for testing __annotations__ -var_annot_global: int # a global annotated is necessary for test_var_annot +class CNS: + def __init__(self): + self._dct = {} + def __setitem__(self, item, value): + self._dct[item.lower()] = value + def __getitem__(self, item): + return self._dct[item] class GrammarTests(unittest.TestCase): @@ -298,7 +272,7 @@ def one(): my_lst[one()-1]: int = 5 self.assertEqual(my_lst, [5]) - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_syntax_errors(self): # parser pass check_syntax_error(self, "def f: int") @@ -397,12 +371,24 @@ class F(C, A): self.assertEqual(E.__annotations__, {}) self.assertEqual(F.__annotations__, {}) + + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_var_annot_metaclass_semantics(self): + class CMeta(type): + @classmethod + def __prepare__(metacls, name, bases, **kwds): + return {'__annotations__': CNS()} + class CC(metaclass=CMeta): + XX: 'ANNOT' + self.assertEqual(CC.__annotations__['xx'], 'ANNOT') + + @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_module_semantics(self): self.assertEqual(test.__annotations__, {}) self.assertEqual(ann_module.__annotations__, - {'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float}) + {1: 2, 'x': int, 'y': str, 'f': typing.Tuple[int, int], 'u': int | float}) self.assertEqual(ann_module.M.__annotations__, - {'o': type}) + {'123': 123, 'o': type}) self.assertEqual(ann_module2.__annotations__, {}) def test_var_annot_in_module(self): @@ -416,14 +402,55 @@ def test_var_annot_in_module(self): with self.assertRaises(NameError): ann_module3.D_bad_ann(5) + @unittest.expectedFailure # TODO: RUSTPYTHON def test_var_annot_simple_exec(self): - gns = {}; lns = {} + gns = {}; lns= {} exec("'docstring'\n" + "__annotations__[1] = 2\n" "x: int = 5\n", gns, lns) - self.assertNotIn('__annotate__', gns) - - gns.update(lns) # __annotate__ looks at globals - self.assertEqual(lns["__annotate__"](annotationlib.Format.VALUE), {'x': int}) + self.assertEqual(lns["__annotations__"], {1: 2, 'x': int}) + with self.assertRaises(KeyError): + gns['__annotations__'] + + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_var_annot_custom_maps(self): + # tests with custom locals() and __annotations__ + ns = {'__annotations__': CNS()} + exec('X: int; Z: str = "Z"; (w): complex = 1j', ns) + self.assertEqual(ns['__annotations__']['x'], int) + self.assertEqual(ns['__annotations__']['z'], str) + with self.assertRaises(KeyError): + ns['__annotations__']['w'] + nonloc_ns = {} + class CNS2: + def __init__(self): + self._dct = {} + def __setitem__(self, item, value): + nonlocal nonloc_ns + self._dct[item] = value + nonloc_ns[item] = value + def __getitem__(self, item): + return self._dct[item] + exec('x: int = 1', {}, CNS2()) + self.assertEqual(nonloc_ns['__annotations__']['x'], int) + + @unittest.expectedFailure # TODO: RUSTPYTHON + def test_var_annot_refleak(self): + # complex case: custom locals plus custom __annotations__ + # this was causing refleak + cns = CNS() + nonloc_ns = {'__annotations__': cns} + class CNS2: + def __init__(self): + self._dct = {'__annotations__': cns} + def __setitem__(self, item, value): + nonlocal nonloc_ns + self._dct[item] = value + nonloc_ns[item] = value + def __getitem__(self, item): + return self._dct[item] + exec('X: str', {}, CNS2()) + self.assertEqual(nonloc_ns['__annotations__']['x'], str) def test_var_annot_rhs(self): ns = {} @@ -751,7 +778,7 @@ def test_expr_stmt(self): # Check the heuristic for print & exec covers significant cases # As well as placing some limits on false positives - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_former_statements_refer_to_builtins(self): keywords = "print", "exec" # Cases where we want the custom error @@ -878,294 +905,188 @@ def g3(): self.assertEqual(y, (1, 2, 3), "unparenthesized star expr return") check_syntax_error(self, "class foo:return 1") - def test_control_flow_in_finally(self): - - def run_case(self, src, expected): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', SyntaxWarning) - g, l = {}, { 'self': self } - exec(textwrap.dedent(src), g, l) - self.assertEqual(expected, l['result']) - + def test_break_in_finally(self): + count = 0 + while count < 2: + count += 1 + try: + pass + finally: + break + self.assertEqual(count, 1) - # *********** Break in finally *********** + count = 0 + while count < 2: + count += 1 + try: + continue + finally: + break + self.assertEqual(count, 1) - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - pass - finally: - break - """, - 1) - - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - continue - finally: - break - """, - 1) - - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - 1/0 - finally: - break - """, - 1) - - run_case( - self, - """ - for result in [0, 1]: - self.assertEqual(result, 0) - try: - pass - finally: - break - """, - 0) - - run_case( - self, - """ - for result in [0, 1]: - self.assertEqual(result, 0) - try: - continue - finally: - break - """, - 0) - - run_case( - self, - """ - for result in [0, 1]: - self.assertEqual(result, 0) - try: - 1/0 - finally: - break - """, - 0) + count = 0 + while count < 2: + count += 1 + try: + 1/0 + finally: + break + self.assertEqual(count, 1) + for count in [0, 1]: + self.assertEqual(count, 0) + try: + pass + finally: + break + self.assertEqual(count, 0) - # *********** Continue in finally *********** + for count in [0, 1]: + self.assertEqual(count, 0) + try: + continue + finally: + break + self.assertEqual(count, 0) - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - pass - finally: - continue + for count in [0, 1]: + self.assertEqual(count, 0) + try: + 1/0 + finally: break - """, - 2) + self.assertEqual(count, 0) + def test_continue_in_finally(self): + count = 0 + while count < 2: + count += 1 + try: + pass + finally: + continue + break + self.assertEqual(count, 2) - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - break - finally: - continue - """, - 2) - - run_case( - self, - """ - result = 0 - while result < 2: - result += 1 - try: - 1/0 - finally: - continue + count = 0 + while count < 2: + count += 1 + try: break - """, - 2) + finally: + continue + self.assertEqual(count, 2) - run_case( - self, - """ - for result in [0, 1]: - try: - pass - finally: - continue - break - """, - 1) + count = 0 + while count < 2: + count += 1 + try: + 1/0 + finally: + continue + break + self.assertEqual(count, 2) - run_case( - self, - """ - for result in [0, 1]: - try: - break - finally: - continue - """, - 1) + for count in [0, 1]: + try: + pass + finally: + continue + break + self.assertEqual(count, 1) - run_case( - self, - """ - for result in [0, 1]: - try: - 1/0 - finally: - continue + for count in [0, 1]: + try: break - """, - 1) + finally: + continue + self.assertEqual(count, 1) + for count in [0, 1]: + try: + 1/0 + finally: + continue + break + self.assertEqual(count, 1) - # *********** Return in finally *********** + def test_return_in_finally(self): + def g1(): + try: + pass + finally: + return 1 + self.assertEqual(g1(), 1) - run_case( - self, - """ - def f(): - try: - pass - finally: - return 1 - result = f() - """, - 1) - - run_case( - self, - """ - def f(): - try: - return 2 - finally: - return 3 - result = f() - """, - 3) - - run_case( - self, - """ - def f(): - try: - 1/0 - finally: - return 4 - result = f() - """, - 4) + def g2(): + try: + return 2 + finally: + return 3 + self.assertEqual(g2(), 3) - # See issue #37830 - run_case( - self, - """ - def break_in_finally_after_return1(x): - for count in [0, 1]: - count2 = 0 - while count2 < 20: - count2 += 10 - try: - return count + count2 - finally: - if x: - break - return 'end', count, count2 - - self.assertEqual(break_in_finally_after_return1(False), 10) - self.assertEqual(break_in_finally_after_return1(True), ('end', 1, 10)) - result = True - """, - True) - - - run_case( - self, - """ - def break_in_finally_after_return2(x): - for count in [0, 1]: - for count2 in [10, 20]: - try: - return count + count2 - finally: - if x: - break - return 'end', count, count2 - - self.assertEqual(break_in_finally_after_return2(False), 10) - self.assertEqual(break_in_finally_after_return2(True), ('end', 1, 10)) - result = True - """, - True) + def g3(): + try: + 1/0 + finally: + return 4 + self.assertEqual(g3(), 4) + def test_break_in_finally_after_return(self): # See issue #37830 - run_case( - self, - """ - def continue_in_finally_after_return1(x): - count = 0 - while count < 100: - count += 1 + def g1(x): + for count in [0, 1]: + count2 = 0 + while count2 < 20: + count2 += 10 try: - return count + return count + count2 finally: if x: - continue - return 'end', count - - self.assertEqual(continue_in_finally_after_return1(False), 1) - self.assertEqual(continue_in_finally_after_return1(True), ('end', 100)) - result = True - """, - True) - - run_case( - self, - """ - def continue_in_finally_after_return2(x): - for count in [0, 1]: + break + return 'end', count, count2 + self.assertEqual(g1(False), 10) + self.assertEqual(g1(True), ('end', 1, 10)) + + def g2(x): + for count in [0, 1]: + for count2 in [10, 20]: try: - return count + return count + count2 finally: if x: - continue - return 'end', count + break + return 'end', count, count2 + self.assertEqual(g2(False), 10) + self.assertEqual(g2(True), ('end', 1, 10)) + + def test_continue_in_finally_after_return(self): + # See issue #37830 + def g1(x): + count = 0 + while count < 100: + count += 1 + try: + return count + finally: + if x: + continue + return 'end', count + self.assertEqual(g1(False), 1) + self.assertEqual(g1(True), ('end', 100)) - self.assertEqual(continue_in_finally_after_return2(False), 0) - self.assertEqual(continue_in_finally_after_return2(True), ('end', 1)) - result = True - """, - True) + def g2(x): + for count in [0, 1]: + try: + return count + finally: + if x: + continue + return 'end', count + self.assertEqual(g2(False), 0) + self.assertEqual(g2(True), ('end', 1)) - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_yield(self): # Allowed as standalone statement def g(): yield 1 @@ -1205,7 +1126,7 @@ def g(): rest = 4, 5, 6; yield 1, 2, 3, *rest # Check annotation refleak on SyntaxError check_syntax_error(self, "def g(a:(yield)): pass") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_yield_in_comprehensions(self): # Check yield in comprehensions def g(): [x for x in [(yield 1)]] @@ -1302,7 +1223,7 @@ def test_assert_failures(self): else: self.fail("AssertionError not raised by 'assert False'") - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_assert_syntax_warnings(self): # Ensure that we warn users if they provide a non-zero length tuple as # the assertion test. @@ -1317,7 +1238,7 @@ def test_assert_syntax_warnings(self): compile('assert x, "msg"', '', 'exec') compile('assert False, "msg"', '', 'exec') - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_assert_warning_promotes_to_syntax_error(self): # If SyntaxWarning is configured to be an error, it actually raises a # SyntaxError. @@ -1417,9 +1338,6 @@ def test_try(self): else: pass try: 1/0 except (EOFError, TypeError, ZeroDivisionError): pass - # TODO: RUSTPYTHON; SyntaxError: multiple exception types must be parenthesized - # try: 1/0 - # except EOFError, TypeError, ZeroDivisionError: pass try: 1/0 except (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass @@ -1428,6 +1346,8 @@ def test_try(self): compile("try:\n pass\nexcept Exception as a.b:\n pass", "?", "exec") compile("try:\n pass\nexcept Exception as a[b]:\n pass", "?", "exec") + # TODO: RUSTPYTHON + ''' def test_try_star(self): ### try_stmt: 'try': suite (except_star_clause : suite) + ['else' ':' suite] ### except_star_clause: 'except*' expr ['as' NAME] @@ -1443,9 +1363,6 @@ def test_try_star(self): else: pass try: 1/0 except* (EOFError, TypeError, ZeroDivisionError): pass - # TODO: RUSTPYTHON; SyntaxError: multiple exception types must be parenthesized - # try: 1/0 - # except* EOFError, TypeError, ZeroDivisionError: pass try: 1/0 except* (EOFError, TypeError, ZeroDivisionError) as msg: pass try: pass @@ -1454,6 +1371,7 @@ def test_try_star(self): compile("try:\n pass\nexcept* Exception as a.b:\n pass", "?", "exec") compile("try:\n pass\nexcept* Exception as a[b]:\n pass", "?", "exec") compile("try:\n pass\nexcept*:\n pass", "?", "exec") + ''' def test_suite(self): # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT @@ -1498,7 +1416,7 @@ def test_comparison(self): if 1 not in (): pass if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in x is x is not x: pass - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_comparison_is_literal(self): def check(test, msg): self.check_syntax_warning(test, msg) @@ -1528,7 +1446,7 @@ def check(test, msg): compile('True is x', '', 'exec') compile('... is x', '', 'exec') - @unittest.expectedFailure # TODO: RUSTPYTHON + @unittest.expectedFailure # TODO: RUSTPYTHON def test_warn_missed_comma(self): def check(test): self.check_syntax_warning(test, msg) @@ -1553,8 +1471,6 @@ def check(test): check('[None (3, 4)]') check('[True (3, 4)]') check('[... (3, 4)]') - check('[t"{x}" (3, 4)]') - check('[t"x={x}" (3, 4)]') msg=r'is not subscriptable; perhaps you missed a comma\?' check('[{1, 2} [i, j]]') @@ -1567,8 +1483,6 @@ def check(test): check('[None [i, j]]') check('[True [i, j]]') check('[... [i, j]]') - check('[t"{x}" [i, j]]') - check('[t"x={x}" [i, j]]') msg=r'indices must be integers or slices, not tuple; perhaps you missed a comma\?' check('[(1, 2) [i, j]]') @@ -1599,9 +1513,6 @@ def check(test): check('[[1, 2] [f"{x}"]]') check('[[1, 2] [f"x={x}"]]') check('[[1, 2] ["abc"]]') - msg=r'indices must be integers or slices, not string.templatelib.Template;' - check('[[1, 2] [t"{x}"]]') - check('[[1, 2] [t"x={x}"]]') msg=r'indices must be integers or slices, not' check('[[1, 2] [b"abc"]]') check('[[1, 2] [12.3]]') @@ -1712,6 +1623,8 @@ def test_atoms(self): ### testlist: test (',' test)* [','] # These have been exercised enough above + # TODO: RUSTPYTHON + ''' def test_classdef(self): # 'class' NAME ['(' [testlist] ')'] ':' suite class B: pass @@ -1736,8 +1649,7 @@ class G: pass class H: pass @d := class_decorator class I: pass - # TODO: RUSTPYTHON; SyntaxError: the symbol 'class_decorator' must be present in the symbol table - # @lambda c: class_decorator(c) + @lambda c: class_decorator(c) class J: pass @[..., class_decorator, ...][1] class K: pass @@ -1745,6 +1657,7 @@ class K: pass class L: pass @[class_decorator][0].__call__.__call__ class M: pass + ''' def test_dictcomps(self): # dictorsetmaker: ( (test ':' test (comp_for |