gh-126072: do not add `None` to `co_consts` if there is no docstring (GH-126101)

This commit is contained in:
Xuanteng Huang 2024-10-30 17:01:09 +08:00 committed by GitHub
parent 2ab377a47c
commit 35df4eb959
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 148 additions and 58 deletions

View File

@ -1700,6 +1700,14 @@ which is a bitmap of the following flags:
.. versionadded:: 3.6
.. data:: CO_HAS_DOCSTRING
The flag is set when there is a docstring for the code object in
the source code. If set, it will be the first item in
:attr:`~codeobject.co_consts`.
.. versionadded:: 3.14
.. note::
The flags are specific to CPython, and may not be defined in other
Python implementations. Furthermore, the flags are an implementation

View File

@ -1536,9 +1536,9 @@ Other bits in :attr:`~codeobject.co_flags` are reserved for internal use.
.. index:: single: documentation string
If a code object represents a function, the first item in
:attr:`~codeobject.co_consts` is
the documentation string of the function, or ``None`` if undefined.
If a code object represents a function and has a docstring,
the first item in :attr:`~codeobject.co_consts` is
the docstring of the function.
Methods on code objects
~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -174,6 +174,11 @@ struct PyCodeObject _PyCode_DEF(1);
#define CO_NO_MONITORING_EVENTS 0x2000000
/* Whether the code object has a docstring,
If so, it will be the first item in co_consts
*/
#define CO_HAS_DOCSTRING 0x4000000
/* This should be defined if a future statement modifies the syntax.
For example, when a keyword is added.
*/

View File

