-
-
Save vladimirmyshkovski/9d4c5b0da2ebe18f899384e366b89fa9 to your computer and use it in GitHub Desktop.
Print a Python function's arguments every time it is called
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file defines a decorator '@log_to()' that logs every call to a | |
# function, along with the arguments that function was called with. It | |
# takes a logging function, which is any function that accepts a | |
# string and does something with it. A good choice is the debug | |
# function from the logging module. A second decorator '@logdebug' is | |
# provided that uses 'logging.debug' as the logger. | |
from __future__ import print_function | |
from functools import wraps | |
from inspect import getcallargs, getargspec | |
from collections import OrderedDict, Iterable | |
from itertools import * | |
import logging | |
def flatten(l): | |
"""Flatten a list (or other iterable) recursively""" | |
for el in l: | |
if isinstance(el, Iterable) and not isinstance(el, basestring): | |
for sub in flatten(el): | |
yield sub | |
else: | |
yield el | |
def getargnames(func): | |
"""Return an iterator over all arg names, including nested arg names and varargs. | |
Goes in the order of the functions argspec, with varargs and | |
keyword args last if present.""" | |
(argnames, varargname, kwargname, _) = getargspec(func) | |
return chain(flatten(argnames), ifilter(None, [varargname, kwargname])) | |
def getcallargs_ordered(func, *args, **kwargs): | |
"""Return an OrderedDict of all arguments to a function. | |
Items are ordered by the function's argspec.""" | |
argdict = getcallargs(func, *args, **kwargs) | |
return OrderedDict((name, argdict[name]) for name in getargnames(func)) | |
def describe_call(func, *args, **kwargs): | |
yield "Calling %s with args:" % func.__name__ | |
for argname, argvalue in getcallargs_ordered(func, *args, **kwargs).iteritems(): | |
yield "\t%s = %s" % (argname, repr(argvalue)) | |
def log_to(logger_func): | |
"""A decorator to log every call to function (function name and arg values). | |
logger_func should be a function that accepts a string and logs it | |
somewhere. The default is logging.debug. | |
If logger_func is None, then the resulting decorator does nothing. | |
This is much more efficient than providing a no-op logger | |
function: @log_to(lambda x: None). | |
""" | |
if logger_func is not None: | |
def decorator(func): | |
@wraps(func) | |
def wrapper(*args, **kwargs): | |
for line in describe_call(func, *args, **kwargs): | |
logger_func(line) | |
return func(*args, **kwargs) | |
return wrapper | |
else: | |
decorator = lambda x: x | |
return decorator | |
logdebug = log_to(logging.debug) | |
@logdebug | |
def myfunc(a,b,c, *args, **kwargs): | |
pass | |
if __name__ == "__main__": | |
logging.basicConfig(level=logging.DEBUG) | |
myfunc(1,2,3,4,5,6,x=7,y=8,z=9,g="blarg", f=lambda x: x+2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment