I'm on a quest for making a good debug_print() method for printing out debug information in some of my private projects. When testing I aliased my debug_print() imported from a module to debug() print, and some of the intrinsic of my code stopped working.
This led to a question on Stack Overflow, which with a little nudge in the right direction from SuperBiasedMan, led to the following code which I would like for you to review. First the code from utilities.py:
import inspect
import re
DEBUG_FLAG = True
def _log_args(*args):
"""Uses reflection to returning passing argument code with values."""
prev_frame = inspect.currentframe().f_back
func_name = prev_frame.f_code.co_name
code_context = inspect.getframeinfo(prev_frame.f_back).code_context[0].strip()
# Do some magic, which does work _unless_ func_name is aliased :-)
print('code context : {}'.format(code_context))
print('func_name : {}'.format(func_name))
## Main focus area for review starts here
globals_copy = globals()
# Extract legal tokens from code_context
tokens = re.compile('[_a-zA-Z][a-zA-Z_0-9]*').findall(code_context)
for token in tokens:
# print( ' Checking token : {}'.format(token))
# Check if token is found as an object in globals()
code_object = globals_copy.get(token, None)
if not code_object:
continue
# Check if code_object is one of my userdefined functions
if inspect.isfunction(code_object):
code_func_name = getattr(code_object, '__name__', None)
else:
continue
# Check if expanded token is actually an alias (or equal) to func_name
if code_func_name == func_name:
func_name = token
break
else:
# For-loop went through all tokens, and didn't find anything
func_name = None
if func_name:
print('Calling function : {}'.format(func_name))
else:
print('Didn\'t find a calling function?!')
## Main focus area for review ends here
return ', '.join(str(arg) for arg in args)
def format_args(*args):
"""Returns string with name of arguments with values."""
return _log_args(args)
def debug_print(*args):
"""Prints name of arguments with values."""
if DEBUG_FLAG:
print _log_args(args)
And then some test code from another file:
from utilities import debug_print, format_args, debug_print as debug, format_args as fargs
def main():
a, b = "text", (12, 13)
print "== Unaliased =="
test_text = format_args(a, b)
print test_text # Returns
debug_print(a, b)
print "\n== Aliased =="
test_text = fargs(a, b)
print test_text # Returns
debug(a, b)
if __name__ == '__main__':
main()
The current output reflects that this is a work in progress, and the main focus for this review is commented upon in the code.
== Unaliased ==
code context : test_text = format_args(a, b)
func_name : format_args
Calling function : format_args
('text', (12, 13))
code context : debug_print(a, b)
func_name : debug_print
Calling function : debug_print
('text', (12, 13))
== Aliased ==
code context : test_text = fargs(a, b)
func_name : format_args
Calling function : fargs
('text', (12, 13))
code context : debug(a, b)
func_name : debug_print
Calling function : debug
('text', (12, 13)