forked from VimPlug/jedi
Following os.path should be possible again.
This commit is contained in:
+72
-90
@@ -96,19 +96,11 @@ class ImportWrapper(pr.Base):
|
|||||||
|
|
||||||
importer = get_importer(self._evaluator, tuple(import_path),
|
importer = get_importer(self._evaluator, tuple(import_path),
|
||||||
module, self._import.level)
|
module, self._import.level)
|
||||||
try:
|
|
||||||
module, rest = importer.follow_file_system()
|
|
||||||
except ModuleNotFound as e:
|
|
||||||
analysis.add(self._evaluator, 'import-error', e.name)
|
|
||||||
return []
|
|
||||||
|
|
||||||
if module is None:
|
types, rest = importer.follow_file_system()
|
||||||
# TODO does that really happen? Why?
|
|
||||||
return []
|
|
||||||
|
|
||||||
#if self._import.is_nested() and not self.nested_resolve:
|
#if self._import.is_nested() and not self.nested_resolve:
|
||||||
# scopes = [NestedImportModule(module, self._import)]
|
# scopes = [NestedImportModule(module, self._import)]
|
||||||
types = [module]
|
|
||||||
|
|
||||||
if from_import_name is not None:
|
if from_import_name is not None:
|
||||||
types = list(chain.from_iterable(
|
types = list(chain.from_iterable(
|
||||||
@@ -118,11 +110,7 @@ class ImportWrapper(pr.Base):
|
|||||||
importer = get_importer(self._evaluator,
|
importer = get_importer(self._evaluator,
|
||||||
tuple(import_path + [from_import_name]),
|
tuple(import_path + [from_import_name]),
|
||||||
module, self._import.level)
|
module, self._import.level)
|
||||||
module, _ = importer.follow_file_system()
|
types, _ = importer.follow_file_system()
|
||||||
if module is None:
|
|
||||||
types = []
|
|
||||||
else:
|
|
||||||
types = [module]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -302,39 +290,17 @@ class _Importer(object):
|
|||||||
|
|
||||||
def follow(self, evaluator):
|
def follow(self, evaluator):
|
||||||
try:
|
try:
|
||||||
scope, rest = self.follow_file_system()
|
scopes, _ = self.follow_file_system()
|
||||||
except ModuleNotFound:
|
except ModuleNotFound:
|
||||||
return []
|
return []
|
||||||
if scope is None:
|
return scopes
|
||||||
return []
|
|
||||||
if rest:
|
|
||||||
# follow the rest of the import (not FS -> classes, functions)
|
|
||||||
return self.follow_rest(scope, rest)
|
|
||||||
return [scope]
|
|
||||||
|
|
||||||
def follow_rest(self, module, rest):
|
|
||||||
# Either os.path or path length is smaller.
|
|
||||||
if len(rest) < 2 or len(self.str_import_path) < 4 \
|
|
||||||
and ('os', 'path') == self.str_import_path[:2] and self.level == 0:
|
|
||||||
# This is a huge exception, we follow a nested import
|
|
||||||
# ``os.path``, because it's a very important one in Python
|
|
||||||
# that is being achieved by messing with ``sys.modules`` in
|
|
||||||
# ``os``.
|
|
||||||
scopes = [module]
|
|
||||||
for r in rest:
|
|
||||||
scopes = list(chain.from_iterable(
|
|
||||||
self._evaluator.find_types(s, r)
|
|
||||||
for s in scopes))
|
|
||||||
return scopes
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
|
|
||||||
@memoize_default(NO_DEFAULT)
|
@memoize_default(NO_DEFAULT)
|
||||||
def follow_file_system(self):
|
def follow_file_system(self):
|
||||||
if not self.import_path:
|
if not self.import_path:
|
||||||
return None, []
|
return None, []
|
||||||
module = self._do_import(self.import_path, self.sys_path_with_modifications())
|
modules = self._do_import(self.import_path, self.sys_path_with_modifications())
|
||||||
return module, []
|
return modules, []
|
||||||
|
|
||||||
|
|
||||||
# TODO delete - move!
|
# TODO delete - move!
|
||||||
@@ -413,61 +379,77 @@ class _Importer(object):
|
|||||||
import_parts = [str(i) for i in import_path]
|
import_parts = [str(i) for i in import_path]
|
||||||
module_name = '.'.join(import_parts)
|
module_name = '.'.join(import_parts)
|
||||||
try:
|
try:
|
||||||
return self._evaluator.modules[module_name]
|
return [self._evaluator.modules[module_name]]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
pass
|
||||||
if len(import_path) > 1:
|
|
||||||
# This is a recursive way of importing that works great with
|
|
||||||
# the module cache.
|
|
||||||
base = self._do_import(import_path[:-1], sys_path)
|
|
||||||
try:
|
|
||||||
paths = base.py__path__()
|
|
||||||
except AttributeError:
|
|
||||||
# The module is not a package.
|
|
||||||
_add_error(self._evaluator, import_path[-1])
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
debug.dbg('search_module %s in paths %s', module_name, paths)
|
|
||||||
for path in paths:
|
|
||||||
module_file, module_path, is_pkg = \
|
|
||||||
find_module(import_parts[-1], [path])
|
|
||||||
else:
|
|
||||||
debug.dbg('search_module %s in %s', import_parts[-1], self.file_path)
|
|
||||||
# Override the sys.path. It works only good that way.
|
|
||||||
# Injecting the path directly into `find_module` did not work.
|
|
||||||
sys.path, temp = sys_path, sys.path
|
|
||||||
try:
|
|
||||||
module_file, module_path, is_pkg = \
|
|
||||||
find_module(import_parts[-1])
|
|
||||||
finally:
|
|
||||||
sys.path = temp
|
|
||||||
except ImportError:
|
|
||||||
# The module is not a package.
|
|
||||||
_add_error(self._evaluator, import_path[-1])
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
source = None
|
|
||||||
if is_pkg:
|
|
||||||
# In this case, we don't have a file yet. Search for the
|
|
||||||
# __init__ file.
|
|
||||||
for suffix, _, _ in imp.get_suffixes():
|
|
||||||
path = os.path.join(module_path, '__init__' + suffix)
|
|
||||||
if os.path.exists(path):
|
|
||||||
if suffix == '.py':
|
|
||||||
module_path = path
|
|
||||||
break
|
|
||||||
elif module_file:
|
|
||||||
source = module_file.read()
|
|
||||||
module_file.close()
|
|
||||||
|
|
||||||
if module_file is None and not module_path.endswith('.py'):
|
try:
|
||||||
module = compiled.load_module(module_path)
|
if len(import_path) > 1:
|
||||||
|
# This is a recursive way of importing that works great with
|
||||||
|
# the module cache.
|
||||||
|
bases = self._do_import(import_path[:-1], sys_path)
|
||||||
|
if not bases:
|
||||||
|
return []
|
||||||
|
# We can take the first element, because only the os special
|
||||||
|
# case yields multiple modules, which is not important for
|
||||||
|
# further imports.
|
||||||
|
base = bases[0]
|
||||||
|
|
||||||
|
# This is a huge exception, we follow a nested import
|
||||||
|
# ``os.path``, because it's a very important one in Python
|
||||||
|
# that is being achieved by messing with ``sys.modules`` in
|
||||||
|
# ``os``.
|
||||||
|
if [str(i) for i in import_path] == ['os', 'path']:
|
||||||
|
return self._evaluator.find_types(base, 'path')
|
||||||
|
|
||||||
|
try:
|
||||||
|
paths = base.py__path__()
|
||||||
|
except AttributeError:
|
||||||
|
# The module is not a package.
|
||||||
|
_add_error(self._evaluator, import_path[-1])
|
||||||
|
return []
|
||||||
else:
|
else:
|
||||||
module = _load_module(self._evaluator, module_path, source,
|
debug.dbg('search_module %s in paths %s', module_name, paths)
|
||||||
sys_path, module_name)
|
for path in paths:
|
||||||
|
module_file, module_path, is_pkg = \
|
||||||
|
find_module(import_parts[-1], [path])
|
||||||
|
else:
|
||||||
|
debug.dbg('search_module %s in %s', import_parts[-1], self.file_path)
|
||||||
|
# Override the sys.path. It works only good that way.
|
||||||
|
# Injecting the path directly into `find_module` did not work.
|
||||||
|
sys.path, temp = sys_path, sys.path
|
||||||
|
try:
|
||||||
|
module_file, module_path, is_pkg = \
|
||||||
|
find_module(import_parts[-1])
|
||||||
|
finally:
|
||||||
|
sys.path = temp
|
||||||
|
except ImportError:
|
||||||
|
# The module is not a package.
|
||||||
|
_add_error(self._evaluator, import_path[-1])
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
source = None
|
||||||
|
if is_pkg:
|
||||||
|
# In this case, we don't have a file yet. Search for the
|
||||||
|
# __init__ file.
|
||||||
|
for suffix, _, _ in imp.get_suffixes():
|
||||||
|
path = os.path.join(module_path, '__init__' + suffix)
|
||||||
|
if os.path.exists(path):
|
||||||
|
if suffix == '.py':
|
||||||
|
module_path = path
|
||||||
|
break
|
||||||
|
elif module_file:
|
||||||
|
source = module_file.read()
|
||||||
|
module_file.close()
|
||||||
|
|
||||||
|
if module_file is None and not module_path.endswith('.py'):
|
||||||
|
module = compiled.load_module(module_path)
|
||||||
|
else:
|
||||||
|
module = _load_module(self._evaluator, module_path, source,
|
||||||
|
sys_path, module_name)
|
||||||
|
|
||||||
self._evaluator.modules[module_name] = module
|
self._evaluator.modules[module_name] = module
|
||||||
return module
|
return [module]
|
||||||
|
|
||||||
def _generate_name(self, name):
|
def _generate_name(self, name):
|
||||||
return helpers.FakeName(name, parent=self.module)
|
return helpers.FakeName(name, parent=self.module)
|
||||||
|
|||||||
Reference in New Issue
Block a user