@ -123,6 +123,7 @@ typedef struct _symtable_entry {
unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */
unsigned ste_can_see_class_scope : 1; /* true if this block can see names bound in an
enclosing class scope */
unsigned ste_has_docstring : 1; /* true if docstring present */
int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */
_Py_SourceLocation ste_loc; /* source location of block */
struct _symtable_entry *ste_annotation_block; /* symbol table entry for this entry's annotations */

View File

@ -151,16 +151,17 @@ def distb(tb=None, *, file=None, show_caches=False, adaptive=False, show_offsets
# list of CO_* constants. It is also used by pretty_flags to
# turn the co_flags field into a human readable list.
COMPILER_FLAG_NAMES = {
1: "OPTIMIZED",
2: "NEWLOCALS",
4: "VARARGS",
8: "VARKEYWORDS",
16: "NESTED",
32: "GENERATOR",
64: "NOFREE",
128: "COROUTINE",
256: "ITERABLE_COROUTINE",
512: "ASYNC_GENERATOR",
1: "OPTIMIZED",
2: "NEWLOCALS",
4: "VARARGS",
8: "VARKEYWORDS",
16: "NESTED",
32: "GENERATOR",
64: "NOFREE",
128: "COROUTINE",
256: "ITERABLE_COROUTINE",
512: "ASYNC_GENERATOR",
0x4000000: "HAS_DOCSTRING",
}
def pretty_flags(flags):

View File

@ -56,6 +56,7 @@ __all__ = [
"CO_OPTIMIZED",
"CO_VARARGS",
"CO_VARKEYWORDS",
"CO_HAS_DOCSTRING",
"ClassFoundException",
"ClosureVars",
"EndOfBlock",
@ -409,6 +410,7 @@ def iscode(object):
co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
| 16=nested | 32=generator | 64=nofree | 128=coroutine
| 256=iterable_coroutine | 512=async_generator
| 0x4000000=has_docstring
co_freevars tuple of names of free variables
co_posonlyargcount number of positional only arguments
co_kwonlyargcount number of keyword only arguments (not including ** arg)

View File

@ -17,7 +17,7 @@ cellvars: ('x',)
freevars: ()
nlocals: 2
flags: 3
consts: ('None', '<code object g>')
consts: ('<code object g>',)
>>> dump(f(4).__code__)
name: g
@ -86,7 +86,7 @@ varnames: ()
cellvars: ()
freevars: ()
nlocals: 0
flags: 3
flags: 67108867
consts: ("'doc string'", 'None')
>>> def keywordonly_args(a,b,*,k1):
@ -123,6 +123,61 @@ nlocals: 3
flags: 3
consts: ('None',)
>>> def has_docstring(x: str):
... 'This is a one-line doc string'
... x += x
... x += "hello world"
... # co_flags should be 0x4000003 = 67108867
... return x
>>> dump(has_docstring.__code__)
name: has_docstring
argcount: 1
posonlyargcount: 0
kwonlyargcount: 0
names: ()
varnames: ('x',)
cellvars: ()
freevars: ()
nlocals: 1
flags: 67108867
consts: ("'This is a one-line doc string'", "'hello world'")
>>> async def async_func_docstring(x: str, y: str):
... "This is a docstring from async function"
... import asyncio
... await asyncio.sleep(1)
... # co_flags should be 0x4000083 = 67108995
... return x + y
>>> dump(async_func_docstring.__code__)
name: async_func_docstring
argcount: 2
posonlyargcount: 0
kwonlyargcount: 0
names: ('asyncio', 'sleep')
varnames: ('x', 'y', 'asyncio')
cellvars: ()
freevars: ()
nlocals: 3
flags: 67108995
consts: ("'This is a docstring from async function'", 'None')
>>> def no_docstring(x, y, z):
... return x + "hello" + y + z + "world"
>>> dump(no_docstring.__code__)
name: no_docstring
argcount: 3
posonlyargcount: 0
kwonlyargcount: 0
names: ()
varnames: ('x', 'y', 'z')
cellvars: ()
freevars: ()
nlocals: 3
flags: 3
consts: ("'hello'", "'world'")
"""
import copy

View File

@ -834,7 +834,7 @@ class TestSpecifics(unittest.TestCase):
return "unused"
self.assertEqual(f.__code__.co_consts,
(None, "used"))
(True, "used"))
@support.cpython_only
def test_remove_unused_consts_extended_args(self):
@ -852,9 +852,9 @@ class TestSpecifics(unittest.TestCase):
eval(compile(code, "file.py", "exec"), g)
exec(code, g)
f = g['f']
expected = tuple([None, ''] + [f't{i}' for i in range(N)])
expected = tuple([''] + [f't{i}' for i in range(N)])
self.assertEqual(f.__code__.co_consts, expected)
expected = "".join(expected[2:])
expected = "".join(expected[1:])
self.assertEqual(expected, f())
# Stripping unused constants is not a strict requirement for the
@ -1244,7 +1244,7 @@ class TestSpecifics(unittest.TestCase):
y)
genexp_lines = [0, 4, 2, 0, 4]
genexp_code = return_genexp.__code__.co_consts[1]
genexp_code = return_genexp.__code__.co_consts[0]
code_lines = self.get_code_lines(genexp_code)
self.assertEqual(genexp_lines, code_lines)

View File

@ -84,7 +84,7 @@ class IsolatedAssembleTests(AssemblerTestCase):
return x
return inner() % 2
inner_code = mod_two.__code__.co_consts[1]
inner_code = mod_two.__code__.co_consts[0]
assert isinstance(inner_code, types.CodeType)
metadata = {

View File

@ -197,7 +197,7 @@ dis_bug1333982 = """\
%3d RESUME 0
%3d LOAD_COMMON_CONSTANT 0 (AssertionError)
LOAD_CONST 1 (<code object <genexpr> at 0x..., file "%s", line %d>)
LOAD_CONST 0 (<code object <genexpr> at 0x..., file "%s", line %d>)
MAKE_FUNCTION
LOAD_FAST 0 (x)
GET_ITER
@ -276,10 +276,10 @@ dis_kw_names = """\
LOAD_SMALL_INT 1
LOAD_SMALL_INT 2
LOAD_SMALL_INT 5
LOAD_CONST 1 (('c',))
LOAD_CONST 0 (('c',))
CALL_KW 3
POP_TOP
LOAD_CONST 0 (None)
LOAD_CONST 1 (None)
RETURN_VALUE
""" % (wrap_func_w_kwargs.__code__.co_firstlineno,
wrap_func_w_kwargs.__code__.co_firstlineno + 1)
@ -500,18 +500,18 @@ dis_fstring = """\
%3d LOAD_FAST 0 (a)
FORMAT_SIMPLE
LOAD_CONST 1 (' ')
LOAD_CONST 0 (' ')
LOAD_FAST 1 (b)
LOAD_CONST 2 ('4')
LOAD_CONST 1 ('4')
FORMAT_WITH_SPEC
LOAD_CONST 1 (' ')
LOAD_CONST 0 (' ')
LOAD_FAST 2 (c)
CONVERT_VALUE 2 (repr)
FORMAT_SIMPLE
LOAD_CONST 1 (' ')
LOAD_CONST 0 (' ')
LOAD_FAST 3 (d)
CONVERT_VALUE 2 (repr)
LOAD_CONST 2 ('4')
LOAD_CONST 1 ('4')
FORMAT_WITH_SPEC
BUILD_STRING 7
RETURN_VALUE
@ -785,7 +785,7 @@ dis_nested_0 = """\
%4d LOAD_FAST 0 (y)
BUILD_TUPLE 1
LOAD_CONST 1 (<code object foo at 0x..., file "%s", line %d>)
LOAD_CONST 0 (<code object foo at 0x..., file "%s", line %d>)
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 8 (closure)
STORE_FAST 1 (foo)
@ -884,7 +884,7 @@ dis_loop_test_quickened_code = """\
%3d RESUME_CHECK 0
%3d BUILD_LIST 0
LOAD_CONST 1 ((1, 2, 3))
LOAD_CONST 0 ((1, 2, 3))
LIST_EXTEND 1
LOAD_SMALL_INT 3
BINARY_OP 5 (*)
@ -900,7 +900,7 @@ dis_loop_test_quickened_code = """\
%3d L2: END_FOR
POP_TOP
LOAD_CONST_IMMORTAL 0 (None)
LOAD_CONST_IMMORTAL 1 (None)
RETURN_VALUE
""" % (loop_test.__code__.co_firstlineno,
loop_test.__code__.co_firstlineno + 1,
@ -913,12 +913,12 @@ def extended_arg_quick():
dis_extended_arg_quick_code = """\
%3d RESUME 0
%3d LOAD_CONST 1 (Ellipsis)
%3d LOAD_CONST 0 (Ellipsis)
EXTENDED_ARG 1
UNPACK_EX 256
POP_TOP
STORE_FAST 0 (_)
LOAD_CONST 0 (None)
LOAD_CONST 1 (None)
RETURN_VALUE
"""% (extended_arg_quick.__code__.co_firstlineno,
extended_arg_quick.__code__.co_firstlineno + 1,)
@ -1465,7 +1465,7 @@ Positional-only arguments: 0
Kw-only arguments: 0
Number of locals: 1
Stack size: \\d+
Flags: OPTIMIZED, NEWLOCALS
Flags: OPTIMIZED, NEWLOCALS, HAS_DOCSTRING
Constants:
{code_info_consts}
Names:
@ -1491,8 +1491,8 @@ Number of locals: 10
Stack size: \\d+
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
Constants:
0: None
1: <code object f at (.*), file "(.*)", line (.*)>
0: <code object f at (.*), file "(.*)", line (.*)>
1: None
Variable names:
0: a
1: b
@ -1510,10 +1510,12 @@ Cell variables:
2: [abedfxyz]
3: [abedfxyz]
4: [abedfxyz]
5: [abedfxyz]"""
5: [abedfxyz]
6: [abedfxyz]
7: [abedfxyz]"""
# NOTE: the order of the cell variables above depends on dictionary order!
co_tricky_nested_f = tricky.__func__.__code__.co_consts[1]
co_tricky_nested_f = tricky.__func__.__code__.co_consts[0]
code_info_tricky_nested_f = """\
Filename: (.*)
@ -1677,9 +1679,9 @@ def jumpy():
# End fodder for opinfo generation tests
expected_outer_line = 1
_line_offset = outer.__code__.co_firstlineno - 1
code_object_f = outer.__code__.co_consts[1]
code_object_f = outer.__code__.co_consts[0]
expected_f_line = code_object_f.co_firstlineno - _line_offset
code_object_inner = code_object_f.co_consts[1]
code_object_inner = code_object_f.co_consts[0]
expected_inner_line = code_object_inner.co_firstlineno - _line_offset
expected_jumpy_line = 1
@ -1735,11 +1737,11 @@ expected_opinfo_outer = [
Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None, label=None, positions=None, cache_info=None),
Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=4, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=(3, 4), argrepr='(3, 4)', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='a', argrepr='a', offset=8, start_offset=8, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='b', argrepr='b', offset=10, start_offset=10, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='BUILD_TUPLE', opcode=48, arg=2, argval=2, argrepr='', offset=12, start_offset=12, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_f, argrepr=repr(code_object_f), offset=14, start_offset=14, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=16, start_offset=16, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=18, start_offset=18, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=20, start_offset=20, starts_line=False, line_number=2, label=None, positions=None, cache_info=None),
@ -1747,11 +1749,11 @@ expected_opinfo_outer = [
Instruction(opname='LOAD_GLOBAL', opcode=87, arg=1, argval='print', argrepr='print + NULL', offset=24, start_offset=24, starts_line=True, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
Instruction(opname='LOAD_DEREF', opcode=80, arg=0, argval='a', argrepr='a', offset=34, start_offset=34, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_DEREF', opcode=80, arg=1, argval='b', argrepr='b', offset=36, start_offset=36, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='', argrepr="''", offset=38, start_offset=38, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_SMALL_INT', opcode=89, arg=1, argval=1, argrepr='', offset=40, start_offset=40, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='BUILD_LIST', opcode=43, arg=0, argval=0, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='BUILD_MAP', opcode=44, arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=46, start_offset=46, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=7, argval=7, argrepr='', offset=48, start_offset=48, starts_line=False, line_number=7, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=56, start_offset=56, starts_line=False, line_number=7, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=2, argval='f', argrepr='f', offset=58, start_offset=58, starts_line=True, line_number=8, label=None, positions=None, cache_info=None),
@ -1763,13 +1765,13 @@ expected_opinfo_f = [
Instruction(opname='MAKE_CELL', opcode=92, arg=0, argval='c', argrepr='c', offset=2, start_offset=2, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
Instruction(opname='MAKE_CELL', opcode=92, arg=1, argval='d', argrepr='d', offset=4, start_offset=4, starts_line=False, line_number=None, label=None, positions=None, cache_info=None),
Instruction(opname='RESUME', opcode=149, arg=0, argval=0, argrepr='', offset=6, start_offset=6, starts_line=True, line_number=2, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval=(5, 6), argrepr='(5, 6)', offset=8, start_offset=8, starts_line=True, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=3, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=4, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=0, argval='c', argrepr='c', offset=14, start_offset=14, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST', opcode=81, arg=1, argval='d', argrepr='d', offset=16, start_offset=16, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='BUILD_TUPLE', opcode=48, arg=4, argval=4, argrepr='', offset=18, start_offset=18, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=code_object_inner, argrepr=repr(code_object_inner), offset=20, start_offset=20, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='MAKE_FUNCTION', opcode=23, arg=None, argval=None, argrepr='', offset=22, start_offset=22, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=8, argval=8, argrepr='closure', offset=24, start_offset=24, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='SET_FUNCTION_ATTRIBUTE', opcode=103, arg=1, argval=1, argrepr='defaults', offset=26, start_offset=26, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
@ -1827,7 +1829,7 @@ expected_opinfo_jumpy = [
Instruction(opname='END_FOR', opcode=9, arg=None, argval=None, argrepr='', offset=88, start_offset=88, starts_line=True, line_number=3, label=4, positions=None, cache_info=None),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=90, start_offset=90, starts_line=False, line_number=3, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=92, start_offset=92, starts_line=True, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, start_offset=102, starts_line=False, line_number=10, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=102, start_offset=102, starts_line=False, line_number=10, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=104, start_offset=104, starts_line=False, line_number=10, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=112, start_offset=112, starts_line=False, line_number=10, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_FAST_CHECK', opcode=83, arg=0, argval='i', argrepr='i', offset=114, start_offset=114, starts_line=True, line_number=11, label=5, positions=None, cache_info=None),
@ -1853,7 +1855,7 @@ expected_opinfo_jumpy = [
Instruction(opname='JUMP_BACKWARD', opcode=72, arg=39, argval=114, argrepr='to L5', offset=188, start_offset=188, starts_line=False, line_number=16, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00')]),
Instruction(opname='JUMP_FORWARD', opcode=74, arg=11, argval=216, argrepr='to L9', offset=192, start_offset=192, starts_line=True, line_number=17, label=7, positions=None, cache_info=None),
Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=194, start_offset=194, starts_line=True, line_number=19, label=8, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=False, line_number=19, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=1, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=204, start_offset=204, starts_line=False, line_number=19, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=206, start_offset=206, starts_line=False, line_number=19, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=214, start_offset=214, starts_line=False, line_number=19, label=None, positions=None, cache_info=None),
Instruction(opname='NOP', opcode=27, arg=None, argval=None, argrepr='', offset=216, start_offset=216, starts_line=True, line_number=20, label=9, positions=None, cache_info=None),
@ -1870,19 +1872,19 @@ expected_opinfo_jumpy = [
Instruction(opname='CALL', opcode=49, arg=0, argval=0, argrepr='', offset=240, start_offset=240, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='STORE_FAST', opcode=107, arg=1, argval='dodgy', argrepr='dodgy', offset=248, start_offset=248, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=250, start_offset=250, starts_line=True, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval='Never reach this', argrepr="'Never reach this'", offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=2, argval='Never reach this', argrepr="'Never reach this'", offset=260, start_offset=260, starts_line=False, line_number=26, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=262, start_offset=262, starts_line=False, line_number=26, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=270, start_offset=270, starts_line=False, line_number=26, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=True, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=272, start_offset=272, starts_line=True, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=274, start_offset=274, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=276, start_offset=276, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=3, argval=3, argrepr='', offset=278, start_offset=278, starts_line=False, line_number=25, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=286, start_offset=286, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_GLOBAL', opcode=87, arg=3, argval='print', argrepr='print + NULL', offset=288, start_offset=288, starts_line=True, line_number=28, label=10, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
Instruction(opname='LOAD_CONST', opcode=79, arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=298, start_offset=298, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
Instruction(opname='CALL', opcode=49, arg=1, argval=1, argrepr='', offset=300, start_offset=300, starts_line=False, line_number=28, label=None, positions=None, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
Instruction(opname='POP_TOP', opcode=29, arg=None, argval=None, argrepr='', offset=308, start_offset=308, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=0, argval=None, argrepr='None', offset=310, start_offset=310, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
Instruction(opname='LOAD_CONST', opcode=79, arg=3, argval=None, argrepr='None', offset=310, start_offset=310, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
Instruction(opname='RETURN_VALUE', opcode=33, arg=None, argval=None, argrepr='', offset=312, start_offset=312, starts_line=False, line_number=28, label=None, positions=None, cache_info=None),
Instruction(opname='PUSH_EXC_INFO', opcode=30, arg=None, argval=None, argrepr='', offset=314, start_offset=314, starts_line=True, line_number=25, label=None, positions=None, cache_info=None),
Instruction(opname='WITH_EXCEPT_START', opcode=41, arg=None, argval=None, argrepr='', offset=316, start_offset=316, starts_line=False, line_number=25, label=None, positions=None, cache_info=None),

View File

@ -5373,7 +5373,7 @@ class TestSignatureBind(unittest.TestCase):
# Issue #19611: getcallargs should work with comprehensions
def make_set():
return set(z * z for z in range(5))
gencomp_code = make_set.__code__.co_consts[1]
gencomp_code = make_set.__code__.co_consts[0]
gencomp_func = types.FunctionType(gencomp_code, {})
iterator = iter(range(5))

View File

@ -0,0 +1,3 @@
Add a new attribute in :attr:`~codeobject.co_flags` to indicate whether the
first item in :attr:`~codeobject.co_consts` is the docstring. If a code
object has no docstring, ``None`` will **NOT** be inserted.

View File

@ -162,7 +162,8 @@ PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname
PyObject *consts = code_obj->co_consts;
assert(PyTuple_Check(consts));
PyObject *doc;
if (PyTuple_Size(consts) >= 1) {
if (code_obj->co_flags & CO_HAS_DOCSTRING) {
assert(PyTuple_Size(consts) >= 1);
doc = PyTuple_GetItem(consts, 0);
if (!PyUnicode_Check(doc)) {
doc = Py_None;

View File

@ -1243,10 +1243,10 @@ codegen_function_body(compiler *c, stmt_ty s, int is_async, Py_ssize_t funcflags
_PyCompile_ExitScope(c);
return ERROR;
}
Py_ssize_t idx = _PyCompile_AddConst(c, docstring);
Py_DECREF(docstring);
RETURN_IF_ERROR_IN_SCOPE(c, idx < 0 ? ERROR : SUCCESS);
}
Py_ssize_t idx = _PyCompile_AddConst(c, docstring ? docstring : Py_None);
Py_XDECREF(docstring);
RETURN_IF_ERROR_IN_SCOPE(c, idx < 0 ? ERROR : SUCCESS);
NEW_JUMP_TARGET_LABEL(c, start);
USE_LABEL(c, start);

View File

@ -1285,6 +1285,8 @@ compute_code_flags(compiler *c)
flags |= CO_VARARGS;
if (ste->ste_varkeywords)
flags |= CO_VARKEYWORDS;
if (ste->ste_has_docstring)
flags |= CO_HAS_DOCSTRING;
}
if (ste->ste_coroutine && !ste->ste_generator) {

View File

@ -136,6 +136,8 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
ste->ste_needs_classdict = 0;
ste->ste_annotation_block = NULL;
ste->ste_has_docstring = 0;
ste->ste_symbols = PyDict_New();
ste->ste_varnames = PyList_New(0);
ste->ste_children = PyList_New(0);
@ -1841,6 +1843,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
return 0;
}
if (_PyAST_GetDocString(s->v.FunctionDef.body)) {
new_ste->ste_has_docstring = 1;
}
if (!symtable_visit_annotations(st, s, s->v.FunctionDef.args,
s->v.FunctionDef.returns, new_ste)) {
Py_DECREF(new_ste);
@ -2168,6 +2174,10 @@ symtable_visit_stmt(struct symtable *st, stmt_ty s)
return 0;
}
if (_PyAST_GetDocString(s->v.AsyncFunctionDef.body)) {
new_ste->ste_has_docstring = 1;
}
if (!symtable_visit_annotations(st, s, s->v.AsyncFunctionDef.args,
s->v.AsyncFunctionDef.returns, new_ste)) {
Py_DECREF(new_ste);