classification
Title: sys._getframe(1).f_lineno changed behavior in 3.8
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.8
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Thomas Haller, serhiy.storchaka
Priority: normal Keywords:

Created on 2019-09-26 09:10 by Thomas Haller, last changed 2020-12-02 21:46 by iritkatriel. This issue is now closed.

Messages (8)
msg353279 - (view) Author: Thomas Haller (Thomas Haller) Date: 2019-09-26 09:10
The line number for the frame object changed behaviour in 3.8.

I am seeing this on Fedora rawhide, which ships "3.8.0~b4-1.fc32" package.

That happens when wrapping lines for calling functions.

Before, the line number sys._getframe(1).f_lineno indicate the last line. Now it is the first line.



Reproducer:

>>>
#!/usr/bin/env python

import sys


def func(a, b, c, d):

    frame = sys._getframe(1)

    print('call: %s' % (a))
    print('frame:                %s' % (frame))
    print('frame.f_code.co_name: %s' % (frame.f_code.co_name))
    print('frame.f_lineno:       %s' % (frame.f_lineno))


func('call 1, 1 line', 0, 1, 2)

func('call 2, 2 lines',
     0, 1, 2)

func('call 3, 4 lines',
     0,
     1,
     2)

<<<<


with python2 and python<=3.7, the line numbers are 16, 19, 24, respectively.

With 3.8, it changes to 16, 18, 21.
msg353284 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-26 09:21
Right, it is intended change.
msg353287 - (view) Author: Thomas Haller (Thomas Haller) Date: 2019-09-26 10:06
Do you have a reference to the discussion about that?
msg353290 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-26 10:25
See issue12458 and issue34372.

Related issues: issue34876, issue16806, issue31241.
msg353292 - (view) Author: Thomas Haller (Thomas Haller) Date: 2019-09-26 11:02
OK, I see. Thanks for the references.

FWIW, I think such changes in behavior are really bad. The issue should be fixed without changing existing API.
msg353295 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-26 11:28
Yes, of course. We could keep f_lineno unchanged, despite the fact that its value can be wrong, and introduce f_lineno_new. Then we should change all code in the stdlib which uses f_lineno to use f_new_lineno, or rather, to keep absolute backward compatibility, add other duplicates: warnings.warn_new(), traceback.print_stack_new(), etc, and encourage all third-party projects to change their code too.

But there are some drawbacks in such approach.
msg353310 - (view) Author: Thomas Haller (Thomas Haller) Date: 2019-09-26 14:30
> We could keep f_lineno unchanged, despite the fact that its value can be wrong

It was not completely wrong. It was seemingly good enough for the past 20+ years.


The change in behaviour is one thing. It's also inconvenient that, even when being aware of the change in behaviour, there is no workaround to get the same number across python versions. Something like:

  if hasattr(frame, 'f_lineno_legacy'):
      return frame.f_lineno_legacy
  else
      return frame.f_lineno

Are you aware of such a workaround?


> But there are some drawbacks in such approach.

Definitely. While I don't agree with the decision and priorities for how the final approach was chosen, thank you for explaining them :)
msg353314 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-26 15:01
No, I do not know such workaround. At best, you can analyze the code object and get the line number of the next instruction. It may be the line past the last line of the function call, or be equal to it if the function call is the part of complex expression or if you write several statements on the line. Then you need to analyze the sources.

The information about the first line of the multiline expression looks more useful than information about the last line. And it is more consistent with other cases. Maybe in future we will add information about the range of lines for every expression and statement (some steps was already made in this direction). But this is more complex change.
History
Date User Action Args
2020-12-02 21:46:26iritkatrielsetstatus: open -> closed
resolution: not a bug
stage: resolved
2019-09-26 15:01:17serhiy.storchakasetmessages: + msg353314
2019-09-26 14:30:42Thomas Hallersetmessages: + msg353310
2019-09-26 11:28:03serhiy.storchakasetmessages: + msg353295
2019-09-26 11:02:23Thomas Hallersetmessages: + msg353292
2019-09-26 10:25:50serhiy.storchakasetmessages: + msg353290
2019-09-26 10:06:10Thomas Hallersetmessages: + msg353287
2019-09-26 09:21:36serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg353284
2019-09-26 09:11:37Thomas Hallersettype: behavior
components: + Interpreter Core
versions: + Python 3.8
2019-09-26 09:10:54Thomas Hallercreate