Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you write a @debuggable decorator in python?

When debugging, I like to print out all the inputs and outputs of a function (I know I need a better IDE, but humour me, this could be used for error reporting). So, I'd ideally like to have:

@debuggable
def myfunc(argA,argB,argC):
    return argB+1

and use a global variable to switch on or off debugging. No, you don't like globals either, I guessed.

The best I can come up with is:

DEBUG = True

def debuggable(func):
    if DEBUG:
        def decorated(*args):
            print "Entering ",func.func_name
            print "    args ",args
            ret = func(*args)
            print ret
            return ret
        return decorated
    else:
        return func

@debuggable
def myfunc(this,that):
    return this+that

And running:

>>> myfunc(1,3)
Entering  myfunc
   args  (1, 3)
4

How can I improve that?

like image 388
Phil H Avatar asked May 14 '09 11:05

Phil H


2 Answers

Use a debugger. Seriously. Decorating every function you want to keep track is a bad idea.

Python has a debugger included, so you don't need a good IDE.

If you don't want to use a debugger, you can use the trace function.

import sys

@sys.settrace
def trace_debug(frame, event, arg):
    if event == 'call':
        print ("calling %r on line %d, vars: %r" % 
                (frame.f_code.co_name, 
                 frame.f_lineno,
                 frame.f_locals))
        return trace_debug
    elif event == "return":
        print "returning", arg

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

print fun1(1, 2)

That prints:

calling 'fun1' on line 14, vars: {'a': 1, 'b': 2}
returning 3
3

Even easier would be to use Winpdb:

It is a platform independent graphical GPL Python debugger with support for remote debugging over a network, multiple threads, namespace modification, embedded debugging, encrypted communication and is up to 20 times faster than pdb.

Features:

  • GPL license. Winpdb is Free Software.
  • Compatible with CPython 2.3 or later.
  • Compatible with wxPython 2.6 or later.
  • Platform independent, and tested on Ubuntu Gutsy and Windows XP.
  • User Interfaces: rpdb2 is console based, while winpdb requires wxPython 2.6 or later.

Screenshot
(source: winpdb.org)

like image 64
nosklo Avatar answered Oct 14 '22 00:10

nosklo


I agree with nosklo using a debugger is much better than writing your own. I'll post an improvement to your code. But I still think you should follow nosklo's advice.

Use decorator classes to make your debugger neater:

class Debugger(object):
    enabled = False
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        if self.enabled:
            print 'Entering', self.func.func_name 
            print '    args:', args, kwargs
        return self.func(*args, **kwargs)

Debugger.enabled = True

@Debugger
def myfunc(a, b, c, d):
    pass
like image 36
Nadia Alramli Avatar answered Oct 14 '22 01:10

Nadia Alramli