1
0
forked from VimPlug/jedi

Merge branch 'refactoring'

This commit is contained in:
Dave Halter
2019-08-24 14:38:45 +02:00
158 changed files with 3957 additions and 3840 deletions

View File

@@ -28,19 +28,19 @@ from jedi.api import helpers
from jedi.api.completion import Completion
from jedi.api.environment import InterpreterEnvironment
from jedi.api.project import get_default_project, Project
from jedi.evaluate import Evaluator
from jedi.evaluate import imports
from jedi.evaluate import usages
from jedi.evaluate.arguments import try_iter_content
from jedi.evaluate.helpers import get_module_names, evaluate_call_of_leaf
from jedi.evaluate.sys_path import transform_path_to_dotted
from jedi.evaluate.names import TreeNameDefinition, ParamName
from jedi.evaluate.syntax_tree import tree_name_to_contexts
from jedi.evaluate.context import ModuleContext
from jedi.evaluate.base_context import ContextSet
from jedi.evaluate.context.iterable import unpack_tuple_to_dict
from jedi.evaluate.gradual.conversion import convert_names, convert_contexts
from jedi.evaluate.gradual.utils import load_proper_stub_module
from jedi.inference import InferenceState
from jedi.inference import imports
from jedi.inference import usages
from jedi.inference.arguments import try_iter_content
from jedi.inference.helpers import get_module_names, infer_call_of_leaf
from jedi.inference.sys_path import transform_path_to_dotted
from jedi.inference.names import TreeNameDefinition, ParamName
from jedi.inference.syntax_tree import tree_name_to_values
from jedi.inference.value import ModuleValue
from jedi.inference.base_value import ValueSet
from jedi.inference.value.iterable import unpack_tuple_to_dict
from jedi.inference.gradual.conversion import convert_names, convert_values
from jedi.inference.gradual.utils import load_proper_stub_module
# Jedi uses lots and lots of recursion. By setting this a little bit higher, we
# can remove some "maximum recursion depth" errors.
@@ -62,7 +62,7 @@ class Script(object):
- if `sys_path` parameter is ``None`` and ``VIRTUAL_ENV`` environment
variable is defined, ``sys.path`` for the specified environment will be
guessed (see :func:`jedi.evaluate.sys_path.get_venv_path`) and used for
guessed (see :func:`jedi.inference.sys_path.get_venv_path`) and used for
the script;
- otherwise ``sys.path`` will match that of |jedi|.
@@ -111,11 +111,11 @@ class Script(object):
# TODO deprecate and remove sys_path from the Script API.
if sys_path is not None:
project._sys_path = sys_path
self._evaluator = Evaluator(
self._inference_state = InferenceState(
project, environment=environment, script_path=self.path
)
debug.speed('init')
self._module_node, source = self._evaluator.parse_and_get_code(
self._module_node, source = self._inference_state.parse_and_get_code(
code=source,
path=self.path,
encoding=encoding,
@@ -156,7 +156,7 @@ class Script(object):
is_package = False
if self.path is not None:
import_names, is_p = transform_path_to_dotted(
self._evaluator.get_sys_path(add_parent_paths=False),
self._inference_state.get_sys_path(add_parent_paths=False),
self.path
)
if import_names is not None:
@@ -170,7 +170,7 @@ class Script(object):
if self.path is not None and self.path.endswith('.pyi'):
# We are in a stub file. Try to load the stub properly.
stub_module = load_proper_stub_module(
self._evaluator,
self._inference_state,
file_io,
names,
self._module_node
@@ -181,22 +181,25 @@ class Script(object):
if names is None:
names = ('__main__',)
module = ModuleContext(
self._evaluator, self._module_node, file_io,
module = ModuleValue(
self._inference_state, self._module_node, file_io,
string_names=names,
code_lines=self._code_lines,
is_package=is_package,
)
if names[0] not in ('builtins', '__builtin__', 'typing'):
# These modules are essential for Jedi, so don't overwrite them.
self._evaluator.module_cache.add(names, ContextSet([module]))
self._inference_state.module_cache.add(names, ValueSet([module]))
return module
def _get_module_context(self):
return self._get_module().as_context()
def __repr__(self):
return '<%s: %s %r>' % (
self.__class__.__name__,
repr(self._orig_path),
self._evaluator.environment,
self._inference_state.environment,
)
def completions(self):
@@ -209,7 +212,7 @@ class Script(object):
"""
with debug.increase_indent_cm('completions'):
completion = Completion(
self._evaluator, self._get_module(), self._code_lines,
self._inference_state, self._get_module_context(), self._code_lines,
self._pos, self.call_signatures
)
return completion.completions()
@@ -239,16 +242,16 @@ class Script(object):
if leaf is None:
return []
context = self._evaluator.create_context(self._get_module(), leaf)
context = self._get_module_context().create_context(leaf)
contexts = helpers.evaluate_goto_definition(self._evaluator, context, leaf)
contexts = convert_contexts(
contexts,
values = helpers.infer_goto_definition(self._inference_state, context, leaf)
values = convert_values(
values,
only_stubs=only_stubs,
prefer_stubs=prefer_stubs,
)
defs = [classes.Definition(self._evaluator, c.name) for c in contexts]
defs = [classes.Definition(self._inference_state, c.name) for c in values]
# The additional set here allows the definitions to become unique in an
# API sense. In the internals we want to separate more things than in
# the API.
@@ -276,10 +279,10 @@ class Script(object):
def _goto_assignments(self, follow_imports, follow_builtin_imports,
only_stubs=False, prefer_stubs=False):
def filter_follow_imports(names, check):
def filter_follow_imports(names):
for name in names:
if check(name):
new_names = list(filter_follow_imports(name.goto(), check))
if name.is_import():
new_names = list(filter_follow_imports(name.goto()))
found_builtin = False
if follow_builtin_imports:
for new_name in new_names:
@@ -299,18 +302,18 @@ class Script(object):
# Without a name we really just want to jump to the result e.g.
# executed by `foo()`, if we the cursor is after `)`.
return self.goto_definitions(only_stubs=only_stubs, prefer_stubs=prefer_stubs)
context = self._evaluator.create_context(self._get_module(), tree_name)
names = list(self._evaluator.goto(context, tree_name))
context = self._get_module_context().create_context(tree_name)
names = list(self._inference_state.goto(context, tree_name))
if follow_imports:
names = filter_follow_imports(names, lambda name: name.is_import())
names = filter_follow_imports(names)
names = convert_names(
names,
only_stubs=only_stubs,
prefer_stubs=prefer_stubs,
)
defs = [classes.Definition(self._evaluator, d) for d in set(names)]
defs = [classes.Definition(self._inference_state, d) for d in set(names)]
return helpers.sorted_definitions(defs)
def usages(self, additional_module_paths=(), **kwargs):
@@ -340,9 +343,9 @@ class Script(object):
# Must be syntax
return []
names = usages.usages(self._get_module(), tree_name)
names = usages.usages(self._get_module_context(), tree_name)
definitions = [classes.Definition(self._evaluator, n) for n in names]
definitions = [classes.Definition(self._inference_state, n) for n in names]
if not include_builtins:
definitions = [d for d in definitions if not d.in_builtin_module()]
return helpers.sorted_definitions(definitions)
@@ -368,12 +371,9 @@ class Script(object):
if call_details is None:
return []
context = self._evaluator.create_context(
self._get_module(),
call_details.bracket_leaf
)
context = self._get_module_context().create_context(call_details.bracket_leaf)
definitions = helpers.cache_call_signatures(
self._evaluator,
self._inference_state,
context,
call_details.bracket_leaf,
self._code_lines,
@@ -381,21 +381,21 @@ class Script(object):
)
debug.speed('func_call followed')
# TODO here we use stubs instead of the actual contexts. We should use
# the signatures from stubs, but the actual contexts, probably?!
return [classes.CallSignature(self._evaluator, signature, call_details)
# TODO here we use stubs instead of the actual values. We should use
# the signatures from stubs, but the actual values, probably?!
return [classes.CallSignature(self._inference_state, signature, call_details)
for signature in definitions.get_signatures()]
def _analysis(self):
self._evaluator.is_analysis = True
self._evaluator.analysis_modules = [self._module_node]
module = self._get_module()
self._inference_state.is_analysis = True
self._inference_state.analysis_modules = [self._module_node]
module = self._get_module_context()
try:
for node in get_executable_nodes(self._module_node):
context = module.create_context(node)
if node.type in ('funcdef', 'classdef'):
# Resolve the decorators.
tree_name_to_contexts(self._evaluator, context, node.children[1])
tree_name_to_values(self._inference_state, context, node.children[1])
elif isinstance(node, tree.Import):
import_names = set(node.get_defined_names())
if node.is_nested():
@@ -403,22 +403,22 @@ class Script(object):
for n in import_names:
imports.infer_import(context, n)
elif node.type == 'expr_stmt':
types = context.eval_node(node)
types = context.infer_node(node)
for testlist in node.children[:-1:2]:
# Iterate tuples.
unpack_tuple_to_dict(context, types, testlist)
else:
if node.type == 'name':
defs = self._evaluator.goto_definitions(context, node)
defs = self._inference_state.goto_definitions(context, node)
else:
defs = evaluate_call_of_leaf(context, node)
defs = infer_call_of_leaf(context, node)
try_iter_content(defs)
self._evaluator.reset_recursion_limitations()
self._inference_state.reset_recursion_limitations()
ana = [a for a in self._evaluator.analysis if self.path == a.path]
ana = [a for a in self._inference_state.analysis if self.path == a.path]
return sorted(set(ana), key=lambda x: x.line)
finally:
self._evaluator.is_analysis = False
self._inference_state.is_analysis = False
class Interpreter(Script):
@@ -467,16 +467,20 @@ class Interpreter(Script):
super(Interpreter, self).__init__(source, environment=environment,
_project=Project(os.getcwd()), **kwds)
self.namespaces = namespaces
self._evaluator.allow_descriptor_getattr = self._allow_descriptor_getattr_default
self._inference_state.allow_descriptor_getattr = self._allow_descriptor_getattr_default
def _get_module(self):
return interpreter.MixedModuleContext(
self._evaluator,
self._module_node,
self.namespaces,
@cache.memoize_method
def _get_module_context(self):
tree_module_value = ModuleValue(
self._inference_state, self._module_node,
file_io=KnownContentFileIO(self.path, self._code),
string_names=('__main__',),
code_lines=self._code_lines,
)
return interpreter.MixedModuleContext(
tree_module_value,
self.namespaces,
)
def names(source=None, path=None, encoding='utf-8', all_scopes=False,
@@ -511,10 +515,10 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False,
# Set line/column to a random position, because they don't matter.
script = Script(source, line=1, column=0, path=path, encoding=encoding, environment=environment)
module_context = script._get_module()
module_context = script._get_module_context()
defs = [
classes.Definition(
script._evaluator,
script._inference_state,
create_name(name)
) for name in get_module_names(script._module_node, all_scopes)
]

View File

@@ -9,15 +9,13 @@ import warnings
from jedi import settings
from jedi import debug
from jedi.evaluate.utils import unite
from jedi.inference.utils import unite
from jedi.cache import memoize_method
from jedi.evaluate import imports
from jedi.evaluate import compiled
from jedi.evaluate.imports import ImportName
from jedi.evaluate.context import FunctionExecutionContext
from jedi.evaluate.gradual.typeshed import StubModuleContext
from jedi.evaluate.gradual.conversion import convert_names, convert_contexts
from jedi.evaluate.base_context import ContextSet
from jedi.inference import imports
from jedi.inference.imports import ImportName
from jedi.inference.gradual.typeshed import StubModuleValue
from jedi.inference.gradual.conversion import convert_names, convert_values
from jedi.inference.base_value import ValueSet
from jedi.api.keywords import KeywordName
@@ -25,20 +23,20 @@ def _sort_names_by_start_pos(names):
return sorted(names, key=lambda s: s.start_pos or (0, 0))
def defined_names(evaluator, context):
def defined_names(inference_state, context):
"""
List sub-definitions (e.g., methods in class).
:type scope: Scope
:rtype: list of Definition
"""
filter = next(context.get_filters(search_global=True))
filter = next(context.get_filters())
names = [name for name in filter.values()]
return [Definition(evaluator, n) for n in _sort_names_by_start_pos(names)]
return [Definition(inference_state, n) for n in _sort_names_by_start_pos(names)]
def _contexts_to_definitions(contexts):
return [Definition(c.evaluator, c.name) for c in contexts]
def _values_to_definitions(values):
return [Definition(c.inference_state, c.name) for c in values]
class BaseDefinition(object):
@@ -62,8 +60,8 @@ class BaseDefinition(object):
'argparse._ActionsContainer': 'argparse.ArgumentParser',
}.items())
def __init__(self, evaluator, name):
self._evaluator = evaluator
def __init__(self, inference_state, name):
self._inference_state = inference_state
self._name = name
"""
An instance of :class:`parso.python.tree.Name` subclass.
@@ -71,7 +69,7 @@ class BaseDefinition(object):
self.is_keyword = isinstance(self._name, KeywordName)
@memoize_method
def _get_module(self):
def _get_module_context(self):
# This can take a while to complete, because in the worst case of
# imports (consider `import a` completions), we need to load all
# modules starting with a first.
@@ -80,11 +78,11 @@ class BaseDefinition(object):
@property
def module_path(self):
"""Shows the file path of a module. e.g. ``/usr/lib/python2.7/os.py``"""
module = self._get_module()
module = self._get_module_context()
if module.is_stub() or not module.is_compiled():
# Compiled modules should not return a module path even if they
# have one.
return self._get_module().py__file__()
return self._get_module_context().py__file__()
return None
@@ -97,7 +95,7 @@ class BaseDefinition(object):
:rtype: str or None
"""
return self._name.string_name
return self._name.get_public_name()
@property
def type(self):
@@ -167,8 +165,8 @@ class BaseDefinition(object):
resolve = True
if isinstance(self._name, imports.SubModuleName) or resolve:
for context in self._name.infer():
return context.api_type
for value in self._name.infer():
return value.api_type
return self._name.api_type
@property
@@ -183,14 +181,14 @@ class BaseDefinition(object):
>>> print(d.module_name) # doctest: +ELLIPSIS
json
"""
return self._get_module().name.string_name
return self._get_module_context().py__name__()
def in_builtin_module(self):
"""Whether this is a builtin module."""
if isinstance(self._get_module(), StubModuleContext):
return any(isinstance(context, compiled.CompiledObject)
for context in self._get_module().non_stub_context_set)
return isinstance(self._get_module(), compiled.CompiledObject)
value = self._get_module_context().get_value()
if isinstance(value, StubModuleValue):
return any(v.is_compiled() for v in value.non_stub_value_set)
return value.is_compiled()
@property
def line(self):
@@ -244,7 +242,7 @@ class BaseDefinition(object):
@property
def description(self):
"""A textual description of the object."""
return self._name.string_name
return self._name.get_public_name()
@property
def full_name(self):
@@ -270,7 +268,7 @@ class BaseDefinition(object):
be ``<module 'posixpath' ...>```. However most users find the latter
more practical.
"""
if not self._name.is_context_name:
if not self._name.is_value_name:
return None
names = self._name.get_qualified_names(include_module_names=True)
@@ -286,7 +284,7 @@ class BaseDefinition(object):
return '.'.join(names)
def is_stub(self):
if not self._name.is_context_name:
if not self._name.is_value_name:
return False
return self._name.get_root_context().is_stub()
@@ -298,7 +296,7 @@ class BaseDefinition(object):
def _goto_assignments(self, only_stubs=False, prefer_stubs=False):
assert not (only_stubs and prefer_stubs)
if not self._name.is_context_name:
if not self._name.is_value_name:
return []
names = convert_names(
@@ -306,7 +304,7 @@ class BaseDefinition(object):
only_stubs=only_stubs,
prefer_stubs=prefer_stubs,
)
return [self if n == self._name else Definition(self._evaluator, n)
return [self if n == self._name else Definition(self._inference_state, n)
for n in names]
def infer(self, **kwargs): # Python 2...
@@ -316,20 +314,20 @@ class BaseDefinition(object):
def _infer(self, only_stubs=False, prefer_stubs=False):
assert not (only_stubs and prefer_stubs)
if not self._name.is_context_name:
if not self._name.is_value_name:
return []
# First we need to make sure that we have stub names (if possible) that
# we can follow. If we don't do that, we can end up with the inferred
# results of Python objects instead of stubs.
names = convert_names([self._name], prefer_stubs=True)
contexts = convert_contexts(
ContextSet.from_sets(n.infer() for n in names),
values = convert_values(
ValueSet.from_sets(n.infer() for n in names),
only_stubs=only_stubs,
prefer_stubs=prefer_stubs,
)
resulting_names = [c.name for c in contexts]
return [self if n == self._name else Definition(self._evaluator, n)
resulting_names = [c.name for c in values]
return [self if n == self._name else Definition(self._inference_state, n)
for n in resulting_names]
@property
@@ -343,10 +341,10 @@ class BaseDefinition(object):
"""
# Only return the first one. There might be multiple one, especially
# with overloading.
for context in self._name.infer():
for signature in context.get_signatures():
for value in self._name.infer():
for signature in value.get_signatures():
return [
Definition(self._evaluator, n)
Definition(self._inference_state, n)
for n in signature.get_param_names(resolve_stars=True)
]
@@ -357,16 +355,16 @@ class BaseDefinition(object):
raise AttributeError('There are no params defined on this.')
def parent(self):
if not self._name.is_context_name:
if not self._name.is_value_name:
return None
context = self._name.parent_context
if context is None:
return None
if isinstance(context, FunctionExecutionContext):
context = context.function_context
return Definition(self._evaluator, context.name)
while context.name is None:
# Happens for comprehension contexts
context = context.parent_context
return Definition(self._inference_state, context.name)
def __repr__(self):
return "<%s %sname=%r, description=%r>" % (
@@ -386,7 +384,7 @@ class BaseDefinition(object):
:return str: Returns the line(s) of code or an empty string if it's a
builtin.
"""
if not self._name.is_context_name or self.in_builtin_module():
if not self._name.is_value_name or self.in_builtin_module():
return ''
lines = self._name.get_root_context().code_lines
@@ -396,10 +394,10 @@ class BaseDefinition(object):
return ''.join(lines[start_index:index + after + 1])
def get_signatures(self):
return [Signature(self._evaluator, s) for s in self._name.infer().get_signatures()]
return [Signature(self._inference_state, s) for s in self._name.infer().get_signatures()]
def execute(self):
return _contexts_to_definitions(self._name.infer().execute_evaluated())
return _values_to_definitions(self._name.infer().execute_with_values())
class Completion(BaseDefinition):
@@ -407,8 +405,8 @@ class Completion(BaseDefinition):
`Completion` objects are returned from :meth:`api.Script.completions`. They
provide additional information about a completion.
"""
def __init__(self, evaluator, name, stack, like_name_length):
super(Completion, self).__init__(evaluator, name)
def __init__(self, inference_state, name, stack, like_name_length):
super(Completion, self).__init__(inference_state, name)
self._like_name_length = like_name_length
self._stack = stack
@@ -429,7 +427,7 @@ class Completion(BaseDefinition):
# TODO this doesn't work for nested calls.
append += '='
name = self._name.string_name
name = self._name.get_public_name()
if like_name:
name = name[self._like_name_length:]
return name + append
@@ -485,7 +483,7 @@ class Completion(BaseDefinition):
return Definition.description.__get__(self)
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, self._name.string_name)
return '<%s: %s>' % (type(self).__name__, self._name.get_public_name())
@memoize_method
def follow_definition(self):
@@ -512,8 +510,8 @@ class Definition(BaseDefinition):
*Definition* objects are returned from :meth:`api.Script.goto_assignments`
or :meth:`api.Script.goto_definitions`.
"""
def __init__(self, evaluator, definition):
super(Definition, self).__init__(evaluator, definition)
def __init__(self, inference_state, definition):
super(Definition, self).__init__(inference_state, definition)
@property
def description(self):
@@ -553,7 +551,7 @@ class Definition(BaseDefinition):
if typ == 'function':
# For the description we want a short and a pythonic way.
typ = 'def'
return typ + ' ' + self._name.string_name
return typ + ' ' + self._name.get_public_name()
definition = tree_name.get_definition() or tree_name
# Remove the prefix, because that's not what we want for get_code
@@ -588,7 +586,7 @@ class Definition(BaseDefinition):
"""
defs = self._name.infer()
return sorted(
unite(defined_names(self._evaluator, d) for d in defs),
unite(defined_names(self._inference_state, d.as_context()) for d in defs),
key=lambda s: s._name.start_pos or (0, 0)
)
@@ -606,13 +604,13 @@ class Definition(BaseDefinition):
return self._name.start_pos == other._name.start_pos \
and self.module_path == other.module_path \
and self.name == other.name \
and self._evaluator == other._evaluator
and self._inference_state == other._inference_state
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash((self._name.start_pos, self.module_path, self.name, self._evaluator))
return hash((self._name.start_pos, self.module_path, self.name, self._inference_state))
class Signature(Definition):
@@ -621,8 +619,8 @@ class Signature(Definition):
It knows what functions you are currently in. e.g. `isinstance(` would
return the `isinstance` function. without `(` it would return nothing.
"""
def __init__(self, evaluator, signature):
super(Signature, self).__init__(evaluator, signature.name)
def __init__(self, inference_state, signature):
super(Signature, self).__init__(inference_state, signature.name)
self._signature = signature
@property
@@ -630,7 +628,7 @@ class Signature(Definition):
"""
:return list of ParamDefinition:
"""
return [ParamDefinition(self._evaluator, n)
return [ParamDefinition(self._inference_state, n)
for n in self._signature.get_param_names(resolve_stars=True)]
def to_string(self):
@@ -644,8 +642,8 @@ class CallSignature(Signature):
return the `isinstance` function with its params. Without `(` it would
return nothing.
"""
def __init__(self, evaluator, signature, call_details):
super(CallSignature, self).__init__(evaluator, signature)
def __init__(self, inference_state, signature, call_details):
super(CallSignature, self).__init__(inference_state, signature)
self._call_details = call_details
self._signature = signature
@@ -680,7 +678,7 @@ class ParamDefinition(Definition):
"""
:return list of Definition:
"""
return _contexts_to_definitions(self._name.infer_default())
return _values_to_definitions(self._name.infer_default())
def infer_annotation(self, **kwargs):
"""
@@ -689,7 +687,7 @@ class ParamDefinition(Definition):
:param execute_annotation: If False, the values are not executed and
you get classes instead of instances.
"""
return _contexts_to_definitions(self._name.infer_annotation(**kwargs))
return _values_to_definitions(self._name.infer_annotation(ignore_stars=True, **kwargs))
def to_string(self):
return self._name.to_string()
@@ -709,10 +707,10 @@ class ParamDefinition(Definition):
return self._name.get_kind()
def _format_signatures(context):
def _format_signatures(value):
return '\n'.join(
signature.to_string()
for signature in context.get_signatures()
for signature in value.get_signatures()
)
@@ -725,7 +723,7 @@ class _Help(object):
self._name = definition
@memoize_method
def _get_contexts(self, fast):
def _get_values(self, fast):
if isinstance(self._name, ImportName) and fast:
return {}
@@ -742,20 +740,20 @@ class _Help(object):
"""
full_doc = ''
# Using the first docstring that we see.
for context in self._get_contexts(fast=fast):
for value in self._get_values(fast=fast):
if full_doc:
# In case we have multiple contexts, just return all of them
# In case we have multiple values, just return all of them
# separated by a few dashes.
full_doc += '\n' + '-' * 30 + '\n'
doc = context.py__doc__()
doc = value.py__doc__()
signature_text = ''
if self._name.is_context_name:
if self._name.is_value_name:
if not raw:
signature_text = _format_signatures(context)
if not doc and context.is_stub():
for c in convert_contexts(ContextSet({context}), ignore_compiled=False):
signature_text = _format_signatures(value)
if not doc and value.is_stub():
for c in convert_values(ValueSet({value}), ignore_compiled=False):
doc = c.py__doc__()
if doc:
break

View File

@@ -11,11 +11,11 @@ from jedi.api import classes
from jedi.api import helpers
from jedi.api import keywords
from jedi.api.file_name import file_name_completions
from jedi.evaluate import imports
from jedi.evaluate.helpers import evaluate_call_of_leaf, parse_dotted_names
from jedi.evaluate.filters import get_global_filters
from jedi.evaluate.gradual.conversion import convert_contexts
from jedi.parser_utils import get_statement_of_position, cut_value_at_position
from jedi.inference import imports
from jedi.inference.helpers import infer_call_of_leaf, parse_dotted_names
from jedi.inference.context import get_global_filters
from jedi.inference.gradual.conversion import convert_values
from jedi.parser_utils import cut_value_at_position
def get_call_signature_param_names(call_signatures):
@@ -28,7 +28,7 @@ def get_call_signature_param_names(call_signatures):
yield p._name
def filter_names(evaluator, completion_names, stack, like_name):
def filter_names(inference_state, completion_names, stack, like_name):
comp_dct = {}
if settings.case_insensitive_completion:
like_name = like_name.lower()
@@ -39,7 +39,7 @@ def filter_names(evaluator, completion_names, stack, like_name):
if string.startswith(like_name):
new = classes.Completion(
evaluator,
inference_state,
name,
stack,
len(like_name)
@@ -52,28 +52,12 @@ def filter_names(evaluator, completion_names, stack, like_name):
yield new
def get_user_scope(module_context, position):
def get_user_context(module_context, position):
"""
Returns the scope in which the user resides. This includes flows.
"""
user_stmt = get_statement_of_position(module_context.tree_node, position)
if user_stmt is None:
def scan(scope):
for s in scope.children:
if s.start_pos <= position <= s.end_pos:
if isinstance(s, (tree.Scope, tree.Flow)) \
or s.type in ('async_stmt', 'async_funcdef'):
return scan(s) or s
elif s.type in ('suite', 'decorated'):
return scan(s)
return None
scanned_node = scan(module_context.tree_node)
if scanned_node:
return module_context.create_context(scanned_node, node_is_context=True)
return module_context
else:
return module_context.create_context(user_stmt)
leaf = module_context.tree_node.get_leaf_for_position(position, include_prefixes=True)
return module_context.create_context(leaf)
def get_flow_scope_node(module_node, position):
@@ -85,10 +69,11 @@ def get_flow_scope_node(module_node, position):
class Completion:
def __init__(self, evaluator, module, code_lines, position, call_signatures_callback):
self._evaluator = evaluator
self._module_context = module
self._module_node = module.tree_node
def __init__(self, inference_state, module_context, code_lines, position,
call_signatures_callback):
self._inference_state = inference_state
self._module_context = module_context
self._module_node = module_context.tree_node
self._code_lines = code_lines
# The first step of completions is to get the name
@@ -104,25 +89,25 @@ class Completion:
string, start_leaf = _extract_string_while_in_string(leaf, self._position)
if string is not None:
completions = list(file_name_completions(
self._evaluator, self._module_context, start_leaf, string,
self._inference_state, self._module_context, start_leaf, string,
self._like_name, self._call_signatures_callback,
self._code_lines, self._original_position
))
if completions:
return completions
completion_names = self._get_context_completions(leaf)
completion_names = self._get_value_completions(leaf)
completions = filter_names(self._evaluator, completion_names,
completions = filter_names(self._inference_state, completion_names,
self.stack, self._like_name)
return sorted(completions, key=lambda x: (x.name.startswith('__'),
x.name.startswith('_'),
x.name.lower()))
def _get_context_completions(self, leaf):
def _get_value_completions(self, leaf):
"""
Analyzes the context that a completion is made in and decides what to
Analyzes the value that a completion is made in and decides what to
return.
Technically this works by generating a parser stack and analysing the
@@ -135,7 +120,7 @@ class Completion:
- In params (also lambda): no completion before =
"""
grammar = self._evaluator.grammar
grammar = self._inference_state.grammar
self.stack = stack = None
try:
@@ -149,7 +134,7 @@ class Completion:
# completions since this probably just confuses the user.
return []
# If we don't have a context, just use global completion.
# If we don't have a value, just use global completion.
return self._global_completions()
allowed_transitions = \
@@ -208,7 +193,7 @@ class Completion:
if nodes and nodes[-1] in ('as', 'def', 'class'):
# No completions for ``with x as foo`` and ``import x as foo``.
# Also true for defining names as a class or function.
return list(self._get_class_context_completions(is_function=True))
return list(self._get_class_value_completions(is_function=True))
elif "import_stmt" in nonterminals:
level, names = parse_dotted_names(nodes, "import_from" in nonterminals)
@@ -223,7 +208,7 @@ class Completion:
completion_names += self._trailer_completions(dot.get_previous_leaf())
else:
completion_names += self._global_completions()
completion_names += self._get_class_context_completions(is_function=False)
completion_names += self._get_class_value_completions(is_function=False)
if 'trailer' in nonterminals:
call_signatures = self._call_signatures_callback()
@@ -234,17 +219,16 @@ class Completion:
def _get_keyword_completion_names(self, allowed_transitions):
for k in allowed_transitions:
if isinstance(k, str) and k.isalpha():
yield keywords.KeywordName(self._evaluator, k)
yield keywords.KeywordName(self._inference_state, k)
def _global_completions(self):
context = get_user_scope(self._module_context, self._position)
context = get_user_context(self._module_context, self._position)
debug.dbg('global completion scope: %s', context)
flow_scope_node = get_flow_scope_node(self._module_node, self._position)
filters = get_global_filters(
self._evaluator,
context,
self._position,
origin_scope=flow_scope_node
flow_scope_node
)
completion_names = []
for filter in filters:
@@ -252,52 +236,43 @@ class Completion:
return completion_names
def _trailer_completions(self, previous_leaf):
user_context = get_user_scope(self._module_context, self._position)
evaluation_context = self._evaluator.create_context(
self._module_context, previous_leaf
)
contexts = evaluate_call_of_leaf(evaluation_context, previous_leaf)
user_value = get_user_context(self._module_context, self._position)
inferred_context = self._module_context.create_context(previous_leaf)
values = infer_call_of_leaf(inferred_context, previous_leaf)
completion_names = []
debug.dbg('trailer completion contexts: %s', contexts, color='MAGENTA')
for context in contexts:
for filter in context.get_filters(
search_global=False,
origin_scope=user_context.tree_node):
debug.dbg('trailer completion values: %s', values, color='MAGENTA')
for value in values:
for filter in value.get_filters(origin_scope=user_value.tree_node):
completion_names += filter.values()
python_contexts = convert_contexts(contexts)
for c in python_contexts:
if c not in contexts:
for filter in c.get_filters(
search_global=False,
origin_scope=user_context.tree_node):
python_values = convert_values(values)
for c in python_values:
if c not in values:
for filter in c.get_filters(origin_scope=user_value.tree_node):
completion_names += filter.values()
return completion_names
def _get_importer_names(self, names, level=0, only_modules=True):
names = [n.value for n in names]
i = imports.Importer(self._evaluator, names, self._module_context, level)
return i.completion_names(self._evaluator, only_modules=only_modules)
i = imports.Importer(self._inference_state, names, self._module_context, level)
return i.completion_names(self._inference_state, only_modules=only_modules)
def _get_class_context_completions(self, is_function=True):
def _get_class_value_completions(self, is_function=True):
"""
Autocomplete inherited methods when overriding in child class.
"""
leaf = self._module_node.get_leaf_for_position(self._position, include_prefixes=True)
cls = tree.search_ancestor(leaf, 'classdef')
if isinstance(cls, (tree.Class, tree.Function)):
# Complete the methods that are defined in the super classes.
random_context = self._module_context.create_context(
cls,
node_is_context=True
)
else:
if cls is None:
return
# Complete the methods that are defined in the super classes.
class_value = self._module_context.create_value(cls)
if cls.start_pos[1] >= leaf.start_pos[1]:
return
filters = random_context.get_filters(search_global=False, is_instance=True)
filters = class_value.get_filters(is_instance=True)
# The first dict is the dictionary of class itself.
next(filters)
for filter in filters:

View File

@@ -10,8 +10,8 @@ from collections import namedtuple
from jedi._compatibility import highest_pickle_protocol, which
from jedi.cache import memoize_method, time_cache
from jedi.evaluate.compiled.subprocess import CompiledSubprocess, \
EvaluatorSameProcess, EvaluatorSubprocess
from jedi.inference.compiled.subprocess import CompiledSubprocess, \
InferenceStateSameProcess, InferenceStateSubprocess
import parso
@@ -109,8 +109,8 @@ class Environment(_BaseEnvironment):
version = '.'.join(str(i) for i in self.version_info)
return '<%s: %s in %s>' % (self.__class__.__name__, version, self.path)
def get_evaluator_subprocess(self, evaluator):
return EvaluatorSubprocess(evaluator, self._get_subprocess())
def get_inference_state_subprocess(self, inference_state):
return InferenceStateSubprocess(inference_state, self._get_subprocess())
@memoize_method
def get_sys_path(self):
@@ -140,8 +140,8 @@ class SameEnvironment(_SameEnvironmentMixin, Environment):
class InterpreterEnvironment(_SameEnvironmentMixin, _BaseEnvironment):
def get_evaluator_subprocess(self, evaluator):
return EvaluatorSameProcess(evaluator)
def get_inference_state_subprocess(self, inference_state):
return InferenceStateSameProcess(inference_state)
def get_sys_path(self):
return sys.path
@@ -286,7 +286,7 @@ def find_virtualenvs(paths=None, **kwargs):
for path in os.listdir(directory):
path = os.path.join(directory, path)
if path in _used_paths:
# A path shouldn't be evaluated twice.
# A path shouldn't be inferred twice.
continue
_used_paths.add(path)

View File

@@ -1,37 +1,13 @@
import os
import sys
from jedi._compatibility import FileNotFoundError, force_unicode, scandir
from jedi.evaluate.names import AbstractArbitraryName
from jedi.inference.names import AbstractArbitraryName
from jedi.api import classes
from jedi.evaluate.helpers import get_str_or_none
from jedi.inference.helpers import get_str_or_none
from jedi.parser_utils import get_string_quote
if sys.version_info < (3,6) or True:
"""
A super-minimal shim around listdir that behave like
scandir for the information we need.
"""
class DirEntry:
def __init__(self, name, basepath):
self.name = name
self.basepath = basepath
def is_dir(self):
path_for_name = os.path.join(self.basepath, self.name)
return os.path.isdir(path_for_name)
def scandir(dir):
return [DirEntry(name, dir) for name in os.listdir(dir)]
else:
from os import scandir
def file_name_completions(evaluator, module_context, start_leaf, string,
def file_name_completions(inference_state, module_context, start_leaf, string,
like_name, call_signatures_callback, code_lines, position):
# First we want to find out what can actually be changed as a name.
like_name_length = len(os.path.basename(string) + like_name)
@@ -54,7 +30,7 @@ def file_name_completions(evaluator, module_context, start_leaf, string,
is_in_os_path_join = False
else:
string = to_be_added + string
base_path = os.path.join(evaluator.project._path, string)
base_path = os.path.join(inference_state.project._path, string)
try:
listed = scandir(base_path)
except FileNotFoundError:
@@ -77,8 +53,8 @@ def file_name_completions(evaluator, module_context, start_leaf, string,
name += os.path.sep
yield classes.Completion(
evaluator,
FileName(evaluator, name[len(must_start_with) - like_name_length:]),
inference_state,
FileName(inference_state, name[len(must_start_with) - like_name_length:]),
stack=None,
like_name_length=like_name_length
)
@@ -109,10 +85,10 @@ def _add_strings(context, nodes, add_slash=False):
string = ''
first = True
for child_node in nodes:
contexts = context.eval_node(child_node)
if len(contexts) != 1:
values = context.infer_node(child_node)
if len(values) != 1:
return None
c, = contexts
c, = values
s = get_str_or_none(c)
if s is None:
return None
@@ -125,7 +101,7 @@ def _add_strings(context, nodes, add_slash=False):
class FileName(AbstractArbitraryName):
api_type = u'path'
is_context_name = False
is_value_name = False
def _add_os_path_join(module_context, start_leaf, bracket_start):
@@ -140,10 +116,10 @@ def _add_os_path_join(module_context, start_leaf, bracket_start):
if start_leaf.type == 'error_leaf':
# Unfinished string literal, like `join('`
context_node = start_leaf.parent
index = context_node.children.index(start_leaf)
value_node = start_leaf.parent
index = value_node.children.index(start_leaf)
if index > 0:
error_node = context_node.children[index - 1]
error_node = value_node.children[index - 1]
if error_node.type == 'error_node' and len(error_node.children) >= 2:
index = -2
if error_node.children[-1].type == 'arglist':

View File

@@ -9,10 +9,10 @@ from parso.python.parser import Parser
from parso.python import tree
from jedi._compatibility import u, Parameter
from jedi.evaluate.base_context import NO_CONTEXTS
from jedi.evaluate.syntax_tree import eval_atom
from jedi.evaluate.helpers import evaluate_call_of_leaf
from jedi.evaluate.compiled import get_string_context_set
from jedi.inference.base_value import NO_VALUES
from jedi.inference.syntax_tree import infer_atom
from jedi.inference.helpers import infer_call_of_leaf
from jedi.inference.compiled import get_string_value_set
from jedi.cache import call_signature_time_cache
@@ -87,7 +87,7 @@ def _get_code_for_stack(code_lines, leaf, position):
if is_after_newline:
if user_stmt.start_pos[1] > position[1]:
# This means that it's actually a dedent and that means that we
# start without context (part of a suite).
# start without value (part of a suite).
return u('')
# This is basically getting the relevant lines.
@@ -136,25 +136,25 @@ def get_stack_at_position(grammar, code_lines, leaf, pos):
)
def evaluate_goto_definition(evaluator, context, leaf):
def infer_goto_definition(inference_state, context, leaf):
if leaf.type == 'name':
# In case of a name we can just use goto_definition which does all the
# magic itself.
return evaluator.goto_definitions(context, leaf)
return inference_state.goto_definitions(context, leaf)
parent = leaf.parent
definitions = NO_CONTEXTS
definitions = NO_VALUES
if parent.type == 'atom':
# e.g. `(a + b)`
definitions = context.eval_node(leaf.parent)
definitions = context.infer_node(leaf.parent)
elif parent.type == 'trailer':
# e.g. `a()`
definitions = evaluate_call_of_leaf(context, leaf)
definitions = infer_call_of_leaf(context, leaf)
elif isinstance(leaf, tree.Literal):
# e.g. `"foo"` or `1.0`
return eval_atom(context, leaf)
return infer_atom(context, leaf)
elif leaf.type in ('fstring_string', 'fstring_start', 'fstring_end'):
return get_string_context_set(evaluator)
return get_string_value_set(inference_state)
return definitions
@@ -376,7 +376,7 @@ def get_call_signature_details(module, position):
@call_signature_time_cache("call_signatures_validity")
def cache_call_signatures(evaluator, context, bracket_leaf, code_lines, user_pos):
def cache_call_signatures(inference_state, context, bracket_leaf, code_lines, user_pos):
"""This function calculates the cache key."""
line_index = user_pos[0] - 1
@@ -390,8 +390,8 @@ def cache_call_signatures(evaluator, context, bracket_leaf, code_lines, user_pos
yield None # Don't cache!
else:
yield (module_path, before_bracket, bracket_leaf.start_pos)
yield evaluate_goto_definition(
evaluator,
yield infer_goto_definition(
inference_state,
context,
bracket_leaf.get_previous_leaf(),
)

View File

@@ -2,16 +2,15 @@
TODO Some parts of this module are still not well documented.
"""
from jedi.evaluate.context import ModuleContext
from jedi.evaluate import compiled
from jedi.evaluate.compiled import mixed
from jedi.evaluate.compiled.access import create_access_path
from jedi.evaluate.base_context import ContextWrapper
from jedi.inference import compiled
from jedi.inference.compiled import mixed
from jedi.inference.compiled.access import create_access_path
from jedi.inference.context import ModuleContext
def _create(evaluator, obj):
def _create(inference_state, obj):
return compiled.create_from_access_path(
evaluator, create_access_path(evaluator, obj)
inference_state, create_access_path(inference_state, obj)
)
@@ -20,28 +19,20 @@ class NamespaceObject(object):
self.__dict__ = dct
class MixedModuleContext(ContextWrapper):
type = 'mixed_module'
def __init__(self, evaluator, tree_module, namespaces, file_io, code_lines):
module_context = ModuleContext(
evaluator, tree_module,
file_io=file_io,
string_names=('__main__',),
code_lines=code_lines
)
super(MixedModuleContext, self).__init__(module_context)
class MixedModuleContext(ModuleContext):
def __init__(self, tree_module_value, namespaces):
super(MixedModuleContext, self).__init__(tree_module_value)
self._namespace_objects = [NamespaceObject(n) for n in namespaces]
def get_filters(self, *args, **kwargs):
for filter in self._wrapped_context.get_filters(*args, **kwargs):
for filter in self._value.as_context().get_filters(*args, **kwargs):
yield filter
for namespace_obj in self._namespace_objects:
compiled_object = _create(self.evaluator, namespace_obj)
compiled_object = _create(self.inference_state, namespace_obj)
mixed_object = mixed.MixedObject(
compiled_object=compiled_object,
tree_context=self._wrapped_context
tree_value=self._value
)
for filter in mixed_object.get_filters(*args, **kwargs):
yield filter

View File

@@ -1,7 +1,7 @@
import pydoc
from jedi.evaluate.utils import ignored
from jedi.evaluate.names import AbstractArbitraryName
from jedi.inference.utils import ignored
from jedi.inference.names import AbstractArbitraryName
try:
from pydoc_data import topics as pydoc_topics
@@ -15,24 +15,24 @@ except ImportError:
pydoc_topics = None
def get_operator(evaluator, string, pos):
return Keyword(evaluator, string, pos)
def get_operator(inference_state, string, pos):
return Keyword(inference_state, string, pos)
class KeywordName(AbstractArbitraryName):
api_type = u'keyword'
def infer(self):
return [Keyword(self.evaluator, self.string_name, (0, 0))]
return [Keyword(self.inference_state, self.string_name, (0, 0))]
class Keyword(object):
api_type = u'keyword'
def __init__(self, evaluator, name, pos):
self.name = KeywordName(evaluator, name)
def __init__(self, inference_state, name, pos):
self.name = KeywordName(inference_state, name)
self.start_pos = pos
self.parent = evaluator.builtins_module
self.parent = inference_state.builtins_module
@property
def names(self):
@@ -44,7 +44,7 @@ class Keyword(object):
def get_signatures(self):
# TODO this makes no sense, I think Keyword should somehow merge with
# Context to make it easier for the api/classes.py to deal with all
# Value to make it easier for the api/classes.py to deal with all
# of it.
return []

View File

@@ -6,8 +6,8 @@ from jedi.api.environment import SameEnvironment, \
get_cached_default_environment
from jedi.api.exceptions import WrongVersion
from jedi._compatibility import force_unicode
from jedi.evaluate.sys_path import discover_buildout_paths
from jedi.evaluate.cache import evaluator_as_method_param_cache
from jedi.inference.sys_path import discover_buildout_paths
from jedi.inference.cache import inference_state_as_method_param_cache
from jedi.common.utils import traverse_parents
_CONFIG_FOLDER = '.jedi'
@@ -77,8 +77,8 @@ class Project(object):
py2_comp(path, **kwargs)
@evaluator_as_method_param_cache()
def _get_base_sys_path(self, evaluator, environment=None):
@inference_state_as_method_param_cache()
def _get_base_sys_path(self, inference_state, environment=None):
if self._sys_path is not None:
return self._sys_path
@@ -93,8 +93,8 @@ class Project(object):
pass
return sys_path
@evaluator_as_method_param_cache()
def _get_sys_path(self, evaluator, environment=None, add_parent_paths=True):
@inference_state_as_method_param_cache()
def _get_sys_path(self, inference_state, environment=None, add_parent_paths=True):
"""
Keep this method private for all users of jedi. However internally this
one is used like a public method.
@@ -102,15 +102,15 @@ class Project(object):
suffixed = []
prefixed = []
sys_path = list(self._get_base_sys_path(evaluator, environment))
sys_path = list(self._get_base_sys_path(inference_state, environment))
if self._smart_sys_path:
prefixed.append(self._path)
if evaluator.script_path is not None:
suffixed += discover_buildout_paths(evaluator, evaluator.script_path)
if inference_state.script_path is not None:
suffixed += discover_buildout_paths(inference_state, inference_state.script_path)
if add_parent_paths:
traversed = list(traverse_parents(evaluator.script_path))
traversed = list(traverse_parents(inference_state.script_path))
# AFAIK some libraries have imports like `foo.foo.bar`, which
# leads to the conclusion to by default prefer longer paths