183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh"""Find modules used by a script, using introspection."""
283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# This module should be kept compatible with Python 2.2, see PEP 291.
383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehfrom __future__ import generators
583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport dis
683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport imp
783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport marshal
883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport os
983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport sys
1083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport types
1183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehimport struct
1283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif hasattr(sys.__stdout__, "newlines"):
1483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    READ_MODE = "U"  # universal line endings
1583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehelse:
1683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # remain compatible with Python  < 2.3
1783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    READ_MODE = "r"
1883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
1983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehLOAD_CONST = chr(dis.opname.index('LOAD_CONST'))
2083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehIMPORT_NAME = chr(dis.opname.index('IMPORT_NAME'))
2183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSTORE_NAME = chr(dis.opname.index('STORE_NAME'))
2283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSTORE_GLOBAL = chr(dis.opname.index('STORE_GLOBAL'))
2383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehSTORE_OPS = [STORE_NAME, STORE_GLOBAL]
2483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehHAVE_ARGUMENT = chr(dis.HAVE_ARGUMENT)
2583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
2683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Modulefinder does a good job at simulating Python's, but it can not
2783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# handle __path__ modifications packages make at runtime.  Therefore there
2883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# is a mechanism whereby you can register extra paths in this map for a
2983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# package, and it will be honored.
3083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# Note this is a mapping is lists of paths.
3283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehpackagePathMap = {}
3383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
3483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# A Public interface
3583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef AddPackagePath(packagename, path):
3683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    paths = packagePathMap.get(packagename, [])
3783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    paths.append(path)
3883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    packagePathMap[packagename] = paths
3983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew HsiehreplacePackageMap = {}
4183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# This ReplacePackage mechanism allows modulefinder to work around the
4383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# way the _xmlplus package injects itself under the name "xml" into
4483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml")
4583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh# before running ModuleFinder.
4683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
4783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef ReplacePackage(oldname, newname):
4883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    replacePackageMap[oldname] = newname
4983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass Module:
5283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
5383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, name, file=None, path=None):
5483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.__name__ = name
5583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.__file__ = file
5683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.__path__ = path
5783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.__code__ = None
5883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # The set of global names that are assigned to in the module.
5983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # This includes those names imported through starimports of
6083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Python modules.
6183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.globalnames = {}
6283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # The set of starimports this module did that could not be
6383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # resolved, ie. a starimport from a non-Python module.
6483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.starimports = {}
6583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
6683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __repr__(self):
6783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        s = "Module(%r" % (self.__name__,)
6883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.__file__ is not None:
6983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            s = s + ", %r" % (self.__file__,)
7083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.__path__ is not None:
7183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            s = s + ", %r" % (self.__path__,)
7283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        s = s + ")"
7383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return s
7483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehclass ModuleFinder:
7683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
7783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def __init__(self, path=None, debug=0, excludes=[], replace_paths=[]):
7883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if path is None:
7983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            path = sys.path
8083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.path = path
8183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.modules = {}
8283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.badmodules = {}
8383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.debug = debug
8483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.indent = 0
8583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.excludes = excludes
8683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.replace_paths = replace_paths
8783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.processed_paths = []   # Used in debugging only
8883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
8983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def msg(self, level, str, *args):
9083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if level <= self.debug:
9183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for i in range(self.indent):
9283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print "   ",
9383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print str,
9483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for arg in args:
9583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print repr(arg),
9683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print
9783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
9883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def msgin(self, *args):
9983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        level = args[0]
10083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if level <= self.debug:
10183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.indent = self.indent + 1
10283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msg(*args)
10383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
10483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def msgout(self, *args):
10583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        level = args[0]
10683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if level <= self.debug:
10783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.indent = self.indent - 1
10883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msg(*args)
10983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def run_script(self, pathname):
11183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msg(2, "run_script", pathname)
11283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        fp = open(pathname, READ_MODE)
11383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stuff = ("", "r", imp.PY_SOURCE)
11483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.load_module('__main__', fp, pathname, stuff)
11583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
11683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def load_file(self, pathname):
11783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        dir, name = os.path.split(pathname)
11883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        name, ext = os.path.splitext(name)
11983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        fp = open(pathname, READ_MODE)
12083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        stuff = (ext, "r", imp.PY_SOURCE)
12183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.load_module(name, fp, pathname, stuff)
12283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
12383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def import_hook(self, name, caller=None, fromlist=None, level=-1):
12483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msg(3, "import_hook", name, caller, fromlist, level)
12583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        parent = self.determine_parent(caller, level=level)
12683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        q, tail = self.find_head_package(parent, name)
12783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m = self.load_tail(q, tail)
12883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if not fromlist:
12983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return q
13083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if m.__path__:
13183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.ensure_fromlist(m, fromlist)
13283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return None
13383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
13483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def determine_parent(self, caller, level=-1):
13583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(4, "determine_parent", caller, level)
13683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if not caller or level == 0:
13783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(4, "determine_parent -> None")
13883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return None
13983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        pname = caller.__name__
14083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if level >= 1: # relative import
14183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if caller.__path__:
14283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                level -= 1
14383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if level == 0:
14483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                parent = self.modules[pname]
14583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                assert parent is caller
14683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(4, "determine_parent ->", parent)
14783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                return parent
14883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if pname.count(".") < level:
14983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise ImportError, "relative importpath too deep"
15083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            pname = ".".join(pname.split(".")[:-level])
15183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            parent = self.modules[pname]
15283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(4, "determine_parent ->", parent)
15383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return parent
15483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if caller.__path__:
15583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            parent = self.modules[pname]
15683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            assert caller is parent
15783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(4, "determine_parent ->", parent)
15883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return parent
15983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if '.' in pname:
16083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            i = pname.rfind('.')
16183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            pname = pname[:i]
16283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            parent = self.modules[pname]
16383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            assert parent.__name__ == pname
16483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(4, "determine_parent ->", parent)
16583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return parent
16683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(4, "determine_parent -> None")
16783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return None
16883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
16983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def find_head_package(self, parent, name):
17083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(4, "find_head_package", parent, name)
17183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if '.' in name:
17283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            i = name.find('.')
17383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            head = name[:i]
17483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            tail = name[i+1:]
17583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
17683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            head = name
17783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            tail = ""
17883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if parent:
17983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            qname = "%s.%s" % (parent.__name__, head)
18083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
18183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            qname = head
18283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        q = self.import_module(head, qname, parent)
18383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if q:
18483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(4, "find_head_package ->", (q, tail))
18583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return q, tail
18683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if parent:
18783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            qname = head
18883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            parent = None
18983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            q = self.import_module(head, qname, parent)
19083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if q:
19183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(4, "find_head_package ->", (q, tail))
19283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                return q, tail
19383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(4, "raise ImportError: No module named", qname)
19483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        raise ImportError, "No module named " + qname
19583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
19683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def load_tail(self, q, tail):
19783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(4, "load_tail", q, tail)
19883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m = q
19983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        while tail:
20083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            i = tail.find('.')
20183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if i < 0: i = len(tail)
20283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            head, tail = tail[:i], tail[i+1:]
20383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            mname = "%s.%s" % (m.__name__, head)
20483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m = self.import_module(head, mname, m)
20583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if not m:
20683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(4, "raise ImportError: No module named", mname)
20783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise ImportError, "No module named " + mname
20883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(4, "load_tail ->", m)
20983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return m
21083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
21183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def ensure_fromlist(self, m, fromlist, recursive=0):
21283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msg(4, "ensure_fromlist", m, fromlist, recursive)
21383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for sub in fromlist:
21483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if sub == "*":
21583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if not recursive:
21683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    all = self.find_all_submodules(m)
21783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if all:
21883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self.ensure_fromlist(m, all, 1)
21983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            elif not hasattr(m, sub):
22083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                subname = "%s.%s" % (m.__name__, sub)
22183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                submod = self.import_module(sub, subname, m)
22283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if not submod:
22383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    raise ImportError, "No module named " + subname
22483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
22583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def find_all_submodules(self, m):
22683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if not m.__path__:
22783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return
22883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        modules = {}
22983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # 'suffixes' used to be a list hardcoded to [".py", ".pyc", ".pyo"].
23083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # But we must also collect Python extension modules - although
23183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # we cannot separate normal dlls from Python extensions.
23283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        suffixes = []
23383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for triple in imp.get_suffixes():
23483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            suffixes.append(triple[0])
23583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for dir in m.__path__:
23683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            try:
23783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                names = os.listdir(dir)
23883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            except os.error:
23983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msg(2, "can't list directory", dir)
24083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
24183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for name in names:
24283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mod = None
24383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                for suff in suffixes:
24483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    n = len(suff)
24583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if name[-n:] == suff:
24683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        mod = name[:-n]
24783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        break
24883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if mod and mod != "__init__":
24983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    modules[mod] = mod
25083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return modules.keys()
25183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
25283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def import_module(self, partname, fqname, parent):
25383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(3, "import_module", partname, fqname, parent)
25483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
25583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m = self.modules[fqname]
25683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        except KeyError:
25783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            pass
25883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
25983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(3, "import_module ->", m)
26083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return m
26183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if fqname in self.badmodules:
26283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(3, "import_module -> None")
26383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return None
26483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if parent and parent.__path__ is None:
26583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(3, "import_module -> None")
26683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return None
26783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
26883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            fp, pathname, stuff = self.find_module(partname,
26983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                                   parent and parent.__path__, parent)
27083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        except ImportError:
27183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(3, "import_module ->", None)
27283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return None
27383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
27483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m = self.load_module(fqname, fp, pathname, stuff)
27583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        finally:
27683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if fp: fp.close()
27783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if parent:
27883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            setattr(parent, partname, m)
27983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(3, "import_module ->", m)
28083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return m
28183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
28283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def load_module(self, fqname, fp, pathname, file_info):
28383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        suffix, mode, type = file_info
28483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(2, "load_module", fqname, fp and "fp", pathname)
28583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if type == imp.PKG_DIRECTORY:
28683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m = self.load_package(fqname, pathname)
28783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(2, "load_module ->", m)
28883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return m
28983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if type == imp.PY_SOURCE:
29083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            co = compile(fp.read()+'\n', pathname, 'exec')
29183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        elif type == imp.PY_COMPILED:
29283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if fp.read(4) != imp.get_magic():
29383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(2, "raise ImportError: Bad magic number", pathname)
29483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise ImportError, "Bad magic number in %s" % pathname
29583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            fp.read(4)
29683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            co = marshal.load(fp)
29783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
29883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            co = None
29983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m = self.add_module(fqname)
30083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m.__file__ = pathname
30183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if co:
30283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if self.replace_paths:
30383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                co = self.replace_paths_in_code(co)
30483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m.__code__ = co
30583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.scan_code(co, m)
30683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(2, "load_module ->", m)
30783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return m
30883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
30983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _add_badmodule(self, name, caller):
31083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name not in self.badmodules:
31183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.badmodules[name] = {}
31283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if caller:
31383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.badmodules[name][caller.__name__] = 1
31483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
31583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.badmodules[name]["-"] = 1
31683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
31783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def _safe_import_hook(self, name, caller, fromlist, level=-1):
31883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # wrapper for self.import_hook() that won't raise ImportError
31983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if name in self.badmodules:
32083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self._add_badmodule(name, caller)
32183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return
32283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        try:
32383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.import_hook(name, caller, level=level)
32483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        except ImportError, msg:
32583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msg(2, "ImportError:", str(msg))
32683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self._add_badmodule(name, caller)
32783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
32883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if fromlist:
32983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                for sub in fromlist:
33083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if sub in self.badmodules:
33183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self._add_badmodule(sub, caller)
33283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        continue
33383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    try:
33483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self.import_hook(name, caller, [sub], level=level)
33583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    except ImportError, msg:
33683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self.msg(2, "ImportError:", str(msg))
33783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        fullname = name + "." + sub
33883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        self._add_badmodule(fullname, caller)
33983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
34083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def scan_opcodes(self, co,
34183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                     unpack = struct.unpack):
34283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Scan the code, and yield 'interesting' opcode combinations
34383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Version for Python 2.4 and older
34483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = co.co_code
34583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        names = co.co_names
34683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        consts = co.co_consts
34783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        while code:
34883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            c = code[0]
34983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if c in STORE_OPS:
35083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                oparg, = unpack('<H', code[1:3])
35183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                yield "store", (names[oparg],)
35283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[3:]
35383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
35483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if c == LOAD_CONST and code[3] == IMPORT_NAME:
35583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                oparg_1, oparg_2 = unpack('<xHxH', code[:6])
35683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                yield "import", (consts[oparg_1], names[oparg_2])
35783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[6:]
35883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
35983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if c >= HAVE_ARGUMENT:
36083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[3:]
36183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
36283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[1:]
36383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
36483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def scan_opcodes_25(self, co,
36583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                     unpack = struct.unpack):
36683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Scan the code, and yield 'interesting' opcode combinations
36783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Python 2.5 version (has absolute and relative imports)
36883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = co.co_code
36983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        names = co.co_names
37083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        consts = co.co_consts
37183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        LOAD_LOAD_AND_IMPORT = LOAD_CONST + LOAD_CONST + IMPORT_NAME
37283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        while code:
37383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            c = code[0]
37483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if c in STORE_OPS:
37583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                oparg, = unpack('<H', code[1:3])
37683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                yield "store", (names[oparg],)
37783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[3:]
37883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
37983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if code[:9:3] == LOAD_LOAD_AND_IMPORT:
38083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                oparg_1, oparg_2, oparg_3 = unpack('<xHxHxH', code[:9])
38183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                level = consts[oparg_1]
38283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if level == -1: # normal import
38383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    yield "import", (consts[oparg_2], names[oparg_3])
38483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                elif level == 0: # absolute import
38583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    yield "absolute_import", (consts[oparg_2], names[oparg_3])
38683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else: # relative import
38783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    yield "relative_import", (level, consts[oparg_2], names[oparg_3])
38883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[9:]
38983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
39083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if c >= HAVE_ARGUMENT:
39183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[3:]
39283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
39383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                code = code[1:]
39483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
39583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def scan_code(self, co, m):
39683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        code = co.co_code
39783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if sys.version_info >= (2, 5):
39883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            scanner = self.scan_opcodes_25
39983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
40083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            scanner = self.scan_opcodes
40183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for what, args in scanner(co):
40283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if what == "store":
40383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                name, = args
40483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                m.globalnames[name] = 1
40583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            elif what in ("import", "absolute_import"):
40683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                fromlist, name = args
40783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                have_star = 0
40883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if fromlist is not None:
40983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if "*" in fromlist:
41083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        have_star = 1
41183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    fromlist = [f for f in fromlist if f != "*"]
41283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if what == "absolute_import": level = 0
41383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else: level = -1
41483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self._safe_import_hook(name, m, fromlist, level=level)
41583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if have_star:
41683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # We've encountered an "import *". If it is a Python module,
41783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # the code has already been parsed and we can suck out the
41883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # global names.
41983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    mm = None
42083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if m.__path__:
42183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        # At this point we don't know whether 'name' is a
42283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        # submodule of 'm' or a global module. Let's just try
42383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        # the full name first.
42483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        mm = self.modules.get(m.__name__ + "." + name)
42583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if mm is None:
42683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        mm = self.modules.get(name)
42783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    if mm is not None:
42883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        m.globalnames.update(mm.globalnames)
42983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        m.starimports.update(mm.starimports)
43083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        if mm.__code__ is None:
43183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                            m.starimports[name] = 1
43283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    else:
43383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                        m.starimports[name] = 1
43483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            elif what == "relative_import":
43583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                level, fromlist, name = args
43683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if name:
43783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    self._safe_import_hook(name, m, fromlist, level=level)
43883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else:
43983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    parent = self.determine_parent(m, level=level)
44083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    self._safe_import_hook(parent.__name__, None, fromlist, level=0)
44183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
44283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                # We don't expect anything else from the generator.
44383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                raise RuntimeError(what)
44483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
44583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for c in co.co_consts:
44683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if isinstance(c, type(co)):
44783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.scan_code(c, m)
44883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
44983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def load_package(self, fqname, pathname):
45083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgin(2, "load_package", fqname, pathname)
45183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        newname = replacePackageMap.get(fqname)
45283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if newname:
45383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            fqname = newname
45483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m = self.add_module(fqname)
45583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m.__file__ = pathname
45683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m.__path__ = [pathname]
45783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
45883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # As per comment at top of file, simulate runtime __path__ additions.
45983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        m.__path__ = m.__path__ + packagePathMap.get(fqname, [])
46083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
46183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        fp, buf, stuff = self.find_module("__init__", m.__path__)
46283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.load_module(fqname, fp, buf, stuff)
46383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.msgout(2, "load_package ->", m)
46483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return m
46583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
46683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def add_module(self, fqname):
46783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if fqname in self.modules:
46883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            return self.modules[fqname]
46983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        self.modules[fqname] = m = Module(fqname)
47083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return m
47183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
47283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def find_module(self, name, path, parent=None):
47383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if parent is not None:
47483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            # assert path is not None
47583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            fullname = parent.__name__+'.'+name
47683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
47783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            fullname = name
47883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if fullname in self.excludes:
47983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.msgout(3, "find_module -> Excluded", fullname)
48083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            raise ImportError, name
48183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
48283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if path is None:
48383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if name in sys.builtin_module_names:
48483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                return (None, None, ("", "", imp.C_BUILTIN))
48583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
48683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            path = self.path
48783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return imp.find_module(name, path)
48883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
48983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def report(self):
49083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Print a report to stdout, listing the found modules with their
49183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        paths, as well as modules that are missing, or seem to be missing.
49283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """
49383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print
49483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print "  %-25s %s" % ("Name", "File")
49583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print "  %-25s %s" % ("----", "----")
49683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Print modules found
49783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        keys = self.modules.keys()
49883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        keys.sort()
49983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for key in keys:
50083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            m = self.modules[key]
50183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if m.__path__:
50283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print "P",
50383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
50483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print "m",
50583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print "%-25s" % key, m.__file__ or ""
50683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
50783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Print missing modules
50883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        missing, maybe = self.any_missing_maybe()
50983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if missing:
51083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print
51183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print "Missing modules:"
51283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for name in missing:
51383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mods = self.badmodules[name].keys()
51483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mods.sort()
51583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print "?", name, "imported from", ', '.join(mods)
51683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        # Print modules that may be missing, but then again, maybe not...
51783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if maybe:
51883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print
51983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print "Submodules thay appear to be missing, but could also be",
52083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print "global names in the parent package:"
52183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            for name in maybe:
52283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mods = self.badmodules[name].keys()
52383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mods.sort()
52483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                print "?", name, "imported from", ', '.join(mods)
52583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
52683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def any_missing(self):
52783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Return a list of modules that appear to be missing. Use
52883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        any_missing_maybe() if you want to know which modules are
52983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        certain to be missing, and which *may* be missing.
53083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """
53183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        missing, maybe = self.any_missing_maybe()
53283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return missing + maybe
53383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
53483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def any_missing_maybe(self):
53583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """Return two lists, one with modules that are certainly missing
53683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        and one with modules that *may* be missing. The latter names could
53783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        either be submodules *or* just global names in the package.
53883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
53983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        The reason it can't always be determined is that it's impossible to
54083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        tell which names are imported when "from module import *" is done
54183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        with an extension module, short of actually importing it.
54283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        """
54383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        missing = []
54483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        maybe = []
54583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for name in self.badmodules:
54683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if name in self.excludes:
54783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
54883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            i = name.rfind(".")
54983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if i < 0:
55083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                missing.append(name)
55183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                continue
55283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            subname = name[i+1:]
55383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            pkgname = name[:i]
55483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            pkg = self.modules.get(pkgname)
55583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if pkg is not None:
55683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                if pkgname in self.badmodules[name]:
55783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # The package tried to import this module itself and
55883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # failed. It's definitely missing.
55983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    missing.append(name)
56083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                elif subname in pkg.globalnames:
56183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # It's a global in the package: definitely not missing.
56283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    pass
56383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                elif pkg.starimports:
56483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # It could be missing, but the package did an "import *"
56583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # from a non-Python module, so we simply can't be sure.
56683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    maybe.append(name)
56783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                else:
56883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # It's not a global in the package, the package didn't
56983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # do funny star imports, it's very likely to be missing.
57083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # The symbol could be inserted into the package from the
57183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # outside, but since that's not good style we simply list
57283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    # it missing.
57383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                    missing.append(name)
57483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
57583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                missing.append(name)
57683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        missing.sort()
57783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        maybe.sort()
57883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return missing, maybe
57983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
58083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    def replace_paths_in_code(self, co):
58183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        new_filename = original_filename = os.path.normpath(co.co_filename)
58283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for f, r in self.replace_paths:
58383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if original_filename.startswith(f):
58483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                new_filename = r + original_filename[len(f):]
58583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                break
58683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
58783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if self.debug and original_filename not in self.processed_paths:
58883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if new_filename != original_filename:
58983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(2, "co_filename %r changed to %r" \
59083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                    % (original_filename,new_filename,))
59183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
59283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                self.msgout(2, "co_filename %r remains unchanged" \
59383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                                    % (original_filename,))
59483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            self.processed_paths.append(original_filename)
59583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
59683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        consts = list(co.co_consts)
59783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for i in range(len(consts)):
59883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if isinstance(consts[i], type(co)):
59983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                consts[i] = self.replace_paths_in_code(consts[i])
60083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
60183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return types.CodeType(co.co_argcount, co.co_nlocals, co.co_stacksize,
60283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                         co.co_flags, co.co_code, tuple(consts), co.co_names,
60383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                         co.co_varnames, new_filename, co.co_name,
60483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                         co.co_firstlineno, co.co_lnotab,
60583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                         co.co_freevars, co.co_cellvars)
60683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
60783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
60883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehdef test():
60983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Parse command line
61083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    import getopt
61183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    try:
61283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        opts, args = getopt.getopt(sys.argv[1:], "dmp:qx:")
61383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    except getopt.error, msg:
61483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print msg
61583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        return
61683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
61783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Process options
61883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    debug = 1
61983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    domods = 0
62083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    addpath = []
62183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    exclude = []
62283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    for o, a in opts:
62383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if o == '-d':
62483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            debug = debug + 1
62583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if o == '-m':
62683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            domods = 1
62783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if o == '-p':
62883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            addpath = addpath + a.split(os.pathsep)
62983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if o == '-q':
63083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            debug = 0
63183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if o == '-x':
63283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            exclude.append(a)
63383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
63483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Provide default arguments
63583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    if not args:
63683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        script = "hello.py"
63783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    else:
63883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        script = args[0]
63983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
64083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Set the path based on sys.path and the script directory
64183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    path = sys.path[:]
64283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    path[0] = os.path.dirname(script)
64383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    path = addpath + path
64483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    if debug > 1:
64583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print "path:"
64683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        for item in path:
64783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            print "   ", repr(item)
64883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
64983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    # Create the module finder and turn its crank
65083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    mf = ModuleFinder(path, debug, exclude)
65183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    for arg in args[1:]:
65283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if arg == '-m':
65383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            domods = 1
65483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            continue
65583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        if domods:
65683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            if arg[-2:] == '.*':
65783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mf.import_hook(arg[:-2], None, ["*"])
65883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            else:
65983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh                mf.import_hook(arg)
66083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        else:
66183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh            mf.load_file(arg)
66283760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    mf.run_script(script)
66383760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    mf.report()
66483760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    return mf  # for -i debugging
66583760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
66683760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh
66783760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsiehif __name__ == '__main__':
66883760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    try:
66983760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        mf = test()
67083760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh    except KeyboardInterrupt:
67183760d213fb3bec7b4117d266fcfbf6fe2ba14abAndrew Hsieh        print "\n[interrupt]"
672