mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-07 22:44:27 +08:00
Import names are now always strings
This commit is contained in:
@@ -120,6 +120,8 @@ class Evaluator(object):
|
|||||||
|
|
||||||
self.reset_recursion_limitations()
|
self.reset_recursion_limitations()
|
||||||
self.allow_different_encoding = True
|
self.allow_different_encoding = True
|
||||||
|
|
||||||
|
# Plugin API
|
||||||
from jedi.plugins import plugin_manager
|
from jedi.plugins import plugin_manager
|
||||||
plugin_callbacks = plugin_manager.get_callbacks(self)
|
plugin_callbacks = plugin_manager.get_callbacks(self)
|
||||||
self.execute = plugin_callbacks.decorate('execute', callback=execute)
|
self.execute = plugin_callbacks.decorate('execute', callback=execute)
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ def _add_error(context, name, message=None):
|
|||||||
if message is None:
|
if message is None:
|
||||||
name_str = str(name.value) if isinstance(name, tree.Name) else name
|
name_str = str(name.value) if isinstance(name, tree.Name) else name
|
||||||
message = 'No module named ' + name_str
|
message = 'No module named ' + name_str
|
||||||
if hasattr(name, 'parent'):
|
if hasattr(name, 'parent') and context is not None:
|
||||||
analysis.add(context, 'import-error', name, message)
|
analysis.add(context, 'import-error', name, message)
|
||||||
else:
|
else:
|
||||||
debug.warning('ImportError without origin: ' + message)
|
debug.warning('ImportError without origin: ' + message)
|
||||||
@@ -282,14 +282,26 @@ class Importer(object):
|
|||||||
if not self.import_path:
|
if not self.import_path:
|
||||||
return NO_CONTEXTS
|
return NO_CONTEXTS
|
||||||
|
|
||||||
return self._evaluator.import_module(
|
import_names = tuple(
|
||||||
self._evaluator,
|
force_unicode(i.value if isinstance(i, tree.Name) else i)
|
||||||
self.import_path,
|
for i in self.import_path
|
||||||
self.sys_path_with_modifications(),
|
|
||||||
partial(_add_error, self.module_context),
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self._evaluator.import_module(
|
||||||
|
self._evaluator,
|
||||||
|
import_names,
|
||||||
|
self.sys_path_with_modifications(),
|
||||||
|
|
||||||
|
)
|
||||||
|
except JediImportError as e:
|
||||||
|
# Try to look up the name that was responsible for the import
|
||||||
|
# error. Since this is a plugin API, we intentionally just use
|
||||||
|
# strings, because every plugin would need to unpack the names.
|
||||||
|
name = self.import_path[len(e.import_names) - 1]
|
||||||
|
_add_error(self.module_context, name)
|
||||||
|
return NO_CONTEXTS
|
||||||
|
|
||||||
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.
|
||||||
if in_module is None:
|
if in_module is None:
|
||||||
@@ -378,33 +390,33 @@ class Importer(object):
|
|||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
def import_module(evaluator, import_path, sys_path, add_error_callback):
|
class JediImportError(Exception):
|
||||||
|
def __init__(self, import_names):
|
||||||
|
self.import_names = import_names
|
||||||
|
|
||||||
|
|
||||||
|
def import_module(evaluator, import_names, sys_path):
|
||||||
"""
|
"""
|
||||||
This method is very similar to importlib's `_gcd_import`.
|
This method is very similar to importlib's `_gcd_import`.
|
||||||
"""
|
"""
|
||||||
import_parts = [
|
if import_names[0] in settings.auto_import_modules:
|
||||||
force_unicode(i.value if isinstance(i, tree.Name) else i)
|
|
||||||
for i in import_path
|
|
||||||
]
|
|
||||||
|
|
||||||
if import_parts[0] in settings.auto_import_modules:
|
|
||||||
module = _load_module(
|
module = _load_module(
|
||||||
evaluator,
|
evaluator,
|
||||||
import_names=import_parts,
|
import_names=import_names,
|
||||||
sys_path=sys_path,
|
sys_path=sys_path,
|
||||||
)
|
)
|
||||||
return ContextSet(module)
|
return ContextSet(module)
|
||||||
|
|
||||||
module_name = '.'.join(import_parts)
|
module_name = '.'.join(import_names)
|
||||||
try:
|
try:
|
||||||
return ContextSet(evaluator.module_cache.get(module_name))
|
return ContextSet(evaluator.module_cache.get(module_name))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if len(import_path) > 1:
|
if len(import_names) > 1:
|
||||||
# This is a recursive way of importing that works great with
|
# This is a recursive way of importing that works great with
|
||||||
# the module cache.
|
# the module cache.
|
||||||
bases = evaluator.import_module(evaluator, import_path[:-1], sys_path, add_error_callback)
|
bases = evaluator.import_module(evaluator, import_names[:-1], sys_path)
|
||||||
if not bases:
|
if not bases:
|
||||||
return NO_CONTEXTS
|
return NO_CONTEXTS
|
||||||
# We can take the first element, because only the os special
|
# We can take the first element, because only the os special
|
||||||
@@ -416,15 +428,14 @@ def import_module(evaluator, import_path, sys_path, add_error_callback):
|
|||||||
# ``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_parts == ['os', 'path']:
|
if import_names == ('os', 'path'):
|
||||||
return parent_module.py__getattribute__('path')
|
return parent_module.py__getattribute__('path')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
method = parent_module.py__path__
|
method = parent_module.py__path__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# The module is not a package.
|
# The module is not a package.
|
||||||
add_error_callback(import_path[-1])
|
raise JediImportError(import_names)
|
||||||
return NO_CONTEXTS
|
|
||||||
else:
|
else:
|
||||||
paths = method()
|
paths = method()
|
||||||
debug.dbg('search_module %s in paths %s', module_name, paths)
|
debug.dbg('search_module %s in paths %s', module_name, paths)
|
||||||
@@ -434,7 +445,7 @@ def import_module(evaluator, import_path, sys_path, add_error_callback):
|
|||||||
if not isinstance(path, list):
|
if not isinstance(path, list):
|
||||||
path = [path]
|
path = [path]
|
||||||
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
||||||
string=import_parts[-1],
|
string=import_names[-1],
|
||||||
path=path,
|
path=path,
|
||||||
full_name=module_name,
|
full_name=module_name,
|
||||||
is_global_search=False,
|
is_global_search=False,
|
||||||
@@ -442,26 +453,23 @@ def import_module(evaluator, import_path, sys_path, add_error_callback):
|
|||||||
if module_path is not None:
|
if module_path is not None:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
add_error_callback(import_path[-1])
|
raise JediImportError(import_names)
|
||||||
return NO_CONTEXTS
|
|
||||||
else:
|
else:
|
||||||
debug.dbg('global search_module %s', import_parts[-1])
|
debug.dbg('global search_module %s', import_names[-1])
|
||||||
# Override the sys.path. It works only good that way.
|
# Override the sys.path. It works only good that way.
|
||||||
# Injecting the path directly into `find_module` did not work.
|
# Injecting the path directly into `find_module` did not work.
|
||||||
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
code, module_path, is_pkg = evaluator.compiled_subprocess.get_module_info(
|
||||||
string=import_parts[-1],
|
string=import_names[-1],
|
||||||
full_name=module_name,
|
full_name=module_name,
|
||||||
sys_path=sys_path,
|
sys_path=sys_path,
|
||||||
is_global_search=True,
|
is_global_search=True,
|
||||||
)
|
)
|
||||||
if module_path is None:
|
if module_path is None:
|
||||||
# The module is not a package.
|
raise JediImportError(import_names)
|
||||||
add_error_callback(import_path[-1])
|
|
||||||
return NO_CONTEXTS
|
|
||||||
|
|
||||||
module = _load_module(
|
module = _load_module(
|
||||||
evaluator, module_path, code, sys_path,
|
evaluator, module_path, code, sys_path,
|
||||||
import_names=import_parts,
|
import_names=import_names,
|
||||||
safe_module_name=True,
|
safe_module_name=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from parso.python.tree import Name
|
from parso.python.tree import Name
|
||||||
|
|
||||||
from jedi.plugins.base import BasePlugin
|
from jedi.plugins.base import BasePlugin
|
||||||
|
from jedi.evaluate.imports import JediImportError
|
||||||
|
|
||||||
|
|
||||||
class FlaskPlugin(BasePlugin):
|
class FlaskPlugin(BasePlugin):
|
||||||
@@ -9,21 +10,20 @@ 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_path, *args, **kwargs):
|
def wrapper(evaluator, import_names, *args, **kwargs):
|
||||||
import_parts = [
|
if len(import_names) > 2 and import_names[:2] == ('flask', 'ext'):
|
||||||
i.value if isinstance(i, Name) else i
|
|
||||||
for i in import_path
|
|
||||||
]
|
|
||||||
|
|
||||||
if len(import_path) > 2 and import_parts[:2] == ['flask', 'ext']:
|
|
||||||
# New style.
|
# New style.
|
||||||
ipath = ('flask_' + str(import_parts[2]),) + import_path[3:]
|
ipath = ('flask_' + str(import_names[2]),) + import_names[3:]
|
||||||
modules = callback(evaluator, ipath, *args, **kwargs)
|
try:
|
||||||
if modules:
|
return callback(evaluator, ipath, *args, **kwargs)
|
||||||
return modules
|
except JediImportError:
|
||||||
else:
|
|
||||||
# Old style
|
# Old style
|
||||||
return callback(evaluator, ('flaskext',) + import_path[2:], *args, **kwargs)
|
return callback(
|
||||||
return callback(evaluator, import_path, *args, **kwargs)
|
evaluator,
|
||||||
|
('flaskext',) + import_names[2:],
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
return callback(evaluator, import_names, *args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|||||||
Reference in New Issue
Block a user