mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 14:54:47 +08:00
A lot more fixes - fix all evaluate integration tests.
This commit is contained in:
@@ -216,11 +216,9 @@ class Script(object):
|
|||||||
"""
|
"""
|
||||||
def filter_follow_imports(names):
|
def filter_follow_imports(names):
|
||||||
for name in names:
|
for name in names:
|
||||||
definition = name.get_definition()
|
if isinstance(name, (imports.ImportName, TreeNameDefinition)):
|
||||||
if definition.type in ('import_name', 'import_from'):
|
for context in name.infer():
|
||||||
imp = imports.ImportWrapper(context, name)
|
yield context.name
|
||||||
for name in filter_follow_imports(imp.follow(is_goto=True)):
|
|
||||||
yield name
|
|
||||||
else:
|
else:
|
||||||
yield name
|
yield name
|
||||||
|
|
||||||
@@ -436,13 +434,21 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
|||||||
``definitions=True``. E.g. ``a = b`` returns ``b``.
|
``definitions=True``. E.g. ``a = b`` returns ``b``.
|
||||||
"""
|
"""
|
||||||
def def_ref_filter(_def):
|
def def_ref_filter(_def):
|
||||||
is_def = _def.is_definition()
|
is_def = _def._name.tree_name.is_definition()
|
||||||
return definitions and is_def or references and not is_def
|
return definitions and is_def or references and not is_def
|
||||||
|
|
||||||
# Set line/column to a random position, because they don't matter.
|
# Set line/column to a random position, because they don't matter.
|
||||||
script = Script(source, line=1, column=0, path=path, encoding=encoding)
|
script = Script(source, line=1, column=0, path=path, encoding=encoding)
|
||||||
defs = [classes.Definition(script._evaluator, name_part)
|
module_context = script._get_module()
|
||||||
for name_part in get_module_names(script._get_module().module_node, all_scopes)]
|
defs = [
|
||||||
|
classes.Definition(
|
||||||
|
script._evaluator,
|
||||||
|
TreeNameDefinition(
|
||||||
|
module_context.create_context(name),
|
||||||
|
name
|
||||||
|
)
|
||||||
|
) for name in get_module_names(script._get_module_node(), all_scopes)
|
||||||
|
]
|
||||||
return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column))
|
return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ from jedi.evaluate import instance
|
|||||||
from jedi.evaluate import iterable
|
from jedi.evaluate import iterable
|
||||||
from jedi.evaluate import imports
|
from jedi.evaluate import imports
|
||||||
from jedi.evaluate import compiled
|
from jedi.evaluate import compiled
|
||||||
|
from jedi.evaluate.filters import ParamName
|
||||||
from jedi.evaluate.finder import filter_definition_names
|
from jedi.evaluate.finder import filter_definition_names
|
||||||
|
from jedi.api.keywords import KeywordName
|
||||||
|
|
||||||
|
|
||||||
def defined_names(evaluator, scope):
|
def defined_names(evaluator, scope):
|
||||||
@@ -63,7 +65,7 @@ class BaseDefinition(object):
|
|||||||
An instance of :class:`jedi.parser.reprsentation.Name` subclass.
|
An instance of :class:`jedi.parser.reprsentation.Name` subclass.
|
||||||
"""
|
"""
|
||||||
#self._definition = list(self._name.infer())[0]
|
#self._definition = list(self._name.infer())[0]
|
||||||
#self.is_keyword = isinstance(self._definition, keywords.Keyword)
|
self.is_keyword = isinstance(self._name, KeywordName)
|
||||||
self._definition = None
|
self._definition = None
|
||||||
|
|
||||||
# generate a path to the definition
|
# generate a path to the definition
|
||||||
@@ -232,9 +234,9 @@ class BaseDefinition(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
if raw:
|
if raw:
|
||||||
return _Help(self._definition).raw()
|
return _Help(self._name.parent_context).raw()
|
||||||
else:
|
else:
|
||||||
return _Help(self._definition).full()
|
return _Help(self._name.parent_context).full()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def doc(self):
|
def doc(self):
|
||||||
@@ -259,7 +261,7 @@ class BaseDefinition(object):
|
|||||||
@property
|
@property
|
||||||
def description(self):
|
def description(self):
|
||||||
"""A textual description of the object."""
|
"""A textual description of the object."""
|
||||||
return unicode(self._name)
|
return unicode(self._name.string_name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def full_name(self):
|
def full_name(self):
|
||||||
@@ -298,7 +300,12 @@ class BaseDefinition(object):
|
|||||||
return '.'.join(path if path[0] else path[1:])
|
return '.'.join(path if path[0] else path[1:])
|
||||||
|
|
||||||
def goto_assignments(self):
|
def goto_assignments(self):
|
||||||
defs = self._evaluator.goto(self._name)
|
try:
|
||||||
|
tree_name = self._name.tree_name
|
||||||
|
except AttributeError:
|
||||||
|
return self
|
||||||
|
|
||||||
|
defs = self._evaluator.goto(self._name.parent_context, tree_name)
|
||||||
return [Definition(self._evaluator, d) for d in defs]
|
return [Definition(self._evaluator, d) for d in defs]
|
||||||
|
|
||||||
@memoize_method
|
@memoize_method
|
||||||
@@ -306,6 +313,7 @@ class BaseDefinition(object):
|
|||||||
"""
|
"""
|
||||||
Follow both statements and imports, as far as possible.
|
Follow both statements and imports, as far as possible.
|
||||||
"""
|
"""
|
||||||
|
return self._name.infer()
|
||||||
if self._name.api_type == 'expr_stmt':
|
if self._name.api_type == 'expr_stmt':
|
||||||
return self._evaluator.eval_statement(self._definition)
|
return self._evaluator.eval_statement(self._definition)
|
||||||
elif self._name.api_type == 'import':
|
elif self._name.api_type == 'import':
|
||||||
@@ -351,9 +359,7 @@ class BaseDefinition(object):
|
|||||||
return [_Param(self._evaluator, n) for n in get_param_names(context)]
|
return [_Param(self._evaluator, n) for n in get_param_names(context)]
|
||||||
|
|
||||||
def parent(self):
|
def parent(self):
|
||||||
scope = self._definition.get_parent_scope()
|
return Definition(self._evaluator, self._name.parent_context.name)
|
||||||
scope = self._evaluator.wrap(scope)
|
|
||||||
return Definition(self._evaluator, scope.name)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %s>" % (type(self).__name__, self.description)
|
return "<%s %s>" % (type(self).__name__, self.description)
|
||||||
@@ -371,7 +377,7 @@ class BaseDefinition(object):
|
|||||||
if self.in_builtin_module():
|
if self.in_builtin_module():
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
path = self._definition.get_parent_until().path
|
path = self._name.get_root_context().py__file__()
|
||||||
parser = load_parser(path)
|
parser = load_parser(path)
|
||||||
lines = common.splitlines(parser.source)
|
lines = common.splitlines(parser.source)
|
||||||
|
|
||||||
@@ -401,7 +407,7 @@ class Completion(BaseDefinition):
|
|||||||
and self.type == 'Function':
|
and self.type == 'Function':
|
||||||
append = '('
|
append = '('
|
||||||
|
|
||||||
if isinstance(self._definition, tree.Param) and self._stack is not None:
|
if isinstance(self._name, ParamName) and self._stack is not None:
|
||||||
node_names = list(self._stack.get_node_names(self._evaluator.grammar))
|
node_names = list(self._stack.get_node_names(self._evaluator.grammar))
|
||||||
if 'trailer' in node_names and 'argument' not in node_names:
|
if 'trailer' in node_names and 'argument' not in node_names:
|
||||||
append += '='
|
append += '='
|
||||||
@@ -438,9 +444,10 @@ class Completion(BaseDefinition):
|
|||||||
@property
|
@property
|
||||||
def description(self):
|
def description(self):
|
||||||
"""Provide a description of the completion object."""
|
"""Provide a description of the completion object."""
|
||||||
if self._definition is None:
|
# TODO improve the class structure.
|
||||||
return self._name.string_name
|
return Definition.description.__get__(self)
|
||||||
|
|
||||||
|
# TODO remove
|
||||||
t = self.type
|
t = self.type
|
||||||
if t == 'statement' or t == 'import':
|
if t == 'statement' or t == 'import':
|
||||||
desc = self._definition.get_code()
|
desc = self._definition.get_code()
|
||||||
@@ -461,20 +468,20 @@ class Completion(BaseDefinition):
|
|||||||
the ``foo.docstring(fast=False)`` on every object, because it
|
the ``foo.docstring(fast=False)`` on every object, because it
|
||||||
parses all libraries starting with ``a``.
|
parses all libraries starting with ``a``.
|
||||||
"""
|
"""
|
||||||
definition = self._definition
|
context = self._name.parent_context
|
||||||
if isinstance(definition, tree.Import):
|
if isinstance(self._name, imports.ImportName):
|
||||||
raise DeprecationWarning
|
if fast:
|
||||||
i = imports.ImportWrapper(self._evaluator, self._name)
|
return ''
|
||||||
if len(i.import_path) > 1 or not fast:
|
else:
|
||||||
followed = self._follow_statements_imports()
|
followed = self._name.infer()
|
||||||
if followed:
|
if followed:
|
||||||
# TODO: Use all of the followed objects as input to Documentation.
|
# TODO: Use all of the followed objects as input to Documentation.
|
||||||
definition = list(followed)[0]
|
context = next(iter(followed))
|
||||||
|
|
||||||
if raw:
|
if raw:
|
||||||
return _Help(definition).raw()
|
return _Help(context).raw()
|
||||||
else:
|
else:
|
||||||
return _Help(definition).full()
|
return _Help(context).full()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def type(self):
|
def type(self):
|
||||||
@@ -772,7 +779,7 @@ class _Help(object):
|
|||||||
|
|
||||||
def full(self):
|
def full(self):
|
||||||
try:
|
try:
|
||||||
return self._name.doc
|
return self._name.get_node().doc
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return self.raw()
|
return self.raw()
|
||||||
|
|
||||||
@@ -782,7 +789,7 @@ class _Help(object):
|
|||||||
|
|
||||||
See :attr:`doc` for example.
|
See :attr:`doc` for example.
|
||||||
"""
|
"""
|
||||||
try:
|
node = self._name.get_node()
|
||||||
return self._name.raw_doc
|
if node is None:
|
||||||
except AttributeError:
|
|
||||||
return ''
|
return ''
|
||||||
|
return node.raw_doc
|
||||||
|
|||||||
@@ -112,6 +112,17 @@ class CompiledObject(Context):
|
|||||||
params.append(Param(parts, self))
|
params.append(Param(parts, self))
|
||||||
return params
|
return params
|
||||||
|
|
||||||
|
def get_param_names(self):
|
||||||
|
params_str, ret = self._parse_function_doc()
|
||||||
|
tokens = params_str.split(',')
|
||||||
|
if inspect.ismethoddescriptor(self.obj):
|
||||||
|
tokens.insert(0, 'self')
|
||||||
|
for p in tokens:
|
||||||
|
parts = p.strip().split('=')
|
||||||
|
if len(parts) > 1:
|
||||||
|
parts.insert(1, Operator('=', (0, 0)))
|
||||||
|
yield UnresolvableParamName(self, p[0])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<%s: %s>' % (self.__class__.__name__, repr(self.obj))
|
return '<%s: %s>' % (self.__class__.__name__, repr(self.obj))
|
||||||
|
|
||||||
@@ -278,6 +289,17 @@ class CompiledName(AbstractNameDefinition):
|
|||||||
return [_create_from_name(self._evaluator, module, self.parent_context, self.string_name)]
|
return [_create_from_name(self._evaluator, module, self.parent_context, self.string_name)]
|
||||||
|
|
||||||
|
|
||||||
|
class UnresolvableParamName(AbstractNameDefinition):
|
||||||
|
api_type = 'param'
|
||||||
|
|
||||||
|
def __init__(self, compiled_obj, name):
|
||||||
|
self.parent_context = compiled_obj.parent_context
|
||||||
|
self.string_name = name
|
||||||
|
|
||||||
|
def infer(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
|
|
||||||
class CompiledContextName(AbstractNameDefinition):
|
class CompiledContextName(AbstractNameDefinition):
|
||||||
def __init__(self, parent_context, name):
|
def __init__(self, parent_context, name):
|
||||||
self.string_name = name
|
self.string_name = name
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ class Importer(object):
|
|||||||
if self.str_import_path == ('flask', 'ext'):
|
if self.str_import_path == ('flask', 'ext'):
|
||||||
# List Flask extensions like ``flask_foo``
|
# List Flask extensions like ``flask_foo``
|
||||||
for mod in self._get_module_names():
|
for mod in self._get_module_names():
|
||||||
modname = str(mod)
|
modname = mod.string_name
|
||||||
if modname.startswith('flask_'):
|
if modname.startswith('flask_'):
|
||||||
extname = modname[len('flask_'):]
|
extname = modname[len('flask_'):]
|
||||||
names.append(self._generate_name(extname))
|
names.append(self._generate_name(extname))
|
||||||
|
|||||||
@@ -564,10 +564,14 @@ class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext)):
|
|||||||
# modules on sys_path or whatever the search_path is.
|
# modules on sys_path or whatever the search_path is.
|
||||||
paths = set()
|
paths = set()
|
||||||
for s in search_path:
|
for s in search_path:
|
||||||
other = os.path.join(s, unicode(self.name))
|
other = os.path.join(s, self.name.string_name)
|
||||||
if os.path.isdir(other):
|
if os.path.isdir(other):
|
||||||
paths.add(other)
|
paths.add(other)
|
||||||
|
if paths:
|
||||||
return list(paths)
|
return list(paths)
|
||||||
|
# TODO I'm not sure if this is how nested namespace
|
||||||
|
# packages work. The tests are not really good enough to
|
||||||
|
# show that.
|
||||||
# Default to this.
|
# Default to this.
|
||||||
return [self._get_init_directory()]
|
return [self._get_init_directory()]
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ def test_preload_modules():
|
|||||||
|
|
||||||
api.preload_module('sys')
|
api.preload_module('sys')
|
||||||
check_loaded() # compiled (c_builtin) modules shouldn't be in the cache.
|
check_loaded() # compiled (c_builtin) modules shouldn't be in the cache.
|
||||||
api.preload_module('json', 'token')
|
api.preload_module('types', 'token')
|
||||||
check_loaded('json', 'token')
|
check_loaded('types', 'token')
|
||||||
|
|
||||||
utils.parser_cache = temp_cache
|
utils.parser_cache = temp_cache
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ from textwrap import dedent
|
|||||||
|
|
||||||
from jedi._compatibility import builtins, is_py3
|
from jedi._compatibility import builtins, is_py3
|
||||||
from jedi.parser import load_grammar
|
from jedi.parser import load_grammar
|
||||||
from jedi.parser.tree import Function
|
from jedi.evaluate import compiled, instance
|
||||||
from jedi.evaluate import compiled, representation
|
from jedi.evaluate.representation import FunctionContext
|
||||||
from jedi.evaluate import Evaluator
|
from jedi.evaluate import Evaluator
|
||||||
from jedi import Script
|
from jedi import Script
|
||||||
|
|
||||||
@@ -16,25 +16,24 @@ def test_simple():
|
|||||||
e = _evaluator()
|
e = _evaluator()
|
||||||
bltn = compiled.CompiledObject(e, builtins)
|
bltn = compiled.CompiledObject(e, builtins)
|
||||||
obj = compiled.CompiledObject(e, '_str_', bltn)
|
obj = compiled.CompiledObject(e, '_str_', bltn)
|
||||||
upper = e.find_types(obj, 'upper')
|
upper, = obj.py__getattribute__('upper')
|
||||||
assert len(upper) == 1
|
objs = list(upper.execute_evaluated())
|
||||||
objs = list(e.execute(list(upper)[0]))
|
|
||||||
assert len(objs) == 1
|
assert len(objs) == 1
|
||||||
assert isinstance(objs[0], representation.Instance)
|
assert isinstance(objs[0], instance.CompiledInstance)
|
||||||
|
|
||||||
|
|
||||||
def test_fake_loading():
|
def test_fake_loading():
|
||||||
e = _evaluator()
|
e = _evaluator()
|
||||||
assert isinstance(compiled.create(e, next), Function)
|
assert isinstance(compiled.create(e, next), FunctionContext)
|
||||||
|
|
||||||
builtin = compiled.get_special_object(e, 'BUILTINS')
|
builtin = compiled.get_special_object(e, 'BUILTINS')
|
||||||
string = builtin.get_subscope_by_name('str')
|
string, = builtin.py__getattribute__('str')
|
||||||
from_name = compiled._create_from_name(e, builtin, string, '__init__')
|
from_name = compiled._create_from_name(e, builtin, string, '__init__')
|
||||||
assert isinstance(from_name, Function)
|
assert isinstance(from_name, FunctionContext)
|
||||||
|
|
||||||
|
|
||||||
def test_fake_docstr():
|
def test_fake_docstr():
|
||||||
assert compiled.create(_evaluator(), next).raw_doc == next.__doc__
|
assert compiled.create(_evaluator(), next).get_node().raw_doc == next.__doc__
|
||||||
|
|
||||||
|
|
||||||
def test_parse_function_doc_illegal_docstr():
|
def test_parse_function_doc_illegal_docstr():
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ def test_call_of_leaf_in_brackets():
|
|||||||
type(x)
|
type(x)
|
||||||
""")
|
""")
|
||||||
last_x = names(s, references=True, definitions=False)[-1]
|
last_x = names(s, references=True, definitions=False)[-1]
|
||||||
name = last_x._name
|
name = last_x._name.tree_name
|
||||||
|
|
||||||
call = helpers.call_of_leaf(name)
|
call = helpers.call_of_leaf(name)
|
||||||
assert call == name
|
assert call == name
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ def test_not_importable_file():
|
|||||||
def test_import_unique():
|
def test_import_unique():
|
||||||
src = "import os; os.path"
|
src = "import os; os.path"
|
||||||
defs = jedi.Script(src, path='example.py').goto_definitions()
|
defs = jedi.Script(src, path='example.py').goto_definitions()
|
||||||
defs = [d._definition for d in defs]
|
defs = [d._name.parent_context for d in defs]
|
||||||
assert len(defs) == len(set(defs))
|
assert len(defs) == len(set(defs))
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,16 +49,16 @@ def test_namespace_package():
|
|||||||
for c in script_with_path(source + '; x.').completions():
|
for c in script_with_path(source + '; x.').completions():
|
||||||
if c.name == 'foo':
|
if c.name == 'foo':
|
||||||
completion = c
|
completion = c
|
||||||
solution = "statement: foo = '%s'" % solution
|
solution = "foo = '%s'" % solution
|
||||||
assert completion.description == solution
|
assert completion.description == solution
|
||||||
|
|
||||||
|
|
||||||
def test_nested_namespace_package():
|
def test_nested_namespace_package():
|
||||||
CODE = 'from nested_namespaces.namespace.pkg import CONST'
|
code = 'from nested_namespaces.namespace.pkg import CONST'
|
||||||
|
|
||||||
sys_path = [dirname(__file__)]
|
sys_path = [dirname(__file__)]
|
||||||
|
|
||||||
script = jedi.Script(sys_path=sys_path, source=CODE, line=1, column=45)
|
script = jedi.Script(sys_path=sys_path, source=code, line=1, column=45)
|
||||||
|
|
||||||
result = script.goto_definitions()
|
result = script.goto_definitions()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user