Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 877df85

Browse files
authored
bpo-42246: Partial implementation of PEP 626. (GH-23113)
* Implement new line number table format, as defined in PEP 626.
1 parent cda99b4 commit 877df85

19 files changed

+5358
-4994
lines changed

Include/cpython/code.h

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct PyCodeObject {
3838
Py_ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
3939
PyObject *co_filename; /* unicode (where it was loaded from) */
4040
PyObject *co_name; /* unicode (name, for reference) */
41-
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) See
41+
PyObject *co_linetable; /* string (encoding addr<->lineno mapping) See
4242
Objects/lnotab_notes.txt for details. */
4343
void *co_zombieframe; /* for optimization only (see frameobject.c) */
4444
PyObject *co_weakreflist; /* to support weakrefs to code objects */
@@ -135,16 +135,18 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno);
135135
PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int);
136136

137137
/* for internal use only */
138-
typedef struct _addr_pair {
139-
int ap_lower;
140-
int ap_upper;
141-
} PyAddrPair;
138+
typedef struct _line_offsets {
139+
int ar_start;
140+
int ar_end;
141+
int ar_line;
142+
int ar_computed_line;
143+
char *lo_next;
144+
} PyCodeAddressRange;
142145

143146
/* Update *bounds to describe the first and one-past-the-last instructions in the
144147
same line as lasti. Return the number of that line.
145148
*/
146-
PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co,
147-
int lasti, PyAddrPair *bounds);
149+
PyAPI_FUNC(int) _PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds);
148150

149151
/* Create a comparable key used to compare constants taking in account the
150152
* object type. It is used to make sure types are not coerced (e.g., float and
@@ -163,3 +165,15 @@ PyAPI_FUNC(int) _PyCode_GetExtra(PyObject *code, Py_ssize_t index,
163165
void **extra);
164166
PyAPI_FUNC(int) _PyCode_SetExtra(PyObject *code, Py_ssize_t index,
165167
void *extra);
168+
169+
/** API for initializing the line number table. */
170+
int _PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds);
171+
172+
/** Out of process API for initializing the line number table. */
173+
void PyLineTable_InitAddressRange(char *linetable, int firstlineno, PyCodeAddressRange *range);
174+
175+
/** API for traversing the line number table. */
176+
int PyLineTable_NextAddressRange(PyCodeAddressRange *range);
177+
int PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
178+
179+

Lib/dis.py

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -449,32 +449,15 @@ def findlabels(code):
449449
def findlinestarts(code):
450450
"""Find the offsets in a byte code which are start of lines in the source.
451451
452-
Generate pairs (offset, lineno) as described in Python/compile.c.
453-
452+
Generate pairs (offset, lineno)
454453
"""
455-
byte_increments = code.co_lnotab[0::2]
456-
line_increments = code.co_lnotab[1::2]
457-
bytecode_len = len(code.co_code)
458-
459-
lastlineno = None
460-
lineno = code.co_firstlineno
461-
addr = 0
462-
for byte_incr, line_incr in zip(byte_increments, line_increments):
463-
if byte_incr:
464-
if lineno != lastlineno:
465-
yield (addr, lineno)
466-
lastlineno = lineno
467-
addr += byte_incr
468-
if addr >= bytecode_len:
469-
# The rest of the lnotab byte offsets are past the end of
470-
# the bytecode, so the lines were optimized away.
471-
return
472-
if line_incr >= 0x80:
473-
# line_increments is an array of 8-bit signed integers
474-
line_incr -= 0x100
475-
lineno += line_incr
476-
if lineno != lastlineno:
477-
yield (addr, lineno)
454+
lastline = None
455+
for start, end, line in code.co_lines():
456+
if line is not None and line != lastline:
457+
lastline = line
458+
yield start, line
459+
return
460+
478461

