summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Stein <gstein@lyra.org>2000-06-29 11:05:30 (GMT)
committerGreg Stein <gstein@lyra.org>2000-06-29 11:05:30 (GMT)
commite97ecf97053b1fdd2c978713b9879d6438aaf207 (patch)
tree0290b9963829ba81d20dc7514d89ffbf3252b12d
parent6c68dc7b1afb8f634604435dd0fc2442c8e93e0d (diff)
downloadcpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.zip
cpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.tar.gz
cpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.tar.bz2
demonstration importers
-rw-r--r--Demo/imputil/importers.py248
1 files changed, 248 insertions, 0 deletions
diff --git a/Demo/imputil/importers.py b/Demo/imputil/importers.py
new file mode 100644
index 0000000..cfb2daf
--- /dev/null
+++ b/Demo/imputil/importers.py
@@ -0,0 +1,248 @@
+#
+# 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 use a supplied 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())