summaryrefslogtreecommitdiff
path: root/astroid/modutils.py
diff options
context:
space:
mode:
Diffstat (limited to 'astroid/modutils.py')
-rw-r--r--astroid/modutils.py282
1 files changed, 21 insertions, 261 deletions
diff --git a/astroid/modutils.py b/astroid/modutils.py
index 3334e1e3..d198be7c 100644
--- a/astroid/modutils.py
+++ b/astroid/modutils.py
@@ -19,10 +19,6 @@
:type BUILTIN_MODULES: dict
:var BUILTIN_MODULES: dictionary with builtin module names has key
"""
-
-import abc
-import collections
-import enum
import imp
import os
import platform
@@ -34,12 +30,6 @@ from distutils.errors import DistutilsPlatformError
# distutils is replaced by virtualenv with a module that does
# weird path manipulations in order to get to the
# real distutils module.
-import zipimport
-try:
- import importlib.machinery
- _HAS_MACHINERY = True
-except ImportError:
- _HAS_MACHINERY = False
try:
import pkg_resources
@@ -47,23 +37,8 @@ except ImportError:
pkg_resources = None
import six
-ModuleType = enum.Enum('ModuleType', 'C_BUILTIN C_EXTENSION PKG_DIRECTORY '
- 'PY_CODERESOURCE PY_COMPILED PY_FROZEN PY_RESOURCE '
- 'PY_SOURCE PY_ZIPMODULE PY_NAMESPACE')
-_ImpTypes = {imp.C_BUILTIN: ModuleType.C_BUILTIN,
- imp.C_EXTENSION: ModuleType.C_EXTENSION,
- imp.PKG_DIRECTORY: ModuleType.PKG_DIRECTORY,
- imp.PY_COMPILED: ModuleType.PY_COMPILED,
- imp.PY_FROZEN: ModuleType.PY_FROZEN,
- imp.PY_SOURCE: ModuleType.PY_SOURCE,
- }
-if hasattr(imp, 'PY_RESOURCE'):
- _ImpTypes[imp.PY_RESOURCE] = ModuleType.PY_RESOURCE
-if hasattr(imp, 'PY_CODERESOURCE'):
- _ImpTypes[imp.PY_CODERESOURCE] = ModuleType.PY_CODERESOURCE
-
-def _imp_type_to_module_type(imp_type):
- return _ImpTypes[imp_type]
+from .interpreter._import import spec
+from .interpreter._import import util
if sys.platform.startswith('win'):
PY_SOURCE_EXTS = ('py', 'pyw')
@@ -260,7 +235,7 @@ def load_module_from_modpath(parts, path=None, use_sys=1):
setattr(prevmodule, part, module)
_file = getattr(module, '__file__', '')
prevmodule = module
- if not _file and _is_namespace(curname):
+ if not _file and util.is_namespace(curname):
continue
if not _file and len(modpath) != len(parts):
raise ImportError('no module in %s' % '.'.join(parts[len(modpath):]))
@@ -301,7 +276,7 @@ def check_modpath_has_init(path, mod_path):
modpath.append(part)
path = os.path.join(path, part)
if not _has_init(path):
- old_namespace = _is_namespace('.'.join(modpath))
+ old_namespace = util.is_namespace('.'.join(modpath))
if not old_namespace:
return False
return True
@@ -401,7 +376,7 @@ def file_info_from_modpath(modpath, path=None, context_file=None):
return _spec_from_modpath(modpath, path, context)
elif modpath == ['os', 'path']:
# FIXME: currently ignoring search_path...
- return ModuleSpec(name='os.path', location=os.path.__file__, type=imp.PY_SOURCE)
+ return spec.ModuleSpec(name='os.path', location=os.path.__file__, type=imp.PY_SOURCE)
return _spec_from_modpath(modpath, path, context)
@@ -560,7 +535,7 @@ def is_standard_module(modname, std_path=None):
# (sys and __builtin__ for instance)
if filename is None:
# we assume there are no namespaces in stdlib
- return not _is_namespace(modname)
+ return not util.is_namespace(modname)
filename = _normalize_path(filename)
if filename.startswith(_cache_normalize_path(EXT_LIB_DIR)):
return False
@@ -616,241 +591,26 @@ def _spec_from_modpath(modpath, path=None, context=None):
location = None
if context is not None:
try:
- spec = _find_spec(modpath, [context])
- location = spec.location
+ found_spec = spec.find_spec(modpath, [context])
+ location = found_spec.location
except ImportError:
- spec = _find_spec(modpath, path)
- location = spec.location
+ found_spec = spec.find_spec(modpath, path)
+ location = found_spec.location
else:
- spec = _find_spec(modpath, path)
- if spec.type == ModuleType.PY_COMPILED:
+ found_spec = spec.find_spec(modpath, path)
+ if found_spec.type == spec.ModuleType.PY_COMPILED:
try:
- location = get_source_file(spec.location)
- return spec._replace(location=location, type=ModuleSpec.PY_SOURCE)
+ location = get_source_file(found_spec.location)
+ return found_spec._replace(location=location, type=spec.ModuleSpec.PY_SOURCE)
except NoSourceFile:
- return spec.replace(location=location)
- elif spec.type == ModuleType.C_BUILTIN:
+ return found_spec.replace(location=location)
+ elif found_spec.type == spec.ModuleType.C_BUILTIN:
# integrated builtin module
- return spec._replace(location=None)
- elif spec.type == ModuleType.PKG_DIRECTORY:
- location = _has_init(spec.location)
- return spec._replace(location=location, type=ModuleType.PY_SOURCE)
- return spec
-
-
-def _search_zip(modpath, pic):
- for filepath, importer in list(pic.items()):
- if importer is not None:
- found = importer.find_module(modpath[0])
- if found:
- if not importer.find_module(os.path.sep.join(modpath)):
- raise ImportError('No module named %s in %s/%s' % (
- '.'.join(modpath[1:]), filepath, modpath))
- #import code; code.interact(local=locals())
- return (ModuleType.PY_ZIPMODULE,
- os.path.abspath(filepath) + os.path.sep + os.path.sep.join(modpath),
- filepath)
- raise ImportError('No module named %s' % '.'.join(modpath))
-
-
-def _precache_zipimporters(path=None):
- pic = sys.path_importer_cache
- path = path or sys.path
- for entry_path in path:
- if entry_path not in pic:
- try:
- pic[entry_path] = zipimport.zipimporter(entry_path)
- except zipimport.ZipImportError:
- continue
- return pic
-
-
-def _is_namespace(modname):
- # pylint: disable=no-member; astroid issue #290, modifying globals at runtime.
- return (pkg_resources is not None
- and modname in pkg_resources._namespace_packages)
-
-
-def _is_setuptools_namespace(location):
- try:
- with open(os.path.join(location, '__init__.py'), 'rb') as stream:
- data = stream.read(4096)
- except IOError:
- pass
- else:
- extend_path = b'pkgutil' in data and b'extend_path' in data
- declare_namespace = (
- b"pkg_resources" in data
- and b"declare_namespace(__name__)" in data)
- return extend_path or declare_namespace
-
-
-# Spec finders.
-
-_ModuleSpec = collections.namedtuple('_ModuleSpec', 'name type location '
- 'origin submodule_search_locations')
-
-class ModuleSpec(_ModuleSpec):
-
- def __new__(cls, name, type, location=None, origin=None,
- submodule_search_locations=None):
- return _ModuleSpec.__new__(cls, name=name, type=type,
- location=location, origin=origin,
- submodule_search_locations=submodule_search_locations)
-
-
-class Finder(object):
-
- def __init__(self, path=None):
- self._path = path or sys.path
-
- @abc.abstractmethod
- def find_module(self, modname, module_parts, processed, submodule_path):
- pass
-
- def contribute_to_path(self, filename, processed):
- return None
-
-
-class ImpFinder(Finder):
-
- def find_module(self, modname, _, processed, submodule_path):
- try:
- stream, mp_filename, mp_desc = imp.find_module(modname, submodule_path)
- except ImportError:
- return None
-
- # Close resources.
- if stream:
- stream.close()
-
- return ModuleSpec(name=modname, location=mp_filename,
- type=_imp_type_to_module_type(mp_desc[2]))
-
- def contribute_to_path(self, spec, processed):
- if spec.location is None:
- # Builtin.
- return None
-
- if _is_setuptools_namespace(spec.location):
- # extend_path is called, search sys.path for module/packages
- # of this name see pkgutil.extend_path documentation
- path = [os.path.join(p, *processed) for p in sys.path
- if os.path.isdir(os.path.join(p, *processed))]
- else:
- path = [spec.location]
- return path
-
-
-class DynamicImpFinder(ImpFinder):
-
- def find_module(self, modname, module_parts, processed, submodule_path):
- if _is_namespace(modname) and modname in sys.modules:
- submodule_path = sys.modules[modname].__path__
- return ModuleSpec(name=modname, location='',
- origin='namespace',
- type=ModuleType.PY_NAMESPACE,
- submodule_search_locations=submodule_path)
-
-
- def contribute_to_path(self, spec, processed):
- return spec.submodule_search_locations
-
-
-
-class ZipFinder(Finder):
-
- def __init__(self, path):
- super(ZipFinder, self).__init__(path)
- self._zipimporters = _precache_zipimporters(path)
-
- def find_module(self, modname, module_parts, processed, submodule_path):
- try:
- file_type, filename, path = _search_zip(module_parts, self._zipimporters)
- except ImportError:
- return None
-
- return ModuleSpec(name=modname, location=filename,
- origin='egg', type=file_type,
- submodule_search_locations=path)
-
-
-class PEP420SpecFinder(Finder):
-
- def find_module(self, modname, module_parts, processed, submodule_path):
- spec = importlib.machinery.PathFinder.find_spec(modname, path=submodule_path)
- if spec:
- location = spec.origin if spec.origin != 'namespace' else None
- type = ModuleType.PY_NAMESPACE if spec.origin == 'namespace' else None
- spec = ModuleSpec(name=spec.name, location=location,
- origin=spec.origin, type=type,
- submodule_search_locations=list(spec.submodule_search_locations or []))
- return spec
-
- def contribute_to_path(self, spec, processed):
- if spec.type == ModuleType.PY_NAMESPACE:
- return spec.submodule_search_locations
- return None
-
-_SPEC_FINDERS = (
- ImpFinder,
- ZipFinder,
-)
-if _HAS_MACHINERY and sys.version_info[:2] > (3, 3):
- _SPEC_FINDERS += (PEP420SpecFinder, )
-_SPEC_FINDERS += (DynamicImpFinder, )
-
-
-def _find_spec_with_path(search_path, modname, module_parts, processed, submodule_path):
- finders = [finder(search_path) for finder in _SPEC_FINDERS]
- for finder in finders:
- spec = finder.find_module(modname, module_parts, processed, submodule_path)
- if spec is None:
- continue
- return finder, spec
-
- raise ImportError('No module named %s' % '.'.join(module_parts))
-
-
-def _find_spec(modpath, path=None):
- """get a module type / file path
-
- :type modpath: list or tuple
- :param modpath:
- split module's name (i.e name of a module or package split
- on '.'), with leading empty strings for explicit relative import
-
- :type path: list or None
- :param path:
- optional list of path where the module or package should be
- searched (use sys.path if nothing or None is given)
-
-
- :rtype: tuple(int, str)
- :return: the module type flag and the file path for a module
- """
- _path = path or sys.path
-
- # Need a copy for not mutating the argument.
- modpath = modpath[:]
-
- submodule_path = None
- module_parts = modpath[:]
- processed = []
-
- while modpath:
- modname = modpath.pop(0)
- finder, spec = _find_spec_with_path(_path, modname,
- module_parts, processed,
- submodule_path or path)
- processed.append(modname)
- if modpath:
- submodule_path = finder.contribute_to_path(spec, processed)
-
- if spec.type == ModuleType.PKG_DIRECTORY:
- spec = spec._replace(submodule_search_locations=submodule_path)
-
- return spec
+ return found_spec._replace(location=None)
+ elif found_spec.type == spec.ModuleType.PKG_DIRECTORY:
+ location = _has_init(found_spec.location)
+ return found_spec._replace(location=location, type=spec.ModuleType.PY_SOURCE)
+ return found_spec
def _is_python_file(filename):