mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			248 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #
 | |
| # importers.py
 | |
| #
 | |
| # Demonstration subclasses of imputil.Importer
 | |
| #
 | |
| 
 | |
| # There should be consideration for the imports below if it is desirable
 | |
| # to have "all" modules be imported through the imputil system.
 | |
| 
 | |
| # these are C extensions
 | |
| import sys
 | |
| import imp
 | |
| import struct
 | |
| import marshal
 | |
| 
 | |
| # these are .py modules
 | |
| import imputil
 | |
| import os
 | |
| 
 | |
| ######################################################################
 | |
| 
 | |
| _TupleType = type(())
 | |
| _StringType = type('')
 | |
| 
 | |
| ######################################################################
 | |
| 
 | |
| # byte-compiled file suffic character
 | |
| _suffix_char = __debug__ and 'c' or 'o'
 | |
| 
 | |
| # byte-compiled file suffix
 | |
| _suffix = '.py' + _suffix_char
 | |
| 
 | |
| # the C_EXTENSION suffixes
 | |
| _c_suffixes = filter(lambda x: x[2] == imp.C_EXTENSION, imp.get_suffixes())
 | |
| 
 | |
| def _timestamp(pathname):
 | |
|     "Return the file modification time as a Long."
 | |
|     try:
 | |
|         s = os.stat(pathname)
 | |
|     except OSError:
 | |
|         return None
 | |
|     return long(s[8])
 | |
| 
 | |
| def _fs_import(dir, modname, fqname):
 | |
|     "Fetch a module from the filesystem."
 | |
| 
 | |
|     pathname = os.path.join(dir, modname)
 | |
|     if os.path.isdir(pathname):
 | |
|         values = { '__pkgdir__' : pathname, '__path__' : [ pathname ] }
 | |
|         ispkg = 1
 | |
|         pathname = os.path.join(pathname, '__init__')
 | |
|     else:
 | |
|         values = { }
 | |
|         ispkg = 0
 | |
| 
 | |
|         # look for dynload modules
 | |
|         for desc in _c_suffixes:
 | |
|             file = pathname + desc[0]
 | |
|             try:
 | |
|                 fp = open(file, desc[1])
 | |
|             except IOError:
 | |
|                 pass
 | |
|             else:
 | |
|                 module = imp.load_module(fqname, fp, file, desc)
 | |
|                 values['__file__'] = file
 | |
|                 return 0, module, values
 | |
| 
 | |
|     t_py = _timestamp(pathname + '.py')
 | |
|     t_pyc = _timestamp(pathname + _suffix)
 | |
|     if t_py is None and t_pyc is None:
 | |
|         return None
 | |
|     code = None
 | |
|     if t_py is None or (t_pyc is not None and t_pyc >= t_py):
 | |
|         file = pathname + _suffix
 | |
|         f = open(file, 'rb')
 | |
|         if f.read(4) == imp.get_magic():
 | |
|             t = struct.unpack('<I', f.read(4))[0]
 | |
|             if t == t_py:
 | |
|                 code = marshal.load(f)
 | |
|         f.close()
 | |
|     if code is None:
 | |
|         file = pathname + '.py'
 | |
|         code = _compile(file, t_py)
 | |
| 
 | |
|     values['__file__'] = file
 | |
|     return ispkg, code, values
 | |
| 
 | |
| ######################################################################
 | |
| #
 | |
| # Simple function-based importer
 | |
| #
 | |
| class FuncImporter(imputil.Importer):
 | |
|     "Importer subclass to delegate to a function rather than method overrides."
 | |
|     def __init__(self, func):
 | |
|         self.func = func
 | |
|     def get_code(self, parent, modname, fqname):
 | |
|         return self.func(parent, modname, fqname)
 | |
| 
 | |
| def install_with(func):
 | |
|     FuncImporter(func).install()
 | |
| 
 | |
| 
 | |
| ######################################################################
 | |
| #
 | |
| # Base class for archive-based importing
 | |
| #
 | |
| class PackageArchiveImporter(imputil.Importer):
 | |
|     """Importer subclass to import from (file) archives.
 | |
| 
 | |
|     This Importer handles imports of the style <archive>.<subfile>, where
 | |
|     <archive> can be located using a subclass-specific mechanism and the
 | |
|     <subfile> is found in the archive using a subclass-specific mechanism.
 | |
| 
 | |
|     This class defines two hooks for subclasses: one to locate an archive
 | |
|     (and possibly return some context for future subfile lookups), and one
 | |
|     to locate subfiles.
 | |
|     """
 | |
| 
 | |
|     def get_code(self, parent, modname, fqname):
 | |
|         if parent:
 | |
|             # the Importer._finish_import logic ensures that we handle imports
 | |
|             # under the top level module (package / archive).
 | |
|             assert parent.__importer__ == self
 | |
| 
 | |
|             # if a parent "package" is provided, then we are importing a
 | |
