Skip to content

Commit f07daaf

Browse files
authored
GH-100117: Make co_lines more efficient (GH-100447)
1 parent b2f7b2e commit f07daaf

File tree

4 files changed

+26
-38
lines changed

4 files changed

+26
-38
lines changed

Diff for: Lib/test/test_code.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,8 @@ def test_positions(self):
702702

703703
def check_lines(self, func):
704704
co = func.__code__
705-
lines1 = list(dedup(l for (_, _, l) in co.co_lines()))
705+
lines1 = [line for _, _, line in co.co_lines()]
706+
self.assertEqual(lines1, list(dedup(lines1)))
706707
lines2 = list(lines_from_postions(positions_from_location_table(co)))
707708
for l1, l2 in zip(lines1, lines2):
708709
self.assertEqual(l1, l2)

Diff for: Lib/test/test_compile.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,8 @@ def test_leading_newlines(self):
161161
s256 = "".join(["\n"] * 256 + ["spam"])
162162
co = compile(s256, 'fn', 'exec')
163163
self.assertEqual(co.co_firstlineno, 1)
164-
lines = list(co.co_lines())
165-
self.assertEqual(lines[0][2], 0)
166-
self.assertEqual(lines[1][2], 257)
164+
lines = [line for _, _, line in co.co_lines()]
165+
self.assertEqual(lines, [0, 257])
167166

168167
def test_literals_with_leading_zeroes(self):
169168
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
@@ -955,9 +954,9 @@ def no_code2():
955954
for func in (no_code1, no_code2):
956955
with self.subTest(func=func):
957956
code = func.__code__
958-
lines = list(code.co_lines())
959-
start, end, line = lines[0]
957+
[(start, end, line)] = code.co_lines()
960958
self.assertEqual(start, 0)
959+
self.assertEqual(end, len(code.co_code))
961960
self.assertEqual(line, code.co_firstlineno)
962961

963962
def get_code_lines(self, code):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Improve the output of ``co_lines`` by emitting only one entry for each line
2+
range.

Diff for: Objects/codeobject.c

+18-32
Original file line numberDiff line numberDiff line change
@@ -1183,38 +1183,32 @@ lineiter_dealloc(lineiterator *li)
11831183
Py_TYPE(li)->tp_free(li);
11841184
}
11851185

1186+
static PyObject *
1187+
_source_offset_converter(int *value) {
1188+
if (*value == -1) {
1189+
Py_RETURN_NONE;
1190+
}
1191+
return PyLong_FromLong(*value);
1192+
}
1193+
11861194
static PyObject *
11871195
lineiter_next(lineiterator *li)
11881196
{
11891197
PyCodeAddressRange *bounds = &li->li_line;
11901198
if (!_PyLineTable_NextAddressRange(bounds)) {
11911199
return NULL;
11921200
}
1193-
PyObject *start = NULL;
1194-
PyObject *end = NULL;
1195-
PyObject *line = NULL;
1196-
PyObject *result = PyTuple_New(3);
1197-
start = PyLong_FromLong(bounds->ar_start);
1198-
end = PyLong_FromLong(bounds->ar_end);
1199-
if (bounds->ar_line < 0) {
1200-
line = Py_NewRef(Py_None);
1201-
}
1202-
else {
1203-
line = PyLong_FromLong(bounds->ar_line);
1204-
}
1205-
if (result == NULL || start == NULL || end == NULL || line == NULL) {
1206-
goto error;
1201+
int start = bounds->ar_start;
1202+
int line = bounds->ar_line;
1203+
// Merge overlapping entries:
1204+
while (_PyLineTable_NextAddressRange(bounds)) {
1205+
if (bounds->ar_line != line) {
1206+
_PyLineTable_PreviousAddressRange(bounds);
1207+
break;
1208+
}
12071209
}
1208-
PyTuple_SET_ITEM(result, 0, start);
1209-
PyTuple_SET_ITEM(result, 1, end);
1210-
PyTuple_SET_ITEM(result, 2, line);
1211-
return result;
1212-
error:
1213-
Py_XDECREF(start);
1214-
Py_XDECREF(end);
1215-
Py_XDECREF(line);
1216-
Py_XDECREF(result);
1217-
return result;
1210+
return Py_BuildValue("iiO&", start, bounds->ar_end,
1211+
_source_offset_converter, &line);
12181212
}
12191213

12201214
PyTypeObject _PyLineIterator = {
@@ -1290,14 +1284,6 @@ positionsiter_dealloc(positionsiterator* pi)
12901284
Py_TYPE(pi)->tp_free(pi);
12911285
}
12921286

1293-
static PyObject*
1294-
_source_offset_converter(int* value) {
1295-
if (*value == -1) {
1296-
Py_RETURN_NONE;
1297-
}
1298-
return PyLong_FromLong(*value);
1299-
}
1300-
13011287
static PyObject*
13021288
positionsiter_next(positionsiterator* pi)
13031289
{

0 commit comments

Comments
 (0)