forked from VimPlug/jedi
Merge with master
The deprecation of Python2.6 and the insertion of environments made it quite difficult to merge.
This commit is contained in:
+6
-20
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
To ensure compatibility from Python ``2.6`` - ``3.3``, a module has been
|
||||
To ensure compatibility from Python ``2.7`` - ``3.x``, a module has been
|
||||
created. Clearly there is huge need to use conforming syntax.
|
||||
"""
|
||||
import sys
|
||||
@@ -13,12 +13,10 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
# Cannot use sys.version.major and minor names, because in Python 2.6 it's not
|
||||
# a namedtuple.
|
||||
is_py3 = sys.version_info[0] >= 3
|
||||
is_py33 = is_py3 and sys.version_info[1] >= 3
|
||||
is_py34 = is_py3 and sys.version_info[1] >= 4
|
||||
is_py26 = not is_py3 and sys.version_info[1] < 7
|
||||
is_py35 = is_py3 and sys.version_info[1] >= 5
|
||||
py_version = int(str(sys.version_info[0]) + str(sys.version_info[1]))
|
||||
|
||||
|
||||
@@ -74,7 +72,7 @@ def find_module_py33(string, path=None, loader=None, full_name=None):
|
||||
raise ImportError("Originally " + repr(e))
|
||||
|
||||
if loader is None:
|
||||
raise ImportError("Couldn't find a loader for {0}".format(string))
|
||||
raise ImportError("Couldn't find a loader for {}".format(string))
|
||||
|
||||
try:
|
||||
is_package = loader.is_package(string)
|
||||
@@ -127,14 +125,7 @@ def find_module_pre_py33(string, path=None, full_name=None):
|
||||
if loader:
|
||||
is_package = loader.is_package(string)
|
||||
is_archive = hasattr(loader, 'archive')
|
||||
try:
|
||||
module_path = loader.get_filename(string)
|
||||
except AttributeError:
|
||||
# fallback for py26
|
||||
try:
|
||||
module_path = loader._get_filename(string)
|
||||
except AttributeError:
|
||||
continue
|
||||
module_path = loader.get_filename(string)
|
||||
if is_package:
|
||||
module_path = os.path.dirname(module_path)
|
||||
if is_archive:
|
||||
@@ -142,10 +133,10 @@ def find_module_pre_py33(string, path=None, full_name=None):
|
||||
file = None
|
||||
if not is_package or is_archive:
|
||||
file = DummyFile(loader, string)
|
||||
return (file, module_path, is_package)
|
||||
return file, module_path, is_package
|
||||
except ImportError:
|
||||
pass
|
||||
raise ImportError("No module named {0}".format(string))
|
||||
raise ImportError("No module named {}".format(string))
|
||||
|
||||
|
||||
find_module = find_module_py33 if is_py33 else find_module_pre_py33
|
||||
@@ -260,11 +251,6 @@ import ast
|
||||
|
||||
|
||||
def literal_eval(string):
|
||||
# py3.0, py3.1 and py32 don't support unicode literals. Support those, I
|
||||
# don't want to write two versions of the tokenizer.
|
||||
if is_py3 and sys.version_info.minor < 3:
|
||||
if re.match('[uU][\'"]', string):
|
||||
string = string[1:]
|
||||
return ast.literal_eval(string)
|
||||
|
||||
|
||||
|
||||
+34
-44
@@ -12,8 +12,8 @@ arguments.
|
||||
import os
|
||||
import sys
|
||||
|
||||
import parso
|
||||
from parso.python import tree
|
||||
from parso import python_bytes_to_unicode, split_lines
|
||||
|
||||
from jedi._compatibility import force_unicode, is_py3
|
||||
from jedi.parser_utils import get_executable_nodes
|
||||
@@ -94,9 +94,29 @@ class Script(object):
|
||||
with open(path, 'rb') as f:
|
||||
source = f.read()
|
||||
|
||||
# TODO do we really want that?
|
||||
self._source = python_bytes_to_unicode(source, encoding, errors='replace')
|
||||
self._code_lines = split_lines(self._source)
|
||||
# Load the Python grammar of the current interpreter.
|
||||
self._grammar = parso.load_grammar()
|
||||
|
||||
if sys_path is not None and not is_py3:
|
||||
sys_path = list(map(force_unicode, sys_path))
|
||||
|
||||
# Load the Python grammar of the current interpreter.
|
||||
project = get_default_project()
|
||||
# TODO deprecate and remove sys_path from the Script API.
|
||||
if sys_path is not None:
|
||||
project._sys_path = sys_path
|
||||
self._evaluator = Evaluator(project, environment=environment, script_path=path)
|
||||
self._project = project
|
||||
debug.speed('init')
|
||||
self._module_node, source = self._evaluator.parse_and_get_code(
|
||||
code=source,
|
||||
path=self.path,
|
||||
cache=False, # No disk cache, because the current script often changes.
|
||||
diff_cache=True,
|
||||
cache_path=settings.cache_directory
|
||||
)
|
||||
debug.speed('parsed')
|
||||
self._code_lines = parso.split_lines(source)
|
||||
line = max(len(self._code_lines), 1) if line is None else line
|
||||
if not (0 < line <= len(self._code_lines)):
|
||||
raise ValueError('`line` parameter is not in a valid range.')
|
||||
@@ -111,35 +131,8 @@ class Script(object):
|
||||
cache.clear_time_caches()
|
||||
debug.reset_time()
|
||||
|
||||
if sys_path is not None and not is_py3:
|
||||
sys_path = list(map(force_unicode, sys_path))
|
||||
|
||||
# Load the Python grammar of the current interpreter.
|
||||
project = get_default_project()
|
||||
# TODO deprecate and remove sys_path from the Script API.
|
||||
if sys_path is not None:
|
||||
project._sys_path = sys_path
|
||||
self._evaluator = Evaluator(project, environment=environment, script_path=path)
|
||||
self._project = project
|
||||
debug.speed('init')
|
||||
|
||||
@cache.memoize_method
|
||||
def _get_module_node(self):
|
||||
return self._evaluator.grammar.parse(
|
||||
code=self._source,
|
||||
path=self.path,
|
||||
cache=False, # No disk cache, because the current script often changes.
|
||||
diff_cache=True,
|
||||
cache_path=settings.cache_directory
|
||||
)
|
||||
|
||||
@cache.memoize_method
|
||||
def _get_module(self):
|
||||
module = ModuleContext(
|
||||
self._evaluator,
|
||||
self._get_module_node(),
|
||||
self.path
|
||||
)
|
||||
module = ModuleContext(self._evaluator, self._module_node, self.path)
|
||||
if self.path is not None:
|
||||
name = dotted_path_in_sys_path(self._evaluator.get_sys_path(), self.path)
|
||||
if name is not None:
|
||||
@@ -178,10 +171,9 @@ class Script(object):
|
||||
|
||||
:rtype: list of :class:`classes.Definition`
|
||||
"""
|
||||
module_node = self._get_module_node()
|
||||
leaf = module_node.get_name_of_position(self._pos)
|
||||
leaf = self._module_node.get_name_of_position(self._pos)
|
||||
if leaf is None:
|
||||
leaf = module_node.get_leaf_for_position(self._pos)
|
||||
leaf = self._module_node.get_leaf_for_position(self._pos)
|
||||
if leaf is None:
|
||||
return []
|
||||
|
||||
@@ -212,7 +204,7 @@ class Script(object):
|
||||
else:
|
||||
yield name
|
||||
|
||||
tree_name = self._get_module_node().get_name_of_position(self._pos)
|
||||
tree_name = self._module_node.get_name_of_position(self._pos)
|
||||
if tree_name is None:
|
||||
return []
|
||||
context = self._evaluator.create_context(self._get_module(), tree_name)
|
||||
@@ -243,7 +235,7 @@ class Script(object):
|
||||
|
||||
:rtype: list of :class:`classes.Definition`
|
||||
"""
|
||||
tree_name = self._get_module_node().get_name_of_position(self._pos)
|
||||
tree_name = self._module_node.get_name_of_position(self._pos)
|
||||
if tree_name is None:
|
||||
# Must be syntax
|
||||
return []
|
||||
@@ -270,7 +262,7 @@ class Script(object):
|
||||
:rtype: list of :class:`classes.CallSignature`
|
||||
"""
|
||||
call_signature_details = \
|
||||
helpers.get_call_signature_details(self._get_module_node(), self._pos)
|
||||
helpers.get_call_signature_details(self._module_node, self._pos)
|
||||
if call_signature_details is None:
|
||||
return []
|
||||
|
||||
@@ -295,10 +287,9 @@ class Script(object):
|
||||
|
||||
def _analysis(self):
|
||||
self._evaluator.is_analysis = True
|
||||
module_node = self._get_module_node()
|
||||
self._evaluator.analysis_modules = [module_node]
|
||||
self._evaluator.analysis_modules = [self._module_node]
|
||||
try:
|
||||
for node in get_executable_nodes(module_node):
|
||||
for node in get_executable_nodes(self._module_node):
|
||||
context = self._get_module().create_context(node)
|
||||
if node.type in ('funcdef', 'classdef'):
|
||||
# Resolve the decorators.
|
||||
@@ -374,10 +365,9 @@ class Interpreter(Script):
|
||||
self.namespaces = namespaces
|
||||
|
||||
def _get_module(self):
|
||||
parser_module = super(Interpreter, self)._get_module_node()
|
||||
return interpreter.MixedModuleContext(
|
||||
self._evaluator,
|
||||
parser_module,
|
||||
self._module_node,
|
||||
self.namespaces,
|
||||
path=self.path
|
||||
)
|
||||
@@ -413,7 +403,7 @@ def names(source=None, path=None, encoding='utf-8', all_scopes=False,
|
||||
module_context.create_context(name if name.parent.type == 'file_input' else name.parent),
|
||||
name
|
||||
)
|
||||
) for name in get_module_names(script._get_module_node(), all_scopes)
|
||||
) for name in get_module_names(script._module_node, all_scopes)
|
||||
]
|
||||
return sorted(filter(def_ref_filter, defs), key=lambda x: (x.line, x.column))
|
||||
|
||||
|
||||
+1
-1
@@ -555,7 +555,7 @@ class Definition(BaseDefinition):
|
||||
.. todo:: Add full path. This function is should return a
|
||||
`module.class.function` path.
|
||||
"""
|
||||
position = '' if self.in_builtin_module else '@%s' % (self.line)
|
||||
position = '' if self.in_builtin_module else '@%s' % self.line
|
||||
return "%s:%s%s" % (self.module_name, self.description, position)
|
||||
|
||||
@memoize_method
|
||||
|
||||
@@ -64,6 +64,7 @@ that are not used are just being ignored.
|
||||
|
||||
from parso.python import tree
|
||||
import parso
|
||||
from parso import python_bytes_to_unicode
|
||||
|
||||
from jedi import debug
|
||||
from jedi import parser_utils
|
||||
@@ -106,6 +107,7 @@ class Evaluator(object):
|
||||
self.access_cache = {}
|
||||
|
||||
self.reset_recursion_limitations()
|
||||
self.allow_different_encoding = True
|
||||
|
||||
@property
|
||||
@evaluator_function_cache()
|
||||
@@ -366,3 +368,15 @@ class Evaluator(object):
|
||||
node = node.parent
|
||||
scope_node = parent_scope(node)
|
||||
return from_scope_node(scope_node, is_nested=True, node_is_object=node_is_object)
|
||||
|
||||
def parse_and_get_code(self, code, path, **kwargs):
|
||||
if self.allow_different_encoding:
|
||||
if code is None:
|
||||
with open(path, 'rb') as f:
|
||||
code = f.read()
|
||||
code = python_bytes_to_unicode(code, errors='replace')
|
||||
|
||||
return self.grammar.parse(code=code, path=path, **kwargs), code
|
||||
|
||||
def parse(self, *args, **kwargs):
|
||||
return self.parse_and_get_code(*args, **kwargs)[0]
|
||||
|
||||
+29
-23
@@ -10,6 +10,7 @@ from jedi.evaluate.base_context import NO_CONTEXTS
|
||||
from jedi.evaluate.context import iterable
|
||||
from jedi.evaluate.param import get_params, ExecutedParam
|
||||
|
||||
|
||||
def try_iter_content(types, depth=0):
|
||||
"""Helper method for static analysis."""
|
||||
if depth > 10:
|
||||
@@ -29,6 +30,8 @@ def try_iter_content(types, depth=0):
|
||||
|
||||
class AbstractArguments(object):
|
||||
context = None
|
||||
argument_node = None
|
||||
trailer = None
|
||||
|
||||
def eval_argument_clinic(self, parameters):
|
||||
"""Uses a list with argument clinic information (see PEP 436)."""
|
||||
@@ -95,29 +98,28 @@ class TreeArguments(AbstractArguments):
|
||||
self.trailer = trailer # Can be None, e.g. in a class definition.
|
||||
|
||||
def _split(self):
|
||||
if isinstance(self.argument_node, (tuple, list)):
|
||||
for el in self.argument_node:
|
||||
yield 0, el
|
||||
else:
|
||||
if not (self.argument_node.type == 'arglist' or (
|
||||
# in python 3.5 **arg is an argument, not arglist
|
||||
(self.argument_node.type == 'argument') and
|
||||
self.argument_node.children[0] in ('*', '**'))):
|
||||
yield 0, self.argument_node
|
||||
return
|
||||
if self.argument_node is None:
|
||||
return
|
||||
|
||||
iterator = iter(self.argument_node.children)
|
||||
for child in iterator:
|
||||
if child == ',':
|
||||
continue
|
||||
elif child in ('*', '**'):
|
||||
yield len(child.value), next(iterator)
|
||||
elif child.type == 'argument' and \
|
||||
child.children[0] in ('*', '**'):
|
||||
assert len(child.children) == 2
|
||||
yield len(child.children[0].value), child.children[1]
|
||||
else:
|
||||
yield 0, child
|
||||
if not (self.argument_node.type == 'arglist' or (
|
||||
# in python 3.5 **arg is an argument, not arglist
|
||||
(self.argument_node.type == 'argument') and
|
||||
self.argument_node.children[0] in ('*', '**'))):
|
||||
yield 0, self.argument_node
|
||||
return
|
||||
|
||||
iterator = iter(self.argument_node.children)
|
||||
for child in iterator:
|
||||
if child == ',':
|
||||
continue
|
||||
elif child in ('*', '**'):
|
||||
yield len(child.value), next(iterator)
|
||||
elif child.type == 'argument' and \
|
||||
child.children[0] in ('*', '**'):
|
||||
assert len(child.children) == 2
|
||||
yield len(child.children[0].value), child.children[1]
|
||||
else:
|
||||
yield 0, child
|
||||
|
||||
def unpack(self, funcdef=None):
|
||||
named_args = []
|
||||
@@ -197,7 +199,11 @@ class TreeArguments(AbstractArguments):
|
||||
arguments = param.var_args
|
||||
break
|
||||
|
||||
return [arguments.argument_node or arguments.trailer]
|
||||
if arguments.argument_node is not None:
|
||||
return [arguments.argument_node]
|
||||
if arguments.trailer is not None:
|
||||
return [arguments.trailer]
|
||||
return []
|
||||
|
||||
|
||||
class ValuesArguments(AbstractArguments):
|
||||
|
||||
@@ -89,7 +89,7 @@ else:
|
||||
return getattr(klass, '__dict__', _sentinel)
|
||||
return _shadowed_dict_newstyle(klass)
|
||||
|
||||
class _OldStyleClass():
|
||||
class _OldStyleClass:
|
||||
pass
|
||||
|
||||
_oldstyle_instance_type = type(_OldStyleClass())
|
||||
@@ -124,7 +124,7 @@ def _safe_hasattr(obj, name):
|
||||
|
||||
|
||||
def _safe_is_data_descriptor(obj):
|
||||
return (_safe_hasattr(obj, '__set__') or _safe_hasattr(obj, '__delete__'))
|
||||
return _safe_hasattr(obj, '__set__') or _safe_hasattr(obj, '__delete__')
|
||||
|
||||
|
||||
def getattr_static(obj, attr, default=_sentinel):
|
||||
|
||||
@@ -66,7 +66,7 @@ class MixedName(compiled.CompiledName):
|
||||
contexts = list(self.infer())
|
||||
if not contexts:
|
||||
# This means a start_pos that doesn't exist (compiled objects).
|
||||
return (0, 0)
|
||||
return 0, 0
|
||||
return contexts[0].name.start_pos
|
||||
|
||||
@start_pos.setter
|
||||
|
||||
@@ -132,7 +132,7 @@ class ModuleContext(use_metaclass(CachedMetaClass, TreeContext)):
|
||||
|
||||
def py__package__(self):
|
||||
if self._get_init_directory() is None:
|
||||
return re.sub(r'\.?[^\.]+$', '', self.py__name__())
|
||||
return re.sub(r'\.?[^.]+$', '', self.py__name__())
|
||||
else:
|
||||
return self.py__name__()
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ def _evaluate_for_statement_string(module_context, string):
|
||||
Need this docstring so that if the below part is not valid Python this
|
||||
is still a function.
|
||||
'''
|
||||
{0}
|
||||
{}
|
||||
"""))
|
||||
if string is None:
|
||||
return []
|
||||
@@ -252,7 +252,7 @@ def _execute_array_values(evaluator, array):
|
||||
for typ in lazy_context.infer()
|
||||
)
|
||||
values.append(LazyKnownContexts(objects))
|
||||
return set([FakeSequence(evaluator, array.array_type, values)])
|
||||
return {FakeSequence(evaluator, array.array_type, values)}
|
||||
else:
|
||||
return array.execute_evaluated()
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ def _check_name_for_execution(evaluator, context, compare_node, name, trailer):
|
||||
def create_func_excs():
|
||||
arglist = trailer.children[1]
|
||||
if arglist == ')':
|
||||
arglist = ()
|
||||
arglist = None
|
||||
args = TreeArguments(evaluator, context, arglist, trailer)
|
||||
if value_node.type == 'funcdef':
|
||||
yield value.get_function_execution(args)
|
||||
|
||||
@@ -26,7 +26,7 @@ class AbstractNameDefinition(object):
|
||||
def goto(self):
|
||||
# Typically names are already definitions and therefore a goto on that
|
||||
# name will always result on itself.
|
||||
return set([self])
|
||||
return {self}
|
||||
|
||||
def get_root_context(self):
|
||||
return self.parent_context.get_root_context()
|
||||
@@ -386,7 +386,7 @@ def get_global_filters(evaluator, context, until_position, origin_scope):
|
||||
... def func():
|
||||
... y = None
|
||||
... '''))
|
||||
>>> module_node = script._get_module_node()
|
||||
>>> module_node = script._module_node
|
||||
>>> scope = next(module_node.iter_funcdefs())
|
||||
>>> scope
|
||||
<Function: func@3-5>
|
||||
|
||||
@@ -465,7 +465,7 @@ def _load_module(evaluator, path=None, code=None, sys_path=None, parent_module=N
|
||||
if path is not None and path.endswith(('.py', '.zip', '.egg')) \
|
||||
and dotted_path not in settings.auto_import_modules:
|
||||
|
||||
module_node = evaluator.grammar.parse(
|
||||
module_node = evaluator.parse(
|
||||
code=code, path=path, cache=True, diff_cache=True,
|
||||
cache_path=settings.cache_directory)
|
||||
|
||||
|
||||
@@ -263,8 +263,6 @@ def collections_namedtuple(evaluator, obj, arguments):
|
||||
This has to be done by processing the namedtuple class template and
|
||||
evaluating the result.
|
||||
|
||||
.. note:: |jedi| only supports namedtuples on Python >2.6.
|
||||
|
||||
"""
|
||||
collections_context = obj.parent_context
|
||||
_class_template_set = collections_context.py__getattribute__(u'_class_template')
|
||||
|
||||
@@ -120,7 +120,7 @@ def eval_node(context, element):
|
||||
def eval_trailer(context, base_contexts, trailer):
|
||||
trailer_op, node = trailer.children[:2]
|
||||
if node == ')': # `arglist` is optional.
|
||||
node = ()
|
||||
node = None
|
||||
|
||||
if trailer_op == '[':
|
||||
trailer_op, node, _ = trailer.children
|
||||
@@ -149,7 +149,7 @@ def eval_trailer(context, base_contexts, trailer):
|
||||
name_or_str=node
|
||||
)
|
||||
else:
|
||||
assert trailer_op == '('
|
||||
assert trailer_op == '(', 'trailer_op is actually %s' % trailer_op
|
||||
args = arguments.TreeArguments(context.evaluator, context, node, trailer)
|
||||
return base_contexts.execute(args)
|
||||
|
||||
@@ -287,10 +287,10 @@ def eval_or_test(context, or_test):
|
||||
# handle lazy evaluation of and/or here.
|
||||
if operator in ('and', 'or'):
|
||||
left_bools = set(left.py__bool__() for left in types)
|
||||
if left_bools == set([True]):
|
||||
if left_bools == {True}:
|
||||
if operator == 'and':
|
||||
types = context.eval_node(right)
|
||||
elif left_bools == set([False]):
|
||||
elif left_bools == {False}:
|
||||
if operator != 'and':
|
||||
types = context.eval_node(right)
|
||||
# Otherwise continue, because of uncertainty.
|
||||
|
||||
@@ -146,7 +146,7 @@ def detect_additional_paths(evaluator, script_path):
|
||||
|
||||
def _get_paths_from_buildout_script(evaluator, buildout_script_path):
|
||||
try:
|
||||
module_node = evaluator.grammar.parse(
|
||||
module_node = evaluator.parse(
|
||||
path=buildout_script_path,
|
||||
cache=True,
|
||||
cache_path=settings.cache_directory
|
||||
|
||||
@@ -4,11 +4,10 @@ from inspect import cleandoc
|
||||
from jedi._compatibility import literal_eval, force_unicode
|
||||
from parso.python import tree
|
||||
|
||||
_EXECUTE_NODES = set([
|
||||
'funcdef', 'classdef', 'import_from', 'import_name', 'test', 'or_test',
|
||||
'and_test', 'not_test', 'comparison', 'expr', 'xor_expr', 'and_expr',
|
||||
'shift_expr', 'arith_expr', 'atom_expr', 'term', 'factor', 'power', 'atom'
|
||||
])
|
||||
_EXECUTE_NODES = {'funcdef', 'classdef', 'import_from', 'import_name', 'test',
|
||||
'or_test', 'and_test', 'not_test', 'comparison', 'expr',
|
||||
'xor_expr', 'and_expr', 'shift_expr', 'arith_expr',
|
||||
'atom_expr', 'term', 'factor', 'power', 'atom'}
|
||||
|
||||
_FLOW_KEYWORDS = (
|
||||
'try', 'except', 'finally', 'else', 'if', 'elif', 'with', 'for', 'while'
|
||||
|
||||
+1
-1
@@ -89,7 +89,7 @@ def setup_readline(namespace_module=__main__):
|
||||
lines = split_lines(text)
|
||||
position = (len(lines), len(lines[-1]))
|
||||
name = get_on_completion_name(
|
||||
interpreter._get_module_node(),
|
||||
interpreter._module_node,
|
||||
lines,
|
||||
position
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user