diff options
author | Greg Stein <gstein@lyra.org> | 2000-06-29 11:05:30 (GMT) |
---|---|---|
committer | Greg Stein <gstein@lyra.org> | 2000-06-29 11:05:30 (GMT) |
commit | e97ecf97053b1fdd2c978713b9879d6438aaf207 (patch) | |
tree | 0290b9963829ba81d20dc7514d89ffbf3252b12d /Demo | |
parent | 6c68dc7b1afb8f634604435dd0fc2442c8e93e0d (diff) | |
download | cpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.zip cpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.tar.gz cpython-e97ecf97053b1fdd2c978713b9879d6438aaf207.tar.bz2 |
demonstration importers
Diffstat (limited to 'Demo')
-rw-r--r-- | Demo/imputil/importers.py | 248 |
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()) |