1
0
forked from VimPlug/jedi

A lot more fixes - fix all evaluate integration tests.

This commit is contained in:
Dave Halter
2016-12-03 22:17:38 +01:00
parent ee1f077014
commit 6940900c58
10 changed files with 91 additions and 53 deletions

View File

@@ -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))

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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()]

View File

@@ -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

View File

@@ -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():

View File

@@ -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

View File

@@ -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))

View File

@@ -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()