| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | # | 
					
						
							|  |  |  | # 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): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "Return the file modification time as a Long." | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         s = os.stat(pathname) | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     return long(s[8]) | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def _fs_import(dir, modname, fqname): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "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 | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Simple function-based importer | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class FuncImporter(imputil.Importer): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "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) | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def install_with(func): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     FuncImporter(func).install() | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Base class for archive-based importing | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class PackageArchiveImporter(imputil.Importer): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     """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. | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |             # 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, {} | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |         # 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} | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     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" | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PackageArchive(PackageArchiveImporter): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "PackageArchiveImporter subclass that refers to a specific archive." | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     def __init__(self, modname, archive_pathname): | 
					
						
							|  |  |  |         self.__modname = modname | 
					
						
							|  |  |  |         self.__path = archive_pathname | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     def get_archive(self, modname): | 
					
						
							|  |  |  |         if modname == self.__modname: | 
					
						
							|  |  |  |             return self.__path | 
					
						
							|  |  |  |         return None | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     # get_subfile is passed the full pathname of the archive | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Emulate the standard directory-based import mechanism | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class DirectoryImporter(imputil.Importer): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "Importer subclass to emulate the standard importer." | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     def __init__(self, dir): | 
					
						
							|  |  |  |         self.dir = dir | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     def get_code(self, parent, modname, fqname): | 
					
						
							|  |  |  |         if parent: | 
					
						
							|  |  |  |             dir = parent.__pkgdir__ | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             dir = self.dir | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |         # Return the module (and other info) if found in the specified | 
					
						
							|  |  |  |         # directory. Otherwise, return None. | 
					
						
							|  |  |  |         return _fs_import(dir, modname, fqname) | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     def __repr__(self): | 
					
						
							|  |  |  |         return '<%s.%s for "%s" at 0x%x>' % (self.__class__.__module__, | 
					
						
							|  |  |  |                                              self.__class__.__name__, | 
					
						
							|  |  |  |                                              self.dir, | 
					
						
							|  |  |  |                                              id(self)) | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Emulate the standard path-style import mechanism | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | class PathImporter(imputil.Importer): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ###################################################################### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _test_dir(): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "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()) | 
					
						
							| 
									
										
										
										
											2000-06-29 11:05:30 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def _test_revamp(): | 
					
						
							| 
									
										
										
										
											2000-07-18 09:09:48 +00:00
										 |  |  |     "Debug/test function for the revamped import system." | 
					
						
							|  |  |  |     imputil.ImportManager().install() | 
					
						
							|  |  |  |     sys.path.insert(0, PathImporter()) | 
					
						
							|  |  |  |     sys.path.insert(0, imputil.BuiltinImporter()) |