blob: eeb3034f182d7cb908dff798e67d93a8ee0a804c [file] [log] [blame]
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +00001"""Get useful information from live Python objects.
2
3This module encapsulates the interface provided by the internal special
4attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion.
5It also provides some help for examining source code and class layout.
6
7Here are some of the useful functions provided by this module:
8
9 ismodule(), isclass(), ismethod(), isfunction(), istraceback(),
10 isframe(), iscode(), isbuiltin(), isroutine() - check object types
11 getmembers() - get members of an object that satisfy a given condition
12
13 getfile(), getsourcefile(), getsource() - find an object's source code
14 getdoc(), getcomments() - get documentation on an object
15 getmodule() - determine the module that an object came from
16 getclasstree() - arrange classes so as to represent their hierarchy
17
18 getargspec(), getargvalues() - get info about function arguments
19 formatargspec(), formatargvalues() - format an argument spec
20 getouterframes(), getinnerframes() - get info about frames
21 currentframe() - get the current stack frame
22 stack(), trace() - get info about frames on the stack or in a traceback
23"""
24
25# This module is in the public domain. No warranties.
26
Ka-Ping Yee8b58b842001-03-01 13:56:16 +000027__author__ = 'Ka-Ping Yee <ping@lfw.org>'
28__date__ = '1 Jan 2001'
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +000029
Ka-Ping Yeea6e59712001-03-10 09:31:55 +000030import sys, os, types, string, re, dis, imp, tokenize
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +000031
32# ----------------------------------------------------------- type-checking
33def ismodule(object):
34 """Return true if the object is a module.
35
36 Module objects provide these attributes:
37 __doc__ documentation string
38 __file__ filename (missing for built-in modules)"""
39 return type(object) is types.ModuleType
40
41def isclass(object):
42 """Return true if the object is a class.
43
44 Class objects provide these attributes:
45 __doc__ documentation string
46 __module__ name of module in which this class was defined"""
Ka-Ping Yeea9c6c8d2001-03-23 15:29:59 +000047 return type(object) is types.ClassType or hasattr(object, '__bases__')
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +000048
49def ismethod(object):
50 """Return true if the object is an instance method.
51
52 Instance method objects provide these attributes:
53 __doc__ documentation string
54 __name__ name with which this method was defined
55 im_class class object in which this method belongs
56 im_func function object containing implementation of method
57 im_self instance to which this method is bound, or None"""
58 return type(object) is types.MethodType
59
60def isfunction(object):
61 """Return true if the object is a user-defined function.
62
63 Function objects provide these attributes:
64 __doc__ documentation string
65 __name__ name with which this function was defined
66 func_code code object containing compiled function bytecode
67 func_defaults tuple of any default values for arguments
68 func_doc (same as __doc__)
69 func_globals global namespace in which this function was defined
70 func_name (same as __name__)"""
71 return type(object) in [types.FunctionType, types.LambdaType]
72
73def istraceback(object):
74 """Return true if the object is a traceback.
75
76 Traceback objects provide these attributes:
77 tb_frame frame object at this level
78 tb_lasti index of last attempted instruction in bytecode
79 tb_lineno current line number in Python source code
80 tb_next next inner traceback object (called by this level)"""
81 return type(object) is types.TracebackType
82
83def isframe(object):
84 """Return true if the object is a frame object.
85
86 Frame objects provide these attributes:
87 f_back next outer frame object (this frame's caller)
88 f_builtins built-in namespace seen by this frame
89 f_code code object being executed in this frame
90 f_exc_traceback traceback if raised in this frame, or None
91 f_exc_type exception type if raised in this frame, or None
92 f_exc_value exception value if raised in this frame, or None
93 f_globals global namespace seen by this frame
94 f_lasti index of last attempted instruction in bytecode
95 f_lineno current line number in Python source code
96 f_locals local namespace seen by this frame
97 f_restricted 0 or 1 if frame is in restricted execution mode
98 f_trace tracing function for this frame, or None"""
99 return type(object) is types.FrameType
100
101def iscode(object):
102 """Return true if the object is a code object.
103
104 Code objects provide these attributes:
105 co_argcount number of arguments (not including * or ** args)
106 co_code string of raw compiled bytecode
107 co_consts tuple of constants used in the bytecode
108 co_filename name of file in which this code object was created
109 co_firstlineno number of first line in Python source code
110 co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
111 co_lnotab encoded mapping of line numbers to bytecode indices
112 co_name name with which this code object was defined
113 co_names tuple of names of local variables
114 co_nlocals number of local variables
115 co_stacksize virtual machine stack space required
116 co_varnames tuple of names of arguments and local variables"""
117 return type(object) is types.CodeType
118
119def isbuiltin(object):
120 """Return true if the object is a built-in function or method.
121
122 Built-in functions and methods provide these attributes:
123 __doc__ documentation string
124 __name__ original name of this function or method
125 __self__ instance to which a method is bound, or None"""
126 return type(object) in [types.BuiltinFunctionType,
127 types.BuiltinMethodType]
128
129def isroutine(object):
130 """Return true if the object is any kind of function or method."""
131 return type(object) in [types.FunctionType, types.LambdaType,
132 types.MethodType, types.BuiltinFunctionType,
133 types.BuiltinMethodType]
134
135def getmembers(object, predicate=None):
136 """Return all members of an object as (name, value) pairs sorted by name.
137 Optionally, only return members that satisfy a given predicate."""
138 results = []
139 for key in dir(object):
140 value = getattr(object, key)
141 if not predicate or predicate(value):
142 results.append((key, value))
143 results.sort()
144 return results
145
146# -------------------------------------------------- source code extraction
147def indentsize(line):
148 """Return the indent size, in spaces, at the start of a line of text."""
149 expline = string.expandtabs(line)
150 return len(expline) - len(string.lstrip(expline))
151
152def getdoc(object):
153 """Get the documentation string for an object.
154
155 All tabs are expanded to spaces. To clean up docstrings that are
156 indented to line up with blocks of code, any whitespace than can be
157 uniformly removed from the second line onwards is removed."""
158 if hasattr(object, '__doc__') and object.__doc__:
159 lines = string.split(string.expandtabs(object.__doc__), '\n')
160 margin = None
161 for line in lines[1:]:
162 content = len(string.lstrip(line))
163 if not content: continue
164 indent = len(line) - content
165 if margin is None: margin = indent
166 else: margin = min(margin, indent)
167 if margin is not None:
168 for i in range(1, len(lines)): lines[i] = lines[i][margin:]
169 return string.join(lines, '\n')
170
171def getfile(object):
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000172 """Work out which source or compiled file an object was defined in."""
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000173 if ismodule(object):
174 if hasattr(object, '__file__'):
175 return object.__file__
176 raise TypeError, 'arg is a built-in module'
177 if isclass(object):
178 object = sys.modules[object.__module__]
179 if hasattr(object, '__file__'):
180 return object.__file__
181 raise TypeError, 'arg is a built-in class'
182 if ismethod(object):
183 object = object.im_func
184 if isfunction(object):
185 object = object.func_code
186 if istraceback(object):
187 object = object.tb_frame
188 if isframe(object):
189 object = object.f_code
190 if iscode(object):
191 return object.co_filename
192 raise TypeError, 'arg is not a module, class, method, ' \
193 'function, traceback, frame, or code object'
194
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000195def getsourcefile(object):
196 """Return the Python source file an object was defined in, if it exists."""
197 filename = getfile(object)
198 if string.lower(filename[-4:]) in ['.pyc', '.pyo']:
199 filename = filename[:-4] + '.py'
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000200 for suffix, mode, kind in imp.get_suffixes():
201 if 'b' in mode and string.lower(filename[-len(suffix):]) == suffix:
202 # Looks like a binary file. We want to only return a text file.
203 return None
204 if os.path.exists(filename):
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000205 return filename
206
207def getabsfile(object):
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000208 """Return an absolute path to the source or compiled file for an object.
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000209
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000210 The idea is for each object to have a unique origin, so this routine
211 normalizes the result as much as possible."""
212 return os.path.normcase(
213 os.path.abspath(getsourcefile(object) or getfile(object)))
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000214
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000215modulesbyfile = {}
216
217def getmodule(object):
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000218 """Return the module an object was defined in, or None if not found."""
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000219 if isclass(object):
Ka-Ping Yee8b58b842001-03-01 13:56:16 +0000220 return sys.modules.get(object.__module__)
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000221 try:
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000222 file = getabsfile(object)
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000223 except TypeError:
224 return None
225 if modulesbyfile.has_key(file):
226 return sys.modules[modulesbyfile[file]]
227 for module in sys.modules.values():
228 if hasattr(module, '__file__'):
Ka-Ping Yeec113c242001-03-02 02:08:53 +0000229 modulesbyfile[getabsfile(module)] = module.__name__
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000230 if modulesbyfile.has_key(file):
231 return sys.modules[modulesbyfile[file]]
232 main = sys.modules['__main__']
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000233 if hasattr(main, object.__name__):
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000234 mainobject = getattr(main, object.__name__)
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000235 if mainobject is object:
236 return main
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000237 builtin = sys.modules['__builtin__']
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000238 if hasattr(builtin, object.__name__):
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000239 builtinobject = getattr(builtin, object.__name__)
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000240 if builtinobject is object:
241 return builtin
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000242
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000243def findsource(object):
244 """Return the entire source file and starting line number for an object.
245
246 The argument may be a module, class, method, function, traceback, frame,
247 or code object. The source code is returned as a list of all the lines
248 in the file and the line number indexes a line in that list. An IOError
249 is raised if the source code cannot be retrieved."""
250 try:
251 file = open(getsourcefile(object))
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000252 except (TypeError, IOError):
253 raise IOError, 'could not get source code'
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000254 lines = file.readlines()
255 file.close()
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000256
257 if ismodule(object):
258 return lines, 0
259
260 if isclass(object):
261 name = object.__name__
Ka-Ping Yeea6e59712001-03-10 09:31:55 +0000262 pat = re.compile(r'^\s*class\s*' + name + r'\b')
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000263 for i in range(len(lines)):
Ka-Ping Yeea6e59712001-03-10 09:31:55 +0000264 if pat.match(lines[i]): return lines, i
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000265 else: raise IOError, 'could not find class definition'
266
267 if ismethod(object):
268 object = object.im_func
269 if isfunction(object):
270 object = object.func_code
271 if istraceback(object):
272 object = object.tb_frame
273 if isframe(object):
274 object = object.f_code
275 if iscode(object):
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000276 if not hasattr(object, 'co_firstlineno'):
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000277 raise IOError, 'could not find function definition'
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000278 lnum = object.co_firstlineno - 1
Ka-Ping Yeea6e59712001-03-10 09:31:55 +0000279 pat = re.compile(r'^\s*def\s')
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000280 while lnum > 0:
Ka-Ping Yeea6e59712001-03-10 09:31:55 +0000281 if pat.match(lines[lnum]): break
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000282 lnum = lnum - 1
283 return lines, lnum
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000284
285def getcomments(object):
286 """Get lines of comments immediately preceding an object's source code."""
287 try: lines, lnum = findsource(object)
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000288 except IOError: return None
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000289
290 if ismodule(object):
291 # Look for a comment block at the top of the file.
292 start = 0
293 if lines[0][:2] == '#!': start = 1
294 while start < len(lines) and string.strip(lines[start]) in ['', '#']:
295 start = start + 1
296 if lines[start][:1] == '#':
297 comments = []
298 end = start
299 while end < len(lines) and lines[end][:1] == '#':
300 comments.append(string.expandtabs(lines[end]))
301 end = end + 1
302 return string.join(comments, '')
303
304 # Look for a preceding block of comments at the same indentation.
305 elif lnum > 0:
306 indent = indentsize(lines[lnum])
307 end = lnum - 1
308 if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
309 indentsize(lines[end]) == indent:
310 comments = [string.lstrip(string.expandtabs(lines[end]))]
311 if end > 0:
312 end = end - 1
313 comment = string.lstrip(string.expandtabs(lines[end]))
314 while comment[:1] == '#' and indentsize(lines[end]) == indent:
315 comments[:0] = [comment]
316 end = end - 1
317 if end < 0: break
318 comment = string.lstrip(string.expandtabs(lines[end]))
319 while comments and string.strip(comments[0]) == '#':
320 comments[:1] = []
321 while comments and string.strip(comments[-1]) == '#':
322 comments[-1:] = []
323 return string.join(comments, '')
324
325class ListReader:
326 """Provide a readline() method to return lines from a list of strings."""
327 def __init__(self, lines):
328 self.lines = lines
329 self.index = 0
330
331 def readline(self):
332 i = self.index
333 if i < len(self.lines):
334 self.index = i + 1
335 return self.lines[i]
336 else: return ''
337
338class EndOfBlock(Exception): pass
339
340class BlockFinder:
341 """Provide a tokeneater() method to detect the end of a code block."""
342 def __init__(self):
343 self.indent = 0
344 self.started = 0
345 self.last = 0
346
347 def tokeneater(self, type, token, (srow, scol), (erow, ecol), line):
348 if not self.started:
349 if type == tokenize.NAME: self.started = 1
350 elif type == tokenize.NEWLINE:
351 self.last = srow
352 elif type == tokenize.INDENT:
353 self.indent = self.indent + 1
354 elif type == tokenize.DEDENT:
355 self.indent = self.indent - 1
356 if self.indent == 0: raise EndOfBlock, self.last
357
358def getblock(lines):
359 """Extract the block of code at the top of the given list of lines."""
360 try:
361 tokenize.tokenize(ListReader(lines).readline, BlockFinder().tokeneater)
362 except EndOfBlock, eob:
363 return lines[:eob.args[0]]
364
365def getsourcelines(object):
366 """Return a list of source lines and starting line number for an object.
367
368 The argument may be a module, class, method, function, traceback, frame,
369 or code object. The source code is returned as a list of the lines
370 corresponding to the object and the line number indicates where in the
371 original source file the first line of code was found. An IOError is
372 raised if the source code cannot be retrieved."""
373 lines, lnum = findsource(object)
374
375 if ismodule(object): return lines, 0
376 else: return getblock(lines[lnum:]), lnum + 1
377
378def getsource(object):
379 """Return the text of the source code for an object.
380
381 The argument may be a module, class, method, function, traceback, frame,
382 or code object. The source code is returned as a single string. An
383 IOError is raised if the source code cannot be retrieved."""
384 lines, lnum = getsourcelines(object)
385 return string.join(lines, '')
386
387# --------------------------------------------------- class tree extraction
388def walktree(classes, children, parent):
389 """Recursive helper function for getclasstree()."""
390 results = []
391 classes.sort(lambda a, b: cmp(a.__name__, b.__name__))
392 for c in classes:
393 results.append((c, c.__bases__))
394 if children.has_key(c):
395 results.append(walktree(children[c], children, c))
396 return results
397
398def getclasstree(classes, unique=0):
399 """Arrange the given list of classes into a hierarchy of nested lists.
400
401 Where a nested list appears, it contains classes derived from the class
402 whose entry immediately precedes the list. Each entry is a 2-tuple
403 containing a class and a tuple of its base classes. If the 'unique'
404 argument is true, exactly one entry appears in the returned structure
405 for each class in the given list. Otherwise, classes using multiple
406 inheritance and their descendants will appear multiple times."""
407 children = {}
408 roots = []
409 for c in classes:
410 if c.__bases__:
411 for parent in c.__bases__:
412 if not children.has_key(parent):
413 children[parent] = []
414 children[parent].append(c)
415 if unique and parent in classes: break
416 elif c not in roots:
417 roots.append(c)
418 for parent in children.keys():
419 if parent not in classes:
420 roots.append(parent)
421 return walktree(roots, children, None)
422
423# ------------------------------------------------ argument list extraction
424# These constants are from Python's compile.h.
425CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
426
427def getargs(co):
428 """Get information about the arguments accepted by a code object.
429
430 Three things are returned: (args, varargs, varkw), where 'args' is
431 a list of argument names (possibly containing nested lists), and
432 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
433 if not iscode(co): raise TypeError, 'arg is not a code object'
434
435 code = co.co_code
436 nargs = co.co_argcount
437 names = co.co_varnames
438 args = list(names[:nargs])
439 step = 0
440
441 # The following acrobatics are for anonymous (tuple) arguments.
442 for i in range(nargs):
443 if args[i][:1] in ['', '.']:
444 stack, remain, count = [], [], []
445 while step < len(code):
446 op = ord(code[step])
447 step = step + 1
448 if op >= dis.HAVE_ARGUMENT:
449 opname = dis.opname[op]
450 value = ord(code[step]) + ord(code[step+1])*256
451 step = step + 2
452 if opname in ['UNPACK_TUPLE', 'UNPACK_SEQUENCE']:
453 remain.append(value)
454 count.append(value)
455 elif opname == 'STORE_FAST':
456 stack.append(names[value])
457 remain[-1] = remain[-1] - 1
458 while remain[-1] == 0:
459 remain.pop()
460 size = count.pop()
461 stack[-size:] = [stack[-size:]]
462 if not remain: break
463 remain[-1] = remain[-1] - 1
464 if not remain: break
465 args[i] = stack[0]
466
467 varargs = None
468 if co.co_flags & CO_VARARGS:
469 varargs = co.co_varnames[nargs]
470 nargs = nargs + 1
471 varkw = None
472 if co.co_flags & CO_VARKEYWORDS:
473 varkw = co.co_varnames[nargs]
474 return args, varargs, varkw
475
476def getargspec(func):
477 """Get the names and default values of a function's arguments.
478
479 A tuple of four things is returned: (args, varargs, varkw, defaults).
480 'args' is a list of the argument names (it may contain nested lists).
481 'varargs' and 'varkw' are the names of the * and ** arguments or None.
482 'defaults' is an n-tuple of the default values of the last n arguments."""
483 if not isfunction(func): raise TypeError, 'arg is not a Python function'
484 args, varargs, varkw = getargs(func.func_code)
485 return args, varargs, varkw, func.func_defaults
486
487def getargvalues(frame):
488 """Get information about arguments passed into a particular frame.
489
490 A tuple of four things is returned: (args, varargs, varkw, locals).
491 'args' is a list of the argument names (it may contain nested lists).
492 'varargs' and 'varkw' are the names of the * and ** arguments or None.
493 'locals' is the locals dictionary of the given frame."""
494 args, varargs, varkw = getargs(frame.f_code)
495 return args, varargs, varkw, frame.f_locals
496
497def joinseq(seq):
498 if len(seq) == 1:
499 return '(' + seq[0] + ',)'
500 else:
501 return '(' + string.join(seq, ', ') + ')'
502
503def strseq(object, convert, join=joinseq):
504 """Recursively walk a sequence, stringifying each element."""
505 if type(object) in [types.ListType, types.TupleType]:
506 return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
507 else:
508 return convert(object)
509
510def formatargspec(args, varargs=None, varkw=None, defaults=None,
511 formatarg=str,
512 formatvarargs=lambda name: '*' + name,
513 formatvarkw=lambda name: '**' + name,
514 formatvalue=lambda value: '=' + repr(value),
515 join=joinseq):
516 """Format an argument spec from the 4 values returned by getargspec.
517
518 The first four arguments are (args, varargs, varkw, defaults). The
519 other four arguments are the corresponding optional formatting functions
520 that are called to turn names and values into strings. The ninth
521 argument is an optional function to format the sequence of arguments."""
522 specs = []
523 if defaults:
524 firstdefault = len(args) - len(defaults)
525 for i in range(len(args)):
526 spec = strseq(args[i], formatarg, join)
527 if defaults and i >= firstdefault:
528 spec = spec + formatvalue(defaults[i - firstdefault])
529 specs.append(spec)
530 if varargs:
531 specs.append(formatvarargs(varargs))
532 if varkw:
533 specs.append(formatvarkw(varkw))
534 return '(' + string.join(specs, ', ') + ')'
535
536def formatargvalues(args, varargs, varkw, locals,
537 formatarg=str,
538 formatvarargs=lambda name: '*' + name,
539 formatvarkw=lambda name: '**' + name,
540 formatvalue=lambda value: '=' + repr(value),
541 join=joinseq):
542 """Format an argument spec from the 4 values returned by getargvalues.
543
544 The first four arguments are (args, varargs, varkw, locals). The
545 next four arguments are the corresponding optional formatting functions
546 that are called to turn names and values into strings. The ninth
547 argument is an optional function to format the sequence of arguments."""
548 def convert(name, locals=locals,
549 formatarg=formatarg, formatvalue=formatvalue):
550 return formatarg(name) + formatvalue(locals[name])
551 specs = []
552 for i in range(len(args)):
553 specs.append(strseq(args[i], convert, join))
554 if varargs:
555 specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
556 if varkw:
557 specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
558 return '(' + string.join(specs, ', ') + ')'
559
560# -------------------------------------------------- stack frame extraction
561def getframeinfo(frame, context=1):
562 """Get information about a frame or traceback object.
563
564 A tuple of five things is returned: the filename, the line number of
565 the current line, the function name, a list of lines of context from
566 the source code, and the index of the current line within that list.
567 The optional second argument specifies the number of lines of context
568 to return, which are centered around the current line."""
569 if istraceback(frame):
570 frame = frame.tb_frame
571 if not isframe(frame):
572 raise TypeError, 'arg is not a frame or traceback object'
573
574 filename = getsourcefile(frame)
Ka-Ping Yee59ade082001-03-01 03:55:35 +0000575 lineno = getlineno(frame)
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000576 if context > 0:
Ka-Ping Yee59ade082001-03-01 03:55:35 +0000577 start = lineno - 1 - context/2
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000578 try:
579 lines, lnum = findsource(frame)
Ka-Ping Yee4eb0c002001-03-02 05:50:34 +0000580 except IOError:
581 lines = index = None
582 else:
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000583 start = max(start, 1)
584 start = min(start, len(lines) - context)
585 lines = lines[start:start+context]
Ka-Ping Yee59ade082001-03-01 03:55:35 +0000586 index = lineno - 1 - start
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000587 else:
588 lines = index = None
589
Ka-Ping Yee59ade082001-03-01 03:55:35 +0000590 return (filename, lineno, frame.f_code.co_name, lines, index)
591
592def getlineno(frame):
593 """Get the line number from a frame object, allowing for optimization."""
594 # Written by Marc-André Lemburg; revised by Jim Hugunin and Fredrik Lundh.
595 lineno = frame.f_lineno
596 code = frame.f_code
597 if hasattr(code, 'co_lnotab'):
598 table = code.co_lnotab
599 lineno = code.co_firstlineno
600 addr = 0
601 for i in range(0, len(table), 2):
602 addr = addr + ord(table[i])
603 if addr > frame.f_lasti: break
604 lineno = lineno + ord(table[i+1])
605 return lineno
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000606
607def getouterframes(frame, context=1):
608 """Get a list of records for a frame and all higher (calling) frames.
609
610 Each record contains a frame object, filename, line number, function
611 name, a list of lines of context, and index within the context."""
612 framelist = []
613 while frame:
614 framelist.append((frame,) + getframeinfo(frame, context))
615 frame = frame.f_back
616 return framelist
617
618def getinnerframes(tb, context=1):
619 """Get a list of records for a traceback's frame and all lower frames.
620
621 Each record contains a frame object, filename, line number, function
622 name, a list of lines of context, and index within the context."""
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000623 framelist = []
624 while tb:
625 framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
626 tb = tb.tb_next
627 return framelist
628
629def currentframe():
630 """Return the frame object for the caller's stack frame."""
631 try:
632 raise 'catch me'
633 except:
634 return sys.exc_traceback.tb_frame.f_back
635
636if hasattr(sys, '_getframe'): currentframe = sys._getframe
637
638def stack(context=1):
639 """Return a list of records for the stack above the caller's frame."""
640 return getouterframes(currentframe().f_back, context)
641
642def trace(context=1):
Tim Peters85ba6732001-02-28 08:26:44 +0000643 """Return a list of records for the stack below the current exception."""
Ka-Ping Yee6397c7c2001-02-27 14:43:21 +0000644 return getinnerframes(sys.exc_traceback, context)