Method and class method debugging decorator A little while ago in The 2nd Monitor, me and @Phrancis were talking about Python and debugging, and the topic of function decorators came up with this message:


  Ethan Bierlein: You could even build a debug decorator. Give me a sec.


So, I built a small, simple debugging decorator, which would just print out the arguments of any method it was applied to.



I decided to go a little further though, and build two separate decorators. One for regular methods, and one built specifically for class methods. Essentially, the regular method decorator takes a function, and will print out it's arguments, and keyword arguments if debug=True. The class method decorator does the same, except it also prints out the attributes of the class it's contained in as well.

I'm wondering a couple of things though:


Is this a "pythonic" way to debug the arguments of a function?
Is there any additional data that should be debugged, that I missed?
Is the extra ClassMethodDecorator really needed? Or is there a simpler way to support both with one decorator?
I've built this to be Python 3, and Python 2.7 compatible. Did I do this correctly?


debug.py

from pprint import pprint

class MethodDebug(object):
    """Debug a normal method.

    This decorator is used for debugging a normal method,
    with normal arguments, i.e, not printing out the data
    of the class it's contained in.

    Keyword arguments:
    debug -- Whether or not you want to debug the method.
    """
    def __init__(self, debug):
        self.debug = debug

    def __call__(self, function):
        def wrapper(*args, **kwargs):
            if self.debug:
                pprint(args)
                pprint(kwargs)
            return function(*args, **kwargs)
        return wrapper


class ClassMethodDebug(object):
    """Debug a class method.

    This decorator is used for debugging a class method,
    with normal arguments, and self. When using this
    decorator, the method will print out it's arguments
    and the attributes of the class it's contained in.

    Keyword arguments:
    debug -- Whether or not you want to debug the method.
    """
    def __init__(self, debug):
        self.debug = debug

    def __call__(self, function):
        def wrapper(function_self, *args, **kwargs):
            if self.debug:
                pprint(function_self.__dict__)
                pprint(args)
                pprint(kwargs)
            return function(function_self, *args, **kwargs)
        return wrapper


test.py

from debug import MethodDebug, ClassMethodDebug

@MethodDebug(debug=True)
def normal_method(a, b):
    return a * b

print(normal_method(10, 10))


class TestClass(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    @ClassMethodDebug(debug=True)
    def class_method(self, c):
        return self.a * self.b * c

a = TestClass(10, 10)
print(a.class_method(10))
To address your specific questions:


Is it Pythonic enough? I think so.
Is there any additional data that should be debugged? If I was using this for my debugging, I’d want a bit more information:


The name of the function that’s been called – knowing which args/kwargs were supplied to an unknown function is not that useful
The return value of that function
A trace statement when the function returns


There should also be something to distinguish trace output from regular output. That makes it much easier for me to reconstruct the call flow afterwards. Here’s an example of the sort of output I mean:

[trace] enter my_function {
[trace]   args: (10, 10)
[trace]   kwargs: {}
hello world
[trace] return 100 } exit my_function


For extra brownie points, use the traceback module to indent a function and its arguments/return value to match their level in the call tree.
Do I need a separate function and method decorator? It seems like it would be possible to do. I haven’t tried it, but https://stackoverflow.com/q/19314405/1558022 seems like it might have a couple of approaches.

If applied to a method, your function decorator will always print the repr() of the object. That might be enough in most cases – perhaps rather than defining a second decorator, you add an argument debug_object to your function decorator which additionally prints the object dict on demand.
Is it compatible with Python 2.7 and Python 3? As far as I can tell, yes.




Two other (minor) comments:


I would rename the decorators. The first is misleading, because it’s described as “method debug”, but actually gets applied to functions. More generally, I’d be inclined to violate naming principles and make these lowercase instead, so they don’t look out of place next to the decorated functions. I’d probably call them something like @internaltrace.
The docstring for “debug” is not very useful. A better docstring would tell me exactly what debugging means in this context – here, something like “print the arguments supplied to the function” would be better.

I’d be inclined to rename this parameter to “trace”, but I think correcting the docstring is more important.




A couple of additional ideas that came to me this morning:


You might want to tie this into the logging library, and direct all trace output to a dedicated file (say inttrc.log). That isolates trace statements from regular prints without putting [trace] everywhere, and is easier to search through later.

This will get you timestamps, which are worth including, but I forgot about yesterday.
Although pprint is nice, I think a one-line string might be better. You can always unpack it later if you need to, but having all the associated parts of args/kwargs on the same line will be easy for parsing later.