]> git.proxmox.com Git - mirror_edk2.git/blobdiff - AppPkg/Applications/Python/Python-2.7.10/Lib/inspect.py
AppPkg/Applications/Python/Python-2.7.10: Initial Checkin part 4/5.
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.10 / Lib / inspect.py
diff --git a/AppPkg/Applications/Python/Python-2.7.10/Lib/inspect.py b/AppPkg/Applications/Python/Python-2.7.10/Lib/inspect.py
new file mode 100644 (file)
index 0000000..ada3873
--- /dev/null
@@ -0,0 +1,1059 @@
+# -*- coding: iso-8859-1 -*-\r
+"""Get useful information from live Python objects.\r
+\r
+This module encapsulates the interface provided by the internal special\r
+attributes (func_*, co_*, im_*, tb_*, etc.) in a friendlier fashion.\r
+It also provides some help for examining source code and class layout.\r
+\r
+Here are some of the useful functions provided by this module:\r
+\r
+    ismodule(), isclass(), ismethod(), isfunction(), isgeneratorfunction(),\r
+        isgenerator(), istraceback(), isframe(), iscode(), isbuiltin(),\r
+        isroutine() - check object types\r
+    getmembers() - get members of an object that satisfy a given condition\r
+\r
+    getfile(), getsourcefile(), getsource() - find an object's source code\r
+    getdoc(), getcomments() - get documentation on an object\r
+    getmodule() - determine the module that an object came from\r
+    getclasstree() - arrange classes so as to represent their hierarchy\r
+\r
+    getargspec(), getargvalues(), getcallargs() - get info about function arguments\r
+    formatargspec(), formatargvalues() - format an argument spec\r
+    getouterframes(), getinnerframes() - get info about frames\r
+    currentframe() - get the current stack frame\r
+    stack(), trace() - get info about frames on the stack or in a traceback\r
+"""\r
+\r
+# This module is in the public domain.  No warranties.\r
+\r
+__author__ = 'Ka-Ping Yee <ping@lfw.org>'\r
+__date__ = '1 Jan 2001'\r
+\r
+import sys\r
+import os\r
+import types\r
+import string\r
+import re\r
+import dis\r
+import imp\r
+import tokenize\r
+import linecache\r
+from operator import attrgetter\r
+from collections import namedtuple\r
+\r
+# These constants are from Include/code.h.\r
+CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 0x1, 0x2, 0x4, 0x8\r
+CO_NESTED, CO_GENERATOR, CO_NOFREE = 0x10, 0x20, 0x40\r
+# See Include/object.h\r
+TPFLAGS_IS_ABSTRACT = 1 << 20\r
+\r
+# ----------------------------------------------------------- type-checking\r
+def ismodule(object):\r
+    """Return true if the object is a module.\r
+\r
+    Module objects provide these attributes:\r
+        __doc__         documentation string\r
+        __file__        filename (missing for built-in modules)"""\r
+    return isinstance(object, types.ModuleType)\r
+\r
+def isclass(object):\r
+    """Return true if the object is a class.\r
+\r
+    Class objects provide these attributes:\r
+        __doc__         documentation string\r
+        __module__      name of module in which this class was defined"""\r
+    return isinstance(object, (type, types.ClassType))\r
+\r
+def ismethod(object):\r
+    """Return true if the object is an instance method.\r
+\r
+    Instance method objects provide these attributes:\r
+        __doc__         documentation string\r
+        __name__        name with which this method was defined\r
+        im_class        class object in which this method belongs\r
+        im_func         function object containing implementation of method\r
+        im_self         instance to which this method is bound, or None"""\r
+    return isinstance(object, types.MethodType)\r
+\r
+def ismethoddescriptor(object):\r
+    """Return true if the object is a method descriptor.\r
+\r
+    But not if ismethod() or isclass() or isfunction() are true.\r
+\r
+    This is new in Python 2.2, and, for example, is true of int.__add__.\r
+    An object passing this test has a __get__ attribute but not a __set__\r
+    attribute, but beyond that the set of attributes varies.  __name__ is\r
+    usually sensible, and __doc__ often is.\r
+\r
+    Methods implemented via descriptors that also pass one of the other\r
+    tests return false from the ismethoddescriptor() test, simply because\r
+    the other tests promise more -- you can, e.g., count on having the\r
+    im_func attribute (etc) when an object passes ismethod()."""\r
+    return (hasattr(object, "__get__")\r
+            and not hasattr(object, "__set__") # else it's a data descriptor\r
+            and not ismethod(object)           # mutual exclusion\r
+            and not isfunction(object)\r
+            and not isclass(object))\r
+\r
+def isdatadescriptor(object):\r
+    """Return true if the object is a data descriptor.\r
+\r
+    Data descriptors have both a __get__ and a __set__ attribute.  Examples are\r
+    properties (defined in Python) and getsets and members (defined in C).\r
+    Typically, data descriptors will also have __name__ and __doc__ attributes\r
+    (properties, getsets, and members have both of these attributes), but this\r
+    is not guaranteed."""\r
+    return (hasattr(object, "__set__") and hasattr(object, "__get__"))\r
+\r
+if hasattr(types, 'MemberDescriptorType'):\r
+    # CPython and equivalent\r
+    def ismemberdescriptor(object):\r
+        """Return true if the object is a member descriptor.\r
+\r
+        Member descriptors are specialized descriptors defined in extension\r
+        modules."""\r
+        return isinstance(object, types.MemberDescriptorType)\r
+else:\r
+    # Other implementations\r
+    def ismemberdescriptor(object):\r
+        """Return true if the object is a member descriptor.\r
+\r
+        Member descriptors are specialized descriptors defined in extension\r
+        modules."""\r
+        return False\r
+\r
+if hasattr(types, 'GetSetDescriptorType'):\r
+    # CPython and equivalent\r
+    def isgetsetdescriptor(object):\r
+        """Return true if the object is a getset descriptor.\r
+\r
+        getset descriptors are specialized descriptors defined in extension\r
+        modules."""\r
+        return isinstance(object, types.GetSetDescriptorType)\r
+else:\r
+    # Other implementations\r
+    def isgetsetdescriptor(object):\r
+        """Return true if the object is a getset descriptor.\r
+\r
+        getset descriptors are specialized descriptors defined in extension\r
+        modules."""\r
+        return False\r
+\r
+def isfunction(object):\r
+    """Return true if the object is a user-defined function.\r
+\r
+    Function objects provide these attributes:\r
+        __doc__         documentation string\r
+        __name__        name with which this function was defined\r
+        func_code       code object containing compiled function bytecode\r
+        func_defaults   tuple of any default values for arguments\r
+        func_doc        (same as __doc__)\r
+        func_globals    global namespace in which this function was defined\r
+        func_name       (same as __name__)"""\r
+    return isinstance(object, types.FunctionType)\r
+\r
+def isgeneratorfunction(object):\r
+    """Return true if the object is a user-defined generator function.\r
+\r
+    Generator function objects provides same attributes as functions.\r
+\r
+    See help(isfunction) for attributes listing."""\r
+    return bool((isfunction(object) or ismethod(object)) and\r
+                object.func_code.co_flags & CO_GENERATOR)\r
+\r
+def isgenerator(object):\r
+    """Return true if the object is a generator.\r
+\r
+    Generator objects provide these attributes:\r
+        __iter__        defined to support iteration over container\r
+        close           raises a new GeneratorExit exception inside the\r
+                        generator to terminate the iteration\r
+        gi_code         code object\r
+        gi_frame        frame object or possibly None once the generator has\r
+                        been exhausted\r
+        gi_running      set to 1 when generator is executing, 0 otherwise\r
+        next            return the next item from the container\r
+        send            resumes the generator and "sends" a value that becomes\r
+                        the result of the current yield-expression\r
+        throw           used to raise an exception inside the generator"""\r
+    return isinstance(object, types.GeneratorType)\r
+\r
+def istraceback(object):\r
+    """Return true if the object is a traceback.\r
+\r
+    Traceback objects provide these attributes:\r
+        tb_frame        frame object at this level\r
+        tb_lasti        index of last attempted instruction in bytecode\r
+        tb_lineno       current line number in Python source code\r
+        tb_next         next inner traceback object (called by this level)"""\r
+    return isinstance(object, types.TracebackType)\r
+\r
+def isframe(object):\r
+    """Return true if the object is a frame object.\r
+\r
+    Frame objects provide these attributes:\r
+        f_back          next outer frame object (this frame's caller)\r
+        f_builtins      built-in namespace seen by this frame\r
+        f_code          code object being executed in this frame\r
+        f_exc_traceback traceback if raised in this frame, or None\r
+        f_exc_type      exception type if raised in this frame, or None\r
+        f_exc_value     exception value if raised in this frame, or None\r
+        f_globals       global namespace seen by this frame\r
+        f_lasti         index of last attempted instruction in bytecode\r
+        f_lineno        current line number in Python source code\r
+        f_locals        local namespace seen by this frame\r
+        f_restricted    0 or 1 if frame is in restricted execution mode\r
+        f_trace         tracing function for this frame, or None"""\r
+    return isinstance(object, types.FrameType)\r
+\r
+def iscode(object):\r
+    """Return true if the object is a code object.\r
+\r
+    Code objects provide these attributes:\r
+        co_argcount     number of arguments (not including * or ** args)\r
+        co_code         string of raw compiled bytecode\r
+        co_consts       tuple of constants used in the bytecode\r
+        co_filename     name of file in which this code object was created\r
+        co_firstlineno  number of first line in Python source code\r
+        co_flags        bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg\r
+        co_lnotab       encoded mapping of line numbers to bytecode indices\r
+        co_name         name with which this code object was defined\r
+        co_names        tuple of names of local variables\r
+        co_nlocals      number of local variables\r
+        co_stacksize    virtual machine stack space required\r
+        co_varnames     tuple of names of arguments and local variables"""\r
+    return isinstance(object, types.CodeType)\r
+\r
+def isbuiltin(object):\r
+    """Return true if the object is a built-in function or method.\r
+\r
+    Built-in functions and methods provide these attributes:\r
+        __doc__         documentation string\r
+        __name__        original name of this function or method\r
+        __self__        instance to which a method is bound, or None"""\r
+    return isinstance(object, types.BuiltinFunctionType)\r
+\r
+def isroutine(object):\r
+    """Return true if the object is any kind of function or method."""\r
+    return (isbuiltin(object)\r
+            or isfunction(object)\r
+            or ismethod(object)\r
+            or ismethoddescriptor(object))\r
+\r
+def isabstract(object):\r
+    """Return true if the object is an abstract base class (ABC)."""\r
+    return bool(isinstance(object, type) and object.__flags__ & TPFLAGS_IS_ABSTRACT)\r
+\r
+def getmembers(object, predicate=None):\r
+    """Return all members of an object as (name, value) pairs sorted by name.\r
+    Optionally, only return members that satisfy a given predicate."""\r
+    results = []\r
+    for key in dir(object):\r
+        try:\r
+            value = getattr(object, key)\r
+        except AttributeError:\r
+            continue\r
+        if not predicate or predicate(value):\r
+            results.append((key, value))\r
+    results.sort()\r
+    return results\r
+\r
+Attribute = namedtuple('Attribute', 'name kind defining_class object')\r
+\r
+def classify_class_attrs(cls):\r
+    """Return list of attribute-descriptor tuples.\r
+\r
+    For each name in dir(cls), the return list contains a 4-tuple\r
+    with these elements:\r
+\r
+        0. The name (a string).\r
+\r
+        1. The kind of attribute this is, one of these strings:\r
+               'class method'    created via classmethod()\r
+               'static method'   created via staticmethod()\r
+               'property'        created via property()\r
+               'method'          any other flavor of method\r
+               'data'            not a method\r
+\r
+        2. The class which defined this attribute (a class).\r
+\r
+        3. The object as obtained directly from the defining class's\r
+           __dict__, not via getattr.  This is especially important for\r
+           data attributes:  C.data is just a data object, but\r
+           C.__dict__['data'] may be a data descriptor with additional\r
+           info, like a __doc__ string.\r
+    """\r
+\r
+    mro = getmro(cls)\r
+    names = dir(cls)\r
+    result = []\r
+    for name in names:\r
+        # Get the object associated with the name, and where it was defined.\r
+        # Getting an obj from the __dict__ sometimes reveals more than\r
+        # using getattr.  Static and class methods are dramatic examples.\r
+        # Furthermore, some objects may raise an Exception when fetched with\r
+        # getattr(). This is the case with some descriptors (bug #1785).\r
+        # Thus, we only use getattr() as a last resort.\r
+        homecls = None\r
+        for base in (cls,) + mro:\r
+            if name in base.__dict__:\r
+                obj = base.__dict__[name]\r
+                homecls = base\r
+                break\r
+        else:\r
+            obj = getattr(cls, name)\r
+            homecls = getattr(obj, "__objclass__", homecls)\r
+\r
+        # Classify the object.\r
+        if isinstance(obj, staticmethod):\r
+            kind = "static method"\r
+        elif isinstance(obj, classmethod):\r
+            kind = "class method"\r
+        elif isinstance(obj, property):\r
+            kind = "property"\r
+        elif ismethoddescriptor(obj):\r
+            kind = "method"\r
+        elif isdatadescriptor(obj):\r
+            kind = "data"\r
+        else:\r
+            obj_via_getattr = getattr(cls, name)\r
+            if (ismethod(obj_via_getattr) or\r
+                ismethoddescriptor(obj_via_getattr)):\r
+                kind = "method"\r
+            else:\r
+                kind = "data"\r
+            obj = obj_via_getattr\r
+\r
+        result.append(Attribute(name, kind, homecls, obj))\r
+\r
+    return result\r
+\r
+# ----------------------------------------------------------- class helpers\r
+def _searchbases(cls, accum):\r
+    # Simulate the "classic class" search order.\r
+    if cls in accum:\r
+        return\r
+    accum.append(cls)\r
+    for base in cls.__bases__:\r
+        _searchbases(base, accum)\r
+\r
+def getmro(cls):\r
+    "Return tuple of base classes (including cls) in method resolution order."\r
+    if hasattr(cls, "__mro__"):\r
+        return cls.__mro__\r
+    else:\r
+        result = []\r
+        _searchbases(cls, result)\r
+        return tuple(result)\r
+\r
+# -------------------------------------------------- source code extraction\r
+def indentsize(line):\r
+    """Return the indent size, in spaces, at the start of a line of text."""\r
+    expline = string.expandtabs(line)\r
+    return len(expline) - len(string.lstrip(expline))\r
+\r
+def getdoc(object):\r
+    """Get the documentation string for an object.\r
+\r
+    All tabs are expanded to spaces.  To clean up docstrings that are\r
+    indented to line up with blocks of code, any whitespace than can be\r
+    uniformly removed from the second line onwards is removed."""\r
+    try:\r
+        doc = object.__doc__\r
+    except AttributeError:\r
+        return None\r
+    if not isinstance(doc, types.StringTypes):\r
+        return None\r
+    return cleandoc(doc)\r
+\r
+def cleandoc(doc):\r
+    """Clean up indentation from docstrings.\r
+\r
+    Any whitespace that can be uniformly removed from the second line\r
+    onwards is removed."""\r
+    try:\r
+        lines = string.split(string.expandtabs(doc), '\n')\r
+    except UnicodeError:\r
+        return None\r
+    else:\r
+        # Find minimum indentation of any non-blank lines after first line.\r
+        margin = sys.maxint\r
+        for line in lines[1:]:\r
+            content = len(string.lstrip(line))\r
+            if content:\r
+                indent = len(line) - content\r
+                margin = min(margin, indent)\r
+        # Remove indentation.\r
+        if lines:\r
+            lines[0] = lines[0].lstrip()\r
+        if margin < sys.maxint:\r
+            for i in range(1, len(lines)): lines[i] = lines[i][margin:]\r
+        # Remove any trailing or leading blank lines.\r
+        while lines and not lines[-1]:\r
+            lines.pop()\r
+        while lines and not lines[0]:\r
+            lines.pop(0)\r
+        return string.join(lines, '\n')\r
+\r
+def getfile(object):\r
+    """Work out which source or compiled file an object was defined in."""\r
+    if ismodule(object):\r
+        if hasattr(object, '__file__'):\r
+            return object.__file__\r
+        raise TypeError('{!r} is a built-in module'.format(object))\r
+    if isclass(object):\r
+        object = sys.modules.get(object.__module__)\r
+        if hasattr(object, '__file__'):\r
+            return object.__file__\r
+        raise TypeError('{!r} is a built-in class'.format(object))\r
+    if ismethod(object):\r
+        object = object.im_func\r
+    if isfunction(object):\r
+        object = object.func_code\r
+    if istraceback(object):\r
+        object = object.tb_frame\r
+    if isframe(object):\r
+        object = object.f_code\r
+    if iscode(object):\r
+        return object.co_filename\r
+    raise TypeError('{!r} is not a module, class, method, '\r
+                    'function, traceback, frame, or code object'.format(object))\r
+\r
+ModuleInfo = namedtuple('ModuleInfo', 'name suffix mode module_type')\r
+\r
+def getmoduleinfo(path):\r
+    """Get the module name, suffix, mode, and module type for a given file."""\r
+    filename = os.path.basename(path)\r
+    suffixes = map(lambda info:\r
+                   (-len(info[0]), info[0], info[1], info[2]),\r
+                    imp.get_suffixes())\r
+    suffixes.sort() # try longest suffixes first, in case they overlap\r
+    for neglen, suffix, mode, mtype in suffixes:\r
+        if filename[neglen:] == suffix:\r
+            return ModuleInfo(filename[:neglen], suffix, mode, mtype)\r
+\r
+def getmodulename(path):\r
+    """Return the module name for a given file, or None."""\r
+    info = getmoduleinfo(path)\r
+    if info: return info[0]\r
+\r
+def getsourcefile(object):\r
+    """Return the filename that can be used to locate an object's source.\r
+    Return None if no way can be identified to get the source.\r
+    """\r
+    filename = getfile(object)\r
+    if string.lower(filename[-4:]) in ('.pyc', '.pyo'):\r
+        filename = filename[:-4] + '.py'\r
+    for suffix, mode, kind in imp.get_suffixes():\r
+        if 'b' in mode and string.lower(filename[-len(suffix):]) == suffix:\r
+            # Looks like a binary file.  We want to only return a text file.\r
+            return None\r
+    if os.path.exists(filename):\r
+        return filename\r
+    # only return a non-existent filename if the module has a PEP 302 loader\r
+    if hasattr(getmodule(object, filename), '__loader__'):\r
+        return filename\r
+    # or it is in the linecache\r
+    if filename in linecache.cache:\r
+        return filename\r
+\r
+def getabsfile(object, _filename=None):\r
+    """Return an absolute path to the source or compiled file for an object.\r
+\r
+    The idea is for each object to have a unique origin, so this routine\r
+    normalizes the result as much as possible."""\r
+    if _filename is None:\r
+        _filename = getsourcefile(object) or getfile(object)\r
+    return os.path.normcase(os.path.abspath(_filename))\r
+\r
+modulesbyfile = {}\r
+_filesbymodname = {}\r
+\r
+def getmodule(object, _filename=None):\r
+    """Return the module an object was defined in, or None if not found."""\r
+    if ismodule(object):\r
+        return object\r
+    if hasattr(object, '__module__'):\r
+        return sys.modules.get(object.__module__)\r
+    # Try the filename to modulename cache\r
+    if _filename is not None and _filename in modulesbyfile:\r
+        return sys.modules.get(modulesbyfile[_filename])\r
+    # Try the cache again with the absolute file name\r
+    try:\r
+        file = getabsfile(object, _filename)\r
+    except TypeError:\r
+        return None\r
+    if file in modulesbyfile:\r
+        return sys.modules.get(modulesbyfile[file])\r
+    # Update the filename to module name cache and check yet again\r
+    # Copy sys.modules in order to cope with changes while iterating\r
+    for modname, module in sys.modules.items():\r
+        if ismodule(module) and hasattr(module, '__file__'):\r
+            f = module.__file__\r
+            if f == _filesbymodname.get(modname, None):\r
+                # Have already mapped this module, so skip it\r
+                continue\r
+            _filesbymodname[modname] = f\r
+            f = getabsfile(module)\r
+            # Always map to the name the module knows itself by\r
+            modulesbyfile[f] = modulesbyfile[\r
+                os.path.realpath(f)] = module.__name__\r
+    if file in modulesbyfile:\r
+        return sys.modules.get(modulesbyfile[file])\r
+    # Check the main module\r
+    main = sys.modules['__main__']\r
+    if not hasattr(object, '__name__'):\r
+        return None\r
+    if hasattr(main, object.__name__):\r
+        mainobject = getattr(main, object.__name__)\r
+        if mainobject is object:\r
+            return main\r
+    # Check builtins\r
+    builtin = sys.modules['__builtin__']\r
+    if hasattr(builtin, object.__name__):\r
+        builtinobject = getattr(builtin, object.__name__)\r
+        if builtinobject is object:\r
+            return builtin\r
+\r
+def findsource(object):\r
+    """Return the entire source file and starting line number for an object.\r
+\r
+    The argument may be a module, class, method, function, traceback, frame,\r
+    or code object.  The source code is returned as a list of all the lines\r
+    in the file and the line number indexes a line in that list.  An IOError\r
+    is raised if the source code cannot be retrieved."""\r
+\r
+    file = getfile(object)\r
+    sourcefile = getsourcefile(object)\r
+    if not sourcefile and file[:1] + file[-1:] != '<>':\r
+        raise IOError('source code not available')\r
+    file = sourcefile if sourcefile else file\r
+\r
+    module = getmodule(object, file)\r
+    if module:\r
+        lines = linecache.getlines(file, module.__dict__)\r
+    else:\r
+        lines = linecache.getlines(file)\r
+    if not lines:\r
+        raise IOError('could not get source code')\r
+\r
+    if ismodule(object):\r
+        return lines, 0\r
+\r
+    if isclass(object):\r
+        name = object.__name__\r
+        pat = re.compile(r'^(\s*)class\s*' + name + r'\b')\r
+        # make some effort to find the best matching class definition:\r
+        # use the one with the least indentation, which is the one\r
+        # that's most probably not inside a function definition.\r
+        candidates = []\r
+        for i in range(len(lines)):\r
+            match = pat.match(lines[i])\r
+            if match:\r
+                # if it's at toplevel, it's already the best one\r
+                if lines[i][0] == 'c':\r
+                    return lines, i\r
+                # else add whitespace to candidate list\r
+                candidates.append((match.group(1), i))\r
+        if candidates:\r
+            # this will sort by whitespace, and by line number,\r
+            # less whitespace first\r
+            candidates.sort()\r
+            return lines, candidates[0][1]\r
+        else:\r
+            raise IOError('could not find class definition')\r
+\r
+    if ismethod(object):\r
+        object = object.im_func\r
+    if isfunction(object):\r
+        object = object.func_code\r
+    if istraceback(object):\r
+        object = object.tb_frame\r
+    if isframe(object):\r
+        object = object.f_code\r
+    if iscode(object):\r
+        if not hasattr(object, 'co_firstlineno'):\r
+            raise IOError('could not find function definition')\r
+        lnum = object.co_firstlineno - 1\r
+        pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')\r
+        while lnum > 0:\r
+            if pat.match(lines[lnum]): break\r
+            lnum = lnum - 1\r
+        return lines, lnum\r
+    raise IOError('could not find code object')\r
+\r
+def getcomments(object):\r
+    """Get lines of comments immediately preceding an object's source code.\r
+\r
+    Returns None when source can't be found.\r
+    """\r
+    try:\r
+        lines, lnum = findsource(object)\r
+    except (IOError, TypeError):\r
+        return None\r
+\r
+    if ismodule(object):\r
+        # Look for a comment block at the top of the file.\r
+        start = 0\r
+        if lines and lines[0][:2] == '#!': start = 1\r
+        while start < len(lines) and string.strip(lines[start]) in ('', '#'):\r
+            start = start + 1\r
+        if start < len(lines) and lines[start][:1] == '#':\r
+            comments = []\r
+            end = start\r
+            while end < len(lines) and lines[end][:1] == '#':\r
+                comments.append(string.expandtabs(lines[end]))\r
+                end = end + 1\r
+            return string.join(comments, '')\r
+\r
+    # Look for a preceding block of comments at the same indentation.\r
+    elif lnum > 0:\r
+        indent = indentsize(lines[lnum])\r
+        end = lnum - 1\r
+        if end >= 0 and string.lstrip(lines[end])[:1] == '#' and \\r
+            indentsize(lines[end]) == indent:\r
+            comments = [string.lstrip(string.expandtabs(lines[end]))]\r
+            if end > 0:\r
+                end = end - 1\r
+                comment = string.lstrip(string.expandtabs(lines[end]))\r
+                while comment[:1] == '#' and indentsize(lines[end]) == indent:\r
+                    comments[:0] = [comment]\r
+                    end = end - 1\r
+                    if end < 0: break\r
+                    comment = string.lstrip(string.expandtabs(lines[end]))\r
+            while comments and string.strip(comments[0]) == '#':\r
+                comments[:1] = []\r
+            while comments and string.strip(comments[-1]) == '#':\r
+                comments[-1:] = []\r
+            return string.join(comments, '')\r
+\r
+class EndOfBlock(Exception): pass\r
+\r
+class BlockFinder:\r
+    """Provide a tokeneater() method to detect the end of a code block."""\r
+    def __init__(self):\r
+        self.indent = 0\r
+        self.islambda = False\r
+        self.started = False\r
+        self.passline = False\r
+        self.last = 1\r
+\r
+    def tokeneater(self, type, token, srow_scol, erow_ecol, line):\r
+        srow, scol = srow_scol\r
+        erow, ecol = erow_ecol\r
+        if not self.started:\r
+            # look for the first "def", "class" or "lambda"\r
+            if token in ("def", "class", "lambda"):\r
+                if token == "lambda":\r
+                    self.islambda = True\r
+                self.started = True\r
+            self.passline = True    # skip to the end of the line\r
+        elif type == tokenize.NEWLINE:\r
+            self.passline = False   # stop skipping when a NEWLINE is seen\r
+            self.last = srow\r
+            if self.islambda:       # lambdas always end at the first NEWLINE\r
+                raise EndOfBlock\r
+        elif self.passline:\r
+            pass\r
+        elif type == tokenize.INDENT:\r
+            self.indent = self.indent + 1\r
+            self.passline = True\r
+        elif type == tokenize.DEDENT:\r
+            self.indent = self.indent - 1\r
+            # the end of matching indent/dedent pairs end a block\r
+            # (note that this only works for "def"/"class" blocks,\r
+            #  not e.g. for "if: else:" or "try: finally:" blocks)\r
+            if self.indent <= 0:\r
+                raise EndOfBlock\r
+        elif self.indent == 0 and type not in (tokenize.COMMENT, tokenize.NL):\r
+            # any other token on the same indentation level end the previous\r
+            # block as well, except the pseudo-tokens COMMENT and NL.\r
+            raise EndOfBlock\r
+\r
+def getblock(lines):\r
+    """Extract the block of code at the top of the given list of lines."""\r
+    blockfinder = BlockFinder()\r
+    try:\r
+        tokenize.tokenize(iter(lines).next, blockfinder.tokeneater)\r
+    except (EndOfBlock, IndentationError):\r
+        pass\r
+    return lines[:blockfinder.last]\r
+\r
+def getsourcelines(object):\r
+    """Return a list of source lines and starting line number for an object.\r
+\r
+    The argument may be a module, class, method, function, traceback, frame,\r
+    or code object.  The source code is returned as a list of the lines\r
+    corresponding to the object and the line number indicates where in the\r
+    original source file the first line of code was found.  An IOError is\r
+    raised if the source code cannot be retrieved."""\r
+    lines, lnum = findsource(object)\r
+\r
+    if ismodule(object): return lines, 0\r
+    else: return getblock(lines[lnum:]), lnum + 1\r
+\r
+def getsource(object):\r
+    """Return the text of the source code for an object.\r
+\r
+    The argument may be a module, class, method, function, traceback, frame,\r
+    or code object.  The source code is returned as a single string.  An\r
+    IOError is raised if the source code cannot be retrieved."""\r
+    lines, lnum = getsourcelines(object)\r
+    return string.join(lines, '')\r
+\r
+# --------------------------------------------------- class tree extraction\r
+def walktree(classes, children, parent):\r
+    """Recursive helper function for getclasstree()."""\r
+    results = []\r
+    classes.sort(key=attrgetter('__module__', '__name__'))\r
+    for c in classes:\r
+        results.append((c, c.__bases__))\r
+        if c in children:\r
+            results.append(walktree(children[c], children, c))\r
+    return results\r
+\r
+def getclasstree(classes, unique=0):\r
+    """Arrange the given list of classes into a hierarchy of nested lists.\r
+\r
+    Where a nested list appears, it contains classes derived from the class\r
+    whose entry immediately precedes the list.  Each entry is a 2-tuple\r
+    containing a class and a tuple of its base classes.  If the 'unique'\r
+    argument is true, exactly one entry appears in the returned structure\r
+    for each class in the given list.  Otherwise, classes using multiple\r
+    inheritance and their descendants will appear multiple times."""\r
+    children = {}\r
+    roots = []\r
+    for c in classes:\r
+        if c.__bases__:\r
+            for parent in c.__bases__:\r
+                if not parent in children:\r
+                    children[parent] = []\r
+                if c not in children[parent]:\r
+                    children[parent].append(c)\r
+                if unique and parent in classes: break\r
+        elif c not in roots:\r
+            roots.append(c)\r
+    for parent in children:\r
+        if parent not in classes:\r
+            roots.append(parent)\r
+    return walktree(roots, children, None)\r
+\r
+# ------------------------------------------------ argument list extraction\r
+Arguments = namedtuple('Arguments', 'args varargs keywords')\r
+\r
+def getargs(co):\r
+    """Get information about the arguments accepted by a code object.\r
+\r
+    Three things are returned: (args, varargs, varkw), where 'args' is\r
+    a list of argument names (possibly containing nested lists), and\r
+    'varargs' and 'varkw' are the names of the * and ** arguments or None."""\r
+\r
+    if not iscode(co):\r
+        raise TypeError('{!r} is not a code object'.format(co))\r
+\r
+    nargs = co.co_argcount\r
+    names = co.co_varnames\r
+    args = list(names[:nargs])\r
+    step = 0\r
+\r
+    # The following acrobatics are for anonymous (tuple) arguments.\r
+    for i in range(nargs):\r
+        if args[i][:1] in ('', '.'):\r
+            stack, remain, count = [], [], []\r
+            while step < len(co.co_code):\r
+                op = ord(co.co_code[step])\r
+                step = step + 1\r
+                if op >= dis.HAVE_ARGUMENT:\r
+                    opname = dis.opname[op]\r
+                    value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256\r
+                    step = step + 2\r
+                    if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):\r
+                        remain.append(value)\r
+                        count.append(value)\r
+                    elif opname == 'STORE_FAST':\r
+                        stack.append(names[value])\r
+\r
+                        # Special case for sublists of length 1: def foo((bar))\r
+                        # doesn't generate the UNPACK_TUPLE bytecode, so if\r
+                        # `remain` is empty here, we have such a sublist.\r
+                        if not remain:\r
+                            stack[0] = [stack[0]]\r
+                            break\r
+                        else:\r
+                            remain[-1] = remain[-1] - 1\r
+                            while remain[-1] == 0:\r
+                                remain.pop()\r
+                                size = count.pop()\r
+                                stack[-size:] = [stack[-size:]]\r
+                                if not remain: break\r
+                                remain[-1] = remain[-1] - 1\r
+                            if not remain: break\r
+            args[i] = stack[0]\r
+\r
+    varargs = None\r
+    if co.co_flags & CO_VARARGS:\r
+        varargs = co.co_varnames[nargs]\r
+        nargs = nargs + 1\r
+    varkw = None\r
+    if co.co_flags & CO_VARKEYWORDS:\r
+        varkw = co.co_varnames[nargs]\r
+    return Arguments(args, varargs, varkw)\r
+\r
+ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults')\r
+\r
+def getargspec(func):\r
+    """Get the names and default values of a function's arguments.\r
+\r
+    A tuple of four things is returned: (args, varargs, varkw, defaults).\r
+    'args' is a list of the argument names (it may contain nested lists).\r
+    'varargs' and 'varkw' are the names of the * and ** arguments or None.\r
+    'defaults' is an n-tuple of the default values of the last n arguments.\r
+    """\r
+\r
+    if ismethod(func):\r
+        func = func.im_func\r
+    if not isfunction(func):\r
+        raise TypeError('{!r} is not a Python function'.format(func))\r
+    args, varargs, varkw = getargs(func.func_code)\r
+    return ArgSpec(args, varargs, varkw, func.func_defaults)\r
+\r
+ArgInfo = namedtuple('ArgInfo', 'args varargs keywords locals')\r
+\r
+def getargvalues(frame):\r
+    """Get information about arguments passed into a particular frame.\r
+\r
+    A tuple of four things is returned: (args, varargs, varkw, locals).\r
+    'args' is a list of the argument names (it may contain nested lists).\r
+    'varargs' and 'varkw' are the names of the * and ** arguments or None.\r
+    'locals' is the locals dictionary of the given frame."""\r
+    args, varargs, varkw = getargs(frame.f_code)\r
+    return ArgInfo(args, varargs, varkw, frame.f_locals)\r
+\r
+def joinseq(seq):\r
+    if len(seq) == 1:\r
+        return '(' + seq[0] + ',)'\r
+    else:\r
+        return '(' + string.join(seq, ', ') + ')'\r
+\r
+def strseq(object, convert, join=joinseq):\r
+    """Recursively walk a sequence, stringifying each element."""\r
+    if type(object) in (list, tuple):\r
+        return join(map(lambda o, c=convert, j=join: strseq(o, c, j), object))\r
+    else:\r
+        return convert(object)\r
+\r
+def formatargspec(args, varargs=None, varkw=None, defaults=None,\r
+                  formatarg=str,\r
+                  formatvarargs=lambda name: '*' + name,\r
+                  formatvarkw=lambda name: '**' + name,\r
+                  formatvalue=lambda value: '=' + repr(value),\r
+                  join=joinseq):\r
+    """Format an argument spec from the 4 values returned by getargspec.\r
+\r
+    The first four arguments are (args, varargs, varkw, defaults).  The\r
+    other four arguments are the corresponding optional formatting functions\r
+    that are called to turn names and values into strings.  The ninth\r
+    argument is an optional function to format the sequence of arguments."""\r
+    specs = []\r
+    if defaults:\r
+        firstdefault = len(args) - len(defaults)\r
+    for i, arg in enumerate(args):\r
+        spec = strseq(arg, formatarg, join)\r
+        if defaults and i >= firstdefault:\r
+            spec = spec + formatvalue(defaults[i - firstdefault])\r
+        specs.append(spec)\r
+    if varargs is not None:\r
+        specs.append(formatvarargs(varargs))\r
+    if varkw is not None:\r
+        specs.append(formatvarkw(varkw))\r
+    return '(' + string.join(specs, ', ') + ')'\r
+\r
+def formatargvalues(args, varargs, varkw, locals,\r
+                    formatarg=str,\r
+                    formatvarargs=lambda name: '*' + name,\r
+                    formatvarkw=lambda name: '**' + name,\r
+                    formatvalue=lambda value: '=' + repr(value),\r
+                    join=joinseq):\r
+    """Format an argument spec from the 4 values returned by getargvalues.\r
+\r
+    The first four arguments are (args, varargs, varkw, locals).  The\r
+    next four arguments are the corresponding optional formatting functions\r
+    that are called to turn names and values into strings.  The ninth\r
+    argument is an optional function to format the sequence of arguments."""\r
+    def convert(name, locals=locals,\r
+                formatarg=formatarg, formatvalue=formatvalue):\r
+        return formatarg(name) + formatvalue(locals[name])\r
+    specs = []\r
+    for i in range(len(args)):\r
+        specs.append(strseq(args[i], convert, join))\r
+    if varargs:\r
+        specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))\r
+    if varkw:\r
+        specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))\r
+    return '(' + string.join(specs, ', ') + ')'\r
+\r
+def getcallargs(func, *positional, **named):\r
+    """Get the mapping of arguments to values.\r
+\r
+    A dict is returned, with keys the function argument names (including the\r
+    names of the * and ** arguments, if any), and values the respective bound\r
+    values from 'positional' and 'named'."""\r
+    args, varargs, varkw, defaults = getargspec(func)\r
+    f_name = func.__name__\r
+    arg2value = {}\r
+\r
+    # The following closures are basically because of tuple parameter unpacking.\r
+    assigned_tuple_params = []\r
+    def assign(arg, value):\r
+        if isinstance(arg, str):\r
+            arg2value[arg] = value\r
+        else:\r
+            assigned_tuple_params.append(arg)\r
+            value = iter(value)\r
+            for i, subarg in enumerate(arg):\r
+                try:\r
+                    subvalue = next(value)\r
+                except StopIteration:\r
+                    raise ValueError('need more than %d %s to unpack' %\r
+                                     (i, 'values' if i > 1 else 'value'))\r
+                assign(subarg,subvalue)\r
+            try:\r
+                next(value)\r
+            except StopIteration:\r
+                pass\r
+            else:\r
+                raise ValueError('too many values to unpack')\r
+    def is_assigned(arg):\r
+        if isinstance(arg,str):\r
+            return arg in arg2value\r
+        return arg in assigned_tuple_params\r
+    if ismethod(func) and func.im_self is not None:\r
+        # implicit 'self' (or 'cls' for classmethods) argument\r
+        positional = (func.im_self,) + positional\r
+    num_pos = len(positional)\r
+    num_total = num_pos + len(named)\r
+    num_args = len(args)\r
+    num_defaults = len(defaults) if defaults else 0\r
+    for arg, value in zip(args, positional):\r
+        assign(arg, value)\r
+    if varargs:\r
+        if num_pos > num_args:\r
+            assign(varargs, positional[-(num_pos-num_args):])\r
+        else:\r
+            assign(varargs, ())\r
+    elif 0 < num_args < num_pos:\r
+        raise TypeError('%s() takes %s %d %s (%d given)' % (\r
+            f_name, 'at most' if defaults else 'exactly', num_args,\r
+            'arguments' if num_args > 1 else 'argument', num_total))\r
+    elif num_args == 0 and num_total:\r
+        if varkw:\r
+            if num_pos:\r
+                # XXX: We should use num_pos, but Python also uses num_total:\r
+                raise TypeError('%s() takes exactly 0 arguments '\r
+                                '(%d given)' % (f_name, num_total))\r
+        else:\r
+            raise TypeError('%s() takes no arguments (%d given)' %\r
+                            (f_name, num_total))\r
+    for arg in args:\r
+        if isinstance(arg, str) and arg in named:\r
+            if is_assigned(arg):\r
+                raise TypeError("%s() got multiple values for keyword "\r
+                                "argument '%s'" % (f_name, arg))\r
+            else:\r
+                assign(arg, named.pop(arg))\r
+    if defaults:    # fill in any missing values with the defaults\r
+        for arg, value in zip(args[-num_defaults:], defaults):\r
+            if not is_assigned(arg):\r
+                assign(arg, value)\r
+    if varkw:\r
+        assign(varkw, named)\r
+    elif named:\r
+        unexpected = next(iter(named))\r
+        if isinstance(unexpected, unicode):\r
+            unexpected = unexpected.encode(sys.getdefaultencoding(), 'replace')\r
+        raise TypeError("%s() got an unexpected keyword argument '%s'" %\r
+                        (f_name, unexpected))\r
+    unassigned = num_args - len([arg for arg in args if is_assigned(arg)])\r
+    if unassigned:\r
+        num_required = num_args - num_defaults\r
+        raise TypeError('%s() takes %s %d %s (%d given)' % (\r
+            f_name, 'at least' if defaults else 'exactly', num_required,\r
+            'arguments' if num_required > 1 else 'argument', num_total))\r
+    return arg2value\r
+\r
+# -------------------------------------------------- stack frame extraction\r
+\r
+Traceback = namedtuple('Traceback', 'filename lineno function code_context index')\r
+\r
+def getframeinfo(frame, context=1):\r
+    """Get information about a frame or traceback object.\r
+\r
+    A tuple of five things is returned: the filename, the line number of\r
+    the current line, the function name, a list of lines of context from\r
+    the source code, and the index of the current line within that list.\r
+    The optional second argument specifies the number of lines of context\r
+    to return, which are centered around the current line."""\r
+    if istraceback(frame):\r
+        lineno = frame.tb_lineno\r
+        frame = frame.tb_frame\r
+    else:\r
+        lineno = frame.f_lineno\r
+    if not isframe(frame):\r
+        raise TypeError('{!r} is not a frame or traceback object'.format(frame))\r
+\r
+    filename = getsourcefile(frame) or getfile(frame)\r
+    if context > 0:\r
+        start = lineno - 1 - context//2\r
+        try:\r
+            lines, lnum = findsource(frame)\r
+        except IOError:\r
+            lines = index = None\r
+        else:\r
+            start = max(start, 1)\r
+            start = max(0, min(start, len(lines) - context))\r
+            lines = lines[start:start+context]\r
+            index = lineno - 1 - start\r
+    else:\r
+        lines = index = None\r
+\r
+    return Traceback(filename, lineno, frame.f_code.co_name, lines, index)\r
+\r
+def getlineno(frame):\r
+    """Get the line number from a frame object, allowing for optimization."""\r
+    # FrameType.f_lineno is now a descriptor that grovels co_lnotab\r
+    return frame.f_lineno\r
+\r
+def getouterframes(frame, context=1):\r
+    """Get a list of records for a frame and all higher (calling) frames.\r
+\r
+    Each record contains a frame object, filename, line number, function\r
+    name, a list of lines of context, and index within the context."""\r
+    framelist = []\r
+    while frame:\r
+        framelist.append((frame,) + getframeinfo(frame, context))\r
+        frame = frame.f_back\r
+    return framelist\r
+\r
+def getinnerframes(tb, context=1):\r
+    """Get a list of records for a traceback's frame and all lower frames.\r
+\r
+    Each record contains a frame object, filename, line number, function\r
+    name, a list of lines of context, and index within the context."""\r
+    framelist = []\r
+    while tb:\r
+        framelist.append((tb.tb_frame,) + getframeinfo(tb, context))\r
+        tb = tb.tb_next\r
+    return framelist\r
+\r
+if hasattr(sys, '_getframe'):\r
+    currentframe = sys._getframe\r
+else:\r
+    currentframe = lambda _=None: None\r
+\r
+def stack(context=1):\r
+    """Return a list of records for the stack above the caller's frame."""\r
+    return getouterframes(sys._getframe(1), context)\r
+\r
+def trace(context=1):\r
+    """Return a list of records for the stack below the current exception."""\r
+    return getinnerframes(sys.exc_info()[2], context)\r