alexmojaki/snoop

snoop only in certain contexts

alexmojaki opened this issue · 9 comments

I came across an interesting idea a debugging library called behold which might be nice for snoop. Suppose you have a function foo() which gets called in many places, but you only want to debug it when it gets called from bar(). You could write:

def bar():
    foo()

@snoop(context='bar')
def foo():
    ...

Or maybe the context depends on a condition:

def bar():
    for i in range(10):
        with snoop.context('five', when=i == 5):
            foo()

@snoop(context='five')
def foo(i):
    ...

Or (forgetting 'context' for a moment) the condition could be declared by snoop based on arguments:

@snoop(when='i == 5')
def foo(i):
    ...

You might sometimes want to test for the context manually:

def foo(i):
    if snoop.context('bar'):
        pp(i)

Lots of possibilities here. Does anyone think this kind of thing seems useful? Ideally, have you encountered any real use cases? Is it worth bloating the library? What would be a good API?

sirex commented

At least this sounds useful:

def foo(i):
    pp(i, when=i > 42)

Why would you prefer that over if i > 42: pp(i)?

sirex commented

I want to keep all debugging code self contained. There are cases, when I leave debugging code for several days, and once I come back to it, I want to clearly see, what is a debugging code and what is not.

So at least this:

if i > 42:
    pp(i)

Is not instantly clear if if block was only added for debugging purposes, or it was part of a real code.

Turning it into one line helps a bit:

if i > 42: pp(i)

But I guess, I never write if statements in one line, so probably I will end up splitting it into two lines. Also I read from left to right, and it is quite possible, that because line starts with if ..., I could easily miss that it ends with pp(....

That is why, I prefer it to be self contained:

pp(i, when=i > 4)

Here I clearly know, that whole this line is just for debugging, and I can remove it without thinking.

Also, this could be combined with context, making it more consistent:

pp(i, when=i > 4, context='debug')

Also, if condition is passed to pp, it gives more control, for example there could be a new column indicating, that this line was executed on a condition.

But I guess these are just my subjective personal preferences.

Interesting. I think the benefit over an if statement is too small to justify the bloat in API and documentation. Maybe if other people are also interested in your API I'd consider it.

What about context? Do you think you've had cases where that would have been useful?

sirex commented

I never used anything similar to context, usually I get away with just if statements.

Personally, I think this pp(i, when=i > 4, context='debug') is very useful and easy to understand, supporting @snoop(i, when=i > 4, context='debug')(for functions methods) and with snoop.context(i, when=i > 4, context='debug')(for single line or code blocks) would be probably sufficient?

I think you're mixing up snoop and pp. @pp and with pp don't mean anything.

I think you're mixing up snoop and pp. @pp and with pp don't mean anything.

Ops, yes, I mean snoop, not pp. Just changed that.

I still think you're confused. snoop(i, ... doesn't mean anything - what is i? @snoop(when=i > 4) is also usually going to be wrong, assuming i is a parameter of the decorated function and therefore not accessible from the decorator, which is why it would be a string: @snoop(when='i > 4').

And with snoop.context(..., context='debug') isn't right either. You either want with snoop.context('debug') (activate a context) or with snoop(context='debug') (trace this block when the given context is active).