cool-RR / PySnooper

Never use print for debugging again
MIT License
16.37k stars 951 forks source link

`return` event line missing when exception occurred #242

Closed yantaozhao closed 1 year ago

yantaozhao commented 1 year ago

When exception occurred, the return event is not recorded in snoop log. This leaves an unbalanced call-return pairs.

Expected behavior: all event should properly be recorded even though exception happened.

demo code:

import pysnooper

def bar(a, b):
    return a + b

def baz():
    try:
        x = 'hi' + 1  # exception here!
        return 1
    except:
        raise  # <- return event missing
    return -1

def foo():
    r = bar(2, 3)
    print(r)
    return r

@pysnooper.snoop(depth=2, normalize=True)
def main():
    foo()
    try:
        baz()
    except:
        pass

main()

image

In the above demo, return event in line 13 is not recorded like line 20 do. the call-return pair is broken.

cool-RR commented 1 year ago

Which versions of PySnooper and Python? And what OS?

yantaozhao commented 1 year ago

python 3.10, PySnooper 1.2.0, all platforms

cool-RR commented 1 year ago

Ah, it's possible that I have just caused this bug with this most recent version. I'll look into it.

cool-RR commented 1 year ago

If you're interested in writing a failing test case, that'll be helpful.

yantaozhao commented 1 year ago

commit a PR to fix this issue.

cool-RR commented 1 year ago

Can you explain why there should be a return line when an exception is raised? Can you explain what practical problem it causes that this line doesn't exist?

yantaozhao commented 1 year ago

Can you explain why there should be a return line when an exception is raised?

No matter exception raised or not, all return event should be recorded because it really happened. Additionally it make things easy to write a log analyser as the call-return pairs are balanced.

Can you explain what practical problem it causes that this line doesn't exist?

For log readable, consider below example:

import pysnooper

def bar(a, b):
    return a + b

def baz():
    try:
        x = 'hi' + 1  # exception here!
        return 1
    except:
        raise
    finally:  # <-do something and output
        a=1
        b=2
        c=a+b
        foo()
    return -1

def foo():
    r = bar(2, 3)
    print(r)
    return [8]

@pysnooper.snoop(depth=9, normalize=True)
def main():
    try:
        baz()
    except:
        pass

main()

image

if return 18 was not recorded, athough it can, but will spend more time to find that the code ran to and returned from line 18.

alexmojaki commented 1 year ago

It make things easy to write a log analyser

It sounds like you might prefer using something like https://github.com/ionelmc/python-hunter. Or just writing your own function for sys.settrace.

cool-RR commented 1 year ago

@yantaozhao Sorry, I'm not seeing the practical usage here. It actually sounds misleading to write "return" when a function exited because of an exception rather than returned a value. I'm not sure what your use case is, but it sounds like it's a very niche use case that's not worth compromising for.