lsst.pex.config  18.1.0-3-g6b74884
callStack.py
Go to the documentation of this file.
1 # This file is part of pex_config.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 
22 __all__ = ['getCallerFrame', 'getStackFrame', 'StackFrame', 'getCallStack']
23 
24 import inspect
25 import linecache
26 
27 
28 def getCallerFrame(relative=0):
29  """Get the frame for the user's caller.
30 
31  Parameters
32  ----------
33  relative : `int`, optional
34  Number of frames (0 or more) above the caller to retrieve. Default is 0.
35 
36  Returns
37  -------
38  frame : `__builtin__.Frame`
39  Frame for the caller.
40 
41  Notes
42  -----
43  This function is excluded from the frame.
44  """
45  frame = inspect.currentframe().f_back.f_back # Our caller's caller
46  for ii in range(relative):
47  frame = frame.f_back
48  return frame
49 
50 
51 def getStackFrame(relative=0):
52  """Get the `StackFrame` for the user's caller.
53 
54  Parameters
55  ----------
56  relative : `int`, optional
57  Number of frames (0 or more) above the caller to retrieve.
58 
59  Returns
60  -------
61  frame : `StackFrame`
62  Stack frame for the caller.
63  """
64  frame = getCallerFrame(relative + 1)
65  return StackFrame.fromFrame(frame)
66 
67 
68 class StackFrame:
69  """A single element of the stack trace.
70 
71  This differs slightly from the standard system mechanisms for getting a
72  stack trace by the fact that it does not look up the source code until it
73  is absolutely necessary, reducing the I/O.
74 
75  Parameters
76  ----------
77  filename : `str`
78  Name of file containing the code being executed.
79  lineno : `int`
80  Line number of file being executed.
81  function : `str`
82  Function name being executed.
83  content : `str`, optional
84  The actual content being executed. If not provided, it will be loaded
85  from the file.
86 
87  Notes
88  -----
89  This differs slightly from the standard system mechanisms for getting a
90  stack trace by the fact that it does not look up the source code until it
91  is absolutely necessary, reducing the I/O.
92 
93  See also
94  --------
95  getStackFrame
96  """
97 
98  _STRIP = "/python/lsst/"
99  """String to strip from the ``filename`` in the constructor."""
100 
101  def __init__(self, filename, lineno, function, content=None):
102  loc = filename.rfind(self._STRIP)
103  if loc > 0:
104  filename = filename[loc + len(self._STRIP):]
105  self.filename = filename
106  self.lineno = lineno
107  self.function = function
108  self._content = content
109 
110  @property
111  def content(self):
112  """Content being executed (loaded on demand) (`str`).
113  """
114  if self._content is None:
115  self._content = linecache.getline(self.filename, self.lineno).strip()
116  return self._content
117 
118  @classmethod
119  def fromFrame(cls, frame):
120  """Construct from a Frame object.
121 
122  Parameters
123  ----------
124  frame : `Frame`
125  Frame object to interpret, such as from `inspect.currentframe`.
126 
127  Returns
128  -------
129  stackFrame : `StackFrame`
130  A `StackFrame` instance.
131 
132  Examples
133  --------
134  `inspect.currentframe` provides a Frame object. This is a convenience
135  constructor to interpret that Frame object:
136 
137  >>> import inspect
138  >>> stackFrame = StackFrame.fromFrame(inspect.currentframe())
139  """
140  filename = frame.f_code.co_filename
141  lineno = frame.f_lineno
142  function = frame.f_code.co_name
143  return cls(filename, lineno, function)
144 
145  def __repr__(self):
146  return "%s(%s, %s, %s)" % (self.__class__.__name__, self.filename, self.lineno, self.function)
147 
148  def format(self, full=False):
149  """Format for printing.
150 
151  Parameters
152  ----------
153  full : `bool`, optional
154  If `True`, output includes the conentent (`StackFrame.content`) being executed. Default
155  is `False`.
156 
157  Returns
158  -------
159  result : `str`
160  Formatted string.
161  """
162  result = " File %s:%s (%s)" % (self.filename, self.lineno, self.function)
163  if full:
164  result += "\n %s" % (self.content,)
165  return result
166 
167 
168 def getCallStack(skip=0):
169  """Retrieve the call stack for the caller.
170 
171  Parameters
172  ----------
173  skip : `int`, non-negative
174  Number of stack frames above caller to skip.
175 
176  Returns
177  -------
178  output : `list` of `StackFrame`
179  The call stack. The `list` is ordered with the most recent frame to
180  last.
181 
182  Notes
183  -----
184  This function is excluded from the call stack.
185  """
186  frame = getCallerFrame(skip + 1)
187  stack = []
188  while frame:
189  stack.append(StackFrame.fromFrame(frame))
190  frame = frame.f_back
191  return list(reversed(stack))
def getCallStack(skip=0)
Definition: callStack.py:168
def format(self, full=False)
Definition: callStack.py:148
def __init__(self, filename, lineno, function, content=None)
Definition: callStack.py:101
def getStackFrame(relative=0)
Definition: callStack.py:51
def getCallerFrame(relative=0)
Definition: callStack.py:28