mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-06 22:14:27 +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):
|
||||
for name in names:
|
||||
definition = name.get_definition()
|
||||
if definition.type in ('import_name', 'import_from'):
|
||||
imp = imports.ImportWrapper(context, name)
|
||||
for name in filter_follow_imports(imp.follow(is_goto=True)):
|
||||
yield name
|
||||
if isinstance(name, (imports.ImportName, TreeNameDefinition)):
|
||||
for context in name.infer():
|
||||
yield context.name
|
||||
else:
|
||||
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``.
|
||||
"""
|
||||
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
|
||||
|
||||
# Set line/column to a random position, because they don't matter.
|
||||
script = Script(source, line=1, column=0, path=path, encoding=encoding)
|
||||
defs = [classes.Definition(script._evaluator, name_part)
|
||||
for name_part in get_module_names(script._get_module().module_node, all_scopes)]
|
||||
module_context = script._get_module()
|
||||
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))
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ from jedi.evaluate import instance
|
||||
from jedi.evaluate import iterable
|
||||
from jedi.evaluate import imports
|
||||
from jedi.evaluate import compiled
|
||||
from jedi.evaluate.filters import ParamName
|
||||
from jedi.evaluate.finder import filter_definition_names
|
||||
from jedi.api.keywords import KeywordName
|
||||
|
||||
|
||||
def defined_names(evaluator, scope):
|
||||
@@ -63,7 +65,7 @@ class BaseDefinition(object):
|
||||
An instance of :class:`jedi.parser.reprsentation.Name` subclass.
|
||||
"""
|
||||
#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
|
||||
|
||||
# generate a path to the definition
|
||||
@@ -232,9 +234,9 @@ class BaseDefinition(object):
|
||||
|
||||
"""
|
||||
if raw:
|
||||
return _Help(self._definition).raw()
|
||||
return _Help(self._name.parent_context).raw()
|
||||
else:
|
||||
return _Help(self._definition).full()
|
||||
return _Help(self._name.parent_context).full()
|
||||
|
||||
@property
|
||||
def doc(self):
|
||||
@@ -259,7 +261,7 @@ class BaseDefinition(object):
|
||||
@property
|
||||
def description(self):
|
||||
"""A textual description of the object."""
|
||||
return unicode(self._name)
|
||||
return unicode(self._name.string_name)
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
@@ -298,7 +300,12 @@ class BaseDefinition(object):
|
||||
return '.'.join(path if path[0] else path[1:])
|
||||
|
||||
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]
|
||||
|
||||
@memoize_method
|
||||
@@ -306,6 +313,7 @@ class BaseDefinition(object):
|
||||
"""
|
||||
Follow both statements and imports, as far as possible.
|
||||
"""
|
||||
return self._name.infer()
|
||||
if self._name.api_type == 'expr_stmt':
|
||||
return self._evaluator.eval_statement(self._definition)
|
||||
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)]
|
||||
|
||||
def parent(self):
|
||||
scope = self._definition.get_parent_scope()
|
||||
scope = self._evaluator.wrap(scope)
|
||||
return Definition(self._evaluator, scope.name)
|
||||
return Definition(self._evaluator, self._name.parent_context.name)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s %s>" % (type(self).__name__, self.description)
|
||||
@@ -371,7 +377,7 @@ class BaseDefinition(object):
|
||||
if self.in_builtin_module():
|
||||
return ''
|
||||
|
||||
path = self._definition.get_parent_until().path
|
||||
path = self._name.get_root_context().py__file__()
|
||||
parser = load_parser(path)
|
||||
lines = common.splitlines(parser.source)
|
||||
|
||||
@@ -401,7 +407,7 @@ class Completion(BaseDefinition):
|
||||
and self.type == 'Function':
|
||||
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))
|
||||
if 'trailer' in node_names and 'argument' not in node_names:
|
||||
append += '='
|
||||
@@ -438,9 +444,10 @@ class Completion(BaseDefinition):
|
||||
@property
|
||||
def description(self):
|
||||
"""Provide a description of the completion object."""
|
||||
if self._definition is None:
|
||||
return self._name.string_name
|
||||
# TODO improve the class structure.
|
||||
return Definition.description.__get__(self)
|
||||
|
||||
# TODO remove
|
||||
t = self.type
|
||||
if t == 'statement' or t == 'import':
|
||||
desc = self._definition.get_code()
|
||||
@@ -461,20 +468,20 @@ class Completion(BaseDefinition):
|
||||
the ``foo.docstring(fast=False)`` on every object, because it
|
||||
parses all libraries starting with ``a``.
|
||||
"""
|
||||
definition = self._definition
|
||||
if isinstance(definition, tree.Import):
|
||||
raise DeprecationWarning
|
||||
i = imports.ImportWrapper(self._evaluator, self._name)
|
||||
if len(i.import_path) > 1 or not fast:
|
||||
followed = self._follow_statements_imports()
|
||||
context = self._name.parent_context
|
||||
if isinstance(self._name, imports.ImportName):
|
||||
if fast:
|
||||
return ''
|
||||
else:
|
||||
followed = self._name.infer()
|
||||
if followed:
|
||||
# TODO: Use all of the followed objects as input to Documentation.
|
||||
definition = list(followed)[0]
|
||||
context = next(iter(followed))
|
||||
|
||||
if raw:
|
||||
return _Help(definition).raw()
|
||||
return _Help(context).raw()
|
||||
else:
|
||||
return _Help(definition).full()
|
||||
return _Help(context).full()
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
@@ -772,7 +779,7 @@ class _Help(object):
|
||||
|
||||
def full(self):
|
||||
try:
|
||||
return self._name.doc
|
||||
return self._name.get_node().doc
|
||||
except AttributeError:
|
||||
return self.raw()
|
||||
|
||||
@@ -782,7 +789,7 @@ class _Help(object):
|
||||
|
||||
See :attr:`doc` for example.
|
||||
"""
|
||||
try:
|
||||
return self._name.raw_doc
|
||||
except AttributeError:
|
||||
node = self._name.get_node()
|
||||
if node is None:
|
||||
return ''
|
||||
return node.raw_doc
|
||||
|
||||
@@ -112,6 +112,17 @@ class CompiledObject(Context):
|
||||
params.append(Param(parts, self))
|
||||
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):
|
||||
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)]
|
||||
|
||||
|
||||
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):
|
||||
def __init__(self, parent_context, name):
|
||||
self.string_name = name
|
||||
|
||||
@@ -431,7 +431,7 @@ class Importer(object):
|
||||
if self.str_import_path == ('flask', 'ext'):
|
||||
# List Flask extensions like ``flask_foo``
|
||||
for mod in self._get_module_names():
|
||||
modname = str(mod)
|
||||
modname = mod.string_name
|
||||
if modname.startswith('flask_'):
|
||||
extname = modname[len('flask_'):]
|
||||
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.
|
||||
paths = set()
|
||||
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):
|
||||
paths.add(other)
|
||||
return list(paths)
|
||||
if 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.
|
||||
return [self._get_init_directory()]
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ def test_preload_modules():
|
||||
|
||||
api.preload_module('sys')
|
||||
check_loaded() # compiled (c_builtin) modules shouldn't be in the cache.
|
||||
api.preload_module('json', 'token')
|
||||
check_loaded('json', 'token')
|
||||
api.preload_module('types', 'token')
|
||||
check_loaded('types', 'token')
|
||||
|
||||
utils.parser_cache = temp_cache
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ from textwrap import dedent
|
||||
|
||||
from jedi._compatibility import builtins, is_py3
|
||||
from jedi.parser import load_grammar
|
||||
from jedi.parser.tree import Function
|
||||
from jedi.evaluate import compiled, representation
|
||||
from jedi.evaluate import compiled, instance
|
||||
from jedi.evaluate.representation import FunctionContext
|
||||
from jedi.evaluate import Evaluator
|
||||
from jedi import Script
|
||||
|
||||
@@ -16,25 +16,24 @@ def test_simple():
|
||||
e = _evaluator()
|
||||
bltn = compiled.CompiledObject(e, builtins)
|
||||
obj = compiled.CompiledObject(e, '_str_', bltn)
|
||||
upper = e.find_types(obj, 'upper')
|
||||
assert len(upper) == 1
|
||||
objs = list(e.execute(list(upper)[0]))
|
||||
upper, = obj.py__getattribute__('upper')
|
||||
objs = list(upper.execute_evaluated())
|
||||
assert len(objs) == 1
|
||||
assert isinstance(objs[0], representation.Instance)
|
||||
assert isinstance(objs[0], instance.CompiledInstance)
|
||||
|
||||
|
||||
def test_fake_loading():
|
||||
e = _evaluator()
|
||||
assert isinstance(compiled.create(e, next), Function)
|
||||
assert isinstance(compiled.create(e, next), FunctionContext)
|
||||
|
||||
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__')
|
||||
assert isinstance(from_name, Function)
|
||||
assert isinstance(from_name, FunctionContext)
|
||||
|
||||
|
||||
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():
|
||||
|
||||
@@ -10,7 +10,7 @@ def test_call_of_leaf_in_brackets():
|
||||
type(x)
|
||||
""")
|
||||
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)
|
||||
assert call == name
|
||||
|
||||
@@ -97,7 +97,7 @@ def test_not_importable_file():
|
||||
def test_import_unique():
|
||||
src = "import os; os.path"
|
||||
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))
|
||||
|
||||
|
||||
|
||||
@@ -49,16 +49,16 @@ def test_namespace_package():
|
||||
for c in script_with_path(source + '; x.').completions():
|
||||
if c.name == 'foo':
|
||||
completion = c
|
||||
solution = "statement: foo = '%s'" % solution
|
||||
solution = "foo = '%s'" % solution
|
||||
assert completion.description == solution
|
||||
|
||||
|
||||
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__)]
|
||||
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user