diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 3ec531d7..68fa81e7 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -134,20 +134,7 @@ class Evaluator(object): types = self.eval_element(stmt.get_rhs()) if seek_name: - for index in seek_name.assignment_indexes(): - new_types = [] - for r in types: - try: - func = r.get_exact_index_types - except AttributeError: - debug.warning("Invalid tuple lookup #%s of result %s in %s", - index, types, seek_name) - else: - try: - new_types += func(index) - except IndexError: - pass - types = new_types + types = finder.check_tuple_assignments(types, seek_name) ass_details = stmt.assignment_details if ass_details and ass_details[0][1] != '=' and not isinstance(stmt, er.InstanceElement): # TODO don't check for this. diff --git a/jedi/evaluate/finder.py b/jedi/evaluate/finder.py index d5e2930f..b6a9393e 100644 --- a/jedi/evaluate/finder.py +++ b/jedi/evaluate/finder.py @@ -281,8 +281,10 @@ class NameFinder(object): for name in names: typ = name.get_definition() - if typ.isinstance(pr.ForFlow): - types += self._handle_for_loops(typ) + if typ.isinstance(pr.ForStmt): + for_types = self._evaluator.eval_element(typ.children[-3]) + for_types = iterable.get_iterator_types(for_types) + types += check_tuple_assignments(for_types, name) elif isinstance(typ, pr.Param): types += self._eval_param(typ) elif typ.isinstance(pr.ExprStmt): @@ -391,17 +393,6 @@ class NameFinder(object): return res_new return res_new + param.eval(self._evaluator) - def _handle_for_loops(self, loop): - # Take the first statement (for has always only one`in`). - if not loop.inputs: - return [] - result = iterable.get_iterator_types(self._evaluator.eval_statement(loop.inputs[0])) - if len(loop.set_vars) > 1: - expression_list = loop.set_stmt.expression_list() - # loops with loop.set_vars > 0 only have one command - result = _assign_tuples(expression_list[0], result, unicode(self.name_str)) - return result - def _resolve_descriptors(self, types): """Processes descriptors""" if not self.maybe_descriptor: @@ -643,6 +634,27 @@ def find_assignments(lhs, results, seek_name): return [] +def check_tuple_assignments(types, name): + """ + Checks if tuples are assigned. + """ + for index in name.assignment_indexes(): + new_types = [] + for r in types: + try: + func = r.get_exact_index_types + except AttributeError: + debug.warning("Invalid tuple lookup #%s of result %s in %s", + index, types, name) + else: + try: + new_types += func(index) + except IndexError: + pass + types = new_types + return types + + def filter_private_variable(scope, call_scope, var_name): """private variables begin with a double underline `__`""" if isinstance(scope, er.Instance) and var_name.startswith('__') and not var_name.endswith('__'): diff --git a/jedi/parser/representation.py b/jedi/parser/representation.py index d8fd5b5e..cd7eef5d 100644 --- a/jedi/parser/representation.py +++ b/jedi/parser/representation.py @@ -259,6 +259,8 @@ class Name(Leaf): stmt = self.get_definition() if isinstance(stmt, (Function, Class, Module)): return True + elif isinstance(stmt, ForStmt): + return self.start_pos < stmt.children[2].start_pos elif isinstance(stmt, Param): return self == stmt.get_name() else: @@ -280,7 +282,7 @@ class Name(Leaf): node = self.parent compare = self while node is not None: - if is_node(node, 'testlist_comp') or is_node(node, 'testlist_star_expr'): + if is_node(node, 'testlist_comp', 'testlist_star_expr', 'exprlist'): for i, child in enumerate(node.children): if child == compare: indexes.insert(0, int(i / 2)) @@ -478,7 +480,7 @@ class Scope(Simple, DocstringMixin): for element in children: if isinstance(element, typ): elements.append(element) - if is_node(element, 'suite') or is_node(element, 'simple_stmt') \ + if is_node(element, 'suite', 'simple_stmt') \ or isinstance(element, Flow): elements += scan(element.children) return elements