|             # sub-file from the archive.
 | |
|             result = self.get_subfile(parent.__archive__, modname)
 | |
|             if result is None:
 | |
|                 return None
 | |
|             if isinstance(result, _TupleType):
 | |
|                 assert len(result) == 2
 | |
|                 return (0,) + result
 | |
|             return 0, result, {}
 | |
| 
 | |
|         # no parent was provided, so the archive should exist somewhere on the
 | |
|         # default "path".
 | |
|         archive = self.get_archive(modname)
 | |
|         if archive is None:
 | |
|             return None
 | |
|         return 1, "", {'__archive__':archive}
 | |
| 
 | |
|     def get_archive(self, modname):
 | |
|         """Get an archive of modules.
 | |
| 
 | |
|         This method should locate an archive and return a value which can be
 | |
|         used by get_subfile to load modules from it. The value may be a simple
 | |
|         pathname, an open file, or a complex object that caches information
 | |
|         for future imports.
 | |
| 
 | |
|         Return None if the archive was not found.
 | |
|         """
 | |
|         raise RuntimeError, "get_archive not implemented"
 | |
| 
 | |
|     def get_subfile(self, archive, modname):
 | |
|         """Get code from a subfile in the specified archive.
 | |
| 
 | |
|         Given the specified archive (as returned by get_archive()), locate
 | |
|         and return a code object for the specified module name.
 | |
| 
 | |
|         A 2-tuple may be returned, consisting of a code object and a dict
 | |
|         of name/values to place into the target module.
 | |
| 
 | |
|         Return None if the subfile was not found.
 | |
|         """
 | |
|         raise RuntimeError, "get_subfile not implemented"
 | |
| 
 | |
| 
 | |
| class PackageArchive(PackageArchiveImporter):
 | |
|     "PackageArchiveImporter subclass that refers to a specific archive."
 | |
| 
 | |
|     def __init__(self, modname, archive_pathname):
 | |
|         self.__modname = modname
 | |
|         self.__path = archive_pathname
 | |
| 
 | |
|     def get_archive(self, modname):
 | |
|         if modname == self.__modname:
 | |
|             return self.__path
 | |
|         return None
 | |
| 
 | |
|     # get_subfile is passed the full pathname of the archive
 | |
| 
 | |
| 
 | |
| ######################################################################
 | |
| #
 | |
| # Emulate the standard directory-based import mechanism
 | |
| #
 | |
| class DirectoryImporter(imputil.Importer):
 | |
|     "Importer subclass to emulate the standard importer."
 | |
| 
 | |
|     def __init__(self, dir):
 | |
|         self.dir = dir
 | |
| 
 | |
|     def get_code(self, parent, modname, fqname):
 | |
|         if parent:
 | |
|             dir = parent.__pkgdir__
 | |
|         else:
 | |
|             dir = self.dir
 | |
| 
 | |
|         # Return the module (and other info) if found in the specified
 | |
|         # directory. Otherwise, return None.
 | |
|         return _fs_import(dir, modname, fqname)
 | |
| 
 | |
|     def __repr__(self):
 | |
|         return '<%s.%s for "%s" at 0x%x>' % (self.__class__.__module__,
 | |
|                                              self.__class__.__name__,
 | |
|                                              self.dir,
 | |
|                                              id(self))
 | |
| 
 | |
| 
 | |
| ######################################################################
 | |
| #
 | |
| # Emulate the standard path-style import mechanism
 | |
| #
 | |
| class PathImporter(imputil.Importer):
 | |
|     def __init__(self, path=sys.path):
 | |
|         self.path = path
 | |
| 
 | |
|     def get_code(self, parent, modname, fqname):
 | |
|         if parent:
 | |
|             # we are looking for a module inside of a specific package
 | |
|             return _fs_import(parent.__pkgdir__, modname, fqname)
 | |
| 
 | |
|         # scan sys.path, looking for the requested module
 | |
|         for dir in self.path:
 | |
|             if isinstance(dir, _StringType):
 | |
|                 result = _fs_import(dir, modname, fqname)
 | |
|                 if result:
 | |
|                     return result
 | |
| 
 | |
|         # not found
 | |
|         return None
 | |
| 
 | |
| ######################################################################
 | |
| 
 | |
| def _test_dir():
 | |
|     "Debug/test function to create DirectoryImporters from sys.path."
 | |
|     imputil.ImportManager().install()
 | |
|     path = sys.path[:]
 | |
|     path.reverse()
 | |
|     for d in path:
 | |
|         sys.path.insert(0, DirectoryImporter(d))
 | |
|     sys.path.insert(0, imputil.BuiltinImporter())
 | |
| 
 | |
| def _test_revamp():
 | |
|     "Debug/test function for the revamped import system."
 | |
|     imputil.ImportManager().install()
 | |
|     sys.path.insert(0, PathImporter())
 | |
|     sys.path.insert(0, imputil.BuiltinImporter())
 | 
