from time import time
from sys import argv
from functools import wraps
from types import FunctionType
[docs]def set_debug():
"""
Allow for setting debugging from the command line.
eg. ``--debug [ io core ]``
"""
try:
debug = argv.index("--debug")
string = set([])
try:
start = argv.index("[")
end = argv.index("]")
string = {argv[i] for i in range(start + 1, end)}
del argv[end]
for i, j in enumerate(string):
del argv[argv.index(j)]
del argv[start]
del argv[debug]
except ValueError:
del argv[debug]
WHAT_TO_DEBUG = string
DBG = True
except ValueError:
if argv[0] == "Regtests.py":
debug_v = input("Enter debugging variables:\n")
WHAT_TO_DEBUG = set(debug_v.split())
DBG = True
else:
WHAT_TO_DEBUG = set([])
DBG = False
return WHAT_TO_DEBUG, DBG
[docs]class v_print():
"""Debug printing."""
def __init__(self, verbose):
"""Print switch."""
if verbose:
self.print = self._print
else:
self.print = self._dont_print
@staticmethod
def _print(*a, **k):
return print(*a, **k)
@staticmethod
def _dont_print(*a, **k):
pass
WHAT_TO_DEBUG, DBG = set_debug()
verb = v_print(DBG)
[docs]class debug:
"""
Debugging helper.
Aspects are provided as list of arguments which are decorators of the function to debug.
eg. ``set(['io','core'])``
the flag TT will print out the run time for each function only
Inspiration from https://wiki.python.org/moin/PythonDecoratorLibrary#Controllable_DIY_debug
"""
def __init__(self, aspects=None):
"""Set __call__ to debug version if needed."""
if DBG:
self.aspects = set(aspects)
self.f_dict = {}
setattr(debug, '__call__', self.dcall)
self.call = self.dcall
self.no_parallel = "--no-parallel" in argv
@staticmethod
def __call__(f):
"""Do nothing if not in debugging mode."""
return f
[docs] def dcall(self, f):
"""
Wrap function to print debugging info.
Generically gives all wrapped class methods the DBG variable
Can be used to carry out debugging methods (eg. if hasattr(self, "DBG"): ...)
If specifically selected with aspects, prints timing and/or arguments
"""
@wraps(f)
def f_DBG(*args, **kwds):
if f.__name__ == "__init__" and (hasattr(args[0], "__dict__") or hasattr(args[0], "__slots__")):
args[0].DBG = True
elif isinstance(f, FunctionType) and ((len(args) > 0 and not hasattr(args[0], "DBG")) or len(args) == 0):
f_DBG.DBG = True
return f(*args, **kwds)
if ((self.aspects & WHAT_TO_DEBUG) or ('all' in WHAT_TO_DEBUG)) and 'STEP_THROUGH' not in WHAT_TO_DEBUG:
@wraps(f_DBG)
def newf(*args, **kwds):
# checks for self could be better?
if "TT" not in WHAT_TO_DEBUG:
print(f.__name__, args, kwds, [a.__dict__ for a in args if hasattr(a, '__dict__')])
self.start_timer(f.__name__)
f_result = f_DBG(*args, **kwds)
timing(f.__name__, self.f_dict[f.__name__], f_result)
return f_result
return newf
if ("STEP_THROUGH" in WHAT_TO_DEBUG) and (self.aspects & WHAT_TO_DEBUG):
from numpy import ndarray
@wraps(f_DBG)
def stepthrough(*args, **kwds):
print(f_DBG.__name__)
print(*args[1:], **kwds)
out = f_DBG(*args, **kwds)
for i, j in out.items():
print(i)
if isinstance(j, ndarray):
for v in j:
for vv in v:
print(vv)
else:
print(j)
if self.no_parallel:
input()
return out
return stepthrough
return f_DBG
[docs] def start_timer(self, fname):
"""Start timer."""
if fname not in self.f_dict:
self.f_dict[fname] = {"startf": time(), 'tt': 0}
else:
self.f_dict[fname]['startf'] = time()
[docs]def timing(name, f_dict, f_result=None):
"""
Time functions.
Get total run time of functions
"""
f_dict["endf"] = time()
f_dict["step"] = f_dict["endf"] - f_dict["startf"]
f_dict["tt"] += f_dict["step"]
if f_result is None:
print(name, "took {:13.5e}s total {:13.5e}s".format(f_dict[
"step"], f_dict["tt"]))
else:
print(name, "took {:13.5e}s total {:13.5e}s".format(f_dict[
"step"], f_dict["tt"]), "returned", f_result)
[docs]def profile(*args, file=None):
"""Profile code."""
from cProfile import Profile
import pstats
prof = Profile()
out = prof.runcall(*args) # main, argparse, opts) calc.run, stat)
pstats.Stats(prof).strip_dirs().dump_stats(file)
return out
if __name__ == '__main__':
pass