Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Debugging decorator

51 views
Skip to first unread message

Yaşar Arabacı

unread,
Oct 25, 2013, 7:55:23 PM10/25/13
to pytho...@python.org
Hi people,

I wrote this decorator: https://gist.github.com/yasar11732/7163528

When this code executes:

@debugging
def myfunc(a, b, c, d = 48):
a = 129
return a + b

print myfunc(12,15,17)

This is printed:

function myfunc called
a 12
c 17
b 15
d 48
assigned new value to a: 129
returning 144
144

I think I can be used instead of inserting and deleting print
statements when trying to see what is
passed to a function and what is assingned to what etc. I think it can
be helpful during debugging.

It works by rewriting ast of the function and inserting print nodes in it.

What do you think?


--
http://ysar.net/

Chris Angelico

unread,
Oct 25, 2013, 11:08:03 PM10/25/13
to pytho...@python.org
On Sat, Oct 26, 2013 at 10:55 AM, Yaşar Arabacı <yasar...@gmail.com> wrote:
> I think I can be used instead of inserting and deleting print
> statements when trying to see what is
> passed to a function and what is assingned to what etc. I think it can
> be helpful during debugging.
>
> It works by rewriting ast of the function and inserting print nodes in it.
>
> What do you think?

Technologically very cool! I don't know that I'd ever use it for
actual debugging, especially as it'll get VERY spammy as soon as you
start working with complex objects, but it looks like a fun thing to
play with. I see it as a parallel to dis.dis() - one looks at the
disassembly and the other at the resulting actions, and between them
you can get a fairly good idea of what's happening.

Still don't know of any places I'd actually use it productively, but
hey, nothing wrong with cool toys :)

ChrisA

Eric S. Johansson

unread,
Oct 27, 2013, 1:49:09 PM10/27/13
to pytho...@python.org

On 10/25/2013 7:55 PM, Yaşar Arabacı wrote:
> Hi people,
>
> I wrote this decorator: https://gist.github.com/yasar11732/7163528
>
>
wow, this looks really powerful. I would like to add the ability to
associate a tag or set of tags with the decorator so that the debug
output only happens when there is a matching tag in some global or
environmental variable.

Schneider

unread,
Oct 28, 2013, 8:43:38 AM10/28/13
to pytho...@python.org

On 10/26/2013 01:55 AM, Yaşar Arabacı wrote:
> Hi people,
>
> I wrote this decorator: https://gist.github.com/yasar11732/7163528
>
> When this code executes:
>
> @debugging
> def myfunc(a, b, c, d = 48):
> a = 129
> return a + b
>
> print myfunc(12,15,17)
>
> This is printed:
>
> function myfunc called
> a 12
> c 17
> b 15
> d 48
> assigned new value to a: 129
> returning 144
> 144
>
> I think I can be used instead of inserting and deleting print
> statements when trying to see what is
> passed to a function and what is assingned to what etc. I think it can
> be helpful during debugging.
>
> It works by rewriting ast of the function and inserting print nodes in it.
>
> What do you think?
>
>

Looks very nice, but I've three questions:

1. What happens, if a function has more then one decorator? Wouldn't it
be better to
just remove the debugging decorator instead of removing all decorators?

2. In the case of an assignment (but holds for the return statement too).
think about the following code:

a = 0
@debugging
def foo():
a = a + 1

def bar():
#assign something else to a

Imagine foo() and bar() being called in two different threads. Wouldn't
it be better

to replace a = a + 1 by

|global_debugging_lock_objekt.acquire()|
a = a + 1
print "assigned new value to a, %r", a
|global_debugging_lock_objekt.release()|

for some global lock object.

3. What happens in the case of a += 1?

bg,
Johannes

--
GLOBE Development GmbH
Königsberger Strasse 260
48157 MünsterGLOBE Development GmbH
Königsberger Strasse 260
48157 Münster
0251/5205 390

Chris Angelico

