diff --git a/jedi/api/__init__.py b/jedi/api/__init__.py index 945b98a1..b385e116 100644 --- a/jedi/api/__init__.py +++ b/jedi/api/__init__.py @@ -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() diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 2a34cb85..82351aad 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -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) diff --git a/jedi/evaluate/compiled/__init__.py b/jedi/evaluate/compiled/__init__.py index d39c320c..d1da59d0 100644 --- a/jedi/evaluate/compiled/__init__.py +++ b/jedi/evaluate/compiled/__init__.py @@ -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: diff --git a/jedi/evaluate/docstrings.py b/jedi/evaluate/docstrings.py index 84137de5..11bb16ae 100644 --- a/jedi/evaluate/docstrings.py +++ b/jedi/evaluate/docstrings.py @@ -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) diff --git a/jedi/evaluate/dynamic.py b/jedi/evaluate/dynamic.py index 04ed909a..43cdb008 100644 --- a/jedi/evaluate/dynamic.py +++ b/jedi/evaluate/dynamic.py @@ -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 diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index f396740d..c1715850 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -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 diff --git a/jedi/evaluate/imports.py b/jedi/evaluate/imports.py index c14a50c0..24e1f110 100644 --- a/jedi/evaluate/imports.py +++ b/jedi/evaluate/imports.py @@ -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) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 859774d1..54d3a173 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -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) diff --git a/jedi/evaluate/param.py b/jedi/evaluate/param.py index 2423704b..606d16e2 100644 --- a/jedi/evaluate/param.py +++ b/jedi/evaluate/param.py @@ -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 diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 7a2ee6d2..2c6b4da2 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -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]) diff --git a/jedi/evaluate/recursion.py b/jedi/evaluate/recursion.py index a4f5fbc3..32a86b91 100644 --- a/jedi/evaluate/recursion.py +++ b/jedi/evaluate/recursion.py @@ -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() diff --git a/jedi/evaluate/representation.py b/jedi/evaluate/representation.py index 30d4c404..006f6a59 100644 --- a/jedi/evaluate/representation.py +++ b/jedi/evaluate/representation.py @@ -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. diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index 1852117c..fab3dfdc 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -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,