Skip to content

Commit 2f180ce

Browse files
authored
bpo-44530: Add co_qualname field to PyCodeObject (GH-26941)
1 parent 32096df commit 2f180ce

20 files changed

+7448
-7435
lines changed

Doc/c-api/function.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,16 @@ There are a few functions specific to Python functions.
3636
3737
The function's docstring and name are retrieved from the code object. *__module__*
3838
is retrieved from *globals*. The argument defaults, annotations and closure are
39-
set to ``NULL``. *__qualname__* is set to the same value as the function's name.
39+
set to ``NULL``. *__qualname__* is set to the same value as the code object's
40+
``co_qualname`` field.
4041
4142
4243
.. c:function:: PyObject* PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname)
4344
4445
As :c:func:`PyFunction_New`, but also allows setting the function object's
4546
``__qualname__`` attribute. *qualname* should be a unicode object or ``NULL``;
46-
if ``NULL``, the ``__qualname__`` attribute is set to the same value as its
47-
``__name__`` attribute.
47+
if ``NULL``, the ``__qualname__`` attribute is set to the same value as the
48+
code object's ``co_qualname`` field.
4849
4950
.. versionadded:: 3.3
5051

Include/cpython/code.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct PyCodeObject {
7575
PyObject *co_localspluskinds; /* Bytes mapping to local kinds (one byte per variable) */
7676
PyObject *co_filename; /* unicode (where it was loaded from) */
7777
PyObject *co_name; /* unicode (name, for reference) */
78+
PyObject *co_qualname; /* unicode (qualname, for reference) */
7879
PyObject *co_linetable; /* bytes (encoding addr<->lineno mapping) See
7980
Objects/lnotab_notes.txt for details. */
8081
PyObject *co_endlinetable; /* bytes object that holds end lineno for
@@ -154,14 +155,14 @@ PyAPI_DATA(PyTypeObject) PyCode_Type;
154155
PyAPI_FUNC(PyCodeObject *) PyCode_New(
155156
int, int, int, int, int, PyObject *, PyObject *,
156157
PyObject *, PyObject *, PyObject *, PyObject *,
157-
PyObject *, PyObject *, int, PyObject *, PyObject *,
158-
PyObject *, PyObject *);
158+
PyObject *, PyObject *, PyObject *, int, PyObject *,
159+
PyObject *, PyObject *, PyObject *);
159160

160161
PyAPI_FUNC(PyCodeObject *) PyCode_NewWithPosOnlyArgs(
161162
int, int, int, int, int, int, PyObject *, PyObject *,
162163
PyObject *, PyObject *, PyObject *, PyObject *,
163-
PyObject *, PyObject *, int, PyObject *, PyObject *,
164-
PyObject *, PyObject *);
164+
PyObject *, PyObject *, PyObject *, int, PyObject *,
165+
PyObject *, PyObject *, PyObject *);
165166
/* same as struct above */
166167

167168
/* Creates a new empty code object with the specified source location. */

Include/internal/pycore_code.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ struct _PyCodeConstructor {
212212
/* metadata */
213213
PyObject *filename;
214214
PyObject *name;
215+
PyObject *qualname;
215216
int flags;
216217

217218
/* the code */

Lib/ctypes/test/test_values.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ class struct_frozen(Structure):
8080
continue
8181
items.append((entry.name.decode("ascii"), entry.size))
8282

83-
expected = [("__hello__", 159),
84-
("__phello__", -159),
85-
("__phello__.spam", 159),
83+
expected = [("__hello__", 164),
84+
("__phello__", -164),
85+
("__phello__.spam", 164),
8686
]
8787
self.assertEqual(items, expected, "PyImport_FrozenModules example "
8888
"in Doc/library/ctypes.rst may be out of date")

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ def _write_atomic(path, data, mode=0o666):
362362
# Python 3.11a1 3457 (Change localsplus to a bytes object bpo-43693)
363363
# Python 3.11a1 3458 (imported objects now don't use LOAD_METHOD/CALL_METHOD)
364364
# Python 3.11a1 3459 (PEP 657: add end line numbers and column offsets for instructions)
365+
# Python 3.11a1 3460 (Add co_qualname field to PyCodeObject bpo-44530)
365366

366367
#
367368
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -371,7 +372,7 @@ def _write_atomic(path, data, mode=0o666):
371372
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
372373
# in PC/launcher.c must also be updated.
373374

374-
MAGIC_NUMBER = (3459).to_bytes(2, 'little') + b'\r\n'
375+
MAGIC_NUMBER = (3460).to_bytes(2, 'little') + b'\r\n'
375376
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
376377

377378
_PYCACHE = '__pycache__'

Lib/test/test_code.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
freevars: ()
1818
nlocals: 2
1919
flags: 3
20-
consts: ('None', '<code object g>', "'f.<locals>.g'")
20+
consts: ('None', '<code object g>')
2121
2222
>>> dump(f(4).__code__)
2323
name: g
@@ -223,6 +223,7 @@ def func(): pass
223223
co.co_varnames,
224224
co.co_filename,
225225
co.co_name,
226+
co.co_qualname,
226227
co.co_firstlineno,
227228
co.co_lnotab,
228229
co.co_endlinetable,
@@ -231,6 +232,12 @@ def func(): pass
231232
co.co_freevars,
232233
co.co_cellvars)
233234

235+
def test_qualname(self):
236+
self.assertEqual(
237+
CodeTest.test_qualname.__code__.co_qualname,
238+
CodeTest.test_qualname.__qualname__
239+
)
240+
234241
def test_replace(self):
235242
def func():
236243
x = 1
@@ -297,6 +304,7 @@ def func():
297304
co.co_varnames,
298305
co.co_filename,
299306
co.co_name,
307+
co.co_qualname,
300308
co.co_firstlineno,
301309
co.co_lnotab,
302310
co.co_endlinetable,

Lib/test/test_dis.py

Lines changed: 44 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,16 @@ def bug1333982(x=[]):
149149
dis_bug1333982 = """\
150150
%3d 0 LOAD_ASSERTION_ERROR
151151
2 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
152-
4 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
153-
6 MAKE_FUNCTION 0
154-
8 LOAD_FAST 0 (x)
155-
10 GET_ITER
156-
12 CALL_FUNCTION 1
152+
4 MAKE_FUNCTION 0
153+
6 LOAD_FAST 0 (x)
154+
8 GET_ITER
155+
10 CALL_FUNCTION 1
157156
158-
%3d 14 LOAD_CONST 4 (1)
157+
%3d 12 LOAD_CONST 3 (1)
159158
160-
%3d 16 BINARY_ADD
161-
18 CALL_FUNCTION 1
162-
20 RAISE_VARARGS 1
159+
%3d 14 BINARY_ADD
160+
16 CALL_FUNCTION 1
161+
18 RAISE_VARARGS 1
163162
""" % (bug1333982.__code__.co_firstlineno + 1,
164163
__file__,
165164
bug1333982.__code__.co_firstlineno + 1,
@@ -432,12 +431,11 @@ def foo(x):
432431
%3d 2 LOAD_CLOSURE 0 (y)
433432
4 BUILD_TUPLE 1
434433
6 LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
435-
8 LOAD_CONST 2 ('_h.<locals>.foo')
436-
10 MAKE_FUNCTION 8 (closure)
437-
12 STORE_FAST 1 (foo)
434+
8 MAKE_FUNCTION 8 (closure)
435+
10 STORE_FAST 1 (foo)
438436
439-
%3d 14 LOAD_FAST 1 (foo)
440-
16 RETURN_VALUE
437+
%3d 12 LOAD_FAST 1 (foo)
438+
14 RETURN_VALUE
441439
""" % (_h.__code__.co_firstlineno + 1,
442440
__file__,
443441
_h.__code__.co_firstlineno + 1,
@@ -451,12 +449,11 @@ def foo(x):
451449
%3d 2 LOAD_CLOSURE 0 (x)
452450
4 BUILD_TUPLE 1
453451
6 LOAD_CONST 1 (<code object <listcomp> at 0x..., file "%s", line %d>)
454-
8 LOAD_CONST 2 ('_h.<locals>.foo.<locals>.<listcomp>')
455-
10 MAKE_FUNCTION 8 (closure)
456-
12 LOAD_DEREF 1 (y)
457-
14 GET_ITER
458-
16 CALL_FUNCTION 1
459-
18 RETURN_VALUE
452+
8 MAKE_FUNCTION 8 (closure)
453+
10 LOAD_DEREF 1 (y)
454+
12 GET_ITER
455+
14 CALL_FUNCTION 1
456+
16 RETURN_VALUE
460457
""" % (dis_nested_0,
461458
__file__,
462459
_h.__code__.co_firstlineno + 1,
@@ -747,7 +744,6 @@ def f(c=c):
747744
Constants:
748745
0: None
749746
1: <code object f at (.*), file "(.*)", line (.*)>
750-
2: 'tricky.<locals>.f'
751747
Variable names:
752748
0: a
753749
1: b
@@ -975,51 +971,49 @@ def _prepare_test_cases():
975971
expected_opinfo_outer = [
976972
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='a', argrepr='a', offset=0, starts_line=None, is_jump_target=False, positions=None),
977973
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='b', argrepr='b', offset=2, starts_line=None, is_jump_target=False, positions=None),
978-
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval=(3, 4), argrepr='(3, 4)', offset=4, starts_line=2, is_jump_target=False, positions=None),
974+
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=(3, 4), argrepr='(3, 4)', offset=4, starts_line=2, is_jump_target=False, positions=None),
979975
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False, positions=None),
980976
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False, positions=None),
981977
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=10, starts_line=None, is_jump_target=False, positions=None),
982978
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=12, starts_line=None, is_jump_target=False, positions=None),
983-
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=14, starts_line=None, is_jump_target=False, positions=None),
984-
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=16, starts_line=None, is_jump_target=False, positions=None),
985-
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None),
986-
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=20, starts_line=7, is_jump_target=False, positions=None),
987-
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=22, starts_line=None, is_jump_target=False, positions=None),
988-
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=24, starts_line=None, is_jump_target=False, positions=None),
989-
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=26, starts_line=None, is_jump_target=False, positions=None),
990-
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=28, starts_line=None, is_jump_target=False, positions=None),
991-
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None),
992-
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
993-
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=34, starts_line=None, is_jump_target=False, positions=None),
994-
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
995-
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
996-
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=40, starts_line=8, is_jump_target=False, positions=None),
997-
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
979+
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=14, starts_line=None, is_jump_target=False, positions=None),
980+
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=16, starts_line=None, is_jump_target=False, positions=None),
981+
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=18, starts_line=7, is_jump_target=False, positions=None),
982+
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='a', argrepr='a', offset=20, starts_line=None, is_jump_target=False, positions=None),
983+
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='b', argrepr='b', offset=22, starts_line=None, is_jump_target=False, positions=None),
984+
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='', argrepr="''", offset=24, starts_line=None, is_jump_target=False, positions=None),
985+
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=26, starts_line=None, is_jump_target=False, positions=None),
986+
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
987+
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None),
988+
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=32, starts_line=None, is_jump_target=False, positions=None),
989+
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
990+
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
991+
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=38, starts_line=8, is_jump_target=False, positions=None),
992+
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
998993
]
999994

