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