Remove the imputil module.
This commit is contained in:
parent
6d4df9b343
commit
0ec585575d
|
@ -1,234 +0,0 @@
|
|||
|
||||
:mod:`imputil` --- Import utilities
|
||||
===================================
|
||||
|
||||
.. module:: imputil
|
||||
:synopsis: Manage and augment the import process.
|
||||
|
||||
|
||||
.. index:: statement: import
|
||||
|
||||
This module provides a very handy and useful mechanism for custom
|
||||
:keyword:`import` hooks. Compared to the older :mod:`ihooks` module,
|
||||
:mod:`imputil` takes a dramatically simpler and more straight-forward
|
||||
approach to custom :keyword:`import` functions.
|
||||
|
||||
|
||||
.. class:: ImportManager([fs_imp])
|
||||
|
||||
Manage the import process.
|
||||
|
||||
.. method:: ImportManager.install([namespace])
|
||||
|
||||
Install this ImportManager into the specified namespace.
|
||||
|
||||
.. method:: ImportManager.uninstall()
|
||||
|
||||
Restore the previous import mechanism.
|
||||
|
||||
.. method:: ImportManager.add_suffix(suffix, importFunc)
|
||||
|
||||
Undocumented.
|
||||
|
||||
|
||||
.. class:: Importer()
|
||||
|
||||
Base class for replacing standard import functions.
|
||||
|
||||
.. method:: Importer.import_top(name)
|
||||
|
||||
Import a top-level module.
|
||||
|
||||
.. method:: Importer.get_code(parent, modname, fqname)
|
||||
|
||||
Find and retrieve the code for the given module.
|
||||
|
||||
*parent* specifies a parent module to define a context for importing.
|
||||
It may be ``None``, indicating no particular context for the search.
|
||||
|
||||
*modname* specifies a single module (not dotted) within the parent.
|
||||
|
||||
*fqname* specifies the fully-qualified module name. This is a
|
||||
(potentially) dotted name from the "root" of the module namespace
|
||||
down to the modname.
|
||||
|
||||
If there is no parent, then modname==fqname.
|
||||
|
||||
This method should return ``None``, or a 3-tuple.
|
||||
|
||||
* If the module was not found, then ``None`` should be returned.
|
||||
|
||||
* The first item of the 2- or 3-tuple should be the integer 0 or 1,
|
||||
specifying whether the module that was found is a package or not.
|
||||
|
||||
* The second item is the code object for the module (it will be
|
||||
executed within the new module's namespace). This item can also
|
||||
be a fully-loaded module object (e.g. loaded from a shared lib).
|
||||
|
||||
* The third item is a dictionary of name/value pairs that will be
|
||||
inserted into new module before the code object is executed. This
|
||||
is provided in case the module's code expects certain values (such
|
||||
as where the module was found). When the second item is a module
|
||||
object, then these names/values will be inserted *after* the module
|
||||
has been loaded/initialized.
|
||||
|
||||
|
||||
.. class:: BuiltinImporter()
|
||||
|
||||
Emulate the import mechanism for builtin and frozen modules. This is a
|
||||
sub-class of the :class:`Importer` class.
|
||||
|
||||
.. method:: BuiltinImporter.get_code(parent, modname, fqname)
|
||||
|
||||
Undocumented.
|
||||
|
||||
.. function:: py_suffix_importer(filename, finfo, fqname)
|
||||
|
||||
Undocumented.
|
||||
|
||||
.. class:: DynLoadSuffixImporter([desc])
|
||||
|
||||
Undocumented.
|
||||
|
||||
.. method:: DynLoadSuffixImporter.import_file(filename, finfo, fqname)
|
||||
|
||||
Undocumented.
|
||||
|
||||
.. _examples-imputil:
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
This is a re-implementation of hierarchical module import.
|
||||
|
||||
This code is intended to be read, not executed. However, it does work
|
||||
-- all you need to do to enable it is "import knee".
|
||||
|
||||
(The name is a pun on the klunkier predecessor of this module, "ni".)
|
||||
|
||||
::
|
||||
|
||||
import sys, imp, builtins
|
||||
|
||||
# Replacement for __import__()
|
||||
def import_hook(name, globals=None, locals=None, fromlist=None):
|
||||
parent = determine_parent(globals)
|
||||
q, tail = find_head_package(parent, name)
|
||||
m = load_tail(q, tail)
|
||||
if not fromlist:
|
||||
return q
|
||||
if hasattr(m, "__path__"):
|
||||
ensure_fromlist(m, fromlist)
|
||||
return m
|
||||
|
||||
def determine_parent(globals):
|
||||
if not globals or not "__name__" in globals:
|
||||
return None
|
||||
pname = globals['__name__']
|
||||
if "__path__" in globals:
|
||||
parent = sys.modules[pname]
|
||||
assert globals is parent.__dict__
|
||||
return parent
|
||||
if '.' in pname:
|
||||
i = pname.rfind('.')
|
||||
pname = pname[:i]
|
||||
parent = sys.modules[pname]
|
||||
assert parent.__name__ == pname
|
||||
return parent
|
||||
return None
|
||||
|
||||
def find_head_package(parent, name):
|
||||
if '.' in name:
|
||||
i = name.find('.')
|
||||
head = name[:i]
|
||||
tail = name[i+1:]
|
||||
else:
|
||||
head = name
|
||||
tail = ""
|
||||
if parent:
|
||||
qname = "%s.%s" % (parent.__name__, head)
|
||||
else:
|
||||
qname = head
|
||||
q = import_module(head, qname, parent)
|
||||
if q: return q, tail
|
||||
if parent:
|
||||
qname = head
|
||||
parent = None
|
||||
q = import_module(head, qname, parent)
|
||||
if q: return q, tail
|
||||
raise ImportError("No module named " + qname)
|
||||
|
||||
def load_tail(q, tail):
|
||||
m = q
|
||||
while tail:
|
||||
i = tail.find('.')
|
||||
if i < 0: i = len(tail)
|
||||
head, tail = tail[:i], tail[i+1:]
|
||||
mname = "%s.%s" % (m.__name__, head)
|
||||
m = import_module(head, mname, m)
|
||||
if not m:
|
||||
raise ImportError("No module named " + mname)
|
||||
return m
|
||||
|
||||
def ensure_fromlist(m, fromlist, recursive=0):
|
||||
for sub in fromlist:
|
||||
if sub == "*":
|
||||
if not recursive:
|
||||
try:
|
||||
all = m.__all__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
ensure_fromlist(m, all, 1)
|
||||
continue
|
||||
if sub != "*" and not hasattr(m, sub):
|
||||
subname = "%s.%s" % (m.__name__, sub)
|
||||
submod = import_module(sub, subname, m)
|
||||
if not submod:
|
||||
raise ImportError("No module named " + subname)
|
||||
|
||||
def import_module(partname, fqname, parent):
|
||||
try:
|
||||
return sys.modules[fqname]
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
fp, pathname, stuff = imp.find_module(partname,
|
||||
parent and parent.__path__)
|
||||
except ImportError:
|
||||
return None
|
||||
try:
|
||||
m = imp.load_module(fqname, fp, pathname, stuff)
|
||||
finally:
|
||||
if fp: fp.close()
|
||||
if parent:
|
||||
setattr(parent, partname, m)
|
||||
return m
|
||||
|
||||
|
||||
# Replacement for reload()
|
||||
def reload_hook(module):
|
||||
name = module.__name__
|
||||
if '.' not in name:
|
||||
return import_module(name, name, None)
|
||||
i = name.rfind('.')
|
||||
pname = name[:i]
|
||||
parent = sys.modules[pname]
|
||||
return import_module(name[i+1:], name, parent)
|
||||
|
||||
|
||||
# Save the original hooks
|
||||
original_import = builtins.__import__
|
||||
original_reload = builtins.reload
|
||||
|
||||
# Now install our hooks
|
||||
builtins.__import__ = import_hook
|
||||
builtins.reload = reload_hook
|
||||
|
||||
.. index::
|
||||
module: knee
|
||||
|
||||
Also see the :mod:`importers` module (which can be found
|
||||
in :file:`Demo/imputil/` in the Python source distribution) for additional
|
||||
examples.
|
||||
|
|
@ -14,7 +14,6 @@ The full list of modules described in this chapter is:
|
|||
.. toctree::
|
||||
|
||||
imp.rst
|
||||
imputil.rst
|
||||
zipimport.rst
|
||||
pkgutil.rst
|
||||
modulefinder.rst
|
||||
|
|
712
Lib/imputil.py
712
Lib/imputil.py
|
@ -1,712 +0,0 @@
|
|||
"""
|
||||
Import utilities
|
||||
|
||||
Exported classes:
|
||||
ImportManager Manage the import process
|
||||
|
||||
Importer Base class for replacing standard import functions
|
||||
BuiltinImporter Emulate the import mechanism for builtin and frozen modules
|
||||
|
||||
DynLoadSuffixImporter
|
||||
"""
|
||||
|
||||
# note: avoid importing non-builtin modules
|
||||
import imp ### not available in JPython?
|
||||
import sys
|
||||
import builtins
|
||||
|
||||
# for the DirectoryImporter
|
||||
import struct
|
||||
import marshal
|
||||
|
||||
__all__ = ["ImportManager","Importer","BuiltinImporter"]
|
||||
|
||||
_ModuleType = type(sys) ### doesn't work in JPython...
|
||||
|
||||
class ImportManager:
|
||||
"Manage the import process."
|
||||
|
||||
def install(self, namespace=vars(builtins)):
|
||||
"Install this ImportManager into the specified namespace."
|
||||
|
||||
if isinstance(namespace, _ModuleType):
|
||||
namespace = vars(namespace)
|
||||
|
||||
# Note: we have no notion of "chaining"
|
||||
|
||||
# Record the previous import hook, then install our own.
|
||||
self.previous_importer = namespace['__import__']
|
||||
self.namespace = namespace
|
||||
namespace['__import__'] = self._import_hook
|
||||
|
||||
def uninstall(self):
|
||||
"Restore the previous import mechanism."
|
||||
self.namespace['__import__'] = self.previous_importer
|
||||
|
||||
def add_suffix(self, suffix, importFunc):
|
||||
assert hasattr(importFunc, '__call__')
|
||||
self.fs_imp.add_suffix(suffix, importFunc)
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# PRIVATE METHODS
|
||||
#
|
||||
|
||||
clsFilesystemImporter = None
|
||||
|
||||
def __init__(self, fs_imp=None):
|
||||
# we're definitely going to be importing something in the future,
|
||||
# so let's just load the OS-related facilities.
|
||||
if not _os_stat:
|
||||
_os_bootstrap()
|
||||
|
||||
# This is the Importer that we use for grabbing stuff from the
|
||||
# filesystem. It defines one more method (import_from_dir) for our use.
|
||||
if fs_imp is None:
|
||||
cls = self.clsFilesystemImporter or _FilesystemImporter
|
||||
fs_imp = cls()
|
||||
self.fs_imp = fs_imp
|
||||
|
||||
# Initialize the set of suffixes that we recognize and import.
|
||||
# The default will import dynamic-load modules first, followed by
|
||||
# .py files (or a .py file's cached bytecode)
|
||||
for desc in imp.get_suffixes():
|
||||
if desc[2] == imp.C_EXTENSION:
|
||||
self.add_suffix(desc[0],
|
||||
DynLoadSuffixImporter(desc).import_file)
|
||||
self.add_suffix('.py', py_suffix_importer)
|
||||
|
||||
def _import_hook(self, fqname, globals=None, locals=None, fromlist=None):
|
||||
"""Python calls this hook to locate and import a module."""
|
||||
|
||||
parts = fqname.split('.')
|
||||
|
||||
# determine the context of this import
|
||||
parent = self._determine_import_context(globals)
|
||||
|
||||
# if there is a parent, then its importer should manage this import
|
||||
if parent:
|
||||
module = parent.__importer__._do_import(parent, parts, fromlist)
|
||||
if module:
|
||||
return module
|
||||
|
||||
# has the top module already been imported?
|
||||
try:
|
||||
top_module = sys.modules[parts[0]]
|
||||
except KeyError:
|
||||
|
||||
# look for the topmost module
|
||||
top_module = self._import_top_module(parts[0])
|
||||
if not top_module:
|
||||
# the topmost module wasn't found at all.
|
||||
raise ImportError('No module named ' + fqname)
|
||||
|
||||
# fast-path simple imports
|
||||
if len(parts) == 1:
|
||||
if not fromlist:
|
||||
return top_module
|
||||
|
||||
if not top_module.__dict__.get('__ispkg__'):
|
||||
# __ispkg__ isn't defined (the module was not imported by us),
|
||||
# or it is zero.
|
||||
#
|
||||
# In the former case, there is no way that we could import
|
||||
# sub-modules that occur in the fromlist (but we can't raise an
|
||||
# error because it may just be names) because we don't know how
|
||||
# to deal with packages that were imported by other systems.
|
||||
#
|
||||
# In the latter case (__ispkg__ == 0), there can't be any sub-
|
||||
# modules present, so we can just return.
|
||||
#
|
||||
# In both cases, since len(parts) == 1, the top_module is also
|
||||
# the "bottom" which is the defined return when a fromlist
|
||||
# exists.
|
||||
return top_module
|
||||
|
||||
importer = top_module.__dict__.get('__importer__')
|
||||
if importer:
|
||||
return importer._finish_import(top_module, parts[1:], fromlist)
|
||||
|
||||
# Grrr, some people "import os.path" or do "from os.path import ..."
|
||||
if len(parts) == 2 and hasattr(top_module, parts[1]):
|
||||
if fromlist:
|
||||
return getattr(top_module, parts[1])
|
||||
else:
|
||||
return top_module
|
||||
|
||||
# If the importer does not exist, then we have to bail. A missing
|
||||
# importer means that something else imported the module, and we have
|
||||
# no knowledge of how to get sub-modules out of the thing.
|
||||
raise ImportError('No module named ' + fqname)
|
||||
|
||||
def _determine_import_context(self, globals):
|
||||
"""Returns the context in which a module should be imported.
|
||||
|
||||
The context could be a loaded (package) module and the imported module
|
||||
will be looked for within that package. The context could also be None,
|
||||
meaning there is no context -- the module should be looked for as a
|
||||
"top-level" module.
|
||||
"""
|
||||
|
||||
if not globals or not globals.get('__importer__'):
|
||||
# globals does not refer to one of our modules or packages. That
|
||||
# implies there is no relative import context (as far as we are
|
||||
# concerned), and it should just pick it off the standard path.
|
||||
return None
|
||||
|
||||
# The globals refer to a module or package of ours. It will define
|
||||
# the context of the new import. Get the module/package fqname.
|
||||
parent_fqname = globals['__name__']
|
||||
|
||||
# if a package is performing the import, then return itself (imports
|
||||
# refer to pkg contents)
|
||||
if globals['__ispkg__']:
|
||||
parent = sys.modules[parent_fqname]
|
||||
assert globals is parent.__dict__
|
||||
return parent
|
||||
|
||||
i = parent_fqname.rfind('.')
|
||||
|
||||
# a module outside of a package has no particular import context
|
||||
if i == -1:
|
||||
return None
|
||||
|
||||
# if a module in a package is performing the import, then return the
|
||||
# package (imports refer to siblings)
|
||||
parent_fqname = parent_fqname[:i]
|
||||
parent = sys.modules[parent_fqname]
|
||||
assert parent.__name__ == parent_fqname
|
||||
return parent
|
||||
|
||||
def _import_top_module(self, name):
|
||||
# scan sys.path looking for a location in the filesystem that contains
|
||||
# the module, or an Importer object that can import the module.
|
||||
for item in sys.path:
|
||||
if isinstance(item, str):
|
||||
module = self.fs_imp.import_from_dir(item, name)
|
||||
else:
|
||||
module = item.import_top(name)
|
||||
if module:
|
||||
return module
|
||||
return None
|
||||
|
||||
|
||||
class Importer:
|
||||
"Base class for replacing standard import functions."
|
||||
|
||||
def import_top(self, name):
|
||||
"Import a top-level module."
|
||||
return self._import_one(None, name, name)
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# PRIVATE METHODS
|
||||
#
|
||||
def _finish_import(self, top, parts, fromlist):
|
||||
# if "a.b.c" was provided, then load the ".b.c" portion down from
|
||||
# below the top-level module.
|
||||
bottom = self._load_tail(top, parts)
|
||||
|
||||
# if the form is "import a.b.c", then return "a"
|
||||
if not fromlist:
|
||||
# no fromlist: return the top of the import tree
|
||||
return top
|
||||
|
||||
# the top module was imported by self.
|
||||
#
|
||||
# this means that the bottom module was also imported by self (just
|
||||
# now, or in the past and we fetched it from sys.modules).
|
||||
#
|
||||
# since we imported/handled the bottom module, this means that we can
|
||||
# also handle its fromlist (and reliably use __ispkg__).
|
||||
|
||||
# if the bottom node is a package, then (potentially) import some
|
||||
# modules.
|
||||
#
|
||||
# note: if it is not a package, then "fromlist" refers to names in
|
||||
# the bottom module rather than modules.
|
||||
# note: for a mix of names and modules in the fromlist, we will
|
||||
# import all modules and insert those into the namespace of
|
||||
# the package module. Python will pick up all fromlist names
|
||||
# from the bottom (package) module; some will be modules that
|
||||
# we imported and stored in the namespace, others are expected
|
||||
# to be present already.
|
||||
if bottom.__ispkg__:
|
||||
self._import_fromlist(bottom, fromlist)
|
||||
|
||||
# if the form is "from a.b import c, d" then return "b"
|
||||
return bottom
|
||||
|
||||
def _import_one(self, parent, modname, fqname):
|
||||
"Import a single module."
|
||||
|
||||
# has the module already been imported?
|
||||
try:
|
||||
return sys.modules[fqname]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# load the module's code, or fetch the module itself
|
||||
result = self.get_code(parent, modname, fqname)
|
||||
if result is None:
|
||||
return None
|
||||
|
||||
module = self._process_result(result, fqname)
|
||||
|
||||
# insert the module into its parent
|
||||
if parent:
|
||||
setattr(parent, modname, module)
|
||||
return module
|
||||
|
||||
def _process_result(self, result, fqname):
|
||||
# unpack result
|
||||
ispkg, code, values = result
|
||||
|
||||
# did get_code() return an actual module? (rather than a code object)
|
||||
is_module = isinstance(code, _ModuleType)
|
||||
|
||||
# use the returned module, or create a new one to exec code into
|
||||
if is_module:
|
||||
module = code
|
||||
else:
|
||||
module = imp.new_module(fqname)
|
||||
|
||||
### record packages a bit differently??
|
||||
module.__importer__ = self
|
||||
module.__ispkg__ = ispkg
|
||||
|
||||
# insert additional values into the module (before executing the code)
|
||||
module.__dict__.update(values)
|
||||
|
||||
# the module is almost ready... make it visible
|
||||
sys.modules[fqname] = module
|
||||
|
||||
# execute the code within the module's namespace
|
||||
if not is_module:
|
||||
try:
|
||||
exec(code, module.__dict__)
|
||||
except:
|
||||
if fqname in sys.modules:
|
||||
del sys.modules[fqname]
|
||||
raise
|
||||
|
||||
# fetch from sys.modules instead of returning module directly.
|
||||
# also make module's __name__ agree with fqname, in case
|
||||
# the "exec code in module.__dict__" played games on us.
|
||||
module = sys.modules[fqname]
|
||||
module.__name__ = fqname
|
||||
return module
|
||||
|
||||
def _load_tail(self, m, parts):
|
||||
"""Import the rest of the modules, down from the top-level module.
|
||||
|
||||
Returns the last module in the dotted list of modules.
|
||||
"""
|
||||
for part in parts:
|
||||
fqname = "%s.%s" % (m.__name__, part)
|
||||
m = self._import_one(m, part, fqname)
|
||||
if not m:
|
||||
raise ImportError("No module named " + fqname)
|
||||
return m
|
||||
|
||||
def _import_fromlist(self, package, fromlist):
|
||||
'Import any sub-modules in the "from" list.'
|
||||
|
||||
# if '*' is present in the fromlist, then look for the '__all__'
|
||||
# variable to find additional items (modules) to import.
|
||||
if '*' in fromlist:
|
||||
fromlist = list(fromlist) + \
|
||||
list(package.__dict__.get('__all__', []))
|
||||
|
||||
for sub in fromlist:
|
||||
# if the name is already present, then don't try to import it (it
|
||||
# might not be a module!).
|
||||
if sub != '*' and not hasattr(package, sub):
|
||||
subname = "%s.%s" % (package.__name__, sub)
|
||||
submod = self._import_one(package, sub, subname)
|
||||
if not submod:
|
||||
raise ImportError("cannot import name " + subname)
|
||||
|
||||
def _do_import(self, parent, parts, fromlist):
|
||||
"""Attempt to import the module relative to parent.
|
||||
|
||||
This method is used when the import context specifies that <self>
|
||||
imported the parent module.
|
||||
"""
|
||||
top_name = parts[0]
|
||||
top_fqname = parent.__name__ + '.' + top_name
|
||||
top_module = self._import_one(parent, top_name, top_fqname)
|
||||
if not top_module:
|
||||
# this importer and parent could not find the module (relatively)
|
||||
return None
|
||||
|
||||
return self._finish_import(top_module, parts[1:], fromlist)
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# METHODS TO OVERRIDE
|
||||
#
|
||||
def get_code(self, parent, modname, fqname):
|
||||
"""Find and retrieve the code for the given module.
|
||||
|
||||
parent specifies a parent module to define a context for importing. It
|
||||
may be None, indicating no particular context for the search.
|
||||
|
||||
modname specifies a single module (not dotted) within the parent.
|
||||
|
||||
fqname specifies the fully-qualified module name. This is a
|
||||
(potentially) dotted name from the "root" of the module namespace
|
||||
down to the modname.
|
||||
If there is no parent, then modname==fqname.
|
||||
|
||||
This method should return None, or a 3-tuple.
|
||||
|
||||
* If the module was not found, then None should be returned.
|
||||
|
||||
* The first item of the 2- or 3-tuple should be the integer 0 or 1,
|
||||
specifying whether the module that was found is a package or not.
|
||||
|
||||
* The second item is the code object for the module (it will be
|
||||
executed within the new module's namespace). This item can also
|
||||
be a fully-loaded module object (e.g. loaded from a shared lib).
|
||||
|
||||
* The third item is a dictionary of name/value pairs that will be
|
||||
inserted into new module before the code object is executed. This
|
||||
is provided in case the module's code expects certain values (such
|
||||
as where the module was found). When the second item is a module
|
||||
object, then these names/values will be inserted *after* the module
|
||||
has been loaded/initialized.
|
||||
"""
|
||||
raise RuntimeError("get_code not implemented")
|
||||
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Some handy stuff for the Importers
|
||||
#
|
||||
|
||||
# byte-compiled file suffix character
|
||||
_suffix_char = __debug__ and 'c' or 'o'
|
||||
|
||||
# byte-compiled file suffix
|
||||
_suffix = '.py' + _suffix_char
|
||||
|
||||
def _compile(pathname, timestamp):
|
||||
"""Compile (and cache) a Python source file.
|
||||
|
||||
The file specified by <pathname> is compiled to a code object and
|
||||
returned.
|
||||
|
||||
Presuming the appropriate privileges exist, the bytecodes will be
|
||||
saved back to the filesystem for future imports. The source file's
|
||||
modification timestamp must be provided as a Long value.
|
||||
"""
|
||||
codestring = open(pathname, 'rU').read()
|
||||
if codestring and codestring[-1] != '\n':
|
||||
codestring = codestring + '\n'
|
||||
code = builtins.compile(codestring, pathname, 'exec')
|
||||
|
||||
# try to cache the compiled code
|
||||
try:
|
||||
f = open(pathname + _suffix_char, 'wb')
|
||||
except IOError:
|
||||
pass
|
||||
else:
|
||||
f.write('\0\0\0\0')
|
||||
f.write(struct.pack('<I', timestamp))
|
||||
marshal.dump(code, f)
|
||||
f.flush()
|
||||
f.seek(0, 0)
|
||||
f.write(imp.get_magic())
|
||||
f.close()
|
||||
|
||||
return code
|
||||
|
||||
_os_stat = _os_path_join = None
|
||||
def _os_bootstrap():
|
||||
"Set up 'os' module replacement functions for use during import bootstrap."
|
||||
|
||||
names = sys.builtin_module_names
|
||||
|
||||
join = None
|
||||
if 'posix' in names:
|
||||
sep = '/'
|
||||
from posix import stat
|
||||
elif 'nt' in names:
|
||||
sep = '\\'
|
||||
from nt import stat
|
||||
elif 'dos' in names:
|
||||
sep = '\\'
|
||||
from dos import stat
|
||||
elif 'os2' in names:
|
||||
sep = '\\'
|
||||
from os2 import stat
|
||||
elif 'mac' in names:
|
||||
from mac import stat
|
||||
def join(a, b):
|
||||
if a == '':
|
||||
return b
|
||||
if ':' not in a:
|
||||
a = ':' + a
|
||||
if a[-1:] != ':':
|
||||
a = a + ':'
|
||||
return a + b
|
||||
else:
|
||||
raise ImportError('no os specific module found')
|
||||
|
||||
if join is None:
|
||||
def join(a, b, sep=sep):
|
||||
if a == '':
|
||||
return b
|
||||
lastchar = a[-1:]
|
||||
if lastchar == '/' or lastchar == sep:
|
||||
return a + b
|
||||
return a + sep + b
|
||||
|
||||
global _os_stat
|
||||
_os_stat = stat
|
||||
|
||||
global _os_path_join
|
||||
_os_path_join = join
|
||||
|
||||
def _os_path_isdir(pathname):
|
||||
"Local replacement for os.path.isdir()."
|
||||
try:
|
||||
s = _os_stat(pathname)
|
||||
except OSError:
|
||||
return None
|
||||
return (s.st_mode & 0o170000) == 0o040000
|
||||
|
||||
def _timestamp(pathname):
|
||||
"Return the file modification time as a Long."
|
||||
try:
|
||||
s = _os_stat(pathname)
|
||||
except OSError:
|
||||
return None
|
||||
return int(s.st_mtime)
|
||||
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Emulate the import mechanism for builtin and frozen modules
|
||||
#
|
||||
class BuiltinImporter(Importer):
|
||||
def get_code(self, parent, modname, fqname):
|
||||
if parent:
|
||||
# these modules definitely do not occur within a package context
|
||||
return None
|
||||
|
||||
# look for the module
|
||||
if imp.is_builtin(modname):
|
||||
type = imp.C_BUILTIN
|
||||
elif imp.is_frozen(modname):
|
||||
type = imp.PY_FROZEN
|
||||
else:
|
||||
# not found
|
||||
return None
|
||||
|
||||
# got it. now load and return it.
|
||||
module = imp.load_module(modname, None, modname, ('', '', type))
|
||||
return 0, module, { }
|
||||
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Internal importer used for importing from the filesystem
|
||||
#
|
||||
class _FilesystemImporter(Importer):
|
||||
def __init__(self):
|
||||
self.suffixes = [ ]
|
||||
|
||||
def add_suffix(self, suffix, importFunc):
|
||||
assert hasattr(importFunc, '__call__')
|
||||
self.suffixes.append((suffix, importFunc))
|
||||
|
||||
def import_from_dir(self, dir, fqname):
|
||||
result = self._import_pathname(_os_path_join(dir, fqname), fqname)
|
||||
if result:
|
||||
return self._process_result(result, fqname)
|
||||
return None
|
||||
|
||||
def get_code(self, parent, modname, fqname):
|
||||
# This importer is never used with an empty parent. Its existence is
|
||||
# private to the ImportManager. The ImportManager uses the
|
||||
# import_from_dir() method to import top-level modules/packages.
|
||||
# This method is only used when we look for a module within a package.
|
||||
assert parent
|
||||
|
||||
for submodule_path in parent.__path__:
|
||||
code = self._import_pathname(_os_path_join(submodule_path, modname), fqname)
|
||||
if code is not None:
|
||||
return code
|
||||
return self._import_pathname(_os_path_join(parent.__pkgdir__, modname),
|
||||
fqname)
|
||||
|
||||
def _import_pathname(self, pathname, fqname):
|
||||
if _os_path_isdir(pathname):
|
||||
result = self._import_pathname(_os_path_join(pathname, '__init__'),
|
||||
fqname)
|
||||
if result:
|
||||
values = result[2]
|
||||
values['__pkgdir__'] = pathname
|
||||
values['__path__'] = [ pathname ]
|
||||
return 1, result[1], values
|
||||
return None
|
||||
|
||||
for suffix, importFunc in self.suffixes:
|
||||
filename = pathname + suffix
|
||||
try:
|
||||
finfo = _os_stat(filename)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
return importFunc(filename, finfo, fqname)
|
||||
return None
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# SUFFIX-BASED IMPORTERS
|
||||
#
|
||||
|
||||
def py_suffix_importer(filename, finfo, fqname):
|
||||
file = filename[:-3] + _suffix
|
||||
t_py = int(finfo[8])
|
||||
t_pyc = _timestamp(file)
|
||||
|
||||
code = None
|
||||
if t_pyc is not None and t_pyc >= t_py:
|
||||
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 = filename
|
||||
code = _compile(file, t_py)
|
||||
|
||||
return 0, code, { '__file__' : file }
|
||||
|
||||
class DynLoadSuffixImporter:
|
||||
def __init__(self, desc):
|
||||
self.desc = desc
|
||||
|
||||
def import_file(self, filename, finfo, fqname):
|
||||
fp = open(filename, self.desc[1])
|
||||
module = imp.load_module(fqname, fp, filename, self.desc)
|
||||
module.__file__ = filename
|
||||
return 0, module, { }
|
||||
|
||||
|
||||
######################################################################
|
||||
|
||||
def _print_importers():
|
||||
items = sys.modules.items()
|
||||
items.sort()
|
||||
for name, module in items:
|
||||
if module:
|
||||
print(name, module.__dict__.get('__importer__', '-- no importer'))
|
||||
else:
|
||||
print(name, '-- non-existent module')
|
||||
|
||||
def _test_revamp():
|
||||
ImportManager().install()
|
||||
sys.path.insert(0, BuiltinImporter())
|
||||
|
||||
######################################################################
|
||||
|
||||
#
|
||||
# TODO
|
||||
#
|
||||
# from Finn Bock:
|
||||
# type(sys) is not a module in JPython. what to use instead?
|
||||
# imp.C_EXTENSION is not in JPython. same for get_suffixes and new_module
|
||||
#
|
||||
# given foo.py of:
|
||||
# import sys
|
||||
# sys.modules['foo'] = sys
|
||||
#
|
||||
# ---- standard import mechanism
|
||||
# >>> import foo
|
||||
# >>> foo
|
||||
# <module 'sys' (built-in)>
|
||||
#
|
||||
# ---- revamped import mechanism
|
||||
# >>> import imputil
|
||||
# >>> imputil._test_revamp()
|
||||
# >>> import foo
|
||||
# >>> foo
|
||||
# <module 'foo' from 'foo.py'>
|
||||
#
|
||||
#
|
||||
# from MAL:
|
||||
# should BuiltinImporter exist in sys.path or hard-wired in ImportManager?
|
||||
# need __path__ processing
|
||||
# performance
|
||||
# move chaining to a subclass [gjs: it's been nuked]
|
||||
# deinstall should be possible
|
||||
# query mechanism needed: is a specific Importer installed?
|
||||
# py/pyc/pyo piping hooks to filter/process these files
|
||||
# wish list:
|
||||
# distutils importer hooked to list of standard Internet repositories
|
||||
# module->file location mapper to speed FS-based imports
|
||||
# relative imports
|
||||
# keep chaining so that it can play nice with other import hooks
|
||||
#
|
||||
# from Gordon:
|
||||
# push MAL's mapper into sys.path[0] as a cache (hard-coded for apps)
|
||||
#
|
||||
# from Guido:
|
||||
# need hook for MAL's walk-me-up import strategy, or Tim's absolute strategy
|
||||
# watch out for sys.modules[...] is None
|
||||
# flag to force absolute imports? (speeds _determine_import_context and
|
||||
# checking for a relative module)
|
||||
# insert names of archives into sys.path (see quote below)
|
||||
# shift import mechanisms and policies around; provide for hooks, overrides
|
||||
# (see quote below)
|
||||
# add get_source stuff
|
||||
# get_topcode and get_subcode
|
||||
# CRLF handling in _compile
|
||||
# race condition in _compile
|
||||
# refactoring of os.py to deal with _os_bootstrap problem
|
||||
# any special handling to do for importing a module with a SyntaxError?
|
||||
# (e.g. clean up the traceback)
|
||||
# implement "domain" for path-type functionality using pkg namespace
|
||||
# (rather than FS-names like __path__)
|
||||
# don't use the word "private"... maybe "internal"
|
||||
#
|
||||
#
|
||||
# Guido's comments on sys.path caching:
|
||||
#
|
||||
# We could cache this in a dictionary: the ImportManager can have a
|
||||
# cache dict mapping pathnames to importer objects, and a separate
|
||||
# method for coming up with an importer given a pathname that's not yet
|
||||
# in the cache. The method should do a stat and/or look at the
|
||||
# extension to decide which importer class to use; you can register new
|
||||
# importer classes by registering a suffix or a Boolean function, plus a
|
||||
# class. If you register a new importer class, the cache is zapped.
|
||||
# The cache is independent from sys.path (but maintained per
|
||||
# ImportManager instance) so that rearrangements of sys.path do the
|
||||
# right thing. If a path is dropped from sys.path the corresponding
|
||||
# cache entry is simply no longer used.
|
||||
#
|
||||
# My/Guido's comments on factoring ImportManager and Importer:
|
||||
#
|
||||
# > However, we still have a tension occurring here:
|
||||
# >
|
||||
# > 1) implementing policy in ImportManager assists in single-point policy
|
||||
# > changes for app situations
|
||||
# > 2) implementing policy in Importer assists in package-private policy
|
||||
# > changes for normal, operating conditions
|
||||
# >
|
||||
# > I'll see if I can sort out a way to do this. Maybe the Importer class will
|
||||
# > implement the methods (which can be overridden to change policy) by
|
||||
# > delegating to ImportManager.
|
||||
#
|
||||
# Maybe also think about what kind of policies an Importer would be
|
||||
# likely to want to change. I have a feeling that a lot of the code
|
||||
# there is actually not so much policy but a *necessity* to get things
|
||||
# working given the calling conventions for the __import__ hook: whether
|
||||
# to return the head or tail of a dotted name, or when to do the "finish
|
||||
# fromlist" stuff.
|
||||
#
|
|
@ -108,8 +108,6 @@ def updatecache(filename, module_globals=None):
|
|||
# Try looking through the module search path.
|
||||
|
||||
for dirname in sys.path:
|
||||
# When using imputil, sys.path may contain things other than
|
||||
# strings; ignore them when it happens.
|
||||
try:
|
||||
fullname = os.path.join(dirname, basename)
|
||||
except (TypeError, AttributeError):
|
||||
|
|
|
@ -79,7 +79,6 @@ class AllTest(unittest.TestCase):
|
|||
self.check_all("ihooks")
|
||||
self.check_all("imaplib")
|
||||
self.check_all("imghdr")
|
||||
self.check_all("imputil")
|
||||
self.check_all("keyword")
|
||||
self.check_all("linecache")
|
||||
self.check_all("locale")
|
||||
|
|
|
@ -51,7 +51,6 @@ class TestUntestedModules(unittest.TestCase):
|
|||
import htmlentitydefs
|
||||
import ihooks
|
||||
import imghdr
|
||||
import imputil
|
||||
import keyword
|
||||
import linecache
|
||||
import macurl2path
|
||||
|
|
Loading…
Reference in New Issue