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