forked from VimPlug/jedi
Refactor some of the import logic so it's possible to load typeshed modules
This commit is contained in:
@@ -12,7 +12,6 @@ This module also supports import autocompletion, which means to complete
|
|||||||
statements like ``from datetim`` (cursor at the end would return ``datetime``).
|
statements like ``from datetim`` (cursor at the end would return ``datetime``).
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from parso.python import tree
|
from parso.python import tree
|
||||||
from parso.tree import search_ancestor
|
from parso.tree import search_ancestor
|
||||||
@@ -287,20 +286,22 @@ class Importer(object):
|
|||||||
for i in self.import_path
|
for i in self.import_path
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
context_set = [None]
|
||||||
return self._evaluator.import_module(
|
for i, name in enumerate(self.import_path):
|
||||||
self._evaluator,
|
try:
|
||||||
import_names,
|
context_set = ContextSet.from_sets([
|
||||||
self.sys_path_with_modifications(),
|
self._evaluator.import_module(
|
||||||
|
self._evaluator,
|
||||||
)
|
import_names[:i+1],
|
||||||
except JediImportError as e:
|
module_context,
|
||||||
# Try to look up the name that was responsible for the import
|
self.sys_path_with_modifications(),
|
||||||
# error. Since this is a plugin API, we intentionally just use
|
)
|
||||||
# strings, because every plugin would need to unpack the names.
|
for module_context in context_set
|
||||||
name = self.import_path[len(e.import_names) - 1]
|
])
|
||||||
_add_error(self.module_context, name)
|
except JediImportError:
|
||||||
return NO_CONTEXTS
|
_add_error(self.module_context, name)
|
||||||
|
return NO_CONTEXTS
|
||||||
|
return context_set
|
||||||
|
|
||||||
def _generate_name(self, name, in_module=None):
|
def _generate_name(self, name, in_module=None):
|
||||||
# Create a pseudo import to be able to follow them.
|
# Create a pseudo import to be able to follow them.
|
||||||
@@ -355,7 +356,8 @@ class Importer(object):
|
|||||||
if context.api_type != 'module': # not a module
|
if context.api_type != 'module': # not a module
|
||||||
continue
|
continue
|
||||||
# namespace packages
|
# namespace packages
|
||||||
if isinstance(context, ModuleContext) and context.py__file__().endswith('__init__.py'):
|
if isinstance(context, ModuleContext) \
|
||||||
|
and context.py__file__().endswith('__init__.py'):
|
||||||
paths = context.py__path__()
|
paths = context.py__path__()
|
||||||
names += self._get_module_names(paths, in_module=context)
|
names += self._get_module_names(paths, in_module=context)
|
||||||
|
|
||||||
@@ -395,7 +397,7 @@ class JediImportError(Exception):
|
|||||||
self.import_names = import_names
|
self.import_names = import_names
|
||||||
|
|
||||||
|
|
||||||
def import_module(evaluator, import_names, sys_path):
|
def import_module(evaluator, import_names, module_context, sys_path):
|
||||||
"""
|
"""
|
||||||
This method is very similar to importlib's `_gcd_import`.
|
This method is very similar to importlib's `_gcd_import`.
|
||||||
"""
|
"""
|
||||||
@@ -413,19 +415,21 @@ def import_module(evaluator, import_names, sys_path):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if len(import_names) > 1:
|
if module_context is None:
|
||||||
# This is a recursive way of importing that works great with
|
debug.dbg('global search_module %s', import_names[-1])
|
||||||
# the module cache.
|
# Override the sys.path. It works only good that way.
|
||||||
bases = evaluator.import_module(evaluator, import_names[:-1], sys_path)
|
# Injecting the path directly into `find_module` did not work.
|
||||||
if not bases:
|
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
||||||
return NO_CONTEXTS
|
string=import_names[-1],
|
||||||
# We can take the first element, because only the os special
|
full_name=module_name,
|
||||||
# case yields multiple modules, which is not important for
|
sys_path=sys_path,
|
||||||
# further imports.
|
is_global_search=True,
|
||||||
parent_module = list(bases)[0]
|
)
|
||||||
|
if module_path is None:
|
||||||
|
raise JediImportError(import_names)
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
method = parent_module.py__path__
|
method = module_context.py__path__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# The module is not a package.
|
# The module is not a package.
|
||||||
raise JediImportError(import_names)
|
raise JediImportError(import_names)
|
||||||
@@ -447,18 +451,6 @@ def import_module(evaluator, import_names, sys_path):
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise JediImportError(import_names)
|
raise JediImportError(import_names)
|
||||||
else:
|
|
||||||
debug.dbg('global search_module %s', import_names[-1])
|
|
||||||
# Override the sys.path. It works only good that way.
|
|
||||||
# Injecting the path directly into `find_module` did not work.
|
|
||||||
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
|
||||||
string=import_names[-1],
|
|
||||||
full_name=module_name,
|
|
||||||
sys_path=sys_path,
|
|
||||||
is_global_search=True,
|
|
||||||
)
|
|
||||||
if module_path is None:
|
|
||||||
raise JediImportError(import_names)
|
|
||||||
|
|
||||||
module = _load_module(
|
module = _load_module(
|
||||||
evaluator, module_path, code, sys_path,
|
evaluator, module_path, code, sys_path,
|
||||||
|
|||||||
@@ -10,20 +10,21 @@ class FlaskPlugin(BasePlugin):
|
|||||||
Handle "magic" Flask extension imports:
|
Handle "magic" Flask extension imports:
|
||||||
``flask.ext.foo`` is really ``flask_foo`` or ``flaskext.foo``.
|
``flask.ext.foo`` is really ``flask_foo`` or ``flaskext.foo``.
|
||||||
"""
|
"""
|
||||||
def wrapper(evaluator, import_names, *args, **kwargs):
|
def wrapper(evaluator, import_names, module_context, sys_path):
|
||||||
if len(import_names) > 2 and import_names[:2] == ('flask', 'ext'):
|
if len(import_names) == 3 and import_names[:2] == ('flask', 'ext'):
|
||||||
# New style.
|
# New style.
|
||||||
ipath = ('flask_' + str(import_names[2]),) + import_names[3:]
|
ipath = ('flask_' + import_names[2]),
|
||||||
try:
|
try:
|
||||||
return callback(evaluator, ipath, *args, **kwargs)
|
return callback(evaluator, ipath, None, sys_path)
|
||||||
except JediImportError:
|
except JediImportError:
|
||||||
# Old style
|
context_set = callback(evaluator, ('flaskext',), None, sys_path)
|
||||||
|
# If context_set has no content a JediImportError is raised
|
||||||
|
# which should be caught anyway by the caller.
|
||||||
return callback(
|
return callback(
|
||||||
evaluator,
|
evaluator,
|
||||||
('flaskext',) + import_names[2:],
|
('flaskext', import_names[2]),
|
||||||
*args,
|
next(iter(context_set)),
|
||||||
**kwargs
|
sys_path
|
||||||
)
|
)
|
||||||
return callback(evaluator, import_names, *args, **kwargs)
|
return callback(evaluator, import_names, module_context, sys_path)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
@@ -78,14 +78,14 @@ class StdlibPlugin(BasePlugin):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
def import_module(self, callback):
|
def import_module(self, callback):
|
||||||
def wrapper(evaluator, import_names, sys_path):
|
def wrapper(evaluator, import_names, module_context, sys_path):
|
||||||
# This is a huge exception, we follow a nested import
|
# This is a huge exception, we follow a nested import
|
||||||
# ``os.path``, because it's a very important one in Python
|
# ``os.path``, because it's a very important one in Python
|
||||||
# that is being achieved by messing with ``sys.modules`` in
|
# that is being achieved by messing with ``sys.modules`` in
|
||||||
# ``os``.
|
# ``os``.
|
||||||
if import_names == ('os', 'path'):
|
if import_names == ('os', 'path'):
|
||||||
return callback(evaluator, ('os',), sys_path).py__getattribute__('path')
|
return module_context.py__getattribute__('path')
|
||||||
return callback(evaluator, import_names, sys_path)
|
return callback(evaluator, import_names, module_context, sys_path)
|
||||||
|
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
Reference in New Issue
Block a user