blob: 408e454a8a1aede96626281e9bdf6311669bf1af [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
27__version__ = 'Ka-Ping Yee <ping@lfw.org>, 1 Jan 2001'
28
29import sys, types, string, dis, imp, tokenize
30
31# ----------------------------------------------------------- type-checking
32def ismodule(object):
33 """Return true if the object is a module.
34
35 Module objects provide these attributes:
36 __doc__ documentation string
37 __file__ filename (missing for built-in modules)"""
38 return type(object) is types.ModuleType
39
40def isclass(object):
41 """Return true if the object is a class.
42
43 Class objects provide these attributes:
44 __doc__ documentation string
45 __module__ name of module in which this class was defined"""
46 return type(object) is types.ClassType
47
48def ismethod(object):
49 """Return true if the object is an instance method.
50
51 Instance method objects provide these attributes:
52 __doc__ documentation string
53 __name__ name with which this method was defined
54 im_class class object in which this method belongs
55 im_func function object containing implementation of method
56 im_self instance to which this method is bound, or None"""
57 return type(object) is types.MethodType
58
59def isfunction(object):
60 """Return true if the object is a user-defined function.
61
62 Function objects provide these attributes:
63 __doc__ documentation string
64 __name__ name with which this function was defined
65 func_code code object containing compiled function bytecode
66 func_defaults tuple of any default values for arguments
67 func_doc (same as __doc__)
68 func_globals global namespace in which this function was defined
69 func_name (same as __name__)"""
70 return type(object) in [types.FunctionType, types.LambdaType]
71
72def istraceback(object):
73 """Return true if the object is a traceback.
74
75 Traceback objects provide these attributes:
76 tb_frame frame object at this level
77 tb_lasti index of last attempted instruction in bytecode
78 tb_lineno current line number in Python source code
79 tb_next next inner traceback object (called by this level)"""
80 return type(object) is types.TracebackType
81
82def isframe(object):
83 """Return true if the object is a frame object.
84
85 Frame objects provide these attributes:
86 f_back next outer frame object (this frame's caller)
87 f_builtins built-in namespace seen by this frame
88 f_code code object being executed in this frame
89 f_exc_traceback traceback if raised in this frame, or None
90 f_exc_type exception type if raised in this frame, or None
91 f_exc_value exception value if raised in this frame, or None
92 f_globals global namespace seen by this frame
93 f_lasti index of last attempted instruction in bytecode
94 f_lineno current line number in Python source code
95 f_locals local namespace seen by this frame
96 f_restricted 0 or 1 if frame is in restricted execution mode
97 f_trace tracing function for this frame, or None"""
98 return type(object) is types.FrameType
99
100def iscode(object):
101 """Return true if the object is a code object.
102
103 Code objects provide these attributes:
104 co_argcount number of arguments (not including * or ** args)
105 co_code string of raw compiled bytecode
106 co_consts tuple of constants used in the bytecode
107 co_filename name of file in which this code object was created
108 co_firstlineno number of first line in Python source code
109 co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
110 co_lnotab encoded mapping of line numbers to bytecode indices
111 co_name name with which this code object was defined
112 co_names tuple of names of local variables
113 co_nlocals number of local variables
114 co_stacksize virtual machine stack space required
115 co_varnames tuple of names of arguments and local variables"""
116 return type(object) is types.CodeType
117
118def isbuiltin(object):
119 """Return true if the object is a built-in function or method.
120
121 Built-in functions and methods provide these attributes:
122 __doc__ documentation string
123 __name__ original name of this function or method
124 __self__ instance to which a method is bound, or None"""
125 return type(object) in [types.BuiltinFunctionType,
126 types.BuiltinMethodType]
127
128def isroutine(object):
129 """Return true if the object is any kind of function or method."""
130 return type(object) in [types.FunctionType, types.LambdaType,
131 types.MethodType, types.BuiltinFunctionType,
132 types.BuiltinMethodType]
133
134def getmembers(object, predicate=None):
135 """Return all members of an object as (name, value) pairs sorted by name.
136 Optionally, only return members that satisfy a given predicate."""
137 results = []
138 for key in dir(object):
139 value = getattr(object, key)
140 if not predicate or predicate(value):
141 results.append((key, value))
142 results.sort()
143 return results
144
145# -------------------------------------------------- source code extraction
146def indentsize(line):
147 """Return the indent size, in spaces, at the start of a line of text."""
148 expline = string.expandtabs(line)
149 return len(expline) - len(string.lstrip(expline))
150
151def getdoc(object):
152 """Get the documentation string for an object.
153
154 All tabs are expanded to spaces. To clean up docstrings that are
155 indented to line up with blocks of code, any whitespace than can be
156 uniformly removed from the second line onwards is removed."""
157 if hasattr(object, '__doc__') and object.__doc__:
158 lines = string.split(string.expandtabs(object.__doc__), '\n')
159 margin = None
160 for line in lines[1:]:
161 content = len(string.lstrip(line))
162 if not content: continue
163 indent = len(line) - content
164 if margin is None: margin = indent
165 else: margin = min(margin, indent)
166 if margin is not None:
167 for i in range(1, len(lines)): lines[i] = lines[i][margin:]
168 return string.join(lines, '\n')
169
170def getfile(object):
171 """Try to guess which (text or binary) file an object was defined in."""
172 if ismodule(object):
173 if hasattr(object, '__file__'):
174 return object.__file__
175 raise TypeError, 'arg is a built-in module'
176 if isclass(object):
177 object = sys.modules[object.__module__]
178 if hasattr(object, '__file__'):
179 return object.__file__
180 raise TypeError, 'arg is a built-in class'
181 if ismethod(object):
182 object = object.im_func
183 if isfunction(object):
184 object = object.func_code
185 if istraceback(object):
186 object = object.tb_frame
187 if isframe(object):
188 object = object.f_code
189 if iscode(object):
190 return object.co_filename
191 raise TypeError, 'arg is not a module, class, method, ' \
192 'function, traceback, frame, or code object'
193
194modulesbyfile = {}
195
196def getmodule(object):
197 """Try to guess which module an object was defined in."""
198 if isclass(object):
199 return sys.modules[object.__module__]
200 try:
201 file = getsourcefile(object)
202 except TypeError:
203 return None
204 if modulesbyfile.has_key(file):
205 return sys.modules[modulesbyfile[file]]
206 for module in sys.modules.values():
207 if hasattr(module, '__file__'):
208 modulesbyfile[getsourcefile(module)] = module.__name__
209 if modulesbyfile.has_key(file):
210 return sys.modules[modulesbyfile[file]]
211 main = sys.modules['__main__']
212 try:
213 mainobject = getattr(main, object.__name__)
214 if mainobject is object: return main
215 except AttributeError: pass
216 builtin = sys.modules['__builtin__']
217 try:
218 builtinobject = getattr(builtin, object.__name__)
219 if builtinobject is object: return builtin
220 except AttributeError: pass
221
222def getsourcefile(object):
223 """Try to guess which Python source file an object was defined in."""
224 filename = getfile(object)
225 if filename[-4:] == '.pyc':
226 filename = filename[:-4] + '.py'
227 return filename
228
229def findsource(object):
230 """Return the entire source file and starting line number for an object.
231
232 The argument may be a module, class, method, function, traceback, frame,
233 or code object. The source code is returned as a list of all the lines
234 in the file and the line number indexes a line in that list. An IOError
235 is raised if the source code cannot be retrieved."""
236 try:
237 file = open(getsourcefile(object))
238 lines = file.readlines()
239 file.close()
240 except (TypeError, IOError):
241 raise IOError, 'could not get source code'
242
243 if ismodule(object):
244 return lines, 0
245
246 if isclass(object):
247 name = object.__name__
248 matches = (['class', name], ['class', name + ':'])
249 for i in range(len(lines)):
250 if string.split(lines[i])[:2] in matches:
251 return lines, i
252 else: raise IOError, 'could not find class definition'
253
254 if ismethod(object):
255 object = object.im_func
256 if isfunction(object):
257 object = object.func_code
258 if istraceback(object):
259 object = object.tb_frame
260 if isframe(object):
261 object = object.f_code
262 if iscode(object):
263 try:
264 lnum = object.co_firstlineno - 1
265 except AttributeError:
266 raise IOError, 'could not find function definition'
267 else:
268 while lnum > 0:
269 if string.split(lines[lnum])[:1] == ['def']: break
270 lnum = lnum - 1
271 return lines, lnum
272
273def getcomments(object):
274 """Get lines of comments immediately preceding an object's source code."""
275 try: lines, lnum = findsource(object)
276 except: return None
277
278 if ismodule(object):
279 # Look for a comment block at the top of the file.
280 start = 0
281 if lines[0][:2] == '#!': start = 1
282 while start < len(lines) and string.strip(lines[start]) in ['', '#']:
283 start = start + 1
284 if lines[start][:1] == '#':
285 comments = []
286 end = start
287 while end < len(lines) and lines[end][:1] == '#':
288 comments.append(string.expandtabs(lines[end]))
289 end = end + 1
290 return string.join(comments, '')
291
292 # Look for a preceding block of comments at the same indentation.
293 elif lnum > 0:
294 indent = indentsize(lines[lnum])
295 end = lnum - 1
296 if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \
297 indentsize(lines[end]) == indent:
298 comments = [string.lstrip(string.expandtabs(lines[end]))]
299 if end > 0:
300 end = end - 1
301 comment = string.lstrip(string.expandtabs(lines[end]))
302 while comment[:1] == '#' and indentsize(lines[end]) == indent:
303 comments[:0] = [comment]
304 end = end - 1
305 if end < 0: break
306 comment = string.lstrip(string.expandtabs(lines[end]))
307 while comments and string.strip(comments[0]) == '#':
308 comments[:1] = []
309 while comments and string.strip(comments[-1]) == '#':
310 comments[-1:] = []
311 return string.join(comments, '')
312
313class ListReader:
314 """Provide a readline() method to return lines from a list of strings."""
315 def __init__(self, lines):
316 self.lines = lines
317 self.index = 0
318
319 def readline(self):
320 i = self.index
321 if i < len(self.lines):
322 self.index = i + 1
323 return self.lines[i]
324 else: return ''
325
326class EndOfBlock(Exception): pass
327
328class BlockFinder:
329 """Provide a tokeneater() method to detect the end of a code block."""
330 def __init__(self):
331 self.indent = 0
332 self.started = 0
333 self.last = 0
334
335 def tokeneater(self, type, token, (srow, scol), (erow, ecol), line):
336 if not self.started:
337 if type == tokenize.NAME: self.started = 1
338 elif type == tokenize.NEWLINE:
339 self.last = srow
340 elif type == tokenize.INDENT:
341 self.indent = self.indent + 1
342 elif type == tokenize.DEDENT:
343 self.indent = self.indent - 1
344 if self.indent == 0: raise EndOfBlock, self.last
345
346def getblock(lines):
347 """Extract the block of code at the top of the given list of lines."""
348 try:
349 tokenize.tokenize(ListReader(lines).readline, BlockFinder().tokeneater)
350 except EndOfBlock, eob:
351 return lines[:eob.args[0]]
352
353def getsourcelines(object):
354 """Return a list of source lines and starting line number for an object.
355
356 The argument may be a module, class, method, function, traceback, frame,
357 or code object. The source code is returned as a list of the lines
358 corresponding to the object and the line number indicates where in the
359 original source file the first line of code was found. An IOError is
360 raised if the source code cannot be retrieved."""
361 lines, lnum = findsource(object)
362
363 if ismodule(object): return lines, 0
364 else: return getblock(lines[lnum:]), lnum + 1
365
366def getsource(object):
367 """Return the text of the source code for an object.
368
369 The argument may be a module, class, method, function, traceback, frame,
370 or code object. The source code is returned as a single string. An
371 IOError is raised if the source code cannot be retrieved."""
372 lines, lnum = getsourcelines(object)
373 return string.join(lines, '')
374
375# --------------------------------------------------- class tree extraction
376def walktree(classes, children, parent):
377 """Recursive helper function for getclasstree()."""
378 results = []
379 classes.sort(lambda a, b: cmp(a.__name__, b.__name__))
380 for c in classes:
381 results.append((c, c.__bases__))
382 if children.has_key(c):
383 results.append(walktree(children[c], children, c))
384 return results
385
386def getclasstree(classes, unique=0):
387 """Arrange the given list of classes into a hierarchy of nested lists.
388
389 Where a nested list appears, it contains classes derived from the class
390 whose entry immediately precedes the list. Each entry is a 2-tuple
391 containing a class and a tuple of its base classes. If the 'unique'
392 argument is true, exactly one entry appears in the returned structure
393 for each class in the given list. Otherwise, classes using multiple
394 inheritance and their descendants will appear multiple times."""
395 children = {}
396 roots = []
397 for c in classes:
398 if c.__bases__:
399 for parent in c.__bases__:
400 if not children.has_key(parent):
401 children[parent] = []
402 children[parent].append(c)
403 if unique and parent in classes: break
404 elif c not in roots:
405 roots.append(c)
406 for parent in children.keys():
407 if parent not in classes:
408 roots.append(parent)
409 return walktree(roots, children, None)
410
411# ------------------------------------------------ argument list extraction
412# These constants are from Python's compile.h.
413CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
414
415def getargs(co):
416 """Get information about the arguments accepted by a code object.
417
418 Three things are returned: (args, varargs, varkw), where 'args' is
419 a list of argument names (possibly containing nested lists), and
420 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
421 if not iscode(co): raise TypeError, 'arg is not a code object'
422
423 code = co.co_code
424 nargs = co.co_argcount
425 names = co.co_varnames
426 args = list(names[:nargs])
427 step = 0
428
429 # The following acrobatics are for anonymous (tuple) arguments.
430 for i in range(nargs):
431 if args[i][:1] in ['', '.']:
432 stack, remain, count = [], [], []
433 while step < len(code):
434 op = ord(code[step])
435 step = step + 1
436 if op >= dis.HAVE_ARGUMENT:
437 opname = dis.opname[op]
438 value = ord(code[step]) + ord(code[step+1])*256
439 step = step + 2
440 if opname in ['UNPACK_TUPLE', 'UNPACK_SEQUENCE']:
441 remain.append(value)
442 count.append(value)
443 elif opname == 'STORE_FAST':
444 stack.append(names[value])
445 remain[-1] = remain[-1] - 1
446 while remain[-1] == 0:
447 remain.pop()
448 size = count.pop()
449 stack[-size:] = [stack[-size:]]
450 if not remain: break
451 remain[-1] = remain[-1] - 1
452 if not remain: break
453 args[i] = stack[0]
454
455 varargs = None
456 if co.co_flags & CO_VARARGS:
457 varargs = co.co_varnames[nargs]
458 nargs = nargs + 1
459 varkw = None
460 if co.co_flags & CO_VARKEYWORDS:
461 varkw = co.co_varnames[nargs]
462 return args, varargs, varkw
463
464def getargspec(func):
465 """Get the names and default values of a function's arguments.
466
467 A tuple of four things is returned: (args, varargs, varkw, defaults).
468 'args' is a list of the argument names (it may contain nested lists).
469 'varargs' and 'varkw' are the names of the * and ** arguments or None.
470 'defaults' is an n-tuple of the default values of the last n arguments."""
471 if not isfunction(func): raise TypeError, 'arg is not a Python function'
472 args, varargs, varkw = getargs(func.func_code)
473 return args, varargs, varkw, func.func_defaults
474
475def getargvalues(frame):
476 """Get information about arguments passed into a particular frame.
477
478 A tuple of four things is returned: (args, varargs, varkw, locals).
479 'args' is a list of the argument names (it may contain nested lists).
480 'varargs' and 'varkw' are the names of the * and ** arguments or None.
481 'locals' is the locals dictionary of the given frame."""
482 args, varargs, varkw = getargs(frame.f_code)
483 return args, varargs, varkw, frame.f_locals
484
485def joinseq(seq):
486 if len(seq) == 1:
487 return '(' + seq[0] + ',)'
488 else:
489 return '(' + string.join(seq, ', ') + ')'
490
491def strseq(object, convert, join=joinseq):
492 """Recursively walk a sequence, stringifying each element."""
493 if type(object) in [types.ListType, types.TupleType]:
494 return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))
495 else:
496 return convert(object)
497
498def formatargspec(args, varargs=None, varkw=None, defaults=None,
499 formatarg=str,
500 formatvarargs=lambda name: '*' + name,
501 formatvarkw=lambda name: '**' + name,
502 formatvalue=lambda value: '=' + repr(value),
503 join=joinseq):
504 """Format an argument spec from the 4 values returned by getargspec.
505
506 The first four arguments are (args, varargs, varkw, defaults). The
507 other four arguments are the corresponding optional formatting functions
508 that are called to turn names and values into strings. The ninth
509 argument is an optional function to format the sequence of arguments."""
510 specs = []
511 if defaults:
512 firstdefault = len(args) - len(defaults)
513 for i in range(len(args)):
514 spec = strseq(args[i], formatarg, join)
515 if defaults and i >= firstdefault:
516 spec = spec + formatvalue(defaults[i - firstdefault])
517 specs.append(spec)
518 if varargs:
519 specs.append(formatvarargs(varargs))
520 if varkw:
521 specs.append(formatvarkw(varkw))
522 return '(' + string.join(specs, ', ') + ')'
523
524def formatargvalues(args, varargs, varkw, locals,
525 formatarg=str,
526 formatvarargs=lambda name: '*' + name,
527 formatvarkw=lambda name: '**' + name,
528 formatvalue=lambda value: '=' + repr(value),
529 join=joinseq):
530 """Format an argument spec from the 4 values returned by getargvalues.
531
532 The first four arguments are (args, varargs, varkw, locals). The
533 next four arguments are the corresponding optional formatting functions
534 that are called to turn names and values into strings. The ninth
535 argument is an optional function to format the sequence of arguments."""
536 def convert(name, locals=locals,
537 formatarg=formatarg, formatvalue=formatvalue):
538 return formatarg(name) + formatvalue(locals[name])
539 specs = []
540 for i in range(len(args)):
541 specs.append(strseq(args[i], convert, join))
542 if varargs:
543 specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
544 if varkw:
545 specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
546 return '(' + string.join(specs, ', ') + ')'
547
548# -------------------------------------------------- stack frame extraction
549def getframeinfo(frame, context=1):
550 """Get information about a frame or traceback object.
551
552 A tuple of five things is returned: the filename, the line number of
553 the current line, the function name, a list of lines of context from
554 the source code, and the index of the current line within that list.
555 The optional second argument specifies the number of lines of context
556 to return, which are centered around the current line."""
557 if istraceback(frame):
558 frame = frame.tb_frame
559 if not isframe(frame):
560 raise TypeError, 'arg is not a frame or traceback object'
561
562 filename = getsourcefile(frame)
563 if context > 0:
564 start = frame.f_lineno - 1 - context/2
565 try:
566 lines, lnum = findsource(frame)
567 start = max(start, 1)
568 start = min(start, len(lines) - context)
569 lines = lines[start:start+context]
570 index = frame.f_lineno - 1 - start
571 except:
572 lines = index = None
573 else:
574 lines = index = None
575
576 return (filename, frame.f_lineno, frame.f_code.co_name, lines, index)
577
578def getouterframes(frame, context=1):
579 """Get a list of records for a frame and all higher (calling) frames.
580
581 Each record contains a frame object, filename, line number, function
582 name, a list of lines of context, and index within the context."""
583 framelist = []
584 while frame:
585 framelist.append((frame,) + getframeinfo(frame, context))
586 frame = frame.f_back
587 return framelist
588
589def getinnerframes(tb, context=1):
590 """Get a list of records for a traceback's frame and all lower frames.
591
592 Each record contains a frame object, filename, line number, function
593 name, a list of lines of context, and index within the context."""
594 tb = tb.tb_next
595 framelist = []
596 while tb:
597 framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
598 tb = tb.tb_next
599 return framelist
600
601def currentframe():
602 """Return the frame object for the caller's stack frame."""
603 try:
604 raise 'catch me'
605 except:
606 return sys.exc_traceback.tb_frame.f_back
607
608if hasattr(sys, '_getframe'): currentframe = sys._getframe
609
610def stack(context=1):
611 """Return a list of records for the stack above the caller's frame."""
612 return getouterframes(currentframe().f_back, context)
613
614def trace(context=1):
615 """Return a list of records for the stack below the current exception."""
616 return getinnerframes(sys.exc_traceback, context)