From 69d1245685cf95ddc678633e978a56673da64865 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Mon, 5 Jun 2023 06:07:17 -0700 Subject: gh-105164: Detect annotations inside match blocks (#105177) --- Lib/test/test_type_annotations.py | 111 +++++++++++++++++++++ .../2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst | 2 + Python/compile.c | 10 ++ 3 files changed, 123 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 87f46c2c..3dbb35a 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -1,4 +1,6 @@ +import textwrap import unittest +from test.support import run_code class TypeAnnotationTests(unittest.TestCase): @@ -101,3 +103,112 @@ class TypeAnnotationTests(unittest.TestCase): with self.assertRaises(AttributeError): del D.__annotations__ self.assertEqual(D.__annotations__, {}) + + +class TestSetupAnnotations(unittest.TestCase): + def check(self, code: str): + code = textwrap.dedent(code) + for scope in ("module", "class"): + with self.subTest(scope=scope): + if scope == "class": + code = f"class C:\n{textwrap.indent(code, ' ')}" + ns = run_code(code) + if scope == "class": + annotations = ns["C"].__annotations__ + else: + annotations = ns["__annotations__"] + self.assertEqual(annotations, {"x": int}) + + def test_top_level(self): + self.check("x: int = 1") + + def test_blocks(self): + self.check("if True:\n x: int = 1") + self.check(""" + while True: + x: int = 1 + break + """) + self.check(""" + while False: + pass + else: + x: int = 1 + """) + self.check(""" + for i in range(1): + x: int = 1 + """) + self.check(""" + for i in range(1): + pass + else: + x: int = 1 + """) + + def test_try(self): + self.check(""" + try: + x: int = 1 + except: + pass + """) + self.check(""" + try: + pass + except: + pass + else: + x: int = 1 + """) + self.check(""" + try: + pass + except: + pass + finally: + x: int = 1 + """) + self.check(""" + try: + 1/0 + except: + x: int = 1 + """) + + def test_try_star(self): + self.check(""" + try: + x: int = 1 + except* Exception: + pass + """) + self.check(""" + try: + pass + except* Exception: + pass + else: + x: int = 1 + """) + self.check(""" + try: + pass + except* Exception: + pass + finally: + x: int = 1 + """) + self.check(""" + try: + 1/0 + except* Exception: + x: int = 1 + """) + + def test_match(self): + self.check(""" + match 0: + case 0: + x: int = 1 + """) diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst new file mode 100644 index 0000000..7d3486c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-31-19-35-22.gh-issue-105164.6Wajph.rst @@ -0,0 +1,2 @@ +Ensure annotations are set up correctly if the only annotation in a block is +within a :keyword:`match` block. Patch by Jelle Zijlstra. diff --git a/Python/compile.c b/Python/compile.c index 4fa1ee5..d52c2b0 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1398,8 +1398,18 @@ find_ann(asdl_stmt_seq *stmts) find_ann(st->v.TryStar.finalbody) || find_ann(st->v.TryStar.orelse); break; + case Match_kind: + for (j = 0; j < asdl_seq_LEN(st->v.Match.cases); j++) { + match_case_ty match_case = (match_case_ty)asdl_seq_GET( + st->v.Match.cases, j); + if (find_ann(match_case->body)) { + return true; + } + } + break; default: res = false; + break; } if (res) { break; -- cgit v0.12