1#
2# Gramps - a GTK+/GNOME based genealogy program
3#
4# Copyright (C) 2000-2007  Donald N. Allingham
5# Copyright (C) 2009       Gary Burton
6# Copyright (C) 2011       Tim G L Lyons
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22
23"""
24Debugging utilities
25"""
26import cProfile
27import pstats
28import sys
29
30
31#-------------------------------------------------------------------------
32#
33# Debugging utilities
34#
35#-------------------------------------------------------------------------
36def profile(func, *args, **kwargs):
37
38    prf = cProfile.Profile()
39    print("Start")
40    r = prf.runcall(func, *args, **kwargs)
41    print("Finished")
42    print("Loading profile")
43    stats = pstats.Stats(prf, stream=sys.stdout)
44    print("done")
45    stats.strip_dirs()
46    stats.sort_stats('time', 'calls')
47    stats.print_stats(100)
48    stats.print_callers(100)
49    return r
50
51def format_exception(tb_type=None, tb_value=None, tb=None):
52    """
53    Get the usual traceback information, followed by a listing of all the
54    local variables in each frame.
55    Based on:
56    code.activestate.com/recipes/52215-get-more-information-from-tracebacks
57    """
58    import sys
59    import traceback
60    if tb_type is None:
61        tb_type = sys.exc_type
62    if tb_value is None:
63        tb_value = sys.exc_value
64    if tb is None:
65        tb = sys.exc_info()[2]
66    retval = traceback.format_exception(tb_type, tb_value, tb) + ["\n"]
67    while tb.tb_next:
68        tb = tb.tb_next
69    stack = []
70    f = tb.tb_frame
71    while f:
72        stack.append(f)
73        f = f.f_back
74    stack.reverse()
75    retval.append("Local variables (most recent frame last):\n")
76    for frame in stack:
77        retval.append(" Frame %s, File \"%s\", line %s:\n" % (frame.f_code.co_name,
78                                                              frame.f_code.co_filename,
79                                                              frame.f_lineno))
80        for key, value in frame.f_locals.items():
81            if key.startswith("__"):
82                continue
83            #We have to be careful not to cause a new error in our error
84            #handler! Calling str() on an unknown object could cause an
85            #error we don't want.
86            try:
87                line = "  %s = %s\n" % (key, str(value))
88            except:
89                line = "  %s = %s\n" % (key, "<ERROR PRINTING VALUE>")
90            retval.append(line)
91    return retval
92