|
|
@ -405,7 +405,7 @@ class ModuleFinder(object):
|
|
|
|
"""Attempt to fetch source code via pkgutil. In an ideal world, this
|
|
|
|
"""Attempt to fetch source code via pkgutil. In an ideal world, this
|
|
|
|
would be the only required implementation of get_module()."""
|
|
|
|
would be the only required implementation of get_module()."""
|
|
|
|
loader = pkgutil.find_loader(fullname)
|
|
|
|
loader = pkgutil.find_loader(fullname)
|
|
|
|
LOG.debug('pkgutil.find_loader(%r) -> %r', fullname, loader)
|
|
|
|
LOG.debug('pkgutil._get_module_via_pkgutil(%r) -> %r', fullname, loader)
|
|
|
|
if not loader:
|
|
|
|
if not loader:
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
@ -420,51 +420,54 @@ class ModuleFinder(object):
|
|
|
|
def _get_module_via_sys_modules(self, fullname):
|
|
|
|
def _get_module_via_sys_modules(self, fullname):
|
|
|
|
"""Attempt to fetch source code via sys.modules. This is specifically
|
|
|
|
"""Attempt to fetch source code via sys.modules. This is specifically
|
|
|
|
to support __main__, but it may catch a few more cases."""
|
|
|
|
to support __main__, but it may catch a few more cases."""
|
|
|
|
if fullname not in sys.modules:
|
|
|
|
module = sys.modules.get(fullname)
|
|
|
|
LOG.debug('%r does not appear in sys.modules', fullname)
|
|
|
|
if not isinstance(module, types.ModuleType):
|
|
|
|
|
|
|
|
LOG.debug('sys.modules[%r] absent or not a regular module',
|
|
|
|
|
|
|
|
fullname)
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
if 'six.moves' in fullname:
|
|
|
|
modpath = getattr(module, '__file__', '')
|
|
|
|
# TODO: causes inspect.getsource() to explode.
|
|
|
|
|
|
|
|
return None, None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modpath = getattr(sys.modules[fullname], '__file__', '')
|
|
|
|
|
|
|
|
if not modpath.rstrip('co').endswith('.py'):
|
|
|
|
if not modpath.rstrip('co').endswith('.py'):
|
|
|
|
# Probably a native module.
|
|
|
|
# Probably a native module.
|
|
|
|
return None, None, None
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
is_pkg = hasattr(sys.modules[fullname], '__path__')
|
|
|
|
is_pkg = hasattr(module, '__path__')
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
source = inspect.getsource(sys.modules[fullname])
|
|
|
|
source = inspect.getsource(module)
|
|
|
|
except IOError:
|
|
|
|
except IOError:
|
|
|
|
# Work around inspect.getsourcelines() bug.
|
|
|
|
# Work around inspect.getsourcelines() bug.
|
|
|
|
if not is_pkg:
|
|
|
|
if not is_pkg:
|
|
|
|
raise
|
|
|
|
raise
|
|
|
|
source = '\n'
|
|
|
|
source = '\n'
|
|
|
|
|
|
|
|
|
|
|
|
return (sys.modules[fullname].__file__.rstrip('co'),
|
|
|
|
return (module.__file__.rstrip('co'),
|
|
|
|
source,
|
|
|
|
source,
|
|
|
|
hasattr(sys.modules[fullname], '__path__'))
|
|
|
|
hasattr(module, '__path__'))
|
|
|
|
|
|
|
|
|
|
|
|
def _get_module_via_parent_enumeration(self, fullname):
|
|
|
|
def _get_module_via_parent(self, fullname):
|
|
|
|
"""Attempt to fetch source code by examining the module's (hopefully
|
|
|
|
"""Attempt to fetch source code by examining the module's (hopefully
|
|
|
|
less insane) parent package. Required for ansible.compat.six."""
|
|
|
|
less insane) parent package. Required for ansible.compat.six."""
|
|
|
|
|
|
|
|
# Need to find the ancient version of Ansible with the ancient
|
|
|
|
|
|
|
|
# non-package version of six that required this method to exist.
|
|
|
|
|
|
|
|
# Currently it doesn't seem to be needed at all, and it's broken for
|
|
|
|
|
|
|
|
# packages.
|
|
|
|
pkgname, _, modname = fullname.rpartition('.')
|
|
|
|
pkgname, _, modname = fullname.rpartition('.')
|
|
|
|
pkg = sys.modules.get(pkgname)
|
|
|
|
pkg = sys.modules.get(pkgname)
|
|
|
|
if pkg is None or not hasattr(pkg, '__file__'):
|
|
|
|
if not (isinstance(pkg, types.ModuleType) and hasattr(pkg, '__file__')):
|
|
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
pkg_path = os.path.dirname(pkg.__file__)
|
|
|
|
pkg_path = os.path.dirname(pkg.__file__)
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
fp, path, ext = imp.find_module(modname, [pkg_path])
|
|
|
|
fp, path, ext = imp.find_module(modname, [pkg_path])
|
|
|
|
LOG.error('%r', (fp, path, ext))
|
|
|
|
if ext and ext[-1] == imp.PKG_DIRECTORY:
|
|
|
|
|
|
|
|
assert 0, "TODO"
|
|
|
|
return path, fp.read(), False
|
|
|
|
return path, fp.read(), False
|
|
|
|
except ImportError, e:
|
|
|
|
except ImportError, e:
|
|
|
|
LOG.debug('imp.find_module(%r, %r) -> %s', modname, [pkg_path], e)
|
|
|
|
LOG.debug('imp.find_module(%r, %r) -> %s', modname, [pkg_path], e)
|
|
|
|
|
|
|
|
|
|
|
|
get_module_methods = [_get_module_via_pkgutil,
|
|
|
|
get_module_methods = [_get_module_via_pkgutil,
|
|
|
|
_get_module_via_sys_modules,
|
|
|
|
_get_module_via_sys_modules,
|
|
|
|
_get_module_via_parent_enumeration]
|
|
|
|
_get_module_via_parent]
|
|
|
|
|
|
|
|
|
|
|
|
def get_module_source(self, fullname):
|
|
|
|
def get_module_source(self, fullname):
|
|
|
|
"""Given the name of a loaded module `fullname`, attempt to find its
|
|
|
|
"""Given the name of a loaded module `fullname`, attempt to find its
|
|
|
@ -489,11 +492,11 @@ class ModuleFinder(object):
|
|
|
|
"""Given an ImportFrom AST node, guess the prefix that should be tacked
|
|
|
|
"""Given an ImportFrom AST node, guess the prefix that should be tacked
|
|
|
|
on to an alias name to produce a canonical name. `fullname` is the name
|
|
|
|
on to an alias name to produce a canonical name. `fullname` is the name
|
|
|
|
of the module in which the ImportFrom appears."""
|
|
|
|
of the module in which the ImportFrom appears."""
|
|
|
|
if level == 0:
|
|
|
|
if level == 0 or not fullname:
|
|
|
|
return ''
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
|
|
bits = fullname.split('.')
|
|
|
|
bits = fullname.split('.')
|
|
|
|
if len(bits) < level:
|
|
|
|
if len(bits) <= level:
|
|
|
|
# This would be an ImportError in real code.
|
|
|
|
# This would be an ImportError in real code.
|
|
|
|
return ''
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
|
|
@ -536,13 +539,15 @@ class ModuleFinder(object):
|
|
|
|
for name in namelist
|
|
|
|
for name in namelist
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return self._related_cache.setdefault(fullname, [
|
|
|
|
return self._related_cache.setdefault(fullname, sorted(
|
|
|
|
|
|
|
|
set(
|
|
|
|
name
|
|
|
|
name
|
|
|
|
for name in maybe_names
|
|
|
|
for name in maybe_names
|
|
|
|
if sys.modules.get(name) is not None
|
|
|
|
if sys.modules.get(name) is not None
|
|
|
|
and not self.is_stdlib_name(name)
|
|
|
|
and not self.is_stdlib_name(name)
|
|
|
|
and 'six.moves' not in name # TODO: crap
|
|
|
|
and 'six.moves' not in name # TODO: crap
|
|
|
|
])
|
|
|
|
)
|
|
|
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
def find_related(self, fullname):
|
|
|
|
def find_related(self, fullname):
|
|
|
|
stack = [fullname]
|
|
|
|
stack = [fullname]
|
|
|
|