summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/whatsnew/3.13.rst3
-rw-r--r--Lib/test/test_type_params.py50
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-04-17-17-52-32.gh-issue-109118.q9iPEI.rst2
-rw-r--r--Python/symtable.c11
4 files changed, 53 insertions, 13 deletions
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index c04dc92..67d1956 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -241,6 +241,9 @@ Other Language Changes
ones if configured to do so.
(Contributed by Pedro Sousa Lacerda in :gh:`66449`.)
+* :ref:`annotation scope <annotation-scopes>` within class scopes can now
+ contain lambdas. (Contributed by Jelle Zijlstra in :gh:`109118`.)
+
New Modules
===========
diff --git a/Lib/test/test_type_params.py b/Lib/test/test_type_params.py
index 25ee188..fbb80d9 100644
--- a/Lib/test/test_type_params.py
+++ b/Lib/test/test_type_params.py
@@ -486,8 +486,6 @@ class TypeParamsAccessTest(unittest.TestCase):
{}
"""
error_cases = [
- "type Alias1[T] = lambda: T",
- "type Alias2 = lambda: T",
"type Alias3[T] = (T for _ in (1,))",
"type Alias4 = (T for _ in (1,))",
"type Alias5[T] = [T for _ in (1,)]",
@@ -499,6 +497,54 @@ class TypeParamsAccessTest(unittest.TestCase):
r"Cannot use [a-z]+ in annotation scope within class scope"):
run_code(code.format(case))
+ def test_lambda_in_alias_in_class(self):
+ code = """
+ T = "global"
+ class C:
+ T = "class"
+ type Alias = lambda: T
+ """
+ C = run_code(code)["C"]
+ self.assertEqual(C.Alias.__value__(), "global")
+
+ def test_lambda_in_alias_in_generic_class(self):
+ code = """
+ class C[T]:
+ T = "class"
+ type Alias = lambda: T
+ """
+ C = run_code(code)["C"]
+ self.assertIs(C.Alias.__value__(), C.__type_params__[0])
+
+ def test_lambda_in_generic_alias_in_class(self):
+ # A lambda nested in the alias cannot see the class scope, but can see
+ # a surrounding annotation scope.
+ code = """
+ T = U = "global"
+ class C:
+ T = "class"
+ U = "class"
+ type Alias[T] = lambda: (T, U)
+ """
+ C = run_code(code)["C"]
+ T, U = C.Alias.__value__()
+ self.assertIs(T, C.Alias.__type_params__[0])
+ self.assertEqual(U, "global")
+
+ def test_lambda_in_generic_alias_in_generic_class(self):
+ # A lambda nested in the alias cannot see the class scope, but can see
+ # a surrounding annotation scope.
+ code = """
+ class C[T, U]:
+ T = "class"
+ U = "class"
+ type Alias[T] = lambda: (T, U)
+ """
+ C = run_code(code)["C"]
+ T, U = C.Alias.__value__()
+ self.assertIs(T, C.Alias.__type_params__[0])
+ self.assertIs(U, C.__type_params__[1])
+
def make_base(arg):
class Base:
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-04-17-17-52-32.gh-issue-109118.q9iPEI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-04-17-17-52-32.gh-issue-109118.q9iPEI.rst
new file mode 100644
index 0000000..1245400
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-04-17-17-52-32.gh-issue-109118.q9iPEI.rst
@@ -0,0 +1,2 @@
+:ref:`annotation scope <annotation-scopes>` within class scopes can now
+contain lambdas.
diff --git a/Python/symtable.c b/Python/symtable.c
index 36ccc0e..483ef1c 100644
--- a/Python/symtable.c
+++ b/Python/symtable.c
@@ -2140,17 +2140,6 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
VISIT(st, expr, e->v.UnaryOp.operand);
break;
case Lambda_kind: {
- if (st->st_cur->ste_can_see_class_scope) {
- // gh-109118
- PyErr_Format(PyExc_SyntaxError,
- "Cannot use lambda in annotation scope within class scope");
- PyErr_RangedSyntaxLocationObject(st->st_filename,
- e->lineno,
- e->col_offset + 1,
- e->end_lineno,
- e->end_col_offset + 1);
- VISIT_QUIT(st, 0);
- }
if (e->v.Lambda.args->defaults)
VISIT_SEQ(st, expr, e->v.Lambda.args->defaults);
if (e->v.Lambda.args->kw_defaults)