Skip to content

Commit f29b8b9

Browse files
committed
gh-137814: Fix __qualname__ of __annotate__
1 parent ec4021c commit f29b8b9

File tree

5 files changed

+31
-0
lines changed

5 files changed

+31
-0
lines changed

Include/internal/pycore_symtable.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ typedef struct _symtable_entry {
9090
PyObject *ste_id; /* int: key in ste_table->st_blocks */
9191
PyObject *ste_symbols; /* dict: variable names to flags */
9292
PyObject *ste_name; /* string: name of current block */
93+
PyObject *ste_function_name; /* string or NULL: for annotation blocks: name of the corresponding functions */
9394
PyObject *ste_varnames; /* list of function parameters */
9495
PyObject *ste_children; /* list of child blocks */
9596
PyObject *ste_directives;/* locations of global and nonlocal statements */

Lib/test/test_type_annotations.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,3 +835,17 @@ def test_complex_comprehension_inlining_exec(self):
835835
genexp = annos["unique_name_2"][0]
836836
lamb = list(genexp)[0]
837837
self.assertEqual(lamb(), 42)
838+
839+
def test_annotate_qualname(self):
840+
code = """
841+
def f() -> None: pass
842+
class Outer:
843+
x: int
844+
def method(self, x: int):
845+
pass
846+
"""
847+
ns = run_code(code)
848+
method = ns["Outer"].method
849+
self.assertEqual(method.__annotate__.__qualname__, "Outer.method.__annotate__")
850+
self.assertEqual(ns["f"].__annotate__.__qualname__, "f.__annotate__")
851+
self.assertEqual(ns["Outer"].__annotate__.__qualname__, "Outer.__annotate__")
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the ``__qualname__`` attribute of ``__annotate__`` functions on
2+
functions.

Python/compile.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,17 @@ compiler_set_qualname(compiler *c)
289289
base = Py_NewRef(parent->u_metadata.u_qualname);
290290
}
291291
}
292+
if (u->u_ste->ste_function_name != NULL) {
293+
base = PyUnicode_FromFormat("%U.%U",
294+
parent->u_metadata.u_qualname,
295+
u->u_ste->ste_function_name);
296+
if (base == NULL) {
297+
return ERROR;
298+
}
299+
}
300+
}
301+
else if (u->u_ste->ste_function_name != NULL) {
302+
base = Py_NewRef(u->u_ste->ste_function_name);
292303
}
293304

294305
if (base != NULL) {

Python/symtable.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
108108
ste->ste_id = k; /* ste owns reference to k */
109109

110110
ste->ste_name = Py_NewRef(name);
111+
ste->ste_function_name = NULL;
111112

112113
ste->ste_symbols = NULL;
113114
ste->ste_varnames = NULL;
@@ -185,6 +186,7 @@ ste_dealloc(PyObject *op)
185186
ste->ste_table = NULL;
186187
Py_XDECREF(ste->ste_id);
187188
Py_XDECREF(ste->ste_name);
189+
Py_XDECREF(ste->ste_function_name);
188190
Py_XDECREF(ste->ste_symbols);
189191
Py_XDECREF(ste->ste_varnames);
190192
Py_XDECREF(ste->ste_children);
@@ -2830,6 +2832,7 @@ symtable_visit_annotations(struct symtable *st, stmt_ty o, arguments_ty a, expr_
28302832
(void *)a, LOCATION(o))) {
28312833
return 0;
28322834
}
2835+
Py_XSETREF(st->st_cur->ste_function_name, Py_NewRef(function_ste->ste_name));
28332836
if (is_in_class || current_type == ClassBlock) {
28342837
st->st_cur->ste_can_see_class_scope = 1;
28352838
if (!symtable_add_def(st, &_Py_ID(__classdict__), USE, LOCATION(o))) {

0 commit comments

Comments
 (0)