]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | # -*- coding: iso-8859-1 -*-\r |
2 | """Get useful information from live Python objects.\r | |
3 | \r | |
4 | This module encapsulates the interface provided by the internal special\r | |
5 | attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion.\r | |
6 | It also provides some help for examining source code and class layout.\r | |
7 | \r | |
8 | Here are some of the useful functions provided by this module:\r | |
9 | \r | |
10 | ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),\r | |
11 | isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),\r | |
12 | isroutine() - check object types\r | |
13 | getmembers() - get members of an object that satisfy a given condition\r | |
14 | \r | |
15 | getfile(), getsourcefile(), getsource() - find an object's source code\r | |
16 | getdoc(), getcomments() - get documentation on an object\r | |
17 | getmodule() - determine the module that an object came from\r | |
18 | getclasstree() - arrange classes so as to represent their hierarchy\r | |
19 | \r | |
20 | getargspec(), getargvalues(), getcallargs() - get info about function arguments\r | |
21 | formatargspec(), formatargvalues() - format an argument spec\r | |
22 | getouterframes(), getinnerframes() - get info about frames\r | |
23 | currentframe() - get the current stack frame\r | |
24 | stack(), trace() - get info about frames on the stack or in a traceback\r | |
25 | """\r | |
26 | \r | |
27 | # This module is in the public domain. No warranties.\r | |
28 | \r | |
29 | __author__ = 'Ka-Ping Yee <ping@lfw.org>'\r | |
30 | __date__ = '1 Jan 2001'\r | |
31 | \r | |
32 | import sys\r | |
33 | import os\r | |
34 | import types\r | |
35 | import string\r | |
36 | import re\r | |
37 | import dis\r | |
38 | import imp\r | |
39 | import tokenize\r | |
40 | import linecache\r | |
41 | from operator import attrgetter\r | |
42 | from collections import namedtuple\r | |
43 | \r | |
44 | # These constants are from Include/code.h.\r | |
45 | CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8\r | |
46 | CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40\r | |
47 | # See Include/object.h\r | |
48 | TPFLAGS_IS_ABSTRACT = 1 << 20\r | |
49 | \r | |
50 | # ----------------------------------------------------------- type-checking\r | |
51 | def ismodule(object):\r | |
52 | """Return true if the object is a module.\r | |
53 | \r | |
54 | Module objects provide these attributes:\r | |
55 | __doc__ documentation string\r | |
56 | __file__ filename (missing for built-in modules)"""\r | |
57 | return isinstance(object, types.ModuleType)\r | |
58 | \r | |
59 | def isclass(object):\r | |
60 | """Return true if the object is a class.\r | |
61 | \r | |
62 | Class objects provide these attributes:\r | |
63 | __doc__ documentation string\r | |
64 | __module__ name of module in which this class was defined"""\r | |
65 | return isinstance(object, (type, types.ClassType))\r | |
66 | \r | |
67 | def ismethod(object):\r | |
68 | """Return true if the object is an instance method.\r | |
69 | \r | |
70 | Instance method objects provide these attributes:\r | |
71 | __doc__ documentation string\r | |
72 | __name__ name with which this method was defined\r | |
73 | im_class class object in which this method belongs\r | |
74 | im_func function object containing implementation of method\r | |
75 | im_self instance to which this method is bound, or None"""\r | |
76 | return isinstance(object, types.MethodType)\r | |
77 | \r | |
78 | def ismethoddescriptor(object):\r | |
79 | """Return true if the object is a method descriptor.\r | |
80 | \r | |
81 | But not if ismethod() or isclass() or isfunction() are true.\r | |
82 | \r | |
83 | This is new in Python 2.2, and, for example, is true of int.__add__.\r | |
84 | An object passing this test has a __get__ attribute but not a __set__\r | |
85 | attribute, but beyond that the set of attributes varies. __name__ is\r | |
86 | usually sensible, and __doc__ often is.\r | |
87 | \r | |
88 | Methods implemented via descriptors that also pass one of the other\r | |
89 | tests return false from the ismethoddescriptor() test, simply because\r | |
90 | the other tests promise more -- you can, e.g., count on having the\r | |
91 | im_func attribute (etc) when an object passes ismethod()."""\r | |
92 | return (hasattr(object, "__get__")\r | |
93 | and not hasattr(object, "__set__") # else it's a data descriptor\r | |
94 | and not ismethod(object) # mutual exclusion\r | |
95 | and not isfunction(object)\r | |
96 | and not isclass(object))\r | |
97 | \r | |
98 | def isdatadescriptor(object):\r | |
99 | """Return true if the object is a data descriptor.\r | |
100 | \r | |
101 | Data descriptors have both a __get__ and a __set__ attribute. Examples are\r | |
102 | properties (defined in Python) and getsets and members (defined in C).\r | |
103 | Typically, data descriptors will also have __name__ and __doc__ attributes\r | |
104 | (properties, getsets, and members have both of these attributes), but this\r | |
105 | is not guaranteed."""\r | |
106 | return (hasattr(object, "__set__") and hasattr(object, "__get__"))\r | |
107 | \r | |
108 | if hasattr(types, 'MemberDescriptorType'):\r | |
109 | # CPython and equivalent\r | |
110 | def ismemberdescriptor(object):\r | |
111 | """Return true if the object is a member descriptor.\r | |
112 | \r | |
113 | Member descriptors are specialized descriptors defined in extension\r | |
114 | modules."""\r | |
115 | return isinstance(object, types.MemberDescriptorType)\r | |
116 | else:\r | |
117 | # Other implementations\r | |
118 | def ismemberdescriptor(object):\r | |
119 | """Return true if the object is a member descriptor.\r | |
120 | \r | |
121 | Member descriptors are specialized descriptors defined in extension\r | |
122 | modules."""\r | |
123 | return False\r | |
124 | \r | |
125 | if hasattr(types, 'GetSetDescriptorType'):\r | |
126 | # CPython and equivalent\r | |
127 | def isgetsetdescriptor(object):\r | |
128 | """Return true if the object is a getset descriptor.\r | |
129 | \r | |
130 | getset descriptors are specialized descriptors defined in extension\r | |
131 | modules."""\r | |
132 | return isinstance(object, types.GetSetDescriptorType)\r | |
133 | else:\r | |
134 | # Other implementations\r | |
135 | def isgetsetdescriptor(object):\r | |
136 | """Return true if the object is a getset descriptor.\r | |
137 | \r | |
138 | getset descriptors are specialized descriptors defined in extension\r | |
139 | modules."""\r | |
140 | return False\r | |
141 | \r | |
142 | def isfunction(object):\r | |
143 | """Return true if the object is a user-defined function.\r | |
144 | \r | |
145 | Function objects provide these attributes:\r | |
146 | __doc__ documentation string\r | |
147 | __name__ name with which this function was defined\r | |
148 | func_code code object containing compiled function bytecode\r | |
149 | func_defaults tuple of any default values for arguments\r | |
150 | func_doc (same as __doc__)\r | |
151 | func_globals global namespace in which this function was defined\r | |
152 | func_name (same as __name__)"""\r | |
153 | return isinstance(object, types.FunctionType)\r | |
154 | \r | |
155 | def isgeneratorfunction(object):\r | |
156 | """Return true if the object is a user-defined generator function.\r | |
157 | \r | |
158 | Generator function objects provides same attributes as functions.\r | |
159 | \r | |
160 | See help(isfunction) for attributes listing."""\r | |
161 | return bool((isfunction(object) or ismethod(object)) and\r | |
162 | object.func_code.co_flags & CO_GENERATOR)\r | |
163 | \r | |
164 | def isgenerator(object):\r | |
165 | """Return true if the object is a generator.\r | |
166 | \r | |
167 | Generator objects provide these attributes:\r | |
168 | __iter__ defined to support interation over container\r | |
169 | close raises a new GeneratorExit exception inside the\r | |
170 | generator to terminate the iteration\r | |
171 | gi_code code object\r | |
172 | gi_frame frame object or possibly None once the generator has\r | |
173 | been exhausted\r | |
174 | gi_running set to 1 when generator is executing, 0 otherwise\r | |
175 | next return the next item from the container\r | |
176 | send resumes the generator and "sends" a value that becomes\r | |
177 | the result of the current yield-expression\r | |
178 | throw used to raise an exception inside the generator"""\r | |
179 | return isinstance(object, types.GeneratorType)\r | |
180 | \r | |
181 | def istraceback(object):\r | |
182 | """Return true if the object is a traceback.\r | |
183 | \r | |
184 | Traceback objects provide these attributes:\r | |
185 | tb_frame frame object at this level\r | |
186 | tb_lasti index of last attempted instruction in bytecode\r | |
187 | tb_lineno current line number in Python source code\r | |
188 | tb_next next inner traceback object (called by this level)"""\r | |
189 | return isinstance(object, types.TracebackType)\r | |
190 | \r | |
191 | def isframe(object):\r | |
192 | """Return true if the object is a frame object.\r | |
193 | \r | |
194 | Frame objects provide these attributes:\r | |
195 | f_back next outer frame object (this frame's caller)\r | |
196 | f_builtins built-in namespace seen by this frame\r | |
197 | f_code code object being executed in this frame\r | |
198 | f_exc_traceback traceback if raised in this frame, or None\r | |
199 | f_exc_type exception type if raised in this frame, or None\r | |
200 | f_exc_value exception value if raised in this frame, or None\r | |
201 | f_globals global namespace seen by this frame\r | |
202 | f_lasti index of last attempted instruction in bytecode\r | |
203 | f_lineno current line number in Python source code\r | |
204 | f_locals local namespace seen by this frame\r | |
205 | f_restricted 0 or 1 if frame is in restricted execution mode\r | |
206 | f_trace tracing function for this frame, or None"""\r | |
207 | return isinstance(object, types.FrameType)\r | |
208 | \r | |
209 | def iscode(object):\r | |
210 | """Return true if the object is a code object.\r | |
211 | \r | |
212 | Code objects provide these attributes:\r | |
213 | co_argcount number of arguments (not including * or ** args)\r | |
214 | co_code string of raw compiled bytecode\r | |
215 | co_consts tuple of constants used in the bytecode\r | |
216 | co_filename name of file in which this code object was created\r | |
217 | co_firstlineno number of first line in Python source code\r | |
218 | co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg\r | |
219 | co_lnotab encoded mapping of line numbers to bytecode indices\r | |
220 | co_name name with which this code object was defined\r | |
221 | co_names tuple of names of local variables\r | |
222 | co_nlocals number of local variables\r | |
223 | co_stacksize virtual machine stack space required\r | |
224 | co_varnames tuple of names of arguments and local variables"""\r | |
225 | return isinstance(object, types.CodeType)\r | |
226 | \r | |
227 | def isbuiltin(object):\r | |
228 | """Return true if the object is a built-in function or method.\r | |
229 | \r | |
230 | Built-in functions and methods provide these attributes:\r | |
231 | __doc__ documentation string\r | |
232 | __name__ original name of this function or method\r | |
233 | __self__ instance to which a method is bound, or None"""\r | |
234 | return isinstance(object, types.BuiltinFunctionType)\r | |
235 | \r | |
236 | def isroutine(object):\r | |
237 | """Return true if the object is any kind of function or method."""\r | |
238 | return (isbuiltin(object)\r | |
239 | or isfunction(object)\r | |
240 | or ismethod(object)\r | |
241 | or ismethoddescriptor(object))\r | |
242 | \r | |
243 | def isabstract(object):\r | |
244 | """Return true if the object is an abstract base class (ABC)."""\r | |
245 | return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT)\r | |
246 | \r | |
247 | def getmembers(object, predicate=None):\r | |
248 | """Return all members of an object as (name, value) pairs sorted by name.\r | |
249 | Optionally, only return members that satisfy a given predicate."""\r | |
250 | results = []\r | |
251 | for key in dir(object):\r | |
252 | try:\r | |
253 | value = getattr(object, key)\r | |
254 | except AttributeError:\r | |
255 | continue\r | |
256 | if not predicate or predicate(value):\r | |
257 | results.append((key, value))\r | |
258 | results.sort()\r | |
259 | return results\r | |
260 | \r | |
261 | Attribute = namedtuple('Attribute', 'name kind defining_class object')\r | |
262 | \r | |
263 | def classify_class_attrs(cls):\r | |
264 | """Return list of attribute-descriptor tuples.\r | |
265 | \r | |
266 | For each name in dir(cls), the return list contains a 4-tuple\r | |
267 | with these elements:\r | |
268 | \r | |
269 | 0. The name (a string).\r | |
270 | \r | |
271 | 1. The kind of attribute this is, one of these strings:\r | |
272 | 'class method' created via classmethod()\r | |
273 | 'static method' created via staticmethod()\r | |
274 | 'property' created via property()\r | |
275 | 'method' any other flavor of method\r | |
276 | 'data' not a method\r | |
277 | \r | |
278 | 2. The class which defined this attribute (a class).\r | |
279 | \r | |
280 | 3. The object as obtained directly from the defining class's\r | |
281 | __dict__, not via getattr. This is especially important for\r | |
282 | data attributes: C.data is just a data object, but\r | |
283 | C.__dict__['data'] may be a data descriptor with additional\r | |
284 | info, like a __doc__ string.\r | |
285 | """\r | |
286 | \r | |
287 | mro = getmro(cls)\r | |
288 | names = dir(cls)\r | |
289 | result = []\r | |
290 | for name in names:\r | |
291 | # Get the object associated with the name.\r | |
292 | # Getting an obj from the __dict__ sometimes reveals more than\r | |
293 | # using getattr. Static and class methods are dramatic examples.\r | |
294 | if name in cls.__dict__:\r | |
295 | obj = cls.__dict__[name]\r | |
296 | else:\r | |
297 | obj = getattr(cls, name)\r | |
298 | \r | |
299 | # Figure out where it was defined.\r | |
300 | homecls = getattr(obj, "__objclass__", None)\r | |
301 | if homecls is None:\r | |
302 | # search the dicts.\r | |
303 | for base in mro:\r | |
304 | if name in base.__dict__:\r | |
305 | homecls = base\r | |
306 | break\r | |
307 | \r | |
308 | # Get the object again, in order to get it from the defining\r | |
309 | # __dict__ instead of via getattr (if possible).\r | |
310 | if homecls is not None and name in homecls.__dict__:\r | |
311 | obj = homecls.__dict__[name]\r | |
312 | \r | |
313 | # Also get the object via getattr.\r | |
314 | obj_via_getattr = getattr(cls, name)\r | |
315 | \r | |
316 | # Classify the object.\r | |
317 | if isinstance(obj, staticmethod):\r | |
318 | kind = "static method"\r | |
319 | elif isinstance(obj, classmethod):\r | |
320 | kind = "class method"\r | |
321 | elif isinstance(obj, property):\r | |
322 | kind = "property"\r | |
323 | elif (ismethod(obj_via_getattr) or\r | |
324 | ismethoddescriptor(obj_via_getattr)):\r | |
325 | kind = "method"\r | |
326 | else:\r | |
327 | kind = "data"\r | |
328 | \r | |
329 | result.append(Attribute(name, kind, homecls, obj))\r | |
330 | \r | |
331 | return result\r | |
332 | \r | |
333 | # ----------------------------------------------------------- class helpers\r | |
334 | def _searchbases(cls, accum):\r | |
335 | # Simulate the "classic class" search order.\r | |
336 | if cls in accum:\r | |
337 | return\r | |
338 | accum.append(cls)\r | |
339 | for base in cls.__bases__:\r | |
340 | _searchbases(base, accum)\r | |
341 | \r | |
342 | def getmro(cls):\r | |
343 | "Return tuple of base classes (including cls) in method resolution order."\r | |
344 | if hasattr(cls, "__mro__"):\r | |
345 | return cls.__mro__\r | |
346 | else:\r | |
347 | result = []\r | |
348 | _searchbases(cls, result)\r | |
349 | return tuple(result)\r | |
350 | \r | |
351 | # -------------------------------------------------- source code extraction\r | |
352 | def indentsize(line):\r | |
353 | """Return the indent size, in spaces, at the start of a line of text."""\r | |
354 | expline = string.expandtabs(line)\r | |
355 | return len(expline) - len(string.lstrip(expline))\r | |
356 | \r | |
357 | def getdoc(object):\r | |
358 | """Get the documentation string for an object.\r | |
359 | \r | |
360 | All tabs are expanded to spaces. To clean up docstrings that are\r | |
361 | indented to line up with blocks of code, any whitespace than can be\r | |
362 | uniformly removed from the second line onwards is removed."""\r | |
363 | try:\r | |
364 | doc = object.__doc__\r | |
365 | except AttributeError:\r | |
366 | return None\r | |
367 | if not isinstance(doc, types.StringTypes):\r | |
368 | return None\r | |
369 | return cleandoc(doc)\r | |
370 | \r | |
371 | def cleandoc(doc):\r | |
372 | """Clean up indentation from docstrings.\r | |
373 | \r | |
374 | Any whitespace that can be uniformly removed from the second line\r | |
375 | onwards is removed."""\r | |
376 | try:\r | |
377 | lines = string.split(string.expandtabs(doc), '\n')\r | |
378 | except UnicodeError:\r | |
379 | return None\r | |
380 | else:\r | |
381 | # Find minimum indentation of any non-blank lines after first line.\r | |
382 | margin = sys.maxint\r | |
383 | for line in lines[1:]:\r | |
384 | content = len(string.lstrip(line))\r | |
385 | if content:\r | |
386 | indent = len(line) - content\r | |
387 | margin = min(margin, indent)\r | |
388 | # Remove indentation.\r | |
389 | if lines:\r | |
390 | lines[0] = lines[0].lstrip()\r | |
391 | if margin < sys.maxint:\r | |
392 | for i in range(1, len(lines)): lines[i] = lines[i][margin:]\r | |
393 | # Remove any trailing or leading blank lines.\r | |
394 | while lines and not lines[-1]:\r | |
395 | lines.pop()\r | |
396 | while lines and not lines[0]:\r | |
397 | lines.pop(0)\r | |
398 | return string.join(lines, '\n')\r | |
399 | \r | |
400 | def getfile(object):\r | |
401 | """Work out which source or compiled file an object was defined in."""\r | |
402 | if ismodule(object):\r | |
403 | if hasattr(object, '__file__'):\r | |
404 | return object.__file__\r | |
405 | raise TypeError('{!r} is a built-in module'.format(object))\r | |
406 | if isclass(object):\r | |
407 | object = sys.modules.get(object.__module__)\r | |
408 | if hasattr(object, '__file__'):\r | |
409 | return object.__file__\r | |
410 | raise TypeError('{!r} is a built-in class'.format(object))\r | |
411 | if ismethod(object):\r | |
412 | object = object.im_func\r | |
413 | if isfunction(object):\r | |
414 | object = object.func_code\r | |
415 | if istraceback(object):\r | |
416 | object = object.tb_frame\r | |
417 | if isframe(object):\r | |
418 | object = object.f_code\r | |
419 | if iscode(object):\r | |
420 | return object.co_filename\r | |
421 | raise TypeError('{!r} is not a module, class, method, '\r | |
422 | 'function, traceback, frame, or code object'.format(object))\r | |
423 | \r | |
424 | ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')\r | |
425 | \r | |
426 | def getmoduleinfo(path):\r | |
427 | """Get the module name, suffix, mode, and module type for a given file."""\r | |
428 | filename = os.path.basename(path)\r | |
429 | suffixes = map(lambda info:\r | |
430 | (-len(info[0]), info[0], info[1], info[2]),\r | |
431 | imp.get_suffixes())\r | |
432 | suffixes.sort() # try longest suffixes first, in case they overlap\r | |
433 | for neglen, suffix, mode, mtype in suffixes:\r | |
434 | if filename[neglen:] == suffix:\r | |
435 | return ModuleInfo(filename[:neglen], suffix, mode, mtype)\r | |
436 | \r | |
437 | def getmodulename(path):\r | |
438 | """Return the module name for a given file, or None."""\r | |
439 | info = getmoduleinfo(path)\r | |
440 | if info: return info[0]\r | |
441 | \r | |
442 | def getsourcefile(object):\r | |
443 | """Return the filename that can be used to locate an object's source.\r | |
444 | Return None if no way can be identified to get the source.\r | |
445 | """\r | |
446 | filename = getfile(object)\r | |
447 | if string.lower(filename[-4:]) in ('.pyc', '.pyo'):\r | |
448 | filename = filename[:-4] + '.py'\r | |
449 | for suffix, mode, kind in imp.get_suffixes():\r | |
450 | if 'b' in mode and string.lower(filename[-len(suffix):]) == suffix:\r | |
451 | # Looks like a binary file. We want to only return a text file.\r | |
452 | return None\r | |
453 | if os.path.exists(filename):\r | |
454 | return filename\r | |
455 | # only return a non-existent filename if the module has a PEP 302 loader\r | |
456 | if hasattr(getmodule(object, filename), '__loader__'):\r | |
457 | return filename\r | |
458 | # or it is in the linecache\r | |
459 | if filename in linecache.cache:\r | |
460 | return filename\r | |
461 | \r | |
462 | def getabsfile(object, _filename=None):\r | |
463 | """Return an absolute path to the source or compiled file for an object.\r | |
464 | \r | |
465 | The idea is for each object to have a unique origin, so this routine\r | |
466 | normalizes the result as much as possible."""\r | |
467 | if _filename is None:\r | |
468 | _filename = getsourcefile(object) or getfile(object)\r | |
469 | return os.path.normcase(os.path.abspath(_filename))\r | |
470 | \r | |
471 | modulesbyfile = {}\r | |
472 | _filesbymodname = {}\r | |
473 | \r | |
474 | def getmodule(object, _filename=None):\r | |
475 | """Return the module an object was defined in, or None if not found."""\r | |
476 | if ismodule(object):\r | |
477 | return object\r | |
478 | if hasattr(object, '__module__'):\r | |
479 | return sys.modules.get(object.__module__)\r | |
480 | # Try the filename to modulename cache\r | |
481 | if _filename is not None and _filename in modulesbyfile:\r | |
482 | return sys.modules.get(modulesbyfile[_filename])\r | |
483 | # Try the cache again with the absolute file name\r | |
484 | try:\r | |
485 | file = getabsfile(object, _filename)\r | |
486 | except TypeError:\r | |
487 | return None\r | |
488 | if file in modulesbyfile:\r | |
489 | return sys.modules.get(modulesbyfile[file])\r | |
490 | # Update the filename to module name cache and check yet again\r | |
491 | # Copy sys.modules in order to cope with changes while iterating\r | |
492 | for modname, module in sys.modules.items():\r | |
493 | if ismodule(module) and hasattr(module, '__file__'):\r | |
494 | f = module.__file__\r | |
495 | if f == _filesbymodname.get(modname, None):\r | |
496 | # Have already mapped this module, so skip it\r | |
497 | continue\r | |
498 | _filesbymodname[modname] = f\r | |
499 | f = getabsfile(module)\r | |
500 | # Always map to the name the module knows itself by\r | |
501 | modulesbyfile[f] = modulesbyfile[\r | |
502 | os.path.realpath(f)] = module.__name__\r | |
503 | if file in modulesbyfile:\r | |
504 | return sys.modules.get(modulesbyfile[file])\r | |
505 | # Check the main module\r | |
506 | main = sys.modules['__main__']\r | |
507 | if not hasattr(object, '__name__'):\r | |
508 | return None\r | |
509 | if hasattr(main, object.__name__):\r | |
510 | mainobject = getattr(main, object.__name__)\r | |
511 | if mainobject is object:\r | |
512 | return main\r | |
513 | # Check builtins\r | |
514 | builtin = sys.modules['__builtin__']\r | |
515 | if hasattr(builtin, object.__name__):\r | |
516 | builtinobject = getattr(builtin, object.__name__)\r | |
517 | if builtinobject is object:\r | |
518 | return builtin\r | |
519 | \r | |
520 | def findsource(object):\r | |
521 | """Return the entire source file and starting line number for an object.\r | |
522 | \r | |
523 | The argument may be a module, class, method, function, traceback, frame,\r | |
524 | or code object. The source code is returned as a list of all the lines\r | |
525 | in the file and the line number indexes a line in that list. An IOError\r | |
526 | is raised if the source code cannot be retrieved."""\r | |
527 | file = getsourcefile(object)\r | |
528 | if not file:\r | |
529 | raise IOError('source code not available')\r | |
530 | module = getmodule(object, file)\r | |
531 | if module:\r | |
532 | lines = linecache.getlines(file, module.__dict__)\r | |
533 | else:\r | |
534 | lines = linecache.getlines(file)\r | |
535 | if not lines:\r | |
536 | raise IOError('could not get source code')\r | |
537 | \r | |
538 | if ismodule(object):\r | |
539 | return lines, 0\r | |
540 | \r | |
541 | if isclass(object):\r | |
542 | name = object.__name__\r | |
543 | pat = re.compile(r'^(\s*)class\s*' + name + r'\b')\r | |
544 | # make some effort to find the best matching class definition:\r | |
545 | # use the one with the least indentation, which is the one\r | |
546 | # that's most probably not inside a function definition.\r | |
547 | candidates = []\r | |
548 | for i in range(len(lines)):\r | |
549 | match = pat.match(lines[i])\r | |
550 | if match:\r | |
551 | # if it's at toplevel, it's already the best one\r | |
552 | if lines[i][0] == 'c':\r | |
553 | return lines, i\r | |
554 | # else add whitespace to candidate list\r | |
555 | candidates.append((match.group(1), i))\r | |
556 | if candidates:\r | |
557 | # this will sort by whitespace, and by line number,\r | |
558 | # less whitespace first\r | |
559 | candidates.sort()\r | |
560 | return lines, candidates[0][1]\r | |
561 | else:\r | |
562 | raise IOError('could not find class definition')\r | |
563 | \r | |
564 | if ismethod(object):\r | |
565 | object = object.im_func\r | |
566 | if isfunction(object):\r | |
567 | object = object.func_code\r | |
568 | if istraceback(object):\r | |
569 | object = object.tb_frame\r | |
570 | if isframe(object):\r | |
571 | object = object.f_code\r | |
572 | if iscode(object):\r | |
573 | if not hasattr(object, 'co_firstlineno'):\r | |
574 | raise IOError('could not find function definition')\r | |
575 | lnum = object.co_firstlineno - 1\r | |
576 | pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')\r | |
577 | while lnum > 0:\r | |
578 | if pat.match(lines[lnum]): break\r | |
579 | lnum = lnum - 1\r | |
580 | return lines, lnum\r | |
581 | raise IOError('could not find code object')\r | |
582 | \r | |
583 | def getcomments(object):\r | |
584 | """Get lines of comments immediately preceding an object's source code.\r | |
585 | \r | |
586 | Returns None when source can't be found.\r | |
587 | """\r | |
588 | try:\r | |
589 | lines, lnum = findsource(object)\r | |
590 | except (IOError, TypeError):\r | |
591 | return None\r | |
592 | \r | |
593 | if ismodule(object):\r | |
594 | # Look for a comment block at the top of the file.\r | |
595 | start = 0\r | |
596 | if lines and lines[0][:2] == '#!': start = 1\r | |
597 | while start < len(lines) and string.strip(lines[start]) in ('', '#'):\r | |
598 | start = start + 1\r | |
599 | if start < len(lines) and lines[start][:1] == '#':\r | |
600 | comments = []\r | |
601 | end = start\r | |
602 | while end < len(lines) and lines[end][:1] == '#':\r | |
603 | comments.append(string.expandtabs(lines[end]))\r | |
604 | end = end + 1\r | |
605 | return string.join(comments, '')\r | |
606 | \r | |
607 | # Look for a preceding block of comments at the same indentation.\r | |
608 | elif lnum > 0:\r | |
609 | indent = indentsize(lines[lnum])\r | |
610 | end = lnum - 1\r | |
611 | if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \\r | |
612 | indentsize(lines[end]) == indent:\r | |
613 | comments = [string.lstrip(string.expandtabs(lines[end]))]\r | |
614 | if end > 0:\r | |
615 | end = end - 1\r | |
616 | comment = string.lstrip(string.expandtabs(lines[end]))\r | |
617 | while comment[:1] == '#' and indentsize(lines[end]) == indent:\r | |
618 | comments[:0] = [comment]\r | |
619 | end = end - 1\r | |
620 | if end < 0: break\r | |
621 | comment = string.lstrip(string.expandtabs(lines[end]))\r | |
622 | while comments and string.strip(comments[0]) == '#':\r | |
623 | comments[:1] = []\r | |
624 | while comments and string.strip(comments[-1]) == '#':\r | |
625 | comments[-1:] = []\r | |
626 | return string.join(comments, '')\r | |
627 | \r | |
628 | class EndOfBlock(Exception): pass\r | |
629 | \r | |
630 | class BlockFinder:\r | |
631 | """Provide a tokeneater() method to detect the end of a code block."""\r | |
632 | def __init__(self):\r | |
633 | self.indent = 0\r | |
634 | self.islambda = False\r | |
635 | self.started = False\r | |
636 | self.passline = False\r | |
637 | self.last = 1\r | |
638 | \r | |
639 | def tokeneater(self, type, token, srow_scol, erow_ecol, line):\r | |
640 | srow, scol = srow_scol\r | |
641 | erow, ecol = erow_ecol\r | |
642 | if not self.started:\r | |
643 | # look for the first "def", "class" or "lambda"\r | |
644 | if token in ("def", "class", "lambda"):\r | |
645 | if token == "lambda":\r | |
646 | self.islambda = True\r | |
647 | self.started = True\r | |
648 | self.passline = True # skip to the end of the line\r | |
649 | elif type == tokenize.NEWLINE:\r | |
650 | self.passline = False # stop skipping when a NEWLINE is seen\r | |
651 | self.last = srow\r | |
652 | if self.islambda: # lambdas always end at the first NEWLINE\r | |
653 | raise EndOfBlock\r | |
654 | elif self.passline:\r | |
655 | pass\r | |
656 | elif type == tokenize.INDENT:\r | |
657 | self.indent = self.indent + 1\r | |
658 | self.passline = True\r | |
659 | elif type == tokenize.DEDENT:\r | |
660 | self.indent = self.indent - 1\r | |
661 | # the end of matching indent/dedent pairs end a block\r | |
662 | # (note that this only works for "def"/"class" blocks,\r | |
663 | # not e.g. for "if: else:" or "try: finally:" blocks)\r | |
664 | if self.indent <= 0:\r | |
665 | raise EndOfBlock\r | |
666 | elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL):\r | |
667 | # any other token on the same indentation level end the previous\r | |
668 | # block as well, except the pseudo-tokens COMMENT and NL.\r | |
669 | raise EndOfBlock\r | |
670 | \r | |
671 | def getblock(lines):\r | |
672 | """Extract the block of code at the top of the given list of lines."""\r | |
673 | blockfinder = BlockFinder()\r | |
674 | try:\r | |
675 | tokenize.tokenize(iter(lines).next, blockfinder.tokeneater)\r | |
676 | except (EndOfBlock, IndentationError):\r | |
677 | pass\r | |
678 | return lines[:blockfinder.last]\r | |
679 | \r | |
680 | def getsourcelines(object):\r | |
681 | """Return a list of source lines and starting line number for an object.\r | |
682 | \r | |
683 | The argument may be a module, class, method, function, traceback, frame,\r | |
684 | or code object. The source code is returned as a list of the lines\r | |
685 | corresponding to the object and the line number indicates where in the\r | |
686 | original source file the first line of code was found. An IOError is\r | |
687 | raised if the source code cannot be retrieved."""\r | |
688 | lines, lnum = findsource(object)\r | |
689 | \r | |
690 | if ismodule(object): return lines, 0\r | |
691 | else: return getblock(lines[lnum:]), lnum + 1\r | |
692 | \r | |
693 | def getsource(object):\r | |
694 | """Return the text of the source code for an object.\r | |
695 | \r | |
696 | The argument may be a module, class, method, function, traceback, frame,\r | |
697 | or code object. The source code is returned as a single string. An\r | |
698 | IOError is raised if the source code cannot be retrieved."""\r | |
699 | lines, lnum = getsourcelines(object)\r | |
700 | return string.join(lines, '')\r | |
701 | \r | |
702 | # --------------------------------------------------- class tree extraction\r | |
703 | def walktree(classes, children, parent):\r | |
704 | """Recursive helper function for getclasstree()."""\r | |
705 | results = []\r | |
706 | classes.sort(key=attrgetter('__module__', '__name__'))\r | |
707 | for c in classes:\r | |
708 | results.append((c, c.__bases__))\r | |
709 | if c in children:\r | |
710 | results.append(walktree(children[c], children, c))\r | |
711 | return results\r | |
712 | \r | |
713 | def getclasstree(classes, unique=0):\r | |
714 | """Arrange the given list of classes into a hierarchy of nested lists.\r | |
715 | \r | |
716 | Where a nested list appears, it contains classes derived from the class\r | |
717 | whose entry immediately precedes the list. Each entry is a 2-tuple\r | |
718 | containing a class and a tuple of its base classes. If the 'unique'\r | |
719 | argument is true, exactly one entry appears in the returned structure\r | |
720 | for each class in the given list. Otherwise, classes using multiple\r | |
721 | inheritance and their descendants will appear multiple times."""\r | |
722 | children = {}\r | |
723 | roots = []\r | |
724 | for c in classes:\r | |
725 | if c.__bases__:\r | |
726 | for parent in c.__bases__:\r | |
727 | if not parent in children:\r | |
728 | children[parent] = []\r | |
729 | children[parent].append(c)\r | |
730 | if unique and parent in classes: break\r | |
731 | elif c not in roots:\r | |
732 | roots.append(c)\r | |
733 | for parent in children:\r | |
734 | if parent not in classes:\r | |
735 | roots.append(parent)\r | |
736 | return walktree(roots, children, None)\r | |
737 | \r | |
738 | # ------------------------------------------------ argument list extraction\r | |
739 | Arguments = namedtuple('Arguments', 'args varargs keywords')\r | |
740 | \r | |
741 | def getargs(co):\r | |
742 | """Get information about the arguments accepted by a code object.\r | |
743 | \r | |
744 | Three things are returned: (args, varargs, varkw), where 'args' is\r | |
745 | a list of argument names (possibly containing nested lists), and\r | |
746 | 'varargs' and 'varkw' are the names of the * and ** arguments or None."""\r | |
747 | \r | |
748 | if not iscode(co):\r | |
749 | raise TypeError('{!r} is not a code object'.format(co))\r | |
750 | \r | |
751 | nargs = co.co_argcount\r | |
752 | names = co.co_varnames\r | |
753 | args = list(names[:nargs])\r | |
754 | step = 0\r | |
755 | \r | |
756 | # The following acrobatics are for anonymous (tuple) arguments.\r | |
757 | for i in range(nargs):\r | |
758 | if args[i][:1] in ('', '.'):\r | |
759 | stack, remain, count = [], [], []\r | |
760 | while step < len(co.co_code):\r | |
761 | op = ord(co.co_code[step])\r | |
762 | step = step + 1\r | |
763 | if op >= dis.HAVE_ARGUMENT:\r | |
764 | opname = dis.opname[op]\r | |
765 | value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256\r | |
766 | step = step + 2\r | |
767 | if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):\r | |
768 | remain.append(value)\r | |
769 | count.append(value)\r | |
770 | elif opname == 'STORE_FAST':\r | |
771 | stack.append(names[value])\r | |
772 | \r | |
773 | # Special case for sublists of length 1: def foo((bar))\r | |
774 | # doesn't generate the UNPACK_TUPLE bytecode, so if\r | |
775 | # `remain` is empty here, we have such a sublist.\r | |
776 | if not remain:\r | |
777 | stack[0] = [stack[0]]\r | |
778 | break\r | |
779 | else:\r | |
780 | remain[-1] = remain[-1] - 1\r | |
781 | while remain[-1] == 0:\r | |
782 | remain.pop()\r | |
783 | size = count.pop()\r | |
784 | stack[-size:] = [stack[-size:]]\r | |
785 | if not remain: break\r | |
786 | remain[-1] = remain[-1] - 1\r | |
787 | if not remain: break\r | |
788 | args[i] = stack[0]\r | |
789 | \r | |
790 | varargs = None\r | |
791 | if co.co_flags & CO_VARARGS:\r | |
792 | varargs = co.co_varnames[nargs]\r | |
793 | nargs = nargs + 1\r | |
794 | varkw = None\r | |
795 | if co.co_flags & CO_VARKEYWORDS:\r | |
796 | varkw = co.co_varnames[nargs]\r | |
797 | return Arguments(args, varargs, varkw)\r | |
798 | \r | |
799 | ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')\r | |
800 | \r | |
801 | def getargspec(func):\r | |
802 | """Get the names and default values of a function's arguments.\r | |
803 | \r | |
804 | A tuple of four things is returned: (args, varargs, varkw, defaults).\r | |
805 | 'args' is a list of the argument names (it may contain nested lists).\r | |
806 | 'varargs' and 'varkw' are the names of the * and ** arguments or None.\r | |
807 | 'defaults' is an n-tuple of the default values of the last n arguments.\r | |
808 | """\r | |
809 | \r | |
810 | if ismethod(func):\r | |
811 | func = func.im_func\r | |
812 | if not isfunction(func):\r | |
813 | raise TypeError('{!r} is not a Python function'.format(func))\r | |
814 | args, varargs, varkw = getargs(func.func_code)\r | |
815 | return ArgSpec(args, varargs, varkw, func.func_defaults)\r | |
816 | \r | |
817 | ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')\r | |
818 | \r | |
819 | def getargvalues(frame):\r | |
820 | """Get information about arguments passed into a particular frame.\r | |
821 | \r | |
822 | A tuple of four things is returned: (args, varargs, varkw, locals).\r | |
823 | 'args' is a list of the argument names (it may contain nested lists).\r | |
824 | 'varargs' and 'varkw' are the names of the * and ** arguments or None.\r | |
825 | 'locals' is the locals dictionary of the given frame."""\r | |
826 | args, varargs, varkw = getargs(frame.f_code)\r | |
827 | return ArgInfo(args, varargs, varkw, frame.f_locals)\r | |
828 | \r | |
829 | def joinseq(seq):\r | |
830 | if len(seq) == 1:\r | |
831 | return '(' + seq[0] + ',)'\r | |
832 | else:\r | |
833 | return '(' + string.join(seq, ', ') + ')'\r | |
834 | \r | |
835 | def strseq(object, convert, join=joinseq):\r | |
836 | """Recursively walk a sequence, stringifying each element."""\r | |
837 | if type(object) in (list, tuple):\r | |
838 | return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))\r | |
839 | else:\r | |
840 | return convert(object)\r | |
841 | \r | |
842 | def formatargspec(args, varargs=None, varkw=None, defaults=None,\r | |
843 | formatarg=str,\r | |
844 | formatvarargs=lambda name: '*' + name,\r | |
845 | formatvarkw=lambda name: '**' + name,\r | |
846 | formatvalue=lambda value: '=' + repr(value),\r | |
847 | join=joinseq):\r | |
848 | """Format an argument spec from the 4 values returned by getargspec.\r | |
849 | \r | |
850 | The first four arguments are (args, varargs, varkw, defaults). The\r | |
851 | other four arguments are the corresponding optional formatting functions\r | |
852 | that are called to turn names and values into strings. The ninth\r | |
853 | argument is an optional function to format the sequence of arguments."""\r | |
854 | specs = []\r | |
855 | if defaults:\r | |
856 | firstdefault = len(args) - len(defaults)\r | |
857 | for i, arg in enumerate(args):\r | |
858 | spec = strseq(arg, formatarg, join)\r | |
859 | if defaults and i >= firstdefault:\r | |
860 | spec = spec + formatvalue(defaults[i - firstdefault])\r | |
861 | specs.append(spec)\r | |
862 | if varargs is not None:\r | |
863 | specs.append(formatvarargs(varargs))\r | |
864 | if varkw is not None:\r | |
865 | specs.append(formatvarkw(varkw))\r | |
866 | return '(' + string.join(specs, ', ') + ')'\r | |
867 | \r | |
868 | def formatargvalues(args, varargs, varkw, locals,\r | |
869 | formatarg=str,\r | |
870 | formatvarargs=lambda name: '*' + name,\r | |
871 | formatvarkw=lambda name: '**' + name,\r | |
872 | formatvalue=lambda value: '=' + repr(value),\r | |
873 | join=joinseq):\r | |
874 | """Format an argument spec from the 4 values returned by getargvalues.\r | |
875 | \r | |
876 | The first four arguments are (args, varargs, varkw, locals). The\r | |
877 | next four arguments are the corresponding optional formatting functions\r | |
878 | that are called to turn names and values into strings. The ninth\r | |
879 | argument is an optional function to format the sequence of arguments."""\r | |
880 | def convert(name, locals=locals,\r | |
881 | formatarg=formatarg, formatvalue=formatvalue):\r | |
882 | return formatarg(name) + formatvalue(locals[name])\r | |
883 | specs = []\r | |
884 | for i in range(len(args)):\r | |
885 | specs.append(strseq(args[i], convert, join))\r | |
886 | if varargs:\r | |
887 | specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))\r | |
888 | if varkw:\r | |
889 | specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))\r | |
890 | return '(' + string.join(specs, ', ') + ')'\r | |
891 | \r | |
892 | def getcallargs(func, *positional, **named):\r | |
893 | """Get the mapping of arguments to values.\r | |
894 | \r | |
895 | A dict is returned, with keys the function argument names (including the\r | |
896 | names of the * and ** arguments, if any), and values the respective bound\r | |
897 | values from 'positional' and 'named'."""\r | |
898 | args, varargs, varkw, defaults = getargspec(func)\r | |
899 | f_name = func.__name__\r | |
900 | arg2value = {}\r | |
901 | \r | |
902 | # The following closures are basically because of tuple parameter unpacking.\r | |
903 | assigned_tuple_params = []\r | |
904 | def assign(arg, value):\r | |
905 | if isinstance(arg, str):\r | |
906 | arg2value[arg] = value\r | |
907 | else:\r | |
908 | assigned_tuple_params.append(arg)\r | |
909 | value = iter(value)\r | |
910 | for i, subarg in enumerate(arg):\r | |
911 | try:\r | |
912 | subvalue = next(value)\r | |
913 | except StopIteration:\r | |
914 | raise ValueError('need more than %d %s to unpack' %\r | |
915 | (i, 'values' if i > 1 else 'value'))\r | |
916 | assign(subarg,subvalue)\r | |
917 | try:\r | |
918 | next(value)\r | |
919 | except StopIteration:\r | |
920 | pass\r | |
921 | else:\r | |
922 | raise ValueError('too many values to unpack')\r | |
923 | def is_assigned(arg):\r | |
924 | if isinstance(arg,str):\r | |
925 | return arg in arg2value\r | |
926 | return arg in assigned_tuple_params\r | |
927 | if ismethod(func) and func.im_self is not None:\r | |
928 | # implicit 'self' (or 'cls' for classmethods) argument\r | |
929 | positional = (func.im_self,) + positional\r | |
930 | num_pos = len(positional)\r | |
931 | num_total = num_pos + len(named)\r | |
932 | num_args = len(args)\r | |
933 | num_defaults = len(defaults) if defaults else 0\r | |
934 | for arg, value in zip(args, positional):\r | |
935 | assign(arg, value)\r | |
936 | if varargs:\r | |
937 | if num_pos > num_args:\r | |
938 | assign(varargs, positional[-(num_pos-num_args):])\r | |
939 | else:\r | |
940 | assign(varargs, ())\r | |
941 | elif 0 < num_args < num_pos:\r | |
942 | raise TypeError('%s() takes %s %d %s (%d given)' % (\r | |
943 | f_name, 'at most' if defaults else 'exactly', num_args,\r | |
944 | 'arguments' if num_args > 1 else 'argument', num_total))\r | |
945 | elif num_args == 0 and num_total:\r | |
946 | if varkw:\r | |
947 | if num_pos:\r | |
948 | # XXX: We should use num_pos, but Python also uses num_total:\r | |
949 | raise TypeError('%s() takes exactly 0 arguments '\r | |
950 | '(%d given)' % (f_name, num_total))\r | |
951 | else:\r | |
952 | raise TypeError('%s() takes no arguments (%d given)' %\r | |
953 | (f_name, num_total))\r | |
954 | for arg in args:\r | |
955 | if isinstance(arg, str) and arg in named:\r | |
956 | if is_assigned(arg):\r | |
957 | raise TypeError("%s() got multiple values for keyword "\r | |
958 | "argument '%s'" % (f_name, arg))\r | |
959 | else:\r | |
960 | assign(arg, named.pop(arg))\r | |
961 | if defaults: # fill in any missing values with the defaults\r | |
962 | for arg, value in zip(args[-num_defaults:], defaults):\r | |
963 | if not is_assigned(arg):\r | |
964 | assign(arg, value)\r | |
965 | if varkw:\r | |
966 | assign(varkw, named)\r | |
967 | elif named:\r | |
968 | unexpected = next(iter(named))\r | |
969 | if isinstance(unexpected, unicode):\r | |
970 | unexpected = unexpected.encode(sys.getdefaultencoding(), 'replace')\r | |
971 | raise TypeError("%s() got an unexpected keyword argument '%s'" %\r | |
972 | (f_name, unexpected))\r | |
973 | unassigned = num_args - len([arg for arg in args if is_assigned(arg)])\r | |
974 | if unassigned:\r | |
975 | num_required = num_args - num_defaults\r | |
976 | raise TypeError('%s() takes %s %d %s (%d given)' % (\r | |
977 | f_name, 'at least' if defaults else 'exactly', num_required,\r | |
978 | 'arguments' if num_required > 1 else 'argument', num_total))\r | |
979 | return arg2value\r | |
980 | \r | |
981 | # -------------------------------------------------- stack frame extraction\r | |
982 | \r | |
983 | Traceback = namedtuple('Traceback', 'filename lineno function code_context index')\r | |
984 | \r | |
985 | def getframeinfo(frame, context=1):\r | |
986 | """Get information about a frame or traceback object.\r | |
987 | \r | |
988 | A tuple of five things is returned: the filename, the line number of\r | |
989 | the current line, the function name, a list of lines of context from\r | |
990 | the source code, and the index of the current line within that list.\r | |
991 | The optional second argument specifies the number of lines of context\r | |
992 | to return, which are centered around the current line."""\r | |
993 | if istraceback(frame):\r | |
994 | lineno = frame.tb_lineno\r | |
995 | frame = frame.tb_frame\r | |
996 | else:\r | |
997 | lineno = frame.f_lineno\r | |
998 | if not isframe(frame):\r | |
999 | raise TypeError('{!r} is not a frame or traceback object'.format(frame))\r | |
1000 | \r | |
1001 | filename = getsourcefile(frame) or getfile(frame)\r | |
1002 | if context > 0:\r | |
1003 | start = lineno - 1 - context//2\r | |
1004 | try:\r | |
1005 | lines, lnum = findsource(frame)\r | |
1006 | except IOError:\r | |
1007 | lines = index = None\r | |
1008 | else:\r | |
1009 | start = max(start, 1)\r | |
1010 | start = max(0, min(start, len(lines) - context))\r | |
1011 | lines = lines[start:start+context]\r | |
1012 | index = lineno - 1 - start\r | |
1013 | else:\r | |
1014 | lines = index = None\r | |
1015 | \r | |
1016 | return Traceback(filename, lineno, frame.f_code.co_name, lines, index)\r | |
1017 | \r | |
1018 | def getlineno(frame):\r | |
1019 | """Get the line number from a frame object, allowing for optimization."""\r | |
1020 | # FrameType.f_lineno is now a descriptor that grovels co_lnotab\r | |
1021 | return frame.f_lineno\r | |
1022 | \r | |
1023 | def getouterframes(frame, context=1):\r | |
1024 | """Get a list of records for a frame and all higher (calling) frames.\r | |
1025 | \r | |
1026 | Each record contains a frame object, filename, line number, function\r | |
1027 | name, a list of lines of context, and index within the context."""\r | |
1028 | framelist = []\r | |
1029 | while frame:\r | |
1030 | framelist.append((frame,) + getframeinfo(frame, context))\r | |
1031 | frame = frame.f_back\r | |
1032 | return framelist\r | |
1033 | \r | |
1034 | def getinnerframes(tb, context=1):\r | |
1035 | """Get a list of records for a traceback's frame and all lower frames.\r | |
1036 | \r | |
1037 | Each record contains a frame object, filename, line number, function\r | |
1038 | name, a list of lines of context, and index within the context."""\r | |
1039 | framelist = []\r | |
1040 | while tb:\r | |
1041 | framelist.append((tb.tb_frame,) + getframeinfo(tb, context))\r | |
1042 | tb = tb.tb_next\r | |
1043 | return framelist\r | |
1044 | \r | |
1045 | if hasattr(sys, '_getframe'):\r | |
1046 | currentframe = sys._getframe\r | |
1047 | else:\r | |
1048 | currentframe = lambda _=None: None\r | |
1049 | \r | |
1050 | def stack(context=1):\r | |
1051 | """Return a list of records for the stack above the caller's frame."""\r | |
1052 | return getouterframes(sys._getframe(1), context)\r | |
1053 | \r | |
1054 | def trace(context=1):\r | |
1055 | """Return a list of records for the stack below the current exception."""\r | |
1056 | return getinnerframes(sys.exc_info()[2], context)\r |