mirror of https://github.com/python/cpython.git
GH-100117: Make `co_lines` more efficient (GH-100447)
This commit is contained in:
parent
b2f7b2ef0b
commit
f07daaf4f7
|
@ -702,7 +702,8 @@ def test_positions(self):
|
||||||
|
|
||||||
def check_lines(self, func):
|
def check_lines(self, func):
|
||||||
co = func.__code__
|
co = func.__code__
|
||||||
lines1 = list(dedup(l for (_, _, l) in co.co_lines()))
|
lines1 = [line for _, _, line in co.co_lines()]
|
||||||
|
self.assertEqual(lines1, list(dedup(lines1)))
|
||||||
lines2 = list(lines_from_postions(positions_from_location_table(co)))
|
lines2 = list(lines_from_postions(positions_from_location_table(co)))
|
||||||
for l1, l2 in zip(lines1, lines2):
|
for l1, l2 in zip(lines1, lines2):
|
||||||
self.assertEqual(l1, l2)
|
self.assertEqual(l1, l2)
|
||||||
|
|
|
@ -161,9 +161,8 @@ def test_leading_newlines(self):
|
||||||
s256 = "".join(["\n"] * 256 + ["spam"])
|
s256 = "".join(["\n"] * 256 + ["spam"])
|
||||||
co = compile(s256, 'fn', 'exec')
|
co = compile(s256, 'fn', 'exec')
|
||||||
self.assertEqual(co.co_firstlineno, 1)
|
self.assertEqual(co.co_firstlineno, 1)
|
||||||
lines = list(co.co_lines())
|
lines = [line for _, _, line in co.co_lines()]
|
||||||
self.assertEqual(lines[0][2], 0)
|
self.assertEqual(lines, [0, 257])
|
||||||
self.assertEqual(lines[1][2], 257)
|
|
||||||
|
|
||||||
def test_literals_with_leading_zeroes(self):
|
def test_literals_with_leading_zeroes(self):
|
||||||
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
|
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
|
||||||
|
@ -955,9 +954,9 @@ def no_code2():
|
||||||
for func in (no_code1, no_code2):
|
for func in (no_code1, no_code2):
|
||||||
with self.subTest(func=func):
|
with self.subTest(func=func):
|
||||||
code = func.__code__
|
code = func.__code__
|
||||||
lines = list(code.co_lines())
|
[(start, end, line)] = code.co_lines()
|
||||||
start, end, line = lines[0]
|
|
||||||
self.assertEqual(start, 0)
|
self.assertEqual(start, 0)
|
||||||
|
self.assertEqual(end, len(code.co_code))
|
||||||
self.assertEqual(line, code.co_firstlineno)
|
self.assertEqual(line, code.co_firstlineno)
|
||||||
|
|
||||||
def get_code_lines(self, code):
|
def get_code_lines(self, code):
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Improve the output of ``co_lines`` by emitting only one entry for each line
|
||||||
|
range.
|
|
@ -1183,6 +1183,14 @@ lineiter_dealloc(lineiterator *li)
|
||||||
Py_TYPE(li)->tp_free(li);
|
Py_TYPE(li)->tp_free(li);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_source_offset_converter(int *value) {
|
||||||
|
if (*value == -1) {
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
}
|
||||||
|
return PyLong_FromLong(*value);
|
||||||
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
lineiter_next(lineiterator *li)
|
lineiter_next(lineiterator *li)
|
||||||
{
|
{
|
||||||
|
@ -1190,31 +1198,17 @@ lineiter_next(lineiterator *li)
|
||||||
if (!_PyLineTable_NextAddressRange(bounds)) {
|
if (!_PyLineTable_NextAddressRange(bounds)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyObject *start = NULL;
|
int start = bounds->ar_start;
|
||||||
PyObject *end = NULL;
|
int line = bounds->ar_line;
|
||||||
PyObject *line = NULL;
|
// Merge overlapping entries:
|
||||||
PyObject *result = PyTuple_New(3);
|
while (_PyLineTable_NextAddressRange(bounds)) {
|
||||||
start = PyLong_FromLong(bounds->ar_start);
|
if (bounds->ar_line != line) {
|
||||||
end = PyLong_FromLong(bounds->ar_end);
|
_PyLineTable_PreviousAddressRange(bounds);
|
||||||
if (bounds->ar_line < 0) {
|
break;
|
||||||
line = Py_NewRef(Py_None);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
line = PyLong_FromLong(bounds->ar_line);
|
|
||||||
}
|
}
|
||||||
if (result == NULL || start == NULL || end == NULL || line == NULL) {
|
return Py_BuildValue("iiO&", start, bounds->ar_end,
|
||||||
goto error;
|
_source_offset_converter, &line);
|
||||||
}
|
|
||||||
PyTuple_SET_ITEM(result, 0, start);
|
|
||||||
PyTuple_SET_ITEM(result, 1, end);
|
|
||||||
PyTuple_SET_ITEM(result, 2, line);
|
|
||||||
return result;
|
|
||||||
error:
|
|
||||||
Py_XDECREF(start);
|
|
||||||
Py_XDECREF(end);
|
|
||||||
Py_XDECREF(line);
|
|
||||||
Py_XDECREF(result);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PyTypeObject _PyLineIterator = {
|
PyTypeObject _PyLineIterator = {
|
||||||
|
@ -1290,14 +1284,6 @@ positionsiter_dealloc(positionsiterator* pi)
|
||||||
Py_TYPE(pi)->tp_free(pi);
|
Py_TYPE(pi)->tp_free(pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject*
|
|
||||||
_source_offset_converter(int* value) {
|
|
||||||
if (*value == -1) {
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
return PyLong_FromLong(*value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject*
|
static PyObject*
|
||||||
positionsiter_next(positionsiterator* pi)
|
positionsiter_next(positionsiterator* pi)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue