forked from VimPlug/jedi
Replacing the types list with a types set. Some tests are failing, though.
This commit is contained in:
@@ -331,12 +331,13 @@ class Script(object):
|
|||||||
|
|
||||||
:rtype: list of :class:`classes.Definition`
|
:rtype: list of :class:`classes.Definition`
|
||||||
"""
|
"""
|
||||||
def resolve_import_paths(scopes):
|
def resolve_import_paths(definitions):
|
||||||
for s in set(scopes):
|
new_defs = list(definitions)
|
||||||
|
for s in definitions:
|
||||||
if isinstance(s, imports.ImportWrapper):
|
if isinstance(s, imports.ImportWrapper):
|
||||||
scopes.remove(s)
|
new_defs.remove(s)
|
||||||
scopes.update(resolve_import_paths(set(s.follow())))
|
new_defs += resolve_import_paths(set(s.follow()))
|
||||||
return scopes
|
return new_defs
|
||||||
|
|
||||||
goto_path = self._user_context.get_path_under_cursor()
|
goto_path = self._user_context.get_path_under_cursor()
|
||||||
context = self._user_context.get_context()
|
context = self._user_context.get_context()
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ class Evaluator(object):
|
|||||||
# only in for loops without clutter, because they are
|
# only in for loops without clutter, because they are
|
||||||
# predictable.
|
# predictable.
|
||||||
for r in types:
|
for r in types:
|
||||||
left = precedence.calculate(self, left, operator, [r])
|
left = precedence.calculate(self, left, operator, set([r]))
|
||||||
types = left
|
types = left
|
||||||
else:
|
else:
|
||||||
types = precedence.calculate(self, left, operator, types)
|
types = precedence.calculate(self, left, operator, types)
|
||||||
@@ -161,9 +161,9 @@ class Evaluator(object):
|
|||||||
|
|
||||||
def eval_element(self, element):
|
def eval_element(self, element):
|
||||||
if isinstance(element, iterable.AlreadyEvaluated):
|
if isinstance(element, iterable.AlreadyEvaluated):
|
||||||
return list(element)
|
return set(element)
|
||||||
elif isinstance(element, iterable.MergedNodes):
|
elif isinstance(element, iterable.MergedNodes):
|
||||||
return iterable.unite(self.eval_element(e) for e in element)
|
return set(iterable.unite(self.eval_element(e) for e in element))
|
||||||
|
|
||||||
parent = element.get_parent_until((tree.IfStmt, tree.IsScope))
|
parent = element.get_parent_until((tree.IfStmt, tree.IsScope))
|
||||||
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(parent)
|
predefined_if_name_dict = self.predefined_if_name_dict_dict.get(parent)
|
||||||
@@ -208,11 +208,11 @@ class Evaluator(object):
|
|||||||
for name_dict in name_dicts:
|
for name_dict in name_dicts:
|
||||||
name_dict[str(if_name)] = definitions
|
name_dict[str(if_name)] = definitions
|
||||||
if len(name_dicts) > 1:
|
if len(name_dicts) > 1:
|
||||||
result = []
|
result = set()
|
||||||
for name_dict in name_dicts:
|
for name_dict in name_dicts:
|
||||||
self.predefined_if_name_dict_dict[parent] = name_dict
|
self.predefined_if_name_dict_dict[parent] = name_dict
|
||||||
try:
|
try:
|
||||||
result += self._eval_element_not_cached(element)
|
result |= self._eval_element_not_cached(element)
|
||||||
finally:
|
finally:
|
||||||
del self.predefined_if_name_dict_dict[parent]
|
del self.predefined_if_name_dict_dict[parent]
|
||||||
return result
|
return result
|
||||||
@@ -235,13 +235,13 @@ class Evaluator(object):
|
|||||||
elif isinstance(element, tree.Keyword):
|
elif isinstance(element, tree.Keyword):
|
||||||
# For False/True/None
|
# For False/True/None
|
||||||
if element.value in ('False', 'True', 'None'):
|
if element.value in ('False', 'True', 'None'):
|
||||||
return [compiled.builtin.get_by_name(element.value)]
|
return set([compiled.builtin.get_by_name(element.value)])
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
elif element.isinstance(tree.Lambda):
|
elif element.isinstance(tree.Lambda):
|
||||||
return [er.LambdaWrapper(self, element)]
|
return set([er.LambdaWrapper(self, element)])
|
||||||
elif element.isinstance(er.LambdaWrapper):
|
elif element.isinstance(er.LambdaWrapper):
|
||||||
return [element] # TODO this is no real evaluation.
|
return set([element]) # TODO this is no real evaluation.
|
||||||
elif element.type == 'expr_stmt':
|
elif element.type == 'expr_stmt':
|
||||||
return self.eval_statement(element)
|
return self.eval_statement(element)
|
||||||
elif element.type == 'power':
|
elif element.type == 'power':
|
||||||
@@ -254,24 +254,24 @@ class Evaluator(object):
|
|||||||
return types
|
return types
|
||||||
elif element.type in ('testlist_star_expr', 'testlist',):
|
elif element.type in ('testlist_star_expr', 'testlist',):
|
||||||
# The implicit tuple in statements.
|
# The implicit tuple in statements.
|
||||||
return [iterable.ImplicitTuple(self, element)]
|
return set([iterable.ImplicitTuple(self, element)])
|
||||||
elif element.type in ('not_test', 'factor'):
|
elif element.type in ('not_test', 'factor'):
|
||||||
types = self.eval_element(element.children[-1])
|
types = self.eval_element(element.children[-1])
|
||||||
for operator in element.children[:-1]:
|
for operator in element.children[:-1]:
|
||||||
types = list(precedence.factor_calculate(self, types, operator))
|
types = precedence.factor_calculate(self, types, operator)
|
||||||
return types
|
return types
|
||||||
elif element.type == 'test':
|
elif element.type == 'test':
|
||||||
# `x if foo else y` case.
|
# `x if foo else y` case.
|
||||||
return (self.eval_element(element.children[0]) +
|
return (self.eval_element(element.children[0]) |
|
||||||
self.eval_element(element.children[-1]))
|
self.eval_element(element.children[-1]))
|
||||||
elif element.type == 'operator':
|
elif element.type == 'operator':
|
||||||
# Must be an ellipsis, other operators are not evaluated.
|
# Must be an ellipsis, other operators are not evaluated.
|
||||||
return [] # Ignore for now.
|
return set() # Ignore for now.
|
||||||
elif element.type == 'dotted_name':
|
elif element.type == 'dotted_name':
|
||||||
types = self._eval_atom(element.children[0])
|
types = self._eval_atom(element.children[0])
|
||||||
for next_name in element.children[2::2]:
|
for next_name in element.children[2::2]:
|
||||||
types = list(chain.from_iterable(self.find_types(typ, next_name)
|
types = set(chain.from_iterable(self.find_types(typ, next_name)
|
||||||
for typ in types))
|
for typ in types))
|
||||||
return types
|
return types
|
||||||
else:
|
else:
|
||||||
return precedence.calculate_children(self, element.children)
|
return precedence.calculate_children(self, element.children)
|
||||||
@@ -294,7 +294,7 @@ class Evaluator(object):
|
|||||||
stmt = atom
|
stmt = atom
|
||||||
return self.find_types(scope, atom, stmt.start_pos, search_global=True)
|
return self.find_types(scope, atom, stmt.start_pos, search_global=True)
|
||||||
elif isinstance(atom, tree.Literal):
|
elif isinstance(atom, tree.Literal):
|
||||||
return [compiled.create(self, atom.eval())]
|
return set([compiled.create(self, atom.eval())])
|
||||||
else:
|
else:
|
||||||
c = atom.children
|
c = atom.children
|
||||||
# Parentheses without commas are not tuples.
|
# Parentheses without commas are not tuples.
|
||||||
@@ -308,20 +308,20 @@ class Evaluator(object):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
if isinstance(comp_for, tree.CompFor):
|
if isinstance(comp_for, tree.CompFor):
|
||||||
return [iterable.Comprehension.from_atom(self, atom)]
|
return set([iterable.Comprehension.from_atom(self, atom)])
|
||||||
return [iterable.Array(self, atom)]
|
return set([iterable.Array(self, atom)])
|
||||||
|
|
||||||
def eval_trailer(self, types, trailer):
|
def eval_trailer(self, types, trailer):
|
||||||
trailer_op, node = trailer.children[:2]
|
trailer_op, node = trailer.children[:2]
|
||||||
if node == ')': # `arglist` is optional.
|
if node == ')': # `arglist` is optional.
|
||||||
node = ()
|
node = ()
|
||||||
new_types = []
|
new_types = set()
|
||||||
for typ in types:
|
for typ in types:
|
||||||
debug.dbg('eval_trailer: %s in scope %s', trailer, typ)
|
debug.dbg('eval_trailer: %s in scope %s', trailer, typ)
|
||||||
if trailer_op == '.':
|
if trailer_op == '.':
|
||||||
new_types += self.find_types(typ, node)
|
new_types |= self.find_types(typ, node)
|
||||||
elif trailer_op == '(':
|
elif trailer_op == '(':
|
||||||
new_types += self.execute(typ, node, trailer)
|
new_types |= self.execute(typ, node, trailer)
|
||||||
elif trailer_op == '[':
|
elif trailer_op == '[':
|
||||||
try:
|
try:
|
||||||
get = typ.get_index_types
|
get = typ.get_index_types
|
||||||
@@ -329,7 +329,7 @@ class Evaluator(object):
|
|||||||
debug.warning("TypeError: '%s' object is not subscriptable"
|
debug.warning("TypeError: '%s' object is not subscriptable"
|
||||||
% typ)
|
% typ)
|
||||||
else:
|
else:
|
||||||
new_types += get(self, node)
|
new_types |= get(self, node)
|
||||||
return new_types
|
return new_types
|
||||||
|
|
||||||
def execute_evaluated(self, obj, *args):
|
def execute_evaluated(self, obj, *args):
|
||||||
@@ -362,7 +362,7 @@ class Evaluator(object):
|
|||||||
func = obj.py__call__
|
func = obj.py__call__
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
debug.warning("no execution possible %s", obj)
|
debug.warning("no execution possible %s", obj)
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
types = func(self, arguments)
|
types = func(self, arguments)
|
||||||
debug.dbg('execute result: %s in %s', types, obj)
|
debug.dbg('execute result: %s in %s', types, obj)
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ class CompiledObject(Base):
|
|||||||
def actual(evaluator, params):
|
def actual(evaluator, params):
|
||||||
if inspect.isclass(self.obj):
|
if inspect.isclass(self.obj):
|
||||||
from jedi.evaluate.representation import Instance
|
from jedi.evaluate.representation import Instance
|
||||||
return [Instance(evaluator, self, params)]
|
return set([Instance(evaluator, self, params)])
|
||||||
else:
|
else:
|
||||||
return list(self._execute_function(evaluator, params))
|
return set(self._execute_function(evaluator, params))
|
||||||
|
|
||||||
# Might raise an AttributeError, which is intentional.
|
# Might raise an AttributeError, which is intentional.
|
||||||
self.obj.__call__
|
self.obj.__call__
|
||||||
@@ -173,12 +173,12 @@ class CompiledObject(Base):
|
|||||||
# AttributeError.
|
# AttributeError.
|
||||||
if not hasattr(self.obj, '__getitem__'):
|
if not hasattr(self.obj, '__getitem__'):
|
||||||
debug.warning('Tried to call __getitem__ on non-iterable.')
|
debug.warning('Tried to call __getitem__ on non-iterable.')
|
||||||
return []
|
return set()
|
||||||
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
if type(self.obj) not in (str, list, tuple, unicode, bytes, bytearray, dict):
|
||||||
# Get rid of side effects, we won't call custom `__getitem__`s.
|
# Get rid of side effects, we won't call custom `__getitem__`s.
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
result = []
|
result = set()
|
||||||
from jedi.evaluate.iterable import create_indexes_or_slices
|
from jedi.evaluate.iterable import create_indexes_or_slices
|
||||||
for typ in create_indexes_or_slices(evaluator, index_array):
|
for typ in create_indexes_or_slices(evaluator, index_array):
|
||||||
index = None
|
index = None
|
||||||
@@ -188,9 +188,9 @@ class CompiledObject(Base):
|
|||||||
except (KeyError, IndexError, TypeError, AttributeError):
|
except (KeyError, IndexError, TypeError, AttributeError):
|
||||||
# Just try, we don't care if it fails, except for slices.
|
# Just try, we don't care if it fails, except for slices.
|
||||||
if isinstance(index, slice):
|
if isinstance(index, slice):
|
||||||
result.append(self)
|
result.add(self)
|
||||||
else:
|
else:
|
||||||
result.append(CompiledObject(new))
|
result.add(CompiledObject(new))
|
||||||
if not result:
|
if not result:
|
||||||
try:
|
try:
|
||||||
for obj in self.obj:
|
for obj in self.obj:
|
||||||
|
|||||||
@@ -176,11 +176,11 @@ def _execute_array_values(evaluator, array):
|
|||||||
def follow_param(evaluator, param):
|
def follow_param(evaluator, param):
|
||||||
func = param.parent_function
|
func = param.parent_function
|
||||||
|
|
||||||
return [p
|
return set(
|
||||||
for param_str in _search_param_in_docstr(func.raw_doc,
|
[p for param_str in _search_param_in_docstr(func.raw_doc,
|
||||||
str(param.name))
|
str(param.name))
|
||||||
for p in _evaluate_for_statement_string(evaluator, param_str,
|
for p in _evaluate_for_statement_string(evaluator, param_str,
|
||||||
param.get_parent_until())]
|
param.get_parent_until())])
|
||||||
|
|
||||||
|
|
||||||
@memoize_default(None, evaluator_is_first_arg=True)
|
@memoize_default(None, evaluator_is_first_arg=True)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def search_params(evaluator, param):
|
|||||||
names = [n for n in search_function_call(evaluator, func)
|
names = [n for n in search_function_call(evaluator, func)
|
||||||
if n.value == param.name.value]
|
if n.value == param.name.value]
|
||||||
# Evaluate the ExecutedParams to types.
|
# Evaluate the ExecutedParams to types.
|
||||||
result = list(chain.from_iterable(n.parent.eval(evaluator) for n in names))
|
result = set(chain.from_iterable(n.parent.eval(evaluator) for n in names))
|
||||||
debug.dbg('Dynamic param result %s', result)
|
debug.dbg('Dynamic param result %s', result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ class NameFinder(object):
|
|||||||
elif isinstance(scope, tree.IfStmt):
|
elif isinstance(scope, tree.IfStmt):
|
||||||
try:
|
try:
|
||||||
name_dict = self._evaluator.predefined_if_name_dict_dict[scope]
|
name_dict = self._evaluator.predefined_if_name_dict_dict[scope]
|
||||||
types = name_dict[str(self.name_str)]
|
types = set(name_dict[str(self.name_str)])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
@@ -177,7 +177,7 @@ class NameFinder(object):
|
|||||||
check = flow_analysis.break_check(self._evaluator, self.scope,
|
check = flow_analysis.break_check(self._evaluator, self.scope,
|
||||||
origin_scope)
|
origin_scope)
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
self._found_predefined_if_name = []
|
self._found_predefined_if_name = set()
|
||||||
else:
|
else:
|
||||||
self._found_predefined_if_name = types
|
self._found_predefined_if_name = types
|
||||||
break
|
break
|
||||||
@@ -230,7 +230,7 @@ class NameFinder(object):
|
|||||||
|
|
||||||
def _check_getattr(self, inst):
|
def _check_getattr(self, inst):
|
||||||
"""Checks for both __getattr__ and __getattribute__ methods"""
|
"""Checks for both __getattr__ and __getattribute__ methods"""
|
||||||
result = []
|
result = set()
|
||||||
# str is important, because it shouldn't be `Name`!
|
# str is important, because it shouldn't be `Name`!
|
||||||
name = compiled.create(self._evaluator, str(self.name_str))
|
name = compiled.create(self._evaluator, str(self.name_str))
|
||||||
with common.ignored(KeyError):
|
with common.ignored(KeyError):
|
||||||
@@ -285,51 +285,50 @@ class NameFinder(object):
|
|||||||
if not isinstance(name_scope, (er.Instance, tree.Class)):
|
if not isinstance(name_scope, (er.Instance, tree.Class)):
|
||||||
return types
|
return types
|
||||||
|
|
||||||
result = []
|
result = set()
|
||||||
for r in types:
|
for r in types:
|
||||||
try:
|
try:
|
||||||
desc_return = r.get_descriptor_returns
|
desc_return = r.get_descriptor_returns
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
result.append(r)
|
result.add(r)
|
||||||
else:
|
else:
|
||||||
result += desc_return(self.scope)
|
result |= desc_return(self.scope)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@memoize_default([], evaluator_is_first_arg=True)
|
@memoize_default(set(), evaluator_is_first_arg=True)
|
||||||
def _name_to_types(evaluator, name, scope):
|
def _name_to_types(evaluator, name, scope):
|
||||||
types = []
|
types = set()
|
||||||
typ = name.get_definition()
|
typ = name.get_definition()
|
||||||
if typ.isinstance(tree.ForStmt, tree.CompFor):
|
if typ.isinstance(tree.ForStmt, tree.CompFor):
|
||||||
for_types = iterable.get_iterator_types(evaluator, typ.children[3])
|
for_types = iterable.get_iterator_types(evaluator, typ.children[3])
|
||||||
types += check_tuple_assignments(for_types, name)
|
types |= check_tuple_assignments(for_types, name)
|
||||||
elif isinstance(typ, tree.Param):
|
elif isinstance(typ, tree.Param):
|
||||||
types += _eval_param(evaluator, typ, scope)
|
types |= _eval_param(evaluator, typ, scope)
|
||||||
elif typ.isinstance(tree.ExprStmt):
|
elif typ.isinstance(tree.ExprStmt):
|
||||||
types += _remove_statements(evaluator, typ, name)
|
types |= _remove_statements(evaluator, typ, name)
|
||||||
elif typ.isinstance(tree.WithStmt):
|
elif typ.isinstance(tree.WithStmt):
|
||||||
types += evaluator.eval_element(typ.node_from_name(name))
|
types |= evaluator.eval_element(typ.node_from_name(name))
|
||||||
elif isinstance(typ, tree.Import):
|
elif isinstance(typ, tree.Import):
|
||||||
types += imports.ImportWrapper(evaluator, name).follow()
|
types |= imports.ImportWrapper(evaluator, name).follow()
|
||||||
elif isinstance(typ, tree.GlobalStmt):
|
elif isinstance(typ, tree.GlobalStmt):
|
||||||
# TODO theoretically we shouldn't be using search_global here, it
|
# TODO theoretically we shouldn't be using search_global here, it
|
||||||
# doesn't make sense, because it's a local search (for that name)!
|
# doesn't make sense, because it's a local search (for that name)!
|
||||||
# However, globals are not that important and resolving them doesn't
|
# However, globals are not that important and resolving them doesn't
|
||||||
# guarantee correctness in any way, because we don't check for when
|
# guarantee correctness in any way, because we don't check for when
|
||||||
# something is executed.
|
# something is executed.
|
||||||
types += evaluator.find_types(typ.get_parent_scope(), str(name),
|
types |= evaluator.find_types(typ.get_parent_scope(), str(name),
|
||||||
search_global=True)
|
search_global=True)
|
||||||
elif isinstance(typ, tree.TryStmt):
|
elif isinstance(typ, tree.TryStmt):
|
||||||
# TODO an exception can also be a tuple. Check for those.
|
# TODO an exception can also be a tuple. Check for those.
|
||||||
# TODO check for types that are not classes and add it to
|
# TODO check for types that are not classes and add it to
|
||||||
# the static analysis report.
|
# the static analysis report.
|
||||||
exceptions = evaluator.eval_element(name.prev_sibling().prev_sibling())
|
exceptions = evaluator.eval_element(name.prev_sibling().prev_sibling())
|
||||||
types = list(chain.from_iterable(
|
types = set(chain.from_iterable(evaluator.execute(t) for t in exceptions))
|
||||||
evaluator.execute(t) for t in exceptions))
|
|
||||||
else:
|
else:
|
||||||
if typ.isinstance(er.Function):
|
if typ.isinstance(er.Function):
|
||||||
typ = typ.get_decorated_func()
|
typ = typ.get_decorated_func()
|
||||||
types.append(typ)
|
types.add(typ)
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
|
||||||
@@ -340,7 +339,7 @@ def _remove_statements(evaluator, stmt, name):
|
|||||||
Due to lazy evaluation, statements like a = func; b = a; b() have to be
|
Due to lazy evaluation, statements like a = func; b = a; b() have to be
|
||||||
evaluated.
|
evaluated.
|
||||||
"""
|
"""
|
||||||
types = []
|
types = set()
|
||||||
# Remove the statement docstr stuff for now, that has to be
|
# Remove the statement docstr stuff for now, that has to be
|
||||||
# implemented with the evaluator class.
|
# implemented with the evaluator class.
|
||||||
#if stmt.docstr:
|
#if stmt.docstr:
|
||||||
@@ -351,18 +350,18 @@ def _remove_statements(evaluator, stmt, name):
|
|||||||
check_instance = stmt.instance
|
check_instance = stmt.instance
|
||||||
stmt = stmt.var
|
stmt = stmt.var
|
||||||
|
|
||||||
types += evaluator.eval_statement(stmt, seek_name=name)
|
types |= evaluator.eval_statement(stmt, seek_name=name)
|
||||||
|
|
||||||
if check_instance is not None:
|
if check_instance is not None:
|
||||||
# class renames
|
# class renames
|
||||||
types = [er.get_instance_el(evaluator, check_instance, a, True)
|
types = set([er.get_instance_el(evaluator, check_instance, a, True)
|
||||||
if isinstance(a, (er.Function, tree.Function))
|
if isinstance(a, (er.Function, tree.Function))
|
||||||
else a for a in types]
|
else a for a in types])
|
||||||
return types
|
return types
|
||||||
|
|
||||||
|
|
||||||
def _eval_param(evaluator, param, scope):
|
def _eval_param(evaluator, param, scope):
|
||||||
res_new = []
|
res_new = set()
|
||||||
func = param.get_parent_scope()
|
func = param.get_parent_scope()
|
||||||
|
|
||||||
cls = func.parent.get_parent_until((tree.Class, tree.Function))
|
cls = func.parent.get_parent_until((tree.Class, tree.Function))
|
||||||
@@ -373,11 +372,11 @@ def _eval_param(evaluator, param, scope):
|
|||||||
# This is where we add self - if it has never been
|
# This is where we add self - if it has never been
|
||||||
# instantiated.
|
# instantiated.
|
||||||
if isinstance(scope, er.InstanceElement):
|
if isinstance(scope, er.InstanceElement):
|
||||||
res_new.append(scope.instance)
|
res_new.add(scope.instance)
|
||||||
else:
|
else:
|
||||||
inst = er.Instance(evaluator, evaluator.wrap(cls),
|
inst = er.Instance(evaluator, evaluator.wrap(cls),
|
||||||
Arguments(evaluator, ()), is_generated=True)
|
Arguments(evaluator, ()), is_generated=True)
|
||||||
res_new.append(inst)
|
res_new.add(inst)
|
||||||
return res_new
|
return res_new
|
||||||
|
|
||||||
# Instances are typically faked, if the instance is not called from
|
# Instances are typically faked, if the instance is not called from
|
||||||
@@ -392,17 +391,17 @@ def _eval_param(evaluator, param, scope):
|
|||||||
return doc_params
|
return doc_params
|
||||||
|
|
||||||
if isinstance(param, ExecutedParam):
|
if isinstance(param, ExecutedParam):
|
||||||
return res_new + param.eval(evaluator)
|
return res_new | param.eval(evaluator)
|
||||||
else:
|
else:
|
||||||
# Param owns no information itself.
|
# Param owns no information itself.
|
||||||
res_new += dynamic.search_params(evaluator, param)
|
res_new |= dynamic.search_params(evaluator, param)
|
||||||
if not res_new:
|
if not res_new:
|
||||||
if param.stars:
|
if param.stars:
|
||||||
t = 'tuple' if param.stars == 1 else 'dict'
|
t = 'tuple' if param.stars == 1 else 'dict'
|
||||||
typ = evaluator.find_types(compiled.builtin, t)[0]
|
typ = list(evaluator.find_types(compiled.builtin, t))[0]
|
||||||
res_new = evaluator.execute(typ)
|
res_new = evaluator.execute(typ)
|
||||||
if param.default:
|
if param.default:
|
||||||
res_new += evaluator.eval_element(param.default)
|
res_new |= evaluator.eval_element(param.default)
|
||||||
return res_new
|
return res_new
|
||||||
|
|
||||||
|
|
||||||
@@ -418,7 +417,7 @@ def check_flow_information(evaluator, flow, search_name, pos):
|
|||||||
if not settings.dynamic_flow_information:
|
if not settings.dynamic_flow_information:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
result = []
|
result = set()
|
||||||
if flow.is_scope():
|
if flow.is_scope():
|
||||||
# Check for asserts.
|
# Check for asserts.
|
||||||
try:
|
try:
|
||||||
@@ -462,12 +461,12 @@ def _check_isinstance_type(evaluator, element, search_name):
|
|||||||
call = helpers.call_of_name(search_name)
|
call = helpers.call_of_name(search_name)
|
||||||
assert name.get_code() == call.get_code()
|
assert name.get_code() == call.get_code()
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
result = []
|
result = set()
|
||||||
for typ in evaluator.eval_element(classes):
|
for typ in evaluator.eval_element(classes):
|
||||||
for typ in (typ.values() if isinstance(typ, iterable.Array) else [typ]):
|
for typ in (typ.values() if isinstance(typ, iterable.Array) else [typ]):
|
||||||
result += evaluator.execute(typ)
|
result |= evaluator.execute(typ)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -546,7 +545,7 @@ def check_tuple_assignments(types, name):
|
|||||||
Checks if tuples are assigned.
|
Checks if tuples are assigned.
|
||||||
"""
|
"""
|
||||||
for index in name.assignment_indexes():
|
for index in name.assignment_indexes():
|
||||||
new_types = []
|
new_types = set()
|
||||||
for r in types:
|
for r in types:
|
||||||
try:
|
try:
|
||||||
func = r.get_exact_index_types
|
func = r.get_exact_index_types
|
||||||
@@ -555,7 +554,7 @@ def check_tuple_assignments(types, name):
|
|||||||
index, types, name)
|
index, types, name)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
new_types += func(index)
|
new_types |= func(index)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
types = new_types
|
types = new_types
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ class ImportWrapper(tree.Base):
|
|||||||
def follow(self, is_goto=False):
|
def follow(self, is_goto=False):
|
||||||
if self._evaluator.recursion_detector.push_stmt(self._import):
|
if self._evaluator.recursion_detector.push_stmt(self._import):
|
||||||
# check recursion
|
# check recursion
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
module = self._evaluator.wrap(self._import.get_parent_until())
|
module = self._evaluator.wrap(self._import.get_parent_until())
|
||||||
@@ -97,7 +97,7 @@ class ImportWrapper(tree.Base):
|
|||||||
# scopes = [NestedImportModule(module, self._import)]
|
# scopes = [NestedImportModule(module, self._import)]
|
||||||
|
|
||||||
if from_import_name is not None:
|
if from_import_name is not None:
|
||||||
types = list(chain.from_iterable(
|
types = set(chain.from_iterable(
|
||||||
self._evaluator.find_types(t, unicode(from_import_name),
|
self._evaluator.find_types(t, unicode(from_import_name),
|
||||||
is_goto=is_goto)
|
is_goto=is_goto)
|
||||||
for t in types))
|
for t in types))
|
||||||
@@ -109,11 +109,11 @@ class ImportWrapper(tree.Base):
|
|||||||
types = importer.follow()
|
types = importer.follow()
|
||||||
# goto only accepts `Name`
|
# goto only accepts `Name`
|
||||||
if is_goto:
|
if is_goto:
|
||||||
types = [s.name for s in types]
|
types = set(s.name for s in types)
|
||||||
else:
|
else:
|
||||||
# goto only accepts `Name`
|
# goto only accepts `Name`
|
||||||
if is_goto:
|
if is_goto:
|
||||||
types = [s.name for s in types]
|
types = set(s.name for s in types)
|
||||||
|
|
||||||
debug.dbg('after import: %s', types)
|
debug.dbg('after import: %s', types)
|
||||||
finally:
|
finally:
|
||||||
@@ -248,7 +248,7 @@ class Importer(object):
|
|||||||
@memoize_default(NO_DEFAULT)
|
@memoize_default(NO_DEFAULT)
|
||||||
def follow(self):
|
def follow(self):
|
||||||
if not self.import_path:
|
if not self.import_path:
|
||||||
return []
|
return set()
|
||||||
return self._do_import(self.import_path, self.sys_path_with_modifications())
|
return self._do_import(self.import_path, self.sys_path_with_modifications())
|
||||||
|
|
||||||
def _do_import(self, import_path, sys_path):
|
def _do_import(self, import_path, sys_path):
|
||||||
@@ -271,7 +271,7 @@ class Importer(object):
|
|||||||
|
|
||||||
module_name = '.'.join(import_parts)
|
module_name = '.'.join(import_parts)
|
||||||
try:
|
try:
|
||||||
return [self._evaluator.modules[module_name]]
|
return set([self._evaluator.modules[module_name]])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -280,11 +280,11 @@ class Importer(object):
|
|||||||
# the module cache.
|
# the module cache.
|
||||||
bases = self._do_import(import_path[:-1], sys_path)
|
bases = self._do_import(import_path[:-1], sys_path)
|
||||||
if not bases:
|
if not bases:
|
||||||
return []
|
return set()
|
||||||
# We can take the first element, because only the os special
|
# We can take the first element, because only the os special
|
||||||
# case yields multiple modules, which is not important for
|
# case yields multiple modules, which is not important for
|
||||||
# further imports.
|
# further imports.
|
||||||
base = bases[0]
|
base = list(bases)[0]
|
||||||
|
|
||||||
# This is a huge exception, we follow a nested import
|
# This is a huge exception, we follow a nested import
|
||||||
# ``os.path``, because it's a very important one in Python
|
# ``os.path``, because it's a very important one in Python
|
||||||
@@ -301,7 +301,7 @@ class Importer(object):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
# The module is not a package.
|
# The module is not a package.
|
||||||
_add_error(self._evaluator, import_path[-1])
|
_add_error(self._evaluator, import_path[-1])
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
debug.dbg('search_module %s in paths %s', module_name, paths)
|
debug.dbg('search_module %s in paths %s', module_name, paths)
|
||||||
for path in paths:
|
for path in paths:
|
||||||
@@ -315,7 +315,7 @@ class Importer(object):
|
|||||||
module_path = None
|
module_path = None
|
||||||
if module_path is None:
|
if module_path is None:
|
||||||
_add_error(self._evaluator, import_path[-1])
|
_add_error(self._evaluator, import_path[-1])
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
debug.dbg('search_module %s in %s', import_parts[-1], self.file_path)
|
debug.dbg('search_module %s in %s', import_parts[-1], self.file_path)
|
||||||
@@ -330,7 +330,7 @@ class Importer(object):
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
# The module is not a package.
|
# The module is not a package.
|
||||||
_add_error(self._evaluator, import_path[-1])
|
_add_error(self._evaluator, import_path[-1])
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
source = None
|
source = None
|
||||||
if is_pkg:
|
if is_pkg:
|
||||||
@@ -347,7 +347,7 @@ class Importer(object):
|
|||||||
module = _load_module(self._evaluator, module_path, source, sys_path)
|
module = _load_module(self._evaluator, module_path, source, sys_path)
|
||||||
|
|
||||||
self._evaluator.modules[module_name] = module
|
self._evaluator.modules[module_name] = module
|
||||||
return [module]
|
return set([module])
|
||||||
|
|
||||||
def _generate_name(self, name):
|
def _generate_name(self, name):
|
||||||
return helpers.FakeName(name, parent=self.module)
|
return helpers.FakeName(name, parent=self.module)
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ class GeneratorMixin(object):
|
|||||||
def get_index_types(self, evaluator, index_array):
|
def get_index_types(self, evaluator, index_array):
|
||||||
#debug.warning('Tried to get array access on a generator: %s', self)
|
#debug.warning('Tried to get array access on a generator: %s', self)
|
||||||
analysis.add(self._evaluator, 'type-error-generator', index_array)
|
analysis.add(self._evaluator, 'type-error-generator', index_array)
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
def get_exact_index_types(self, index):
|
def get_exact_index_types(self, index):
|
||||||
"""
|
"""
|
||||||
Exact lookups are used for tuple lookups, which are perfectly fine if
|
Exact lookups are used for tuple lookups, which are perfectly fine if
|
||||||
used with generators.
|
used with generators.
|
||||||
"""
|
"""
|
||||||
return [self.iter_content()[index]]
|
return set([list(self.iter_content())[index]])
|
||||||
|
|
||||||
def py__bool__(self):
|
def py__bool__(self):
|
||||||
return True
|
return True
|
||||||
@@ -145,7 +145,9 @@ class Comprehension(IterableWrapper):
|
|||||||
return helpers.deep_ast_copy(comprehension.children[0], parent=last_comp)
|
return helpers.deep_ast_copy(comprehension.children[0], parent=last_comp)
|
||||||
|
|
||||||
def get_exact_index_types(self, index):
|
def get_exact_index_types(self, index):
|
||||||
return [self._evaluator.eval_element(self.eval_node())[index]]
|
# TODO this will return a random type (depending on the current set
|
||||||
|
# hash function).
|
||||||
|
return set([list(self._evaluator.eval_element(self.eval_node()))[index]])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s of %s>" % (type(self).__name__, self._atom)
|
return "<%s of %s>" % (type(self).__name__, self._atom)
|
||||||
@@ -155,9 +157,9 @@ class ArrayMixin(object):
|
|||||||
@memoize_default()
|
@memoize_default()
|
||||||
def names_dicts(self, search_global=False): # Always False.
|
def names_dicts(self, search_global=False): # Always False.
|
||||||
# `array.type` is a string with the type, e.g. 'list'.
|
# `array.type` is a string with the type, e.g. 'list'.
|
||||||
scope = self._evaluator.find_types(compiled.builtin, self.type)[0]
|
scope = list(self._evaluator.find_types(compiled.builtin, self.type))[0]
|
||||||
# builtins only have one class -> [0]
|
# builtins only have one class -> [0]
|
||||||
scope = self._evaluator.execute(scope, (AlreadyEvaluated((self,)),))[0]
|
scope = list(self._evaluator.execute(scope, (AlreadyEvaluated((self,)),)))[0]
|
||||||
return scope.names_dicts(search_global)
|
return scope.names_dicts(search_global)
|
||||||
|
|
||||||
def py__bool__(self):
|
def py__bool__(self):
|
||||||
@@ -217,23 +219,23 @@ class Array(IterableWrapper, ArrayMixin):
|
|||||||
"""
|
"""
|
||||||
indexes = create_indexes_or_slices(evaluator, index)
|
indexes = create_indexes_or_slices(evaluator, index)
|
||||||
lookup_done = False
|
lookup_done = False
|
||||||
types = []
|
types = set()
|
||||||
for index in indexes:
|
for index in indexes:
|
||||||
if isinstance(index, Slice):
|
if isinstance(index, Slice):
|
||||||
types += [self]
|
types.add(self)
|
||||||
lookup_done = True
|
lookup_done = True
|
||||||
elif isinstance(index, compiled.CompiledObject) \
|
elif isinstance(index, compiled.CompiledObject) \
|
||||||
and isinstance(index.obj, (int, str, unicode)):
|
and isinstance(index.obj, (int, str, unicode)):
|
||||||
with ignored(KeyError, IndexError, TypeError):
|
with ignored(KeyError, IndexError, TypeError):
|
||||||
types += self.get_exact_index_types(index.obj)
|
types |= self.get_exact_index_types(index.obj)
|
||||||
lookup_done = True
|
lookup_done = True
|
||||||
|
|
||||||
return types if lookup_done else self.values()
|
return types if lookup_done else self.values()
|
||||||
|
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
def values(self):
|
def values(self):
|
||||||
result = unite(self._evaluator.eval_element(v) for v in self._values())
|
result = set(unite(self._evaluator.eval_element(v) for v in self._values()))
|
||||||
result += check_array_additions(self._evaluator, self)
|
result |= check_array_additions(self._evaluator, self)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_exact_index_types(self, mixed_index):
|
def get_exact_index_types(self, mixed_index):
|
||||||
@@ -353,7 +355,7 @@ class FakeDict(_FakeArray):
|
|||||||
self._dct = dct
|
self._dct = dct
|
||||||
|
|
||||||
def get_exact_index_types(self, index):
|
def get_exact_index_types(self, index):
|
||||||
return unite(self._evaluator.eval_element(v) for v in self._dct[index])
|
return set(unite(self._evaluator.eval_element(v) for v in self._dct[index]))
|
||||||
|
|
||||||
def _items(self):
|
def _items(self):
|
||||||
return self._dct.items()
|
return self._dct.items()
|
||||||
@@ -368,7 +370,7 @@ class MergedArray(_FakeArray):
|
|||||||
raise IndexError
|
raise IndexError
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return unite((a.values() for a in self._arrays))
|
return set(unite((a.values() for a in self._arrays)))
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
for array in self._arrays:
|
for array in self._arrays:
|
||||||
@@ -397,24 +399,24 @@ def get_iterator_types(evaluator, element):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
debug.warning('iterators: No __iter__ method found.')
|
debug.warning('iterators: No __iter__ method found.')
|
||||||
|
|
||||||
result = []
|
result = set()
|
||||||
from jedi.evaluate.representation import Instance
|
from jedi.evaluate.representation import Instance
|
||||||
for it in iterators:
|
for it in iterators:
|
||||||
if isinstance(it, Array):
|
if isinstance(it, Array):
|
||||||
# Array is a little bit special, since this is an internal array,
|
# Array is a little bit special, since this is an internal array,
|
||||||
# but there's also the list builtin, which is another thing.
|
# but there's also the list builtin, which is another thing.
|
||||||
result += it.values()
|
result |= it.values()
|
||||||
elif isinstance(it, Instance):
|
elif isinstance(it, Instance):
|
||||||
# __iter__ returned an instance.
|
# __iter__ returned an instance.
|
||||||
name = '__next__' if is_py3 else 'next'
|
name = '__next__' if is_py3 else 'next'
|
||||||
try:
|
try:
|
||||||
result += it.execute_subscope_by_name(name)
|
result |= it.execute_subscope_by_name(name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
debug.warning('Instance has no __next__ function in %s.', it)
|
debug.warning('Instance has no __next__ function in %s.', it)
|
||||||
else:
|
else:
|
||||||
# TODO this is not correct, __iter__ can return arbitrary input!
|
# TODO this is not correct, __iter__ can return arbitrary input!
|
||||||
# Is a generator.
|
# Is a generator.
|
||||||
result += it.iter_content()
|
result |= it.iter_content()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -422,7 +424,7 @@ def check_array_additions(evaluator, array):
|
|||||||
""" Just a mapper function for the internal _check_array_additions """
|
""" Just a mapper function for the internal _check_array_additions """
|
||||||
if array.type not in ('list', 'set'):
|
if array.type not in ('list', 'set'):
|
||||||
# TODO also check for dict updates
|
# TODO also check for dict updates
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
is_list = array.type == 'list'
|
is_list = array.type == 'list'
|
||||||
try:
|
try:
|
||||||
@@ -431,7 +433,7 @@ def check_array_additions(evaluator, array):
|
|||||||
# If there's no get_parent_until, it's a FakeSequence or another Fake
|
# If there's no get_parent_until, it's a FakeSequence or another Fake
|
||||||
# type. Those fake types are used inside Jedi's engine. No values may
|
# type. Those fake types are used inside Jedi's engine. No values may
|
||||||
# be added to those after their creation.
|
# be added to those after their creation.
|
||||||
return []
|
return set()
|
||||||
return _check_array_additions(evaluator, array, current_module, is_list)
|
return _check_array_additions(evaluator, array, current_module, is_list)
|
||||||
|
|
||||||
|
|
||||||
@@ -444,19 +446,19 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
|
|||||||
>>> a.append(1)
|
>>> a.append(1)
|
||||||
"""
|
"""
|
||||||
if not settings.dynamic_array_additions or isinstance(module, compiled.CompiledObject):
|
if not settings.dynamic_array_additions or isinstance(module, compiled.CompiledObject):
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
def check_additions(arglist, add_name):
|
def check_additions(arglist, add_name):
|
||||||
params = list(param.Arguments(evaluator, arglist).unpack())
|
params = list(param.Arguments(evaluator, arglist).unpack())
|
||||||
result = []
|
result = set()
|
||||||
if add_name in ['insert']:
|
if add_name in ['insert']:
|
||||||
params = params[1:]
|
params = params[1:]
|
||||||
if add_name in ['append', 'add', 'insert']:
|
if add_name in ['append', 'add', 'insert']:
|
||||||
for key, nodes in params:
|
for key, nodes in params:
|
||||||
result += unite(evaluator.eval_element(node) for node in nodes)
|
result |= set(unite(evaluator.eval_element(node) for node in nodes))
|
||||||
elif add_name in ['extend', 'update']:
|
elif add_name in ['extend', 'update']:
|
||||||
for key, nodes in params:
|
for key, nodes in params:
|
||||||
result += unite(get_iterator_types(evaluator, node) for node in nodes)
|
result |= set(unite(get_iterator_types(evaluator, node) for node in nodes))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
from jedi.evaluate import representation as er, param
|
from jedi.evaluate import representation as er, param
|
||||||
@@ -480,7 +482,7 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
|
|||||||
search_names = ['append', 'extend', 'insert'] if is_list else ['add', 'update']
|
search_names = ['append', 'extend', 'insert'] if is_list else ['add', 'update']
|
||||||
comp_arr_parent = get_execution_parent(compare_array)
|
comp_arr_parent = get_execution_parent(compare_array)
|
||||||
|
|
||||||
added_types = []
|
added_types = set()
|
||||||
for add_name in search_names:
|
for add_name in search_names:
|
||||||
try:
|
try:
|
||||||
possible_names = module.used_names[add_name]
|
possible_names = module.used_names[add_name]
|
||||||
@@ -525,7 +527,7 @@ def _check_array_additions(evaluator, compare_array, module, is_list):
|
|||||||
continue
|
continue
|
||||||
if compare_array in evaluator.eval_element(power):
|
if compare_array in evaluator.eval_element(power):
|
||||||
# The arrays match. Now add the results
|
# The arrays match. Now add the results
|
||||||
added_types += check_additions(execution_trailer.children[1], add_name)
|
added_types |= check_additions(execution_trailer.children[1], add_name)
|
||||||
|
|
||||||
evaluator.recursion_detector.pop_stmt()
|
evaluator.recursion_detector.pop_stmt()
|
||||||
# reset settings
|
# reset settings
|
||||||
@@ -564,14 +566,14 @@ class ArrayInstance(IterableWrapper):
|
|||||||
The index is here just ignored, because of all the appends, etc.
|
The index is here just ignored, because of all the appends, etc.
|
||||||
lists/sets are too complicated too handle that.
|
lists/sets are too complicated too handle that.
|
||||||
"""
|
"""
|
||||||
items = []
|
items = set()
|
||||||
for key, nodes in self.var_args.unpack():
|
for key, nodes in self.var_args.unpack():
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
items += get_iterator_types(self._evaluator, node)
|
items |= get_iterator_types(self._evaluator, node)
|
||||||
|
|
||||||
module = self.var_args.get_parent_until()
|
module = self.var_args.get_parent_until()
|
||||||
is_list = str(self.instance.name) == 'list'
|
is_list = str(self.instance.name) == 'list'
|
||||||
items += _check_array_additions(self._evaluator, self.instance, module, is_list)
|
items |= _check_array_additions(self._evaluator, self.instance, module, is_list)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
||||||
@@ -624,5 +626,5 @@ def create_indexes_or_slices(evaluator, index):
|
|||||||
result.append(el)
|
result.append(el)
|
||||||
result += [None] * (3 - len(result))
|
result += [None] * (3 - len(result))
|
||||||
|
|
||||||
return (Slice(evaluator, *result),)
|
return set([Slice(evaluator, *result)])
|
||||||
return evaluator.eval_element(index)
|
return evaluator.eval_element(index)
|
||||||
|
|||||||
@@ -142,8 +142,8 @@ class Arguments(tree.Base):
|
|||||||
debug.warning('TypeError: %s expected at least %s arguments, got %s',
|
debug.warning('TypeError: %s expected at least %s arguments, got %s',
|
||||||
name, len(arguments), i)
|
name, len(arguments), i)
|
||||||
raise ValueError
|
raise ValueError
|
||||||
values = list(chain.from_iterable(self._evaluator.eval_element(el)
|
values = set(chain.from_iterable(self._evaluator.eval_element(el)
|
||||||
for el in va_values))
|
for el in va_values))
|
||||||
if not values and not optional:
|
if not values and not optional:
|
||||||
# For the stdlib we always want values. If we don't get them,
|
# For the stdlib we always want values. If we don't get them,
|
||||||
# that's ok, maybe something is too hard to resolve, however,
|
# that's ok, maybe something is too hard to resolve, however,
|
||||||
@@ -190,9 +190,9 @@ class ExecutedParam(tree.Param):
|
|||||||
self._values = values
|
self._values = values
|
||||||
|
|
||||||
def eval(self, evaluator):
|
def eval(self, evaluator):
|
||||||
types = []
|
types = set()
|
||||||
for v in self._values:
|
for v in self._values:
|
||||||
types += evaluator.eval_element(v)
|
types |= evaluator.eval_element(v)
|
||||||
return types
|
return types
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -26,13 +26,14 @@ COMPARISON_OPERATORS = {
|
|||||||
def _literals_to_types(evaluator, result):
|
def _literals_to_types(evaluator, result):
|
||||||
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
|
# Changes literals ('a', 1, 1.0, etc) to its type instances (str(),
|
||||||
# int(), float(), etc).
|
# int(), float(), etc).
|
||||||
|
result = list(result)
|
||||||
for i, r in enumerate(result):
|
for i, r in enumerate(result):
|
||||||
if is_literal(r):
|
if is_literal(r):
|
||||||
# Literals are only valid as long as the operations are
|
# Literals are only valid as long as the operations are
|
||||||
# correct. Otherwise add a value-free instance.
|
# correct. Otherwise add a value-free instance.
|
||||||
cls = builtin.get_by_name(r.name.get_code())
|
cls = builtin.get_by_name(r.name.get_code())
|
||||||
result[i] = evaluator.execute(cls)[0]
|
result[i] = list(evaluator.execute(cls))[0]
|
||||||
return list(set(result))
|
return set(result)
|
||||||
|
|
||||||
|
|
||||||
def calculate_children(evaluator, children):
|
def calculate_children(evaluator, children):
|
||||||
@@ -64,21 +65,21 @@ def calculate_children(evaluator, children):
|
|||||||
|
|
||||||
|
|
||||||
def calculate(evaluator, left_result, operator, right_result):
|
def calculate(evaluator, left_result, operator, right_result):
|
||||||
result = []
|
result = set()
|
||||||
if not left_result or not right_result:
|
if not left_result or not right_result:
|
||||||
# illegal slices e.g. cause left/right_result to be None
|
# illegal slices e.g. cause left/right_result to be None
|
||||||
result = (left_result or []) + (right_result or [])
|
result = (left_result or set()) | (right_result or set())
|
||||||
result = _literals_to_types(evaluator, result)
|
result = _literals_to_types(evaluator, result)
|
||||||
else:
|
else:
|
||||||
# I don't think there's a reasonable chance that a string
|
# I don't think there's a reasonable chance that a string
|
||||||
# operation is still correct, once we pass something like six
|
# operation is still correct, once we pass something like six
|
||||||
# objects.
|
# objects.
|
||||||
if len(left_result) * len(right_result) > 6:
|
if len(left_result) * len(right_result) > 6:
|
||||||
result = _literals_to_types(evaluator, left_result + right_result)
|
result = _literals_to_types(evaluator, left_result | right_result)
|
||||||
else:
|
else:
|
||||||
for left in left_result:
|
for left in left_result:
|
||||||
for right in right_result:
|
for right in right_result:
|
||||||
result += _element_calculate(evaluator, left, operator, right)
|
result |= _element_calculate(evaluator, left, operator, right)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@@ -130,21 +131,21 @@ def _element_calculate(evaluator, left, operator, right):
|
|||||||
if operator == '*':
|
if operator == '*':
|
||||||
# for iterables, ignore * operations
|
# for iterables, ignore * operations
|
||||||
if isinstance(left, iterable.Array) or is_string(left):
|
if isinstance(left, iterable.Array) or is_string(left):
|
||||||
return [left]
|
return set([left])
|
||||||
elif isinstance(right, iterable.Array) or is_string(right):
|
elif isinstance(right, iterable.Array) or is_string(right):
|
||||||
return [right]
|
return set([right])
|
||||||
elif operator == '+':
|
elif operator == '+':
|
||||||
if l_is_num and r_is_num or is_string(left) and is_string(right):
|
if l_is_num and r_is_num or is_string(left) and is_string(right):
|
||||||
return [create(evaluator, left.obj + right.obj)]
|
return set([create(evaluator, left.obj + right.obj)])
|
||||||
elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right):
|
elif _is_tuple(left) and _is_tuple(right) or _is_list(left) and _is_list(right):
|
||||||
return [iterable.MergedArray(evaluator, (left, right))]
|
return set([iterable.MergedArray(evaluator, (left, right))])
|
||||||
elif operator == '-':
|
elif operator == '-':
|
||||||
if l_is_num and r_is_num:
|
if l_is_num and r_is_num:
|
||||||
return [create(evaluator, left.obj - right.obj)]
|
return set([create(evaluator, left.obj - right.obj)])
|
||||||
elif operator == '%':
|
elif operator == '%':
|
||||||
# With strings and numbers the left type typically remains. Except for
|
# With strings and numbers the left type typically remains. Except for
|
||||||
# `int() % float()`.
|
# `int() % float()`.
|
||||||
return [left]
|
return set([left])
|
||||||
elif operator in COMPARISON_OPERATORS:
|
elif operator in COMPARISON_OPERATORS:
|
||||||
operation = COMPARISON_OPERATORS[operator]
|
operation = COMPARISON_OPERATORS[operator]
|
||||||
if isinstance(left, CompiledObject) and isinstance(right, CompiledObject):
|
if isinstance(left, CompiledObject) and isinstance(right, CompiledObject):
|
||||||
@@ -153,12 +154,12 @@ def _element_calculate(evaluator, left, operator, right):
|
|||||||
right = right.obj
|
right = right.obj
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return [keyword_from_value(operation(left, right))]
|
return set([keyword_from_value(operation(left, right))])
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# Could be True or False.
|
# Could be True or False.
|
||||||
return [true_obj, false_obj]
|
return set([true_obj, false_obj])
|
||||||
elif operator == 'in':
|
elif operator == 'in':
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
def check(obj):
|
def check(obj):
|
||||||
"""Checks if a Jedi object is either a float or an int."""
|
"""Checks if a Jedi object is either a float or an int."""
|
||||||
@@ -171,4 +172,4 @@ def _element_calculate(evaluator, left, operator, right):
|
|||||||
analysis.add(evaluator, 'type-error-operation', operator,
|
analysis.add(evaluator, 'type-error-operation', operator,
|
||||||
message % (left, right))
|
message % (left, right))
|
||||||
|
|
||||||
return [left, right]
|
return set([left, right])
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ def execution_recursion_decorator(func):
|
|||||||
def run(execution, **kwargs):
|
def run(execution, **kwargs):
|
||||||
detector = execution._evaluator.execution_recursion_detector
|
detector = execution._evaluator.execution_recursion_detector
|
||||||
if detector.push_execution(execution):
|
if detector.push_execution(execution):
|
||||||
result = []
|
result = set()
|
||||||
else:
|
else:
|
||||||
result = func(execution, **kwargs)
|
result = func(execution, **kwargs)
|
||||||
detector.pop_execution()
|
detector.pop_execution()
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
|||||||
try:
|
try:
|
||||||
return self.execute_subscope_by_name('__get__', *args)
|
return self.execute_subscope_by_name('__get__', *args)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return [self]
|
return set([self])
|
||||||
|
|
||||||
@memoize_default()
|
@memoize_default()
|
||||||
def names_dicts(self, search_global):
|
def names_dicts(self, search_global):
|
||||||
@@ -207,7 +207,7 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
|
|||||||
method = self.get_subscope_by_name('__getitem__')
|
method = self.get_subscope_by_name('__getitem__')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
debug.warning('No __getitem__, cannot access the array.')
|
debug.warning('No __getitem__, cannot access the array.')
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)])
|
return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)])
|
||||||
|
|
||||||
@@ -440,7 +440,7 @@ class Class(use_metaclass(CachedMetaClass, Wrapper)):
|
|||||||
return [compiled.object_obj]
|
return [compiled.object_obj]
|
||||||
|
|
||||||
def py__call__(self, evaluator, params):
|
def py__call__(self, evaluator, params):
|
||||||
return [Instance(evaluator, self, params)]
|
return set([Instance(evaluator, self, params)])
|
||||||
|
|
||||||
def py__getattribute__(self, name):
|
def py__getattribute__(self, name):
|
||||||
return self._evaluator.find_types(self, name)
|
return self._evaluator.find_types(self, name)
|
||||||
@@ -541,7 +541,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
|
|||||||
# TODO resolve issue with multiple wrappers -> multiple types
|
# TODO resolve issue with multiple wrappers -> multiple types
|
||||||
debug.warning('multiple wrappers found %s %s',
|
debug.warning('multiple wrappers found %s %s',
|
||||||
self.base_func, wrappers)
|
self.base_func, wrappers)
|
||||||
f = wrappers[0]
|
f = list(wrappers)[0]
|
||||||
if isinstance(f, (Instance, Function)):
|
if isinstance(f, (Instance, Function)):
|
||||||
f.decorates = self
|
f.decorates = self
|
||||||
|
|
||||||
@@ -558,7 +558,7 @@ class Function(use_metaclass(CachedMetaClass, Wrapper)):
|
|||||||
@Python3Method
|
@Python3Method
|
||||||
def py__call__(self, evaluator, params):
|
def py__call__(self, evaluator, params):
|
||||||
if self.base.is_generator():
|
if self.base.is_generator():
|
||||||
return [iterable.Generator(evaluator, self, params)]
|
return set([iterable.Generator(evaluator, self, params)])
|
||||||
else:
|
else:
|
||||||
return FunctionExecution(evaluator, self, params).get_return_types()
|
return FunctionExecution(evaluator, self, params).get_return_types()
|
||||||
|
|
||||||
@@ -613,21 +613,21 @@ class FunctionExecution(Executed):
|
|||||||
# If we do have listeners, that means that there's not a regular
|
# If we do have listeners, that means that there's not a regular
|
||||||
# execution ongoing. In this case Jedi is interested in the
|
# execution ongoing. In this case Jedi is interested in the
|
||||||
# inserted params, not in the actual execution of the function.
|
# inserted params, not in the actual execution of the function.
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
if check_yields:
|
if check_yields:
|
||||||
types = []
|
types = set()
|
||||||
returns = self.yields
|
returns = self.yields
|
||||||
else:
|
else:
|
||||||
returns = self.returns
|
returns = self.returns
|
||||||
types = list(docstrings.find_return_types(self._evaluator, func))
|
types = set(docstrings.find_return_types(self._evaluator, func))
|
||||||
|
|
||||||
for r in returns:
|
for r in returns:
|
||||||
check = flow_analysis.break_check(self._evaluator, self, r)
|
check = flow_analysis.break_check(self._evaluator, self, r)
|
||||||
if check is flow_analysis.UNREACHABLE:
|
if check is flow_analysis.UNREACHABLE:
|
||||||
debug.dbg('Return unreachable: %s', r)
|
debug.dbg('Return unreachable: %s', r)
|
||||||
else:
|
else:
|
||||||
types += self._evaluator.eval_element(r.children[1])
|
types |= self._evaluator.eval_element(r.children[1])
|
||||||
if check is flow_analysis.REACHABLE:
|
if check is flow_analysis.REACHABLE:
|
||||||
debug.dbg('Return reachable: %s', r)
|
debug.dbg('Return reachable: %s', r)
|
||||||
break
|
break
|
||||||
@@ -748,7 +748,8 @@ class ModuleWrapper(use_metaclass(CachedMetaClass, tree.Module, Wrapper)):
|
|||||||
@memoize_default()
|
@memoize_default()
|
||||||
def _module_attributes_dict(self):
|
def _module_attributes_dict(self):
|
||||||
def parent_callback():
|
def parent_callback():
|
||||||
return self._evaluator.execute(compiled.create(self._evaluator, str))[0]
|
# Create a string type object (without a defined string in it):
|
||||||
|
return list(self._evaluator.execute(compiled.create(self._evaluator, str)))[0]
|
||||||
|
|
||||||
names = ['__file__', '__package__', '__doc__', '__name__']
|
names = ['__file__', '__package__', '__doc__', '__name__']
|
||||||
# All the additional module attributes are strings.
|
# All the additional module attributes are strings.
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ def argument_clinic(string, want_obj=False, want_scope=False, want_arguments=Fal
|
|||||||
try:
|
try:
|
||||||
lst = list(arguments.eval_argument_clinic(clinic_args))
|
lst = list(arguments.eval_argument_clinic(clinic_args))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
if want_scope:
|
if want_scope:
|
||||||
@@ -97,7 +97,6 @@ def argument_clinic(string, want_obj=False, want_scope=False, want_arguments=Fal
|
|||||||
|
|
||||||
@argument_clinic('object, name[, default], /')
|
@argument_clinic('object, name[, default], /')
|
||||||
def builtins_getattr(evaluator, objects, names, defaults=None):
|
def builtins_getattr(evaluator, objects, names, defaults=None):
|
||||||
types = []
|
|
||||||
# follow the first param
|
# follow the first param
|
||||||
for obj in objects:
|
for obj in objects:
|
||||||
if not isinstance(obj, (er.Instance, er.Class, tree.Module, compiled.CompiledObject)):
|
if not isinstance(obj, (er.Instance, er.Class, tree.Module, compiled.CompiledObject)):
|
||||||
@@ -110,16 +109,16 @@ def builtins_getattr(evaluator, objects, names, defaults=None):
|
|||||||
else:
|
else:
|
||||||
debug.warning('getattr called without str')
|
debug.warning('getattr called without str')
|
||||||
continue
|
continue
|
||||||
return types
|
return set()
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('object[, bases, dict], /')
|
@argument_clinic('object[, bases, dict], /')
|
||||||
def builtins_type(evaluator, objects, bases, dicts):
|
def builtins_type(evaluator, objects, bases, dicts):
|
||||||
if bases or dicts:
|
if bases or dicts:
|
||||||
# It's a type creation... maybe someday...
|
# It's a type creation... maybe someday...
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
return [o.py__class__(evaluator) for o in objects]
|
return set([o.py__class__(evaluator) for o in objects])
|
||||||
|
|
||||||
|
|
||||||
class SuperInstance(er.Instance):
|
class SuperInstance(er.Instance):
|
||||||
@@ -145,20 +144,20 @@ def builtins_super(evaluator, types, objects, scope):
|
|||||||
su = cls.py__bases__(evaluator)
|
su = cls.py__bases__(evaluator)
|
||||||
if su:
|
if su:
|
||||||
return evaluator.execute(su[0])
|
return evaluator.execute(su[0])
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
|
|
||||||
def get_iterable_content(evaluator, arguments, argument_index):
|
def get_iterable_content(evaluator, arguments, argument_index):
|
||||||
nodes = list(arguments.unpack())[argument_index][1]
|
nodes = list(arguments.unpack())[argument_index][1]
|
||||||
return tuple(iterable.unite(iterable.get_iterator_types(evaluator, node)
|
return set(iterable.unite(iterable.get_iterator_types(evaluator, node)
|
||||||
for node in nodes))
|
for node in nodes))
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('sequence, /', want_obj=True, want_arguments=True)
|
@argument_clinic('sequence, /', want_obj=True, want_arguments=True)
|
||||||
def builtins_reversed(evaluator, sequences, obj, arguments):
|
def builtins_reversed(evaluator, sequences, obj, arguments):
|
||||||
# Unpack the iterator values
|
# Unpack the iterator values
|
||||||
objects = get_iterable_content(evaluator, arguments, 0)
|
objects = get_iterable_content(evaluator, arguments, 0)
|
||||||
rev = [iterable.AlreadyEvaluated([o]) for o in reversed(objects)]
|
rev = [iterable.AlreadyEvaluated([o]) for o in reversed(list(objects))]
|
||||||
# Repack iterator values and then run it the normal way. This is
|
# Repack iterator values and then run it the normal way. This is
|
||||||
# necessary, because `reversed` is a function and autocompletion
|
# necessary, because `reversed` is a function and autocompletion
|
||||||
# would fail in certain cases like `reversed(x).__iter__` if we
|
# would fail in certain cases like `reversed(x).__iter__` if we
|
||||||
@@ -166,7 +165,7 @@ def builtins_reversed(evaluator, sequences, obj, arguments):
|
|||||||
rev = iterable.AlreadyEvaluated(
|
rev = iterable.AlreadyEvaluated(
|
||||||
[iterable.FakeSequence(evaluator, rev, 'list')]
|
[iterable.FakeSequence(evaluator, rev, 'list')]
|
||||||
)
|
)
|
||||||
return [er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))]
|
return set([er.Instance(evaluator, obj, param.Arguments(evaluator, [rev]))])
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('obj, type, /', want_arguments=True)
|
@argument_clinic('obj, type, /', want_arguments=True)
|
||||||
@@ -179,7 +178,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
|||||||
# This is temporary. Everything should have a class attribute in
|
# This is temporary. Everything should have a class attribute in
|
||||||
# Python?! Maybe we'll leave it here, because some numpy objects or
|
# Python?! Maybe we'll leave it here, because some numpy objects or
|
||||||
# whatever might not.
|
# whatever might not.
|
||||||
return [compiled.true_obj, compiled.false_obj]
|
return set([compiled.true_obj, compiled.false_obj])
|
||||||
|
|
||||||
mro = mro_func(evaluator)
|
mro = mro_func(evaluator)
|
||||||
|
|
||||||
@@ -191,7 +190,7 @@ def builtins_isinstance(evaluator, objects, types, arguments):
|
|||||||
classes = get_iterable_content(evaluator, arguments, 1)
|
classes = get_iterable_content(evaluator, arguments, 1)
|
||||||
bool_results.add(any(cls in mro for cls in classes))
|
bool_results.add(any(cls in mro for cls in classes))
|
||||||
|
|
||||||
return [compiled.keyword_from_value(x) for x in bool_results]
|
return set(compiled.keyword_from_value(x) for x in bool_results)
|
||||||
|
|
||||||
|
|
||||||
def collections_namedtuple(evaluator, obj, arguments):
|
def collections_namedtuple(evaluator, obj, arguments):
|
||||||
@@ -206,7 +205,7 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
"""
|
"""
|
||||||
# Namedtuples are not supported on Python 2.6
|
# Namedtuples are not supported on Python 2.6
|
||||||
if not hasattr(collections, '_class_template'):
|
if not hasattr(collections, '_class_template'):
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
# Process arguments
|
# Process arguments
|
||||||
name = _follow_param(evaluator, arguments, 0)[0].obj
|
name = _follow_param(evaluator, arguments, 0)[0].obj
|
||||||
@@ -217,9 +216,9 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
try:
|
try:
|
||||||
fields = [v.obj for v in _fields.values()]
|
fields = [v.obj for v in _fields.values()]
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return []
|
return set()
|
||||||
else:
|
else:
|
||||||
return []
|
return set()
|
||||||
|
|
||||||
# Build source
|
# Build source
|
||||||
source = collections._class_template.format(
|
source = collections._class_template.format(
|
||||||
@@ -234,7 +233,7 @@ def collections_namedtuple(evaluator, obj, arguments):
|
|||||||
|
|
||||||
# Parse source
|
# Parse source
|
||||||
generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0]
|
generated_class = Parser(evaluator.grammar, unicode(source)).module.subscopes[0]
|
||||||
return [er.Class(evaluator, generated_class)]
|
return set(er.Class(evaluator, generated_class))
|
||||||
|
|
||||||
|
|
||||||
@argument_clinic('first, /')
|
@argument_clinic('first, /')
|
||||||
@@ -255,8 +254,8 @@ _implemented = {
|
|||||||
'deepcopy': _return_first_param,
|
'deepcopy': _return_first_param,
|
||||||
},
|
},
|
||||||
'json': {
|
'json': {
|
||||||
'load': lambda *args: [],
|
'load': lambda *args: set(),
|
||||||
'loads': lambda *args: [],
|
'loads': lambda *args: set(),
|
||||||
},
|
},
|
||||||
'collections': {
|
'collections': {
|
||||||
'namedtuple': collections_namedtuple,
|
'namedtuple': collections_namedtuple,
|
||||||
|
|||||||
Reference in New Issue
Block a user