1000995

1001996
expected_opinfo_f = [
1002997
Instruction(opname='MAKE_CELL', opcode=135, arg=0, argval='c', argrepr='c', offset=0, starts_line=None, is_jump_target=False, positions=None),
1003998
Instruction(opname='MAKE_CELL', opcode=135, arg=1, argval='d', argrepr='d', offset=2, starts_line=None, is_jump_target=False, positions=None),
1004-
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=(5, 6), argrepr='(5, 6)', offset=4, starts_line=3, is_jump_target=False, positions=None),
999+
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval=(5, 6), argrepr='(5, 6)', offset=4, starts_line=3, is_jump_target=False, positions=None),
10051000
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=3, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False, positions=None),
10061001
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=4, argval='b', argrepr='b', offset=8, starts_line=None, is_jump_target=False, positions=None),
10071002
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=0, argval='c', argrepr='c', offset=10, starts_line=None, is_jump_target=False, positions=None),
10081003
Instruction(opname='LOAD_CLOSURE', opcode=136, arg=1, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False, positions=None),
10091004
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=14, starts_line=None, is_jump_target=False, positions=None),
10101005
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=16, starts_line=None, is_jump_target=False, positions=None),
1011-
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=18, starts_line=None, is_jump_target=False, positions=None),
1012-
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=20, starts_line=None, is_jump_target=False, positions=None),
1013-
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=22, starts_line=None, is_jump_target=False, positions=None),
1014-
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=24, starts_line=5, is_jump_target=False, positions=None),
1015-
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=26, starts_line=None, is_jump_target=False, positions=None),
1016-
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False, positions=None),
1017-
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False, positions=None),
1018-
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False, positions=None),
1019-
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
1020-
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
1021-
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False, positions=None),
1022-
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
1006+
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=9, argval=9, argrepr='defaults, closure', offset=18, starts_line=None, is_jump_target=False, positions=None),
1007+
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=20, starts_line=None, is_jump_target=False, positions=None),
1008+
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=22, starts_line=5, is_jump_target=False, positions=None),
1009+
Instruction(opname='LOAD_DEREF', opcode=137, arg=3, argval='a', argrepr='a', offset=24, starts_line=None, is_jump_target=False, positions=None),
1010+
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=26, starts_line=None, is_jump_target=False, positions=None),
1011+
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=28, starts_line=None, is_jump_target=False, positions=None),
1012+
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=30, starts_line=None, is_jump_target=False, positions=None),
1013+
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=32, starts_line=None, is_jump_target=False, positions=None),
1014+
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
1015+
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=36, starts_line=6, is_jump_target=False, positions=None),
1016+
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
10231017
]
10241018

10251019
expected_opinfo_inner = [
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Added the ``co_qualname`` to the ``PyCodeObject`` structure to propagate the
2+
qualified name from the compiler to code objects.
3+
4+
Patch by Gabriele N. Tornetta

0 commit comments

Comments
 (0)