13257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel"""Find modules used by a script, using introspection."""
23257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# This module should be kept compatible with Python 2.2, see PEP 291.
33257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
43257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielfrom __future__ import generators
53257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport dis
63257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport imp
73257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport marshal
83257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport os
93257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport sys
103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport types
113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielimport struct
123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielif hasattr(sys.__stdout__, "newlines"):
143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    READ_MODE = "U"  # universal line endings
153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielelse:
163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # remain compatible with Python  < 2.3
173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    READ_MODE = "r"
183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielLOAD_CONST = chr(dis.opname.index('LOAD_CONST'))
203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielIMPORT_NAME = chr(dis.opname.index('IMPORT_NAME'))
213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielSTORE_NAME = chr(dis.opname.index('STORE_NAME'))
223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielSTORE_GLOBAL = chr(dis.opname.index('STORE_GLOBAL'))
233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielSTORE_OPS = [STORE_NAME, STORE_GLOBAL]
243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielHAVE_ARGUMENT = chr(dis.HAVE_ARGUMENT)
253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# Modulefinder does a good job at simulating Python's, but it can not
273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# handle __path__ modifications packages make at runtime.  Therefore there
283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# is a mechanism whereby you can register extra paths in this map for a
293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# package, and it will be honored.
303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# Note this is a mapping is lists of paths.
323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielpackagePathMap = {}
333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# A Public interface
353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef AddPackagePath(packagename, path):
363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    paths = packagePathMap.get(packagename, [])
373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    paths.append(path)
383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    packagePathMap[packagename] = paths
393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielreplacePackageMap = {}
413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# This ReplacePackage mechanism allows modulefinder to work around the
433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# way the _xmlplus package injects itself under the name "xml" into
443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml")
453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel# before running ModuleFinder.
463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef ReplacePackage(oldname, newname):
483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    replacePackageMap[oldname] = newname
493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass Module:
523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __init__(self, name, file=None, path=None):
543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.__name__ = name
553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.__file__ = file
563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.__path__ = path
573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.__code__ = None
583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # The set of global names that are assigned to in the module.
593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # This includes those names imported through starimports of
603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Python modules.
613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.globalnames = {}
623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # The set of starimports this module did that could not be
633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # resolved, ie. a starimport from a non-Python module.
643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.starimports = {}
653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __repr__(self):
673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        s = "Module(%r" % (self.__name__,)
683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if self.__file__ is not None:
693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            s = s + ", %r" % (self.__file__,)
703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if self.__path__ is not None:
713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            s = s + ", %r" % (self.__path__,)
723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        s = s + ")"
733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return s
743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielclass ModuleFinder:
763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def __init__(self, path=None, debug=0, excludes=[], replace_paths=[]):
783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if path is None:
793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            path = sys.path
803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.path = path
813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.modules = {}
823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.badmodules = {}
833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.debug = debug
843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.indent = 0
853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.excludes = excludes
863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.replace_paths = replace_paths
873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.processed_paths = []   # Used in debugging only
883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def msg(self, level, str, *args):
903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if level <= self.debug:
913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            for i in range(self.indent):
923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print "   ",
933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print str,
943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            for arg in args:
953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print repr(arg),
963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print
973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def msgin(self, *args):
993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        level = args[0]
1003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if level <= self.debug:
1013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.indent = self.indent + 1
1023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msg(*args)
1033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def msgout(self, *args):
1053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        level = args[0]
1063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if level <= self.debug:
1073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.indent = self.indent - 1
1083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msg(*args)
1093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def run_script(self, pathname):
1113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msg(2, "run_script", pathname)
1123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        with open(pathname, READ_MODE) as fp:
1133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            stuff = ("", "r", imp.PY_SOURCE)
1143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.load_module('__main__', fp, pathname, stuff)
1153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def load_file(self, pathname):
1173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        dir, name = os.path.split(pathname)
1183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        name, ext = os.path.splitext(name)
1193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        with open(pathname, READ_MODE) as fp:
1203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            stuff = (ext, "r", imp.PY_SOURCE)
1213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.load_module(name, fp, pathname, stuff)
1223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def import_hook(self, name, caller=None, fromlist=None, level=-1):
1243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msg(3, "import_hook", name, caller, fromlist, level)
1253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        parent = self.determine_parent(caller, level=level)
1263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        q, tail = self.find_head_package(parent, name)
1273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m = self.load_tail(q, tail)
1283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not fromlist:
1293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return q
1303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if m.__path__:
1313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.ensure_fromlist(m, fromlist)
1323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return None
1333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def determine_parent(self, caller, level=-1):
1353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(4, "determine_parent", caller, level)
1363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not caller or level == 0:
1373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(4, "determine_parent -> None")
1383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return None
1393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        pname = caller.__name__
1403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if level >= 1: # relative import
1413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if caller.__path__:
1423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                level -= 1
1433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if level == 0:
1443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                parent = self.modules[pname]
1453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                assert parent is caller
1463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(4, "determine_parent ->", parent)
1473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return parent
1483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if pname.count(".") < level:
1493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                raise ImportError, "relative importpath too deep"
1503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pname = ".".join(pname.split(".")[:-level])
1513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            parent = self.modules[pname]
1523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(4, "determine_parent ->", parent)
1533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return parent
1543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if caller.__path__:
1553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            parent = self.modules[pname]
1563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            assert caller is parent
1573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(4, "determine_parent ->", parent)
1583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return parent
1593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if '.' in pname:
1603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            i = pname.rfind('.')
1613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pname = pname[:i]
1623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            parent = self.modules[pname]
1633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            assert parent.__name__ == pname
1643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(4, "determine_parent ->", parent)
1653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return parent
1663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(4, "determine_parent -> None")
1673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return None
1683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def find_head_package(self, parent, name):
1703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(4, "find_head_package", parent, name)
1713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if '.' in name:
1723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            i = name.find('.')
1733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            head = name[:i]
1743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            tail = name[i+1:]
1753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
1763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            head = name
1773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            tail = ""
1783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if parent:
1793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            qname = "%s.%s" % (parent.__name__, head)
1803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
1813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            qname = head
1823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        q = self.import_module(head, qname, parent)
1833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if q:
1843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(4, "find_head_package ->", (q, tail))
1853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return q, tail
1863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if parent:
1873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            qname = head
1883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            parent = None
1893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            q = self.import_module(head, qname, parent)
1903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if q:
1913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(4, "find_head_package ->", (q, tail))
1923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return q, tail
1933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(4, "raise ImportError: No module named", qname)
1943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        raise ImportError, "No module named " + qname
1953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
1963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def load_tail(self, q, tail):
1973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(4, "load_tail", q, tail)
1983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m = q
1993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        while tail:
2003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            i = tail.find('.')
2013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if i < 0: i = len(tail)
2023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            head, tail = tail[:i], tail[i+1:]
2033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            mname = "%s.%s" % (m.__name__, head)
2043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m = self.import_module(head, mname, m)
2053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if not m:
2063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(4, "raise ImportError: No module named", mname)
2073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                raise ImportError, "No module named " + mname
2083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(4, "load_tail ->", m)
2093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return m
2103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def ensure_fromlist(self, m, fromlist, recursive=0):
2123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msg(4, "ensure_fromlist", m, fromlist, recursive)
2133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for sub in fromlist:
2143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if sub == "*":
2153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if not recursive:
2163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    all = self.find_all_submodules(m)
2173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if all:
2183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self.ensure_fromlist(m, all, 1)
2193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            elif not hasattr(m, sub):
2203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                subname = "%s.%s" % (m.__name__, sub)
2213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                submod = self.import_module(sub, subname, m)
2223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if not submod:
2233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    raise ImportError, "No module named " + subname
2243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def find_all_submodules(self, m):
2263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if not m.__path__:
2273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return
2283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        modules = {}
2293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # 'suffixes' used to be a list hardcoded to [".py", ".pyc", ".pyo"].
2303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # But we must also collect Python extension modules - although
2313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # we cannot separate normal dlls from Python extensions.
2323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        suffixes = []
2333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for triple in imp.get_suffixes():
2343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            suffixes.append(triple[0])
2353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for dir in m.__path__:
2363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            try:
2373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                names = os.listdir(dir)
2383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            except os.error:
2393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msg(2, "can't list directory", dir)
2403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
2413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            for name in names:
2423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mod = None
2433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                for suff in suffixes:
2443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    n = len(suff)
2453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if name[-n:] == suff:
2463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        mod = name[:-n]
2473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        break
2483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if mod and mod != "__init__":
2493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    modules[mod] = mod
2503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return modules.keys()
2513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def import_module(self, partname, fqname, parent):
2533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(3, "import_module", partname, fqname, parent)
2543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m = self.modules[fqname]
2563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except KeyError:
2573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pass
2583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
2593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(3, "import_module ->", m)
2603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return m
2613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if fqname in self.badmodules:
2623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(3, "import_module -> None")
2633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return None
2643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if parent and parent.__path__ is None:
2653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(3, "import_module -> None")
2663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return None
2673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fp, pathname, stuff = self.find_module(partname,
2693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                                   parent and parent.__path__, parent)
2703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except ImportError:
2713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(3, "import_module ->", None)
2723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return None
2733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
2743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m = self.load_module(fqname, fp, pathname, stuff)
2753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        finally:
2763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if fp: fp.close()
2773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if parent:
2783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            setattr(parent, partname, m)
2793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(3, "import_module ->", m)
2803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return m
2813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
2823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def load_module(self, fqname, fp, pathname, file_info):
2833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        suffix, mode, type = file_info
2843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(2, "load_module", fqname, fp and "fp", pathname)
2853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if type == imp.PKG_DIRECTORY:
2863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m = self.load_package(fqname, pathname)
2873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(2, "load_module ->", m)
2883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return m
2893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if type == imp.PY_SOURCE:
2903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            co = compile(fp.read()+'\n', pathname, 'exec')
2913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        elif type == imp.PY_COMPILED:
2923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if fp.read(4) != imp.get_magic():
2933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(2, "raise ImportError: Bad magic number", pathname)
2943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                raise ImportError, "Bad magic number in %s" % pathname
2953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fp.read(4)
2963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            co = marshal.load(fp)
2973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
2983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            co = None
2993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m = self.add_module(fqname)
3003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m.__file__ = pathname
3013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if co:
3023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if self.replace_paths:
3033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                co = self.replace_paths_in_code(co)
3043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m.__code__ = co
3053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.scan_code(co, m)
3063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(2, "load_module ->", m)
3073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return m
3083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def _add_badmodule(self, name, caller):
3103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if name not in self.badmodules:
3113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.badmodules[name] = {}
3123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if caller:
3133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.badmodules[name][caller.__name__] = 1
3143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
3153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.badmodules[name]["-"] = 1
3163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def _safe_import_hook(self, name, caller, fromlist, level=-1):
3183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # wrapper for self.import_hook() that won't raise ImportError
3193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if name in self.badmodules:
3203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._add_badmodule(name, caller)
3213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return
3223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        try:
3233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.import_hook(name, caller, level=level)
3243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        except ImportError, msg:
3253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msg(2, "ImportError:", str(msg))
3263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self._add_badmodule(name, caller)
3273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
3283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if fromlist:
3293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                for sub in fromlist:
3303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if sub in self.badmodules:
3313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._add_badmodule(sub, caller)
3323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        continue
3333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    try:
3343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self.import_hook(name, caller, [sub], level=level)
3353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    except ImportError, msg:
3363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self.msg(2, "ImportError:", str(msg))
3373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        fullname = name + "." + sub
3383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        self._add_badmodule(fullname, caller)
3393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def scan_opcodes(self, co,
3413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                     unpack = struct.unpack):
3423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Scan the code, and yield 'interesting' opcode combinations
3433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Version for Python 2.4 and older
3443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        code = co.co_code
3453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        names = co.co_names
3463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        consts = co.co_consts
3473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        while code:
3483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            c = code[0]
3493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if c in STORE_OPS:
3503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                oparg, = unpack('<H', code[1:3])
3513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                yield "store", (names[oparg],)
3523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[3:]
3533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
3543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if c == LOAD_CONST and code[3] == IMPORT_NAME:
3553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                oparg_1, oparg_2 = unpack('<xHxH', code[:6])
3563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                yield "import", (consts[oparg_1], names[oparg_2])
3573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[6:]
3583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
3593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if c >= HAVE_ARGUMENT:
3603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[3:]
3613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
3623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[1:]
3633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def scan_opcodes_25(self, co,
3653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                     unpack = struct.unpack):
3663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Scan the code, and yield 'interesting' opcode combinations
3673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Python 2.5 version (has absolute and relative imports)
3683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        code = co.co_code
3693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        names = co.co_names
3703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        consts = co.co_consts
3713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        LOAD_LOAD_AND_IMPORT = LOAD_CONST + LOAD_CONST + IMPORT_NAME
3723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        while code:
3733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            c = code[0]
3743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if c in STORE_OPS:
3753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                oparg, = unpack('<H', code[1:3])
3763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                yield "store", (names[oparg],)
3773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[3:]
3783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
3793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if code[:9:3] == LOAD_LOAD_AND_IMPORT:
3803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                oparg_1, oparg_2, oparg_3 = unpack('<xHxHxH', code[:9])
3813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                level = consts[oparg_1]
3823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if level == -1: # normal import
3833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    yield "import", (consts[oparg_2], names[oparg_3])
3843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                elif level == 0: # absolute import
3853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    yield "absolute_import", (consts[oparg_2], names[oparg_3])
3863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                else: # relative import
3873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    yield "relative_import", (level, consts[oparg_2], names[oparg_3])
3883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[9:]
3893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
3903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if c >= HAVE_ARGUMENT:
3913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[3:]
3923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
3933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                code = code[1:]
3943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
3953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def scan_code(self, co, m):
3963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        code = co.co_code
3973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if sys.version_info >= (2, 5):
3983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            scanner = self.scan_opcodes_25
3993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
4003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            scanner = self.scan_opcodes
4013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for what, args in scanner(co):
4023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if what == "store":
4033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                name, = args
4043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                m.globalnames[name] = 1
4053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            elif what in ("import", "absolute_import"):
4063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                fromlist, name = args
4073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                have_star = 0
4083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if fromlist is not None:
4093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if "*" in fromlist:
4103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        have_star = 1
4113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    fromlist = [f for f in fromlist if f != "*"]
4123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if what == "absolute_import": level = 0
4133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                else: level = -1
4143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self._safe_import_hook(name, m, fromlist, level=level)
4153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if have_star:
4163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # We've encountered an "import *". If it is a Python module,
4173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # the code has already been parsed and we can suck out the
4183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # global names.
4193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    mm = None
4203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if m.__path__:
4213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        # At this point we don't know whether 'name' is a
4223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        # submodule of 'm' or a global module. Let's just try
4233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        # the full name first.
4243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        mm = self.modules.get(m.__name__ + "." + name)
4253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if mm is None:
4263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        mm = self.modules.get(name)
4273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    if mm is not None:
4283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        m.globalnames.update(mm.globalnames)
4293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        m.starimports.update(mm.starimports)
4303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        if mm.__code__ is None:
4313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                            m.starimports[name] = 1
4323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    else:
4333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                        m.starimports[name] = 1
4343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            elif what == "relative_import":
4353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                level, fromlist, name = args
4363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if name:
4373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    self._safe_import_hook(name, m, fromlist, level=level)
4383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                else:
4393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    parent = self.determine_parent(m, level=level)
4403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    self._safe_import_hook(parent.__name__, None, fromlist, level=0)
4413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
4423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                # We don't expect anything else from the generator.
4433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                raise RuntimeError(what)
4443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for c in co.co_consts:
4463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if isinstance(c, type(co)):
4473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.scan_code(c, m)
4483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def load_package(self, fqname, pathname):
4503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgin(2, "load_package", fqname, pathname)
4513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        newname = replacePackageMap.get(fqname)
4523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if newname:
4533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fqname = newname
4543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m = self.add_module(fqname)
4553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m.__file__ = pathname
4563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m.__path__ = [pathname]
4573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # As per comment at top of file, simulate runtime __path__ additions.
4593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        m.__path__ = m.__path__ + packagePathMap.get(fqname, [])
4603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        fp, buf, stuff = self.find_module("__init__", m.__path__)
4623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.load_module(fqname, fp, buf, stuff)
4633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.msgout(2, "load_package ->", m)
4643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if fp:
4653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fp.close()
4663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return m
4673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def add_module(self, fqname):
4693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if fqname in self.modules:
4703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            return self.modules[fqname]
4713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        self.modules[fqname] = m = Module(fqname)
4723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return m
4733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def find_module(self, name, path, parent=None):
4753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if parent is not None:
4763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            # assert path is not None
4773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fullname = parent.__name__+'.'+name
4783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
4793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            fullname = name
4803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if fullname in self.excludes:
4813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.msgout(3, "find_module -> Excluded", fullname)
4823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            raise ImportError, name
4833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if path is None:
4853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if name in sys.builtin_module_names:
4863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                return (None, None, ("", "", imp.C_BUILTIN))
4873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            path = self.path
4893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return imp.find_module(name, path)
4903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
4913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def report(self):
4923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """Print a report to stdout, listing the found modules with their
4933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        paths, as well as modules that are missing, or seem to be missing.
4943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """
4953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print
4963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print "  %-25s %s" % ("Name", "File")
4973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print "  %-25s %s" % ("----", "----")
4983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Print modules found
4993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        keys = self.modules.keys()
5003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        keys.sort()
5013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for key in keys:
5023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            m = self.modules[key]
5033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if m.__path__:
5043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print "P",
5053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
5063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print "m",
5073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print "%-25s" % key, m.__file__ or ""
5083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Print missing modules
5103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        missing, maybe = self.any_missing_maybe()
5113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if missing:
5123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print
5133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print "Missing modules:"
5143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            for name in missing:
5153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mods = self.badmodules[name].keys()
5163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mods.sort()
5173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print "?", name, "imported from", ', '.join(mods)
5183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        # Print modules that may be missing, but then again, maybe not...
5193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if maybe:
5203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print
5213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print "Submodules that appear to be missing, but could also be",
5223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print "global names in the parent package:"
5233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            for name in maybe:
5243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mods = self.badmodules[name].keys()
5253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mods.sort()
5263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                print "?", name, "imported from", ', '.join(mods)
5273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def any_missing(self):
5293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """Return a list of modules that appear to be missing. Use
5303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        any_missing_maybe() if you want to know which modules are
5313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        certain to be missing, and which *may* be missing.
5323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """
5333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        missing, maybe = self.any_missing_maybe()
5343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return missing + maybe
5353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def any_missing_maybe(self):
5373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """Return two lists, one with modules that are certainly missing
5383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        and one with modules that *may* be missing. The latter names could
5393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        either be submodules *or* just global names in the package.
5403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        The reason it can't always be determined is that it's impossible to
5423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        tell which names are imported when "from module import *" is done
5433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        with an extension module, short of actually importing it.
5443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        """
5453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        missing = []
5463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        maybe = []
5473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for name in self.badmodules:
5483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if name in self.excludes:
5493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
5503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            i = name.rfind(".")
5513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if i < 0:
5523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                missing.append(name)
5533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                continue
5543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            subname = name[i+1:]
5553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pkgname = name[:i]
5563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            pkg = self.modules.get(pkgname)
5573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if pkg is not None:
5583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                if pkgname in self.badmodules[name]:
5593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # The package tried to import this module itself and
5603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # failed. It's definitely missing.
5613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    missing.append(name)
5623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                elif subname in pkg.globalnames:
5633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # It's a global in the package: definitely not missing.
5643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    pass
5653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                elif pkg.starimports:
5663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # It could be missing, but the package did an "import *"
5673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # from a non-Python module, so we simply can't be sure.
5683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    maybe.append(name)
5693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                else:
5703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # It's not a global in the package, the package didn't
5713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # do funny star imports, it's very likely to be missing.
5723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # The symbol could be inserted into the package from the
5733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # outside, but since that's not good style we simply list
5743257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    # it missing.
5753257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                    missing.append(name)
5763257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
5773257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                missing.append(name)
5783257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        missing.sort()
5793257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        maybe.sort()
5803257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return missing, maybe
5813257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5823257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    def replace_paths_in_code(self, co):
5833257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        new_filename = original_filename = os.path.normpath(co.co_filename)
5843257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for f, r in self.replace_paths:
5853257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if original_filename.startswith(f):
5863257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                new_filename = r + original_filename[len(f):]
5873257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                break
5883257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5893257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if self.debug and original_filename not in self.processed_paths:
5903257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if new_filename != original_filename:
5913257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(2, "co_filename %r changed to %r" \
5923257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                    % (original_filename,new_filename,))
5933257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
5943257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                self.msgout(2, "co_filename %r remains unchanged" \
5953257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                                    % (original_filename,))
5963257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            self.processed_paths.append(original_filename)
5973257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
5983257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        consts = list(co.co_consts)
5993257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for i in range(len(consts)):
6003257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if isinstance(consts[i], type(co)):
6013257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                consts[i] = self.replace_paths_in_code(consts[i])
6023257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6033257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return types.CodeType(co.co_argcount, co.co_nlocals, co.co_stacksize,
6043257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                         co.co_flags, co.co_code, tuple(consts), co.co_names,
6053257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                         co.co_varnames, new_filename, co.co_name,
6063257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                         co.co_firstlineno, co.co_lnotab,
6073257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                         co.co_freevars, co.co_cellvars)
6083257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6093257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6103257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanieldef test():
6113257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # Parse command line
6123257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    import getopt
6133257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    try:
6143257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:")
6153257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    except getopt.error, msg:
6163257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print msg
6173257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        return
6183257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6193257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # Process options
6203257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    debug = 1
6213257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    domods = 0
6223257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    addpath = []
6233257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    exclude = []
6243257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    for o, a in opts:
6253257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-d':
6263257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            debug = debug + 1
6273257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-m':
6283257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            domods = 1
6293257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-p':
6303257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            addpath = addpath + a.split(os.pathsep)
6313257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-q':
6323257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            debug = 0
6333257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if o == '-x':
6343257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            exclude.append(a)
6353257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6363257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # Provide default arguments
6373257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if not args:
6383257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        script = "hello.py"
6393257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    else:
6403257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        script = args[0]
6413257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6423257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # Set the path based on sys.path and the script directory
6433257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    path = sys.path[:]
6443257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    path[0] = os.path.dirname(script)
6453257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    path = addpath + path
6463257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    if debug > 1:
6473257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print "path:"
6483257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        for item in path:
6493257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            print "   ", repr(item)
6503257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6513257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    # Create the module finder and turn its crank
6523257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    mf = ModuleFinder(path, debug, exclude)
6533257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    for arg in args[1:]:
6543257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if arg == '-m':
6553257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            domods = 1
6563257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            continue
6573257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        if domods:
6583257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            if arg[-2:] == '.*':
6593257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mf.import_hook(arg[:-2], None, ["*"])
6603257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            else:
6613257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel                mf.import_hook(arg)
6623257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        else:
6633257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel            mf.load_file(arg)
6643257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    mf.run_script(script)
6653257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    mf.report()
6663257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    return mf  # for -i debugging
6673257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6683257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel
6693257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDanielif __name__ == '__main__':
6703257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    try:
6713257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        mf = test()
6723257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel    except KeyboardInterrupt:
6733257aa99321d745773a6bd1bd4ce7f6fafe74411Daryl McDaniel        print "\n[interrupt]"
674