unread,
Oct 28, 2013, 9:00:53 AM10/28/13
to pytho...@python.org
On Mon, Oct 28, 2013 at 11:43 PM, Schneider <j...@globe.de> wrote:
> 2. In the case of an assignment (but holds for the return statement too).
> think about the following code:
>
> a = 0
> @debugging
> def foo():
> a = a + 1
>
> def bar():
> #assign something else to a
>
> Imagine foo() and bar() being called in two different threads.

I think threading considerations are rather outside the scope of this
tool. If you're trying to figure out what happens when two threads
mutate the same global, you really want something a lot more
heavy-duty... possibly static code analysis to work out what *might*
happen, rather than what *did* happen this particular run.

ChrisA

Jason Friedman

unread,
Nov 3, 2013, 5:55:08 AM11/3/13
to Yaşar Arabacı, python-list
I ran it with Python 2 and thought it was neat.
Most of my work is Python 3.
I ran 2to3-3.3 against it and I am getting this error:

$ ./simple.py 
Traceback (most recent call last):
  File "./simple.py", line 3, in <module>
    @debugger.debugging
  File "/home/jason/python/debugger.py", line 41, in debugging
    new_function_body.append(make_print_node("function %s called" % func.__name__))
  File "/home/jason/python/debugger.py", line 6, in make_print_node
    return ast.Print(dest=None, values=[ast.Str(s=s)], nl=True)
AttributeError: 'module' object has no attribute 'Print'

Chris Angelico

unread,
Nov 3, 2013, 8:22:08 AM11/3/13
to pytho...@python.org
On Mon, Nov 4, 2013 at 12:20 AM, Chris Angelico <ros...@gmail.com> wrote:
> As print is now a function, you're going to need to construct a
> function call element instead of a special 'print' node. I don't know
> how to do that as I'm not an AST expert, but hopefully you can work it
> out from there?
>
> If you need it to be cross-version, you could probably use
> sys.stdout.write explicitly (not forgetting to add a newline, which
> print does and write - obviously - doesn't). Or just demand that "from
> __future__ import print_function" be used, which will make 2.7 like
> 3.3.

Oh, I just noticed that the person using 2to3 wasn't the OP. My
apologies, my language was aimed at the decorator's primary developer.
Yasar, are you prepared to take on Python 3 support fully? If it's as
simple as tweaking the Print nodes, that shouldn't be too hard (I
hope).

ChrisA

Chris Angelico

unread,
Nov 3, 2013, 8:20:03 AM11/3/13
to pytho...@python.org
Ah, that'd be because 'print' is no longer a statement. Check out this
function's disassembly:

def hello_world():
print("Hello, world!")

Python 2.7:
2 0 LOAD_CONST 1 ('Hello, world!')
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE

Python 3.3:
2 0 LOAD_GLOBAL 0 (print)
3 LOAD_CONST 1 ('Hello, world!')
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 0 (None)
13 RETURN_VALUE

As print is now a function, you're going to need to construct a
function call element instead of a special 'print' node. I don't know
how to do that as I'm not an AST expert, but hopefully you can work it
out from there?

If you need it to be cross-version, you could probably use
sys.stdout.write explicitly (not forgetting to add a newline, which
print does and write - obviously - doesn't). Or just demand that "from
__future__ import print_function" be used, which will make 2.7 like
3.3.

ChrisA

Yaşar Arabacı

unread,
Nov 3, 2013, 4:10:20 PM11/3/13
to Chris Angelico, pytho...@python.org
I don't think it would be much problem. I can do that when I have spare time.

Yasar.

> Oh, I just noticed that the person using 2to3 wasn't the OP. My
> apologies, my language was aimed at the decorator's primary developer.
> Yasar, are you prepared to take on Python 3 support fully? If it's as
> simple as tweaking the Print nodes, that shouldn't be too hard (I
> hope).

> ChrisA

--
http://ysar.net/
0 new messages