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        sys.stderr.write("%s%s: '%s'\n" % (indent, name, value))
137
138def log(name):
139    if debug:
140        frame = inspect.stack()[1][0]
141        value = eval(name, frame.f_globals, frame.f_locals)
142        indent = ' ' * (_report_indent[0])
143        logger("%s%s: %s" % (indent, name, value))
144
145def pprint(name):
146    if debug:
147        frame = inspect.stack()[1][0]
148        value = eval(name, frame.f_globals, frame.f_locals)
149        indent = ' ' * (_report_indent[0])
150        sys.stderr.write("%s%s:\n" % (indent, name))
151        lines = pformat(value).split('\n')
152        for line in lines:
153            sys.stderr.write("%s %s\n"%(indent, line))
154
155def dir(name):
156    if debug:
157        name = "dir(%s)" % name
158        frame = inspect.stack()[1][0]
159        value = eval(name, frame.f_globals, frame.f_locals)
160        indent = ' ' * (_report_indent[0])
161        sys.stderr.write("%s%s:\n" % (indent, name))
162        lines = pformat(value).split('\n')
163        for line in lines:
164            sys.stderr.write("%s %s\n"%(indent, line))
165
166def type(name):
167    if debug:
168        name = "type(%s)" % name
169        frame = inspect.stack()[1][0]
170        value = eval(name, frame.f_globals, frame.f_locals)
171        indent = ' ' * (_report_indent[0])
172        sys.stderr.write("%s%s: %s\n" % (indent, name, value))
173
174def say(s):
175    if debug:
176        indent = ' ' * (_report_indent[0])
177        sys.stderr.write("%s%s\n" % (indent, s))
178        sys.stderr.flush()
179
180def profile(fn):
181    def wrapper(*args, **kwargs):
182        datafn = fn.__name__ + ".profile" # Name the data file sensibly
183        prof = cProfile.Profile()
184        retval = prof.runcall(fn, *args, **kwargs)
185        prof.dump_stats(datafn)
186        return retval
187    if debug:
188        from decorator import decorator
189        return decorator(wrapper, fn)
190    else:
191        return fn
192
193def traceback(levels=None):
194    if debug:
195        indent = ' ' * (_report_indent[0])
196        sys.stderr.write("\n%s---- Stack ----\n" % indent)
197        if levels:
198            start = -2-levels
199        else:
200            start = None
201        for s in tb.format_stack()[start:-1]:
202            sys.stderr.write("%s%s" % (indent, s))
203        sys.stderr.write("%s---------------\n" % indent)
204
205def show_caller(level=None):
206    if debug:
207        indent = ' ' * (_report_indent[0])
208        if level is None:
209            level = -3
210        sys.stderr.write("%sCalled from %s\n" % (indent, tb.format_stack()[level].strip()[4:]))
211
212def info(name):
213    if debug:
214        frame = inspect.stack()[1][0]
215        value = eval(name, frame.f_globals, frame.f_locals)
216        vtype = eval("type(%s)"%name, frame.f_globals, frame.f_locals)
217        indent = ' ' * (_report_indent[0])
218        sys.stderr.write("%s%s: '%s' (%s)\n" % (indent, name, value, vtype))
219