From 62468fb402dfd76cb2bbc226ea8f3d789082b9d0 Mon Sep 17 00:00:00 2001 From: Dave Halter Date: Wed, 14 Oct 2015 16:50:26 +0200 Subject: [PATCH] reversed and for loops now produce strings in the correct order. --- jedi/evaluate/__init__.py | 10 +++++++--- jedi/evaluate/iterable.py | 23 +++++++++++++++++++++++ jedi/evaluate/precedence.py | 20 +++++++++++--------- jedi/evaluate/stdlib.py | 11 ++++++++--- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/jedi/evaluate/__init__.py b/jedi/evaluate/__init__.py index 82351aad..57623e68 100644 --- a/jedi/evaluate/__init__.py +++ b/jedi/evaluate/__init__.py @@ -147,12 +147,16 @@ class Evaluator(object): name = str(stmt.get_defined_names()[0]) parent = self.wrap(stmt.get_parent_scope()) left = self.find_types(parent, name, stmt.start_pos, search_global=True) - if isinstance(stmt.get_parent_until(tree.ForStmt), tree.ForStmt): + + for_stmt = stmt.get_parent_until(tree.ForStmt) + if isinstance(for_stmt, tree.ForStmt): # Iterate through result and add the values, that's possible # only in for loops without clutter, because they are # predictable. - for r in types: - left = precedence.calculate(self, left, operator, set([r])) + for_iterable = self.eval_element(for_stmt.children[3]) + ordered = iterable.ordered_elements_of_iterable(self, for_iterable, types) + for index_types in ordered: + left = precedence.calculate(self, left, operator, index_types) types = left else: types = precedence.calculate(self, left, operator, types) diff --git a/jedi/evaluate/iterable.py b/jedi/evaluate/iterable.py index 219612ed..2171d3bb 100644 --- a/jedi/evaluate/iterable.py +++ b/jedi/evaluate/iterable.py @@ -29,6 +29,7 @@ from jedi.evaluate import compiled from jedi.evaluate import helpers from jedi.evaluate.cache import CachedMetaClass, memoize_default from jedi.evaluate import analysis +from jedi.evaluate.precedence import literals_to_types class IterableWrapper(tree.Base): @@ -390,6 +391,28 @@ class MergedArray(_FakeArray): return sum(len(a) for a in self._arrays) +def ordered_elements_of_iterable(evaluator, iterable_type, all_values): + """ + This function returns the ordered types of an iterable. If the input is not + an Array, we just return all types as the first and only item of the + output list. + """ + ordered = [] + # Unpack the iterator values + for sequence in iterable_type: + if not isinstance(sequence, Array): + ordered = [literals_to_types(evaluator, all_values)] + break + else: + # Try + for i, types in enumerate(sequence.per_index_values()): + try: + ordered[i] |= types + except IndexError: + ordered.append(set(types)) + return ordered + + def get_iterator_types(evaluator, element): """Returns the types of any iterator (arrays, yields, __iter__, etc).""" iterators = [] diff --git a/jedi/evaluate/precedence.py b/jedi/evaluate/precedence.py index 2c6b4da2..38c772ab 100644 --- a/jedi/evaluate/precedence.py +++ b/jedi/evaluate/precedence.py @@ -23,17 +23,19 @@ 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(), # int(), float(), etc). - result = list(result) - for i, r in enumerate(result): - if is_literal(r): + new_result = set() + for typ in result: + if is_literal(typ): # 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] = list(evaluator.execute(cls))[0] - return set(result) + cls = builtin.get_by_name(typ.name.get_code()) + new_result.add(list(evaluator.execute(cls))[0]) + else: + new_result.add(typ) + return new_result def calculate_children(evaluator, children): @@ -69,13 +71,13 @@ def calculate(evaluator, left_result, operator, right_result): if not left_result or not right_result: # illegal slices e.g. cause left/right_result to be None result = (left_result or set()) | (right_result or set()) - result = _literals_to_types(evaluator, result) + 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: diff --git a/jedi/evaluate/stdlib.py b/jedi/evaluate/stdlib.py index fab3dfdc..a2b6617d 100644 --- a/jedi/evaluate/stdlib.py +++ b/jedi/evaluate/stdlib.py @@ -155,9 +155,14 @@ def get_iterable_content(evaluator, arguments, argument_index): @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(list(objects))] + # While we could do without this variable (just by using sequences), we + # want static analysis to work well. Therefore we need to generated the + # values again. + all_sequence_types = get_iterable_content(evaluator, arguments, 0) + + ordered = iterable.ordered_elements_of_iterable(evaluator, sequences, all_sequence_types) + + rev = [iterable.AlreadyEvaluated(o) for o in reversed(ordered)] # 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