479462
class Bytecode:
480463
"""The bytecode operations of a piece of code

Lib/test/test_code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ def func2():
258258
("co_cellvars", ("cellvar",)),
259259
("co_filename", "newfilename"),
260260
("co_name", "newname"),
261-
("co_lnotab", code2.co_lnotab),
261+
("co_linetable", code2.co_linetable),
262262
):
263263
with self.subTest(attr=attr, value=value):
264264
new_code = code.replace(**{attr: value})

Lib/test/test_compile.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ def test_indentation(self):
155155
def test_leading_newlines(self):
156156
s256 = "".join(["\n"] * 256 + ["spam"])
157157
co = compile(s256, 'fn', 'exec')
158-
self.assertEqual(co.co_firstlineno, 257)
159-
self.assertEqual(co.co_lnotab, bytes())
158+
self.assertEqual(co.co_firstlineno, 1)
159+
self.assertEqual(list(co.co_lines()), [(0, 4, 257), (4, 8, None)])
160160

161161
def test_literals_with_leading_zeroes(self):
162162
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",

Lib/test/test_opcodes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_setup_annotations_line(self):
2727
with open(ann_module.__file__) as f:
2828
txt = f.read()
2929
co = compile(txt, ann_module.__file__, 'exec')
30-
self.assertEqual(co.co_firstlineno, 3)
30+
self.assertEqual(co.co_firstlineno, 1)
3131
except OSError:
3232
pass
3333

Lib/test/test_pdb.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1645,9 +1645,10 @@ def test_errors_in_command(self):
16451645
'debug doesnotexist',
16461646
'c',
16471647
])
1648-
stdout, _ = self.run_pdb_script('', commands + '\n')
1648+
stdout, _ = self.run_pdb_script('pass', commands + '\n')
16491649

16501650
self.assertEqual(stdout.splitlines()[1:], [
1651+
'-> pass',
16511652
'(Pdb) *** SyntaxError: unexpected EOF while parsing',
16521653

16531654
'(Pdb) ENTERING RECURSIVE DEBUGGER',

Lib/test/test_sys_settrace.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,7 @@ def ireturn_example():
220220
(2, 'line'),
221221
(3, 'line'),
222222
(4, 'line'),
223-
(6, 'line'),
224-
(6, 'return')]
223+
(4, 'return')]
225224

226225
# Tight loop with while(1) example (SF #765624)
227226
def tightloop_example():
@@ -602,6 +601,17 @@ def run(tracer):
602601
self.compare_events(doit_async.__code__.co_firstlineno,
603602
tracer.events, events)
604603

604+
def test_21_repeated_pass(self):
605+
def func():
606+
pass
607+
pass
608+
609+
self.run_and_compare(func,
610+
[(0, 'call'),
611+
(1, 'line'),
612+
(2, 'line'),
613+
(2, 'return')])
614+
605615
def test_loop_in_try_except(self):
606616
# https://bugs.python.org/issue41670
607617

@@ -766,7 +776,7 @@ def trace(self, frame, event, arg):
766776
if (self.firstLine is None and frame.f_code == self.code and
767777
event == 'line'):
768778
self.firstLine = frame.f_lineno - 1
769-
if (event == self.event and self.firstLine and
779+
if (event == self.event and self.firstLine is not None and
770780
frame.f_lineno == self.firstLine + self.jumpFrom):
771781
f = frame
772782
while f is not None and f.f_code != self.code:
@@ -1540,7 +1550,7 @@ def test_jump_to_firstlineno(self):
15401550
""", "<fake module>", "exec")
15411551
class fake_function:
15421552
__code__ = code
1543-
tracer = JumpTracer(fake_function, 2, 0)
1553+
tracer = JumpTracer(fake_function, 4, 1)
15441554
sys.settrace(tracer.trace)
15451555
namespace = {"output": []}
15461556
exec(code, namespace)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improved accuracy of line tracing events and f_lineno attribute of Frame
2+
objects. See PEP 626 for details.

Objects/clinic/codeobject.c.h

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)