def check_lines(self, func):
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)))
for l1, l2 in zip(lines1, lines2):
self.assertEqual(l1, l2)
s256 = "".join(["\n"] * 256 + ["spam"])
co = compile(s256, 'fn', 'exec')
self.assertEqual(co.co_firstlineno, 1)
- lines = list(co.co_lines())
- self.assertEqual(lines[0][2], 0)
- self.assertEqual(lines[1][2], 257)
+ lines = [line for _, _, line in co.co_lines()]
+ self.assertEqual(lines, [0, 257])
def test_literals_with_leading_zeroes(self):
for arg in ["077787", "0xj", "0x.", "0e", "090000000000000",
for func in (no_code1, no_code2):
with self.subTest(func=func):
code = func.__code__
- lines = list(code.co_lines())
- start, end, line = lines[0]
+ [(start, end, line)] = code.co_lines()
self.assertEqual(start, 0)
+ self.assertEqual(end, len(code.co_code))
self.assertEqual(line, code.co_firstlineno)
def get_code_lines(self, code):
--- /dev/null
+Improve the output of ``co_lines`` by emitting only one entry for each line
+range.
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 *
lineiter_next(lineiterator *li)
{
if (!_PyLineTable_NextAddressRange(bounds)) {
return NULL;
}
- PyObject *start = NULL;
- PyObject *end = NULL;
- PyObject *line = NULL;
- PyObject *result = PyTuple_New(3);
- start = PyLong_FromLong(bounds->ar_start);
- end = PyLong_FromLong(bounds->ar_end);
- if (bounds->ar_line < 0) {
- line = Py_NewRef(Py_None);
- }
- else {
- line = PyLong_FromLong(bounds->ar_line);
- }
- if (result == NULL || start == NULL || end == NULL || line == NULL) {
- goto error;
+ int start = bounds->ar_start;
+ int line = bounds->ar_line;
+ // Merge overlapping entries:
+ while (_PyLineTable_NextAddressRange(bounds)) {
+ if (bounds->ar_line != line) {
+ _PyLineTable_PreviousAddressRange(bounds);
+ break;
+ }
}
- 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;
+ return Py_BuildValue("iiO&", start, bounds->ar_end,
+ _source_offset_converter, &line);
}
PyTypeObject _PyLineIterator = {
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*
positionsiter_next(positionsiterator* pi)
{