Skip to content

Commit

Permalink
work around frame.f_lineno being None sometimes
Browse files Browse the repository at this point in the history
  • Loading branch information
graingert committed Mar 22, 2022
1 parent 1995582 commit db4c627
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 4 deletions.
29 changes: 25 additions & 4 deletions distributed/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from __future__ import annotations

import bisect
import dis
import linecache
import sys
import threading
Expand Down Expand Up @@ -59,21 +60,41 @@ def identifier(frame):
)


# work around some frames lacking an f_lineo eg: https://bugs.python.org/issue47085
def _f_lineno(frame):
f_lineno = frame.f_lineno
if f_lineno is not None:
return f_lineno

f_lasti = frame.f_lasti
code = frame.f_code
prev_line = code.co_firstlineno

for start, next_line in dis.findlinestarts(code):
if f_lasti < start:
return prev_line
prev_line = next_line

return prev_line


def repr_frame(frame):
"""Render a frame as a line for inclusion into a text traceback"""
co = frame.f_code
text = f' File "{co.co_filename}", line {frame.f_lineno}, in {co.co_name}'
line = linecache.getline(co.co_filename, frame.f_lineno, frame.f_globals).lstrip()
f_lineno = _f_lineno(frame)
text = f' File "{co.co_filename}", line {f_lineno}, in {co.co_name}'
line = linecache.getline(co.co_filename, f_lineno, frame.f_globals).lstrip()
return text + "\n\t" + line


def info_frame(frame):
co = frame.f_code
line = linecache.getline(co.co_filename, frame.f_lineno, frame.f_globals).lstrip()
f_lineno = _f_lineno(frame)
line = linecache.getline(co.co_filename, f_lineno, frame.f_globals).lstrip()
return {
"filename": co.co_filename,
"name": co.co_name,
"line_number": frame.f_lineno,
"line_number": f_lineno,
"line": line,
}

Expand Down
112 changes: 112 additions & 0 deletions distributed/tests/test_profile.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from __future__ import annotations

import dataclasses
import sys
import threading
from collections.abc import Iterator, Sequence
from time import sleep

import pytest
Expand All @@ -11,6 +15,7 @@
call_stack,
create,
identifier,
info_frame,
ll_get_stack,
llprocess,
merge,
Expand Down Expand Up @@ -200,3 +205,110 @@ def stop():
while threading.active_count() > start_threads:
assert time() < start + 2
sleep(0.01)


@dataclasses.dataclass(frozen=True)
class FakeCode:
co_filename: str
co_name: str
co_firstlineno: int
co_lnotab: bytes
co_lines_seq: Sequence[tuple[int, int, int | None]]
co_code: bytes

def co_lines(self) -> Iterator[tuple[int, int, int | None]]:
yield from self.co_lines_seq


@dataclasses.dataclass(frozen=True)
class FakeFrame:
f_lasti: int
f_code: FakeCode
f_lineno: int | None = None
f_back: FakeFrame | None = None
f_globals: dict[str, object] = dataclasses.field(default_factory=dict)


@pytest.mark.parametrize(
"f_lasti,f_lineno",
[
(-1, 1),
(0, 2),
(1, 2),
(11, 2),
(12, 3),
(21, 4),
(22, 4),
(23, 4),
(24, 2),
(25, 2),
(26, 2),
(27, 2),
(100, 2),
],
)
def test_info_frame_f_lineno(f_lasti: int, f_lineno: int) -> None:
assert info_frame(
FakeFrame(
f_lasti=f_lasti,
f_code=FakeCode(
co_filename="<stdin>",
co_name="example",
co_firstlineno=1,
co_lnotab=b"\x00\x01\x0c\x01\x08\x01\x04\xfe",
co_lines_seq=[
(0, 12, 2),
(12, 20, 3),
(20, 22, 4),
(22, 24, None),
(24, 28, 2),
],
co_code=b"t\x00d\x01\x83\x01D\x00]\x07}\x00|\x00d\x02k\x05r\x0b\t\x00q\x04d\x00S\x00",
),
)
) == {
"filename": "<stdin>",
"name": "example",
"line_number": f_lineno,
"line": "",
}


@pytest.mark.parametrize(
"f_lasti,f_lineno",
[
(-1, 1),
(0, 2),
(1, 2),
(11, 2),
(12, 3),
(21, 4),
(22, 4),
(23, 4),
(24, 2),
(25, 2),
(26, 2),
(27, 2),
(100, 2),
],
)
def test_call_stack_f_lineno(f_lasti: int, f_lineno: int) -> None:
assert call_stack(
FakeFrame(
f_lasti=f_lasti,
f_code=FakeCode(
co_filename="<stdin>",
co_name="example",
co_firstlineno=1,
co_lnotab=b"\x00\x01\x0c\x01\x08\x01\x04\xfe",
co_lines_seq=[
(0, 12, 2),
(12, 20, 3),
(20, 22, 4),
(22, 24, None),
(24, 28, 2),
],
co_code=b"t\x00d\x01\x83\x01D\x00]\x07}\x00|\x00d\x02k\x05r\x0b\t\x00q\x04d\x00S\x00",
),
)
) == [f' File "<stdin>", line {f_lineno}, in example\n\t']

0 comments on commit db4c627

Please sign in to comment.