New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-39537 New line number table format #18326
Conversation
…n be shown to not crash the intepreter.
…confusing pdb too much.
I haven't understood all the implications of this, I hope it won't have unintended consequences for coverage.py. But I'll start with a small suggestion: don't name this |
@nedbat I too hope it won't have unintended consequences for coverage.py Personally, I don't think it makes sense to expose the line number table at all. |
Yes, coverage.py parses co_lnotab (I assumed you knew this, and was why you made me nosy on the bpo): https://github.com/nedbat/coveragepy/blob/master/coverage/parser.py#L392-L419 . Notice that this code includes having to adapt to the negative offsets introduced in 3.6. Don't you want coverage.py to have access to the more accurate information in the new table? Isn't improved tooling the point of the change? |
Yes, of course I want coverage.py to have access to correct line numbers. Why do you need to parse |
Currently, coverage.py only uses co_lnotab to get the set of all possible line numbers. In the past, it did much more extensive analysis of the byte code. Even then, co_lnotab was simply a list of pairs Keep backward compatibility in mind, though: I won't be able to use a new 3.9 API any time soon, and so will have to adapt to changing data formats. I can make do with a version check if need be. Serhiy is talking on the bpo about adding richer information to this table also. I'm not sure what the right abstract API is for that though, since we're extending the information stored. |
Do you have a number for that bpo issue? |
Would a method on the code object that exposes the C function |
@markshannon By "the bpo", I meant https://bugs.python.org/issue39537, the one that started this pull request. The way coverage.py uses co_lnotab now, PyCode_Addr2Line would be inconvenient: I don't have a byte offset in mind and need the line number. I just iterate the entire table to get the complete set of line numbers. Doing that with PyCode_Addr2Line would require iterating over byte addresses, calling the function each time, which would give O(N^2) behavior. If I had to choose an abstract interface to this table, it would be an iterator of (byte_offset, line_number) pairs, just like the function findlinestarts in dis.py. |
What about bytecodes with no line number? |
Can you give me an example for concreteness? If one of those bytecodes raises an exception, what would the traceback say? |
Either they can't raise an exception, or it is handled locally.
which cannot raise. |
To clarify the above. That bytecode would be emitted to clean up try:
...
except Exception as var:
... |
You asked,
I don't know how to answer that. This would be a new API, so I have to change code to adapt to it. If you tell me some of the line numbers would be None, then I will deal with that. At the moment, I'm just collecting the set of all line numbers, so I would drop None from that set and carry on. I asked about tracebacks to get a sense of what None might actually mean in this new context. |
The format of the line number table is orthogonal to how the compiler generates code that might raise exceptions. All tracebacks will continue to have correct line numbers. |
I've always been taught, and have taught, that any Python byte code can raise exceptions. The code will have to deal with the possibility of a frame in a traceback being at a byte code with no line number. What will the traceback display for it? "None"? Some nearby line number? Will the frame be omitted from the traceback (the worst possibility)? |
Not all bytecodes can raise exceptions. The compiler can guarantee that the certain sequences of generated bytecodes will not raise an exception. Examples: |
Maybe I've been misinformed. Can't a KeyboardInterrupt happen during those bytecodes? |
|
I've given this a bit more thought lately. @nedbat I think a way forward would be to hide any new format, and have the |
Sure, that would work. Anything that lets me get the set of all possible line numbers is fine. |
Closing until PEP 626 is accepted or rejected. |
This PR add a new line number table format as specified in bpo:39537.
It also:
frame.setlineno
to make it more robust, but less "smart". It used to attempt to disallow "unreasonable" jumps. It now just tests whether a jump is safe, that is won't crash the interpreter, allowing any safe jump. This should makeframe.setlineno
much more robust w.r.t. bytecode compiler changes.pass
statements having no code associated with them.To make life easier for tools, we attach a line number to the
LOAD CONSTANT None; RETURN VALUE
pair emitted for empty code object, ensuring that at least one bytecode per code object has a line number.https://bugs.python.org/issue39537