1
0
forked from VimPlug/jedi

Implement py__iter__ for Generators, which means that yield expressions are now orderable, if they are not too complicated.

This commit is contained in:
Dave Halter
2015-11-09 15:15:03 +01:00
parent 4549157d39
commit 9f82cce3bb
3 changed files with 58 additions and 6 deletions

View File

@@ -86,6 +86,11 @@ class Generator(use_metaclass(CachedMetaClass, IterableWrapper, GeneratorMixin))
f = FunctionExecution(self._evaluator, self.func, self.var_args) f = FunctionExecution(self._evaluator, self.func, self.var_args)
return f.get_return_types(check_yields=True) return f.get_return_types(check_yields=True)
def py__iter__(self):
from jedi.evaluate.representation import FunctionExecution
f = FunctionExecution(self._evaluator, self.func, self.var_args)
return f.get_yield_types()
def __getattr__(self, name): def __getattr__(self, name):
if name not in ['start_pos', 'end_pos', 'parent', 'get_imports', if name not in ['start_pos', 'end_pos', 'parent', 'get_imports',
'doc', 'docstr', 'get_parent_until', 'doc', 'docstr', 'get_parent_until',
@@ -274,7 +279,7 @@ class Array(IterableWrapper, ArrayMixin):
raise AttributeError('Strange access on %s: %s.' % (self, name)) raise AttributeError('Strange access on %s: %s.' % (self, name))
return getattr(self.atom, name) return getattr(self.atom, name)
def per_index_values(self): def py__iter__(self):
""" """
While values returns the possible values for any array field, this While values returns the possible values for any array field, this
function returns the value for a certain index. function returns the value for a certain index.
@@ -401,12 +406,13 @@ def ordered_elements_of_iterable(evaluator, iterable_type, all_values):
# Unpack the iterator values # Unpack the iterator values
for sequence in iterable_type: for sequence in iterable_type:
try: try:
per_index_values = sequence.per_index_values # TODO every type should have a py__iter__ method.
py__iter__ = sequence.py__iter__
except AttributeError: except AttributeError:
ordered = [literals_to_types(evaluator, all_values)] ordered = [literals_to_types(evaluator, all_values)]
break break
else: else:
for i, types in enumerate(per_index_values()): for i, types in enumerate(py__iter__()):
try: try:
ordered[i] |= types ordered[i] |= types
except IndexError: except IndexError:

View File

@@ -211,6 +211,17 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
else: else:
return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)]) return self._evaluator.execute(method, [iterable.AlreadyEvaluated(indexes)])
def py__iter__(self):
try:
method = self.get_subscope_by_name('__iter__')
except KeyError:
debug.warning('No __iter__ on %s.' % self)
return
else:
for generator in self._evaluator.execute(method):
for typ in generator.py__iter__():
yield typ
@property @property
@underscore_memoization @underscore_memoization
def name(self): def name(self):
@@ -228,8 +239,8 @@ class Instance(use_metaclass(CachedMetaClass, Executed)):
dec = '' dec = ''
if self.decorates is not None: if self.decorates is not None:
dec = " decorates " + repr(self.decorates) dec = " decorates " + repr(self.decorates)
return "<e%s of %s(%s)%s>" % (type(self).__name__, self.base, return "<%s of %s(%s)%s>" % (type(self).__name__, self.base,
self.var_args, dec) self.var_args, dec)
class LazyInstanceDict(object): class LazyInstanceDict(object):
@@ -633,6 +644,41 @@ class FunctionExecution(Executed):
break break
return types return types
def get_yield_types(self):
yields = self.yields
stopAt = tree.ForStmt, tree.WhileStmt, FunctionExecution
for_parents = [(x, x.get_parent_until((stopAt))) for x in yields]
# Calculate if the yields are placed within the same for loop.
yields_order = []
last_for_stmt = None
for yield_, for_stmt in for_parents:
# For really simple for loops we can predict the order. Otherwise
# we just ignore it.
parent = for_stmt.parent
if parent.type == 'suite':
parent = parent.parent
if for_stmt.type == 'for_stmt' and parent == self \
and for_stmt.defines_one_name(): # Simplicity for now.
if for_stmt == last_for_stmt:
yields_order[-1][1].append(yield_)
else:
yields_order.append((for_stmt, [yield_]))
else:
yield self.get_return_types()
return
last_for_stmt = for_stmt
for for_stmt, yields in yields_order:
for_types = self._evaluator.eval_element(for_stmt.get_input_node())
ordered = iterable.ordered_elements_of_iterable(self._evaluator, for_types, [])
for index_types in ordered:
dct = {str(for_stmt.children[1]): index_types}
self._evaluator.predefined_if_name_dict_dict[for_stmt] = dct
for yield_in_same_for_stmt in yields:
yield self._evaluator.eval_element(yield_in_same_for_stmt.children[1])
del self._evaluator.predefined_if_name_dict_dict[for_stmt]
def names_dicts(self, search_global): def names_dicts(self, search_global):
yield self.names_dict yield self.names_dict

View File

@@ -483,7 +483,7 @@ class BaseNode(Base):
@utf8_repr @utf8_repr
def __repr__(self): def __repr__(self):
code = self.get_code().replace('\n', ' ') code = self.get_code().replace('\n', ' ').strip()
if not is_py3: if not is_py3:
code = code.encode(encoding, 'replace') code = code.encode(encoding, 'replace')
return "<%s: %s@%s,%s>" % \ return "<%s: %s@%s,%s>" % \