1import os
2import sys
3import time as timeutils
4import inspect
5
6try:
7    import syslog
8    logger = syslog.syslog
9except ImportError:                     # import syslog will fail on Windows boxes
10    import logging
11    logging.basicConfig(filename='tracker.log',level=logging.INFO)
12    logger = logging.info
13
14try:
15    from pprint import pformat
16except ImportError:
17    pformat = lambda x: x
18
19import cProfile
20import traceback as tb
21
22# A debug decorator, written by Paul Butler, taken from
23# http://paulbutler.org/archives/python-debugging-with-decorators/
24# Additional functions and decorator functionality added by
25# Henrik Levkowetz
26
27__version__ = "0.16"
28
29increment = 2
30
31debug = False
32
33# Number of times to indent output
34# A list is used to force access by reference
35_report_indent = [4]
36_mark = [ timeutils.time() ]
37
38def set_indent(i):
39    _report_indent[0] = i
40
41def trace(fn):                 # renamed from 'report' by henrik 16 Jun 2011
42    """Decorator to print information about a function
43    call for use while debugging.
44    Prints function name, arguments, and call number
45    when the function is called. Prints this information
46    again along with the return value when the function
47    returns.
48    """
49    def fix(s,n=64):
50        import re
51        s = re.sub(r'\\t', ' ', s)
52        s = re.sub(r'\s+', ' ', s)
53        if len(s) > n+3:
54            s = s[:n]+"..."
55        return s
56    def wrap(fn, *params,**kwargs):
57        call = wrap.callcount = wrap.callcount + 1
58
59        indent = ' ' * _report_indent[0]
60        fr = tb.format_stack()[-3].strip()[4:]                      # call from
61        fi, co = [ l.strip() for l in fr.splitlines()[:2] ]         # file info, code
62        fu = "%s.%s()" % (fn.__module__, fn.__name__)               # function name
63        fc = "%s(%s)" % (fn.__name__, ', '.join(                    # function call
64            [fix(repr(a)) for a in params] +
65            ["%s = %s" % (a, fix(repr(b))) for a,b in kwargs.items()]
66        ))
67
68        if debug:
69            sys.stderr.write("\n%s  From %s:\n%s  |  %s\n%s  %s\n%s* %s [#%s]\n" %
70                (indent, fi, indent, co, indent, fu, indent, fc, call))
71        _report_indent[0] += increment
72        mark = timeutils.time()
73        ret = fn(*params,**kwargs)
74        tau = timeutils.time() - mark
75        _report_indent[0] -= increment
76        if debug:
77            sys.stderr.write("%s  %s | %.3fs [#%s] ==> %s\n" % (indent, fc, tau, call, fix(repr(ret))))
78
79        return ret
80    wrap.callcount = 0
81    if debug:
82        from decorator import decorator
83        return decorator(wrap, fn)
84    else:
85        return fn
86
87def mark():
88    def show_entry(e):
89        sys.stderr.write(" at %s:L%s %s() %s\n" % e)
90    if debug:
91        indent = ' ' * (_report_indent[0])
92        file, line, func, text = tb.extract_stack(None, 2)[0]
93        parts = file.split(os.sep)
94        name = os.sep.join(parts[-2:])
95        sys.stderr.write("%sMark %s:%s\n" % (indent, name, line))
96        _mark[0] = timeutils.time()
97
98def lap(s):
99    if debug:
100        clk = timeutils.time()
101        tau = clk - _mark[0]
102        ts = timeutils.strftime("%H:%M:%S", timeutils.localtime(clk))
103        say("%s: %.3fs since mark: %s" % (ts, tau, s))
104
105def clock(s):
106    if debug:
107        lap(s)
108        _mark[0] = timeutils.time()
109
110def time(fn):
111    """Decorator to print timing information about a function call.
112    """
113    def wrap(fn, *params,**kwargs):
114
115        indent = ' ' * _report_indent[0]
116        fc = "%s.%s()" % (fn.__module__, fn.__name__,)
117
118        mark = timeutils.time()
119        ret = fn(*params,**kwargs)
120        tau = timeutils.time() - mark
121        sys.stderr.write("%s| %s | %.3fs\n" % (indent, fc, tau))
122
123        return ret
124    wrap.callcount = 0
125    if debug:
126        from decorator import decorator
127        return decorator(wrap, fn)
128    else:
129        return fn
130
131def show(name):
132    if debug:
133        frame = inspect.stack()[1][0]
134        value = eval(name, frame.f_globals, frame.f_locals)
135        indent = ' ' * (_report_indent[0])
136        if sys.version_info.major == 2:
137            sys.stderr.write((u"%s%s: '%s'\n" % (indent, name, value)).encode('utf8'))
138        else:
139            sys.stderr.write((u"%s%s: '%s'\n" % (indent, name, value)))
140
141def log(name):
142    if debug:
143        frame = inspect.stack()[1][0]
144        value = eval(name, frame.f_globals, frame.f_locals)
145        indent = ' ' * (_report_indent[0])
146        logger("%s%s: %s" % (indent, name, value))
147
148def pprint(name):
149    if debug:
150        frame = inspect.stack()[1][0]
151        value = eval(name, frame.f_globals, frame.f_locals)
152        indent = ' ' * (_report_indent[0])
153        sys.stderr.write("%s%s:\n" % (indent, name))
154        lines = pformat(value).split('\n')
155        for line in lines:
156            sys.stderr.write("%s %s\n"%(indent, line))
157
158def dir(name):
159    if debug:
160        name = "dir(%s)" % name
161        frame = inspect.stack()[1][0]
162        value = eval(name, frame.f_globals, frame.f_locals)
163        indent = ' ' * (_report_indent[0])
164        sys.stderr.write("%s%s:\n" % (indent, name))
165        lines = pformat(value).split('\n')
166        for line in lines:
167            sys.stderr.write("%s %s\n"%(indent, line))
168
169def type(name):
170    if debug:
171        name = "type(%s)" % name
172        frame = inspect.stack()[1][0]
173        value = eval(name, frame.f_globals, frame.f_locals)
174        indent = ' ' * (_report_indent[0])
175        sys.stderr.write("%s%s: %s\n" % (indent, name, value))
176
177def say(s):
178    if debug:
179        indent = ' ' * (_report_indent[0])
180        sys.stderr.write("%s%s\n" % (indent, s))
181        sys.stderr.flush()
182
183def profile(fn):
184    def wrapper(*args, **kwargs):
185        datafn = fn.__name__ + ".profile" # Name the data file sensibly
186        prof = cProfile.Profile()
187        retval = prof.runcall(fn, *args, **kwargs)
188        prof.dump_stats(datafn)
189        return retval
190    if debug:
191        from decorator import decorator
192        return decorator(wrapper, fn)
193    else:
194        return fn
195
196def traceback(levels=None):
197    if debug:
198        indent = ' ' * (_report_indent[0])
199        sys.stderr.write("\n%s---- Stack ----\n" % indent)
200        if levels:
201            start = -2-levels
202        else:
203            start = None
204        for s in tb.format_stack()[start:-1]:
205            sys.stderr.write("%s%s" % (indent, s))
206        sys.stderr.write("%s---------------\n" % indent)
207
208def show_caller(level=None):
209    if debug:
210        indent = ' ' * (_report_indent[0])
211        if level is None:
212            level = -3
213        sys.stderr.write("%sCalled from %s\n" % (indent, tb.format_stack()[level].strip()[4:]))
214
215def info(name):
216    if debug:
217        frame = inspect.stack()[1][0]
218        value = eval(name, frame.f_globals, frame.f_locals)
219        vtype = eval("type(%s)"%name, frame.f_globals, frame.f_locals)
220        indent = ' ' * (_report_indent[0])
221        sys.stderr.write("%s%s: '%s' (%s)\n" % (indent, name, value, vtype))
222