14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""
24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmImport utilities
34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmExported classes:
54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ImportManager   Manage the import process
64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Importer        Base class for replacing standard import functions
84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    BuiltinImporter Emulate the import mechanism for builtin and frozen modules
94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    DynLoadSuffixImporter
114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm"""
124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom warnings import warnpy3k
134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmwarnpy3k("the imputil module has been removed in Python 3.0", stacklevel=2)
144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdel warnpy3k
154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# note: avoid importing non-builtin modules
174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport imp                      ### not available in Jython?
184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys
194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport __builtin__
204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# for the DirectoryImporter
224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport struct
234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport marshal
244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm__all__ = ["ImportManager","Importer","BuiltinImporter"]
264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_StringType = type('')
284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_ModuleType = type(sys)         ### doesn't work in Jython...
294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass ImportManager:
314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "Manage the import process."
324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def install(self, namespace=vars(__builtin__)):
344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Install this ImportManager into the specified namespace."
354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if isinstance(namespace, _ModuleType):
374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            namespace = vars(namespace)
384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # Note: we have no notion of "chaining"
404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # Record the previous import hook, then install our own.
424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.previous_importer = namespace['__import__']
434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.namespace = namespace
444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        namespace['__import__'] = self._import_hook
454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ### fix this
474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #namespace['reload'] = self._reload_hook
484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def uninstall(self):
504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Restore the previous import mechanism."
514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.namespace['__import__'] = self.previous_importer
524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def add_suffix(self, suffix, importFunc):
544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        assert hasattr(importFunc, '__call__')
554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.fs_imp.add_suffix(suffix, importFunc)
564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ######################################################################
584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    # PRIVATE METHODS
604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    clsFilesystemImporter = None
634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __init__(self, fs_imp=None):
654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # we're definitely going to be importing something in the future,
664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # so let's just load the OS-related facilities.
674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not _os_stat:
684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            _os_bootstrap()
694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # This is the Importer that we use for grabbing stuff from the
714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # filesystem. It defines one more method (import_from_dir) for our use.
724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if fs_imp is None:
734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            cls = self.clsFilesystemImporter or _FilesystemImporter
744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            fs_imp = cls()
754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.fs_imp = fs_imp
764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # Initialize the set of suffixes that we recognize and import.
784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # The default will import dynamic-load modules first, followed by
794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # .py files (or a .py file's cached bytecode)
804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for desc in imp.get_suffixes():
814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if desc[2] == imp.C_EXTENSION:
824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                self.add_suffix(desc[0],
834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                DynLoadSuffixImporter(desc).import_file)
844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.add_suffix('.py', py_suffix_importer)
854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _import_hook(self, fqname, globals=None, locals=None, fromlist=None):
874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Python calls this hook to locate and import a module."""
884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parts = fqname.split('.')
904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # determine the context of this import
924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parent = self._determine_import_context(globals)
934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if there is a parent, then its importer should manage this import
954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if parent:
964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            module = parent.__importer__._do_import(parent, parts, fromlist)
974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if module:
984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return module
994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # has the top module already been imported?
1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        try:
1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            top_module = sys.modules[parts[0]]
1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        except KeyError:
1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # look for the topmost module
1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            top_module = self._import_top_module(parts[0])
1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if not top_module:
1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # the topmost module wasn't found at all.
1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                raise ImportError, 'No module named ' + fqname
1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # fast-path simple imports
1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if len(parts) == 1:
1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if not fromlist:
1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return top_module
1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if not top_module.__dict__.get('__ispkg__'):
1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # __ispkg__ isn't defined (the module was not imported by us),
1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # or it is zero.
1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                #
1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # In the former case, there is no way that we could import
1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # sub-modules that occur in the fromlist (but we can't raise an
1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # error because it may just be names) because we don't know how
1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # to deal with packages that were imported by other systems.
1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                #
1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # In the latter case (__ispkg__ == 0), there can't be any sub-
1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # modules present, so we can just return.
1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                #
1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # In both cases, since len(parts) == 1, the top_module is also
1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # the "bottom" which is the defined return when a fromlist
1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                # exists.
1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return top_module
1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        importer = top_module.__dict__.get('__importer__')
1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if importer:
1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return importer._finish_import(top_module, parts[1:], fromlist)
1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # Grrr, some people "import os.path" or do "from os.path import ..."
1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if len(parts) == 2 and hasattr(top_module, parts[1]):
1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if fromlist:
1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return getattr(top_module, parts[1])
1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else:
1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return top_module
1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # If the importer does not exist, then we have to bail. A missing
1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # importer means that something else imported the module, and we have
1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # no knowledge of how to get sub-modules out of the thing.
1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise ImportError, 'No module named ' + fqname
1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _determine_import_context(self, globals):
1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Returns the context in which a module should be imported.
1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        The context could be a loaded (package) module and the imported module
1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        will be looked for within that package. The context could also be None,
1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        meaning there is no context -- the module should be looked for as a
1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "top-level" module.
1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not globals or not globals.get('__importer__'):
1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # globals does not refer to one of our modules or packages. That
1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # implies there is no relative import context (as far as we are
1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # concerned), and it should just pick it off the standard path.
1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # The globals refer to a module or package of ours. It will define
1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # the context of the new import. Get the module/package fqname.
1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parent_fqname = globals['__name__']
1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if a package is performing the import, then return itself (imports
1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # refer to pkg contents)
1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if globals['__ispkg__']:
1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            parent = sys.modules[parent_fqname]
1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            assert globals is parent.__dict__
1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return parent
1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        i = parent_fqname.rfind('.')
1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # a module outside of a package has no particular import context
1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if i == -1:
1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if a module in a package is performing the import, then return the
1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # package (imports refer to siblings)
1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parent_fqname = parent_fqname[:i]
1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parent = sys.modules[parent_fqname]
1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        assert parent.__name__ == parent_fqname
1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return parent
1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _import_top_module(self, name):
1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # scan sys.path looking for a location in the filesystem that contains
1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # the module, or an Importer object that can import the module.
1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for item in sys.path:
1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if isinstance(item, _StringType):
1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                module = self.fs_imp.import_from_dir(item, name)
1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else:
1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                module = item.import_top(name)
1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if module:
1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return module
1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return None
1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _reload_hook(self, module):
2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Python calls this hook to reload a module."
2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # reloading of a module may or may not be possible (depending on the
2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # importer), but at least we can validate that it's ours to reload
2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        importer = module.__dict__.get('__importer__')
2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not importer:
2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            ### oops. now what...
2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            pass
2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # okay. it is using the imputil system, and we must delegate it, but
2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # we don't know what to do (yet)
2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ### we should blast the module dict and do another get_code(). need to
2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ### flesh this out and add proper docco...
2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise SystemError, "reload not yet implemented"
2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass Importer:
2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "Base class for replacing standard import functions."
2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def import_top(self, name):
2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Import a top-level module."
2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._import_one(None, name, name)
2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ######################################################################
2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    # PRIVATE METHODS
2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _finish_import(self, top, parts, fromlist):
2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if "a.b.c" was provided, then load the ".b.c" portion down from
2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # below the top-level module.
2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        bottom = self._load_tail(top, parts)
2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if the form is "import a.b.c", then return "a"
2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not fromlist:
2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # no fromlist: return the top of the import tree
2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return top
2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # the top module was imported by self.
2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #
2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # this means that the bottom module was also imported by self (just
2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # now, or in the past and we fetched it from sys.modules).
2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #
2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # since we imported/handled the bottom module, this means that we can
2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # also handle its fromlist (and reliably use __ispkg__).
2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if the bottom node is a package, then (potentially) import some
2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # modules.
2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #
2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # note: if it is not a package, then "fromlist" refers to names in
2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       the bottom module rather than modules.
2514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # note: for a mix of names and modules in the fromlist, we will
2524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       import all modules and insert those into the namespace of
2534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       the package module. Python will pick up all fromlist names
2544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       from the bottom (package) module; some will be modules that
2554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       we imported and stored in the namespace, others are expected
2564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        #       to be present already.
2574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if bottom.__ispkg__:
2584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            self._import_fromlist(bottom, fromlist)
2594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if the form is "from a.b import c, d" then return "b"
2614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return bottom
2624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _import_one(self, parent, modname, fqname):
2644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        "Import a single module."
2654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # has the module already been imported?
2674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        try:
2684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return sys.modules[fqname]
2694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        except KeyError:
2704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            pass
2714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # load the module's code, or fetch the module itself
2734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = self.get_code(parent, modname, fqname)
2744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if result is None:
2754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
2764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module = self._process_result(result, fqname)
2784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # insert the module into its parent
2804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if parent:
2814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            setattr(parent, modname, module)
2824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return module
2834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _process_result(self, result, fqname):
2854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ispkg, code, values = result
2864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # did get_code() return an actual module? (rather than a code object)
2874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        is_module = isinstance(code, _ModuleType)
2884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # use the returned module, or create a new one to exec code into
2904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if is_module:
2914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            module = code
2924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
2934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            module = imp.new_module(fqname)
2944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        ### record packages a bit differently??
2964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module.__importer__ = self
2974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module.__ispkg__ = ispkg
2984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
2994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # insert additional values into the module (before executing the code)
3004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module.__dict__.update(values)
3014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # the module is almost ready... make it visible
3034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sys.modules[fqname] = module
3044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # execute the code within the module's namespace
3064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not is_module:
3074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            try:
3084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                exec code in module.__dict__
3094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            except:
3104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if fqname in sys.modules:
3114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    del sys.modules[fqname]
3124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                raise
3134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # fetch from sys.modules instead of returning module directly.
3154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # also make module's __name__ agree with fqname, in case
3164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # the "exec code in module.__dict__" played games on us.
3174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module = sys.modules[fqname]
3184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module.__name__ = fqname
3194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return module
3204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _load_tail(self, m, parts):
3224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Import the rest of the modules, down from the top-level module.
3234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        Returns the last module in the dotted list of modules.
3254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
3264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for part in parts:
3274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            fqname = "%s.%s" % (m.__name__, part)
3284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            m = self._import_one(m, part, fqname)
3294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if not m:
3304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                raise ImportError, "No module named " + fqname
3314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return m
3324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _import_fromlist(self, package, fromlist):
3344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        'Import any sub-modules in the "from" list.'
3354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # if '*' is present in the fromlist, then look for the '__all__'
3374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # variable to find additional items (modules) to import.
3384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if '*' in fromlist:
3394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            fromlist = list(fromlist) + \
3404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                       list(package.__dict__.get('__all__', []))
3414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for sub in fromlist:
3434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # if the name is already present, then don't try to import it (it
3444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # might not be a module!).
3454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if sub != '*' and not hasattr(package, sub):
3464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                subname = "%s.%s" % (package.__name__, sub)
3474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                submod = self._import_one(package, sub, subname)
3484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                if not submod:
3494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                    raise ImportError, "cannot import name " + subname
3504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _do_import(self, parent, parts, fromlist):
3524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Attempt to import the module relative to parent.
3534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        This method is used when the import context specifies that <self>
3554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        imported the parent module.
3564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
3574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        top_name = parts[0]
3584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        top_fqname = parent.__name__ + '.' + top_name
3594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        top_module = self._import_one(parent, top_name, top_fqname)
3604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if not top_module:
3614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # this importer and parent could not find the module (relatively)
3624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
3634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._finish_import(top_module, parts[1:], fromlist)
3654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ######################################################################
3674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
3684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    # METHODS TO OVERRIDE
3694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    #
3704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def get_code(self, parent, modname, fqname):
3714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """Find and retrieve the code for the given module.
3724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        parent specifies a parent module to define a context for importing. It
3744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        may be None, indicating no particular context for the search.
3754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        modname specifies a single module (not dotted) within the parent.
3774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fqname specifies the fully-qualified module name. This is a
3794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        (potentially) dotted name from the "root" of the module namespace
3804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        down to the modname.
3814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        If there is no parent, then modname==fqname.
3824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        This method should return None, or a 3-tuple.
3844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        * If the module was not found, then None should be returned.
3864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        * The first item of the 2- or 3-tuple should be the integer 0 or 1,
3884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            specifying whether the module that was found is a package or not.
3894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        * The second item is the code object for the module (it will be
3914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            executed within the new module's namespace). This item can also
3924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            be a fully-loaded module object (e.g. loaded from a shared lib).
3934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
3944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        * The third item is a dictionary of name/value pairs that will be
3954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            inserted into new module before the code object is executed. This
3964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            is provided in case the module's code expects certain values (such
3974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            as where the module was found). When the second item is a module
3984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            object, then these names/values will be inserted *after* the module
3994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            has been loaded/initialized.
4004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        """
4014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise RuntimeError, "get_code not implemented"
4024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
4054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
4064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Some handy stuff for the Importers
4074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
4084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# byte-compiled file suffix character
4104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_suffix_char = __debug__ and 'c' or 'o'
4114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# byte-compiled file suffix
4134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_suffix = '.py' + _suffix_char
4144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _compile(pathname, timestamp):
4164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """Compile (and cache) a Python source file.
4174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    The file specified by <pathname> is compiled to a code object and
4194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    returned.
4204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    Presuming the appropriate privileges exist, the bytecodes will be
4224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    saved back to the filesystem for future imports. The source file's
4234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    modification timestamp must be provided as a Long value.
4244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    """
4254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    codestring = open(pathname, 'rU').read()
4264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if codestring and codestring[-1] != '\n':
4274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        codestring = codestring + '\n'
4284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    code = __builtin__.compile(codestring, pathname, 'exec')
4294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    # try to cache the compiled code
4314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    try:
4324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f = open(pathname + _suffix_char, 'wb')
4334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    except IOError:
4344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        pass
4354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else:
4364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.write('\0\0\0\0')
4374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.write(struct.pack('<I', timestamp))
4384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        marshal.dump(code, f)
4394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.flush()
4404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.seek(0, 0)
4414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.write(imp.get_magic())
4424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.close()
4434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return code
4454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm_os_stat = _os_path_join = None
4474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _os_bootstrap():
4484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "Set up 'os' module replacement functions for use during import bootstrap."
4494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    names = sys.builtin_module_names
4514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    join = None
4534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if 'posix' in names:
4544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sep = '/'
4554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        from posix import stat
4564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    elif 'nt' in names:
4574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sep = '\\'
4584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        from nt import stat
4594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    elif 'dos' in names:
4604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sep = '\\'
4614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        from dos import stat
4624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    elif 'os2' in names:
4634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        sep = '\\'
4644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        from os2 import stat
4654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    else:
4664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        raise ImportError, 'no os specific module found'
4674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if join is None:
4694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        def join(a, b, sep=sep):
4704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if a == '':
4714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return b
4724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            lastchar = a[-1:]
4734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if lastchar == '/' or lastchar == sep:
4744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return a + b
4754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return a + sep + b
4764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    global _os_stat
4784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _os_stat = stat
4794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    global _os_path_join
4814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    _os_path_join = join
4824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _os_path_isdir(pathname):
4844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "Local replacement for os.path.isdir()."
4854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    try:
4864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        s = _os_stat(pathname)
4874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    except OSError:
4884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return None
4894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return (s.st_mode & 0170000) == 0040000
4904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _timestamp(pathname):
4924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    "Return the file modification time as a Long."
4934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    try:
4944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        s = _os_stat(pathname)
4954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    except OSError:
4964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return None
4974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return long(s.st_mtime)
4984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
4994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
5014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Emulate the import mechanism for builtin and frozen modules
5034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass BuiltinImporter(Importer):
5054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def get_code(self, parent, modname, fqname):
5064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if parent:
5074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # these modules definitely do not occur within a package context
5084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
5094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # look for the module
5114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if imp.is_builtin(modname):
5124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            type = imp.C_BUILTIN
5134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        elif imp.is_frozen(modname):
5144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            type = imp.PY_FROZEN
5154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
5164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            # not found
5174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
5184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # got it. now load and return it.
5204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module = imp.load_module(modname, None, modname, ('', '', type))
5214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0, module, { }
5224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
5254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Internal importer used for importing from the filesystem
5274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass _FilesystemImporter(Importer):
5294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __init__(self):
5304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.suffixes = [ ]
5314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def add_suffix(self, suffix, importFunc):
5334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        assert hasattr(importFunc, '__call__')
5344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.suffixes.append((suffix, importFunc))
5354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def import_from_dir(self, dir, fqname):
5374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        result = self._import_pathname(_os_path_join(dir, fqname), fqname)
5384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if result:
5394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return self._process_result(result, fqname)
5404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return None
5414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def get_code(self, parent, modname, fqname):
5434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # This importer is never used with an empty parent. Its existence is
5444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # private to the ImportManager. The ImportManager uses the
5454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # import_from_dir() method to import top-level modules/packages.
5464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        # This method is only used when we look for a module within a package.
5474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        assert parent
5484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for submodule_path in parent.__path__:
5504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            code = self._import_pathname(_os_path_join(submodule_path, modname), fqname)
5514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if code is not None:
5524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return code
5534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return self._import_pathname(_os_path_join(parent.__pkgdir__, modname),
5544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                     fqname)
5554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def _import_pathname(self, pathname, fqname):
5574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if _os_path_isdir(pathname):
5584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            result = self._import_pathname(_os_path_join(pathname, '__init__'),
5594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                                           fqname)
5604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if result:
5614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                values = result[2]
5624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                values['__pkgdir__'] = pathname
5634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                values['__path__'] = [ pathname ]
5644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return 1, result[1], values
5654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            return None
5664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        for suffix, importFunc in self.suffixes:
5684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            filename = pathname + suffix
5694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            try:
5704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                finfo = _os_stat(filename)
5714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            except OSError:
5724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                pass
5734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            else:
5744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                return importFunc(filename, finfo, fqname)
5754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return None
5764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
5784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# SUFFIX-BASED IMPORTERS
5804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
5814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef py_suffix_importer(filename, finfo, fqname):
5834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    file = filename[:-3] + _suffix
5844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    t_py = long(finfo[8])
5854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    t_pyc = _timestamp(file)
5864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    code = None
5884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if t_pyc is not None and t_pyc >= t_py:
5894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f = open(file, 'rb')
5904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if f.read(4) == imp.get_magic():
5914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            t = struct.unpack('<I', f.read(4))[0]
5924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            if t == t_py:
5934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm                code = marshal.load(f)
5944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        f.close()
5954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    if code is None:
5964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        file = filename
5974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        code = _compile(file, t_py)
5984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
5994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    return 0, code, { '__file__' : file }
6004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass DynLoadSuffixImporter:
6024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def __init__(self, desc):
6034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        self.desc = desc
6044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    def import_file(self, filename, finfo, fqname):
6064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        fp = open(filename, self.desc[1])
6074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module = imp.load_module(fqname, fp, filename, self.desc)
6084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        module.__file__ = filename
6094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        return 0, module, { }
6104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
6134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _print_importers():
6154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    items = sys.modules.items()
6164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    items.sort()
6174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    for name, module in items:
6184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        if module:
6194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            print name, module.__dict__.get('__importer__', '-- no importer')
6204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm        else:
6214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm            print name, '-- non-existent module'
6224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _test_revamp():
6244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    ImportManager().install()
6254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm    sys.path.insert(0, BuiltinImporter())
6264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm######################################################################
6284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm
6294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# TODO
6314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# from Finn Bock:
6334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   type(sys) is not a module in Jython. what to use instead?
6344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   imp.C_EXTENSION is not in Jython. same for get_suffixes and new_module
6354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   given foo.py of:
6374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#      import sys
6384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#      sys.modules['foo'] = sys
6394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   ---- standard import mechanism
6414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> import foo
6424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> foo
6434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   <module 'sys' (built-in)>
6444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   ---- revamped import mechanism
6464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> import imputil
6474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> imputil._test_revamp()
6484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> import foo
6494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   >>> foo
6504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   <module 'foo' from 'foo.py'>
6514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# from MAL:
6544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   should BuiltinImporter exist in sys.path or hard-wired in ImportManager?
6554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   need __path__ processing
6564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   performance
6574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   move chaining to a subclass [gjs: it's been nuked]
6584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   deinstall should be possible
6594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   query mechanism needed: is a specific Importer installed?
6604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   py/pyc/pyo piping hooks to filter/process these files
6614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   wish list:
6624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#     distutils importer hooked to list of standard Internet repositories
6634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#     module->file location mapper to speed FS-based imports
6644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#     relative imports
6654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#     keep chaining so that it can play nice with other import hooks
6664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# from Gordon:
6684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   push MAL's mapper into sys.path[0] as a cache (hard-coded for apps)
6694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# from Guido:
6714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   need to change sys.* references for rexec environs
6724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   need hook for MAL's walk-me-up import strategy, or Tim's absolute strategy
6734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   watch out for sys.modules[...] is None
6744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   flag to force absolute imports? (speeds _determine_import_context and
6754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       checking for a relative module)
6764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   insert names of archives into sys.path  (see quote below)
6774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   note: reload does NOT blast module dict
6784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   shift import mechanisms and policies around; provide for hooks, overrides
6794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       (see quote below)
6804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   add get_source stuff
6814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   get_topcode and get_subcode
6824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   CRLF handling in _compile
6834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   race condition in _compile
6844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   refactoring of os.py to deal with _os_bootstrap problem
6854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   any special handling to do for importing a module with a SyntaxError?
6864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       (e.g. clean up the traceback)
6874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   implement "domain" for path-type functionality using pkg namespace
6884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#       (rather than FS-names like __path__)
6894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#   don't use the word "private"... maybe "internal"
6904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Guido's comments on sys.path caching:
6934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
6944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# We could cache this in a dictionary: the ImportManager can have a
6954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# cache dict mapping pathnames to importer objects, and a separate
6964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# method for coming up with an importer given a pathname that's not yet
6974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# in the cache.  The method should do a stat and/or look at the
6984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# extension to decide which importer class to use; you can register new
6994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# importer classes by registering a suffix or a Boolean function, plus a
7004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# class.  If you register a new importer class, the cache is zapped.
7014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# The cache is independent from sys.path (but maintained per
7024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# ImportManager instance) so that rearrangements of sys.path do the
7034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# right thing.  If a path is dropped from sys.path the corresponding
7044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# cache entry is simply no longer used.
7054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
7064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# My/Guido's comments on factoring ImportManager and Importer:
7074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
7084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > However, we still have a tension occurring here:
7094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# >
7104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > 1) implementing policy in ImportManager assists in single-point policy
7114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# >    changes for app/rexec situations
7124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > 2) implementing policy in Importer assists in package-private policy
7134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# >    changes for normal, operating conditions
7144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# >
7154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > I'll see if I can sort out a way to do this. Maybe the Importer class will
7164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > implement the methods (which can be overridden to change policy) by
7174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# > delegating to ImportManager.
7184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
7194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Maybe also think about what kind of policies an Importer would be
7204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# likely to want to change.  I have a feeling that a lot of the code
7214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# there is actually not so much policy but a *necessity* to get things
7224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# working given the calling conventions for the __import__ hook: whether
7234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# to return the head or tail of a dotted name, or when to do the "finish
7244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# fromlist" stuff.
7254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm#
726