Ran update_copyright.py.
[hooke.git] / hooke / util / caller.py
1 # Copyright (C) 2010-2011 W. Trevor King <wking@drexel.edu>
2 #
3 # This file is part of Hooke.
4 #
5 # Hooke is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Lesser General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
9 #
10 # Hooke is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
13 # Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with Hooke.  If not, see
17 # <http://www.gnu.org/licenses/>.
18
19 """Define :func:`caller_name`.
20
21 This is useful, for example, to declare the `@callback` decorator for
22 making GUI writing less tedious.  See :mod:`hooke.util.callback` and
23 :mod:`hooke.ui.gui` for examples.
24 """
25
26 import sys
27
28
29 def frame(depth=1):
30     """Return the frame for the function `depth` up the call stack.
31
32     Notes
33     -----
34     The `ZeroDivisionError` trick is from stdlib's traceback.py.  See
35     the Python Refrence Manual on `traceback objects`_ and `frame
36     objects`_.
37
38     .. _traceback objects:
39       http://docs.python.org/reference/datamodel.html#index-873
40     .. _frame objects:
41       http://docs.python.org/reference/datamodel.html#index-870
42     """
43     try:
44         raise ZeroDivisionError
45     except ZeroDivisionError:
46         traceback = sys.exc_info()[2]
47     f = traceback.tb_frame
48     for i in range(depth):
49         f = f.f_back
50     return f
51
52 def caller_name(depth=1):
53     """Return the name of the function `depth` up the call stack.
54
55     Examples
56     --------
57
58     >>> def x(depth):
59     ...     y(depth)
60     >>> def y(depth):
61     ...     print caller_name(depth)
62     >>> x(1)
63     y
64     >>> x(2)
65     x
66     >>> x(0)
67     caller_name
68
69     Notes
70     -----
71     See the Python Refrence manual on `frame objects`_ and
72     `code objects`_.
73
74     .. _frame objects:
75       http://docs.python.org/reference/datamodel.html#index-870
76     .. _code objects:
77       http://docs.python.org/reference/datamodel.html#index-866
78     """
79     f = frame(depth=depth+1)
80     return f.f_code.co_name
81
82 def caller_names(depth=1):
83     """Iterate through the names of all functions up the call stack.
84
85     Examples
86     --------
87
88     >>> def x():
89     ...     y()
90     >>> def y():
91     ...     z()
92     >>> def z():
93     ...     print list(caller_names())
94     >>> x()  # doctest: +ELLIPSIS
95     ['z', 'y', 'x', ...]
96     >>> y()  # doctest: +ELLIPSIS
97     ['z', 'y', ...]
98     >>> z()  # doctest: +ELLIPSIS
99     ['z', ...]
100     """
101     depth = 2  # start at caller_names()'s caller.
102     while True:
103         try:
104             yield caller_name(depth=depth)
105         except AttributeError:
106             return
107         depth += 1