Author: Raffael Tfirst <raffael.tfi...@gmail.com>
Branch: py3.5
Changeset: r86288:10f2791aaf2d
Date: 2016-08-18 20:22 +0200
http://bitbucket.org/pypy/pypy/changeset/10f2791aaf2d/

Log:    Merge with py3.5-async

diff --git a/pypy/interpreter/astcompiler/assemble.py 
b/pypy/interpreter/astcompiler/assemble.py
--- a/pypy/interpreter/astcompiler/assemble.py
+++ b/pypy/interpreter/astcompiler/assemble.py
@@ -609,7 +609,7 @@
     ops.WITH_CLEANUP_FINISH: -2,
     ops.LOAD_BUILD_CLASS: 1,
     ops.POP_BLOCK: 0,
-    ops.POP_EXCEPT: -1,
+    ops.POP_EXCEPT: -2,
     ops.END_FINALLY: -4,     # assume always 4: we pretend that SETUP_FINALLY
                              # pushes 4.  In truth, it would only push 1 and
                              # the corresponding END_FINALLY only pops 1.
diff --git a/pypy/interpreter/astcompiler/codegen.py 
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -599,17 +599,21 @@
         b_try_cleanup = self.new_block()
         b_after_loop = self.new_block()
         b_after_loop_else = self.new_block()
+        
         self.emit_jump(ops.SETUP_LOOP, b_after_loop)
         self.push_frame_block(F_BLOCK_LOOP, b_try)
+        
         fr.iter.walkabout(self)
         self.emit_op(ops.GET_AITER)
         self.load_const(self.space.w_None)
         self.emit_op(ops.YIELD_FROM)
+        
         self.use_next_block(b_try)
         # This adds another line, so each for iteration can be traced.
         self.lineno_set = False
         self.emit_jump(ops.SETUP_EXCEPT, b_except)
         self.push_frame_block(F_BLOCK_EXCEPT, b_try)
+        
         self.emit_op(ops.GET_ANEXT)
         self.load_const(self.space.w_None)
         self.emit_op(ops.YIELD_FROM)
@@ -617,9 +621,10 @@
         self.emit_op(ops.POP_BLOCK)
         self.pop_frame_block(F_BLOCK_EXCEPT, b_try)
         self.emit_jump(ops.JUMP_FORWARD, b_after_try)
+        
         self.use_next_block(b_except)
-        self.emit_op(ops.POP_TOP)
-        self.emit_op_name(ops.LOAD_GLOBAL, self.names, "StopIterError")
+        self.emit_op(ops.DUP_TOP)
+        self.emit_op_name(ops.LOAD_GLOBAL, self.names, "StopAsyncIteration")
         self.emit_op_arg(ops.COMPARE_OP, 10)
         self.emit_jump(ops.POP_JUMP_IF_FALSE, b_try_cleanup, True)
         
@@ -632,13 +637,17 @@
         
         self.use_next_block(b_try_cleanup)
         self.emit_op(ops.END_FINALLY)
+        
         self.use_next_block(b_after_try)
         self.visit_sequence(fr.body)
         self.emit_jump(ops.JUMP_ABSOLUTE, b_try, True)
+        
         self.emit_op(ops.POP_BLOCK) # for SETUP_LOOP
         self.pop_frame_block(F_BLOCK_LOOP, b_try)
+        
         self.use_next_block(b_after_loop)
         self.emit_jump(ops.JUMP_ABSOLUTE, b_end, True)
+        
         self.use_next_block(b_after_loop_else)
         self.visit_sequence(fr.orelse)
         
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -798,10 +798,15 @@
 )
 assert not GeneratorIterator.typedef.acceptable_as_base_class  # no __new__
 
+# TODO: to have the same distinction (Coroutine | Iterator) as in cpython 3.5,
+# a wrapper typedef with __anext__ has to be created, and __anext__ has to be
+# removed in coroutine
 Coroutine.typedef = TypeDef("coroutine",
     __repr__   = interp2app(Coroutine.descr__repr__),
     __reduce__   = interp2app(Coroutine.descr__reduce__),
     __setstate__ = interp2app(Coroutine.descr__setstate__),
+    __anext__   = interp2app(Coroutine.descr_next,
+                            descrmismatch='__anext__'),
     send       = interp2app(Coroutine.descr_send,
                             descrmismatch='send'),
     throw      = interp2app(Coroutine.descr_throw,
diff --git a/pypy/module/_asyncio/test/test_asyncio.py 
b/pypy/module/_asyncio/test/test_asyncio.py
--- a/pypy/module/_asyncio/test/test_asyncio.py
+++ b/pypy/module/_asyncio/test/test_asyncio.py
@@ -1,4 +1,5 @@
 class AppTestAsyncIO(object):
+    """These tests are based on the async-await syntax of Python 3.5."""
     
     spaceconfig = dict(usemodules=["select","_socket","thread","signal",
                                    "struct","_multiprocessing","array",
@@ -9,17 +10,71 @@
         # the problem occured at await asyncio.open_connection
         # after calling run_until_complete
         """
-        import encodings.idna
-        import asyncio
-        async def f():
-            reader, writer = await asyncio.open_connection('example.com', 80)
-        
-        loop = asyncio.get_event_loop()
-        loop.run_until_complete(f())
-        print("done with async loop")
+import encodings.idna
+import asyncio
+
+async def f():
+    reader, writer = await asyncio.open_connection('example.com', 80)
+    writer.close()
+
+loop = asyncio.get_event_loop()
+loop.run_until_complete(f())
+        """
+    
+    def test_async_for(self):
+        # tests if async for receives all stores values in the right order
+        # and if the correct methods __aiter__ and __anext__ get called
+        # and if the end results of run_until_complete are None (in a tuple)
+        """
+import asyncio
+
+class AsyncIter:
+    def __init__(self):
+        self._data = list(range(5))
+        self._index = 0
+    
+    async def __aiter__(self):
+        return self
+    
+    async def __anext__(self):
+        while self._index < 5:
+            await asyncio.sleep(1)
+            self._index += 1
+            return self._data[self._index-1]
+        raise StopAsyncIteration
+
+class Corotest(object):
+    def __init__(self):
+        self.res = "-"
+    
+    async def do_loop(self):
+        async for x in AsyncIter():
+            self.res += str(x)
+            self.res += "-"
+
+cor = Corotest()
+loop = asyncio.get_event_loop()
+futures = [asyncio.ensure_future(cor.do_loop()), 
asyncio.ensure_future(cor.do_loop())]
+taskres = loop.run_until_complete(asyncio.wait(futures))
+assert cor.res.count('0') == 2
+assert cor.res.count('1') == 2
+assert cor.res.count('2') == 2
+assert cor.res.count('3') == 2
+assert cor.res.count('4') == 2
+assert cor.res.find("0") < cor.res.find("1")
+assert cor.res.find("1") < cor.res.find("2")
+assert cor.res.find("2") < cor.res.find("3")
+assert cor.res.find("3") < cor.res.find("4")
+assert isinstance(taskres, tuple)
+assert len(taskres) == 2
+assert "result=None" in repr(taskres[0].pop())
+assert "result=None" in repr(taskres[0].pop())
         """
     
     def test_asynchronous_context_managers(self):
+        # it is important that "releasing lock A" happens before "holding lock 
B"
+        # or the other way around, but it is not allowed that both coroutines
+        # hold the lock at the same time
         """
 import encodings.idna
 import asyncio
@@ -44,5 +99,12 @@
 finally:
     loop.close()
 
-assert cor.res == "- coro 1: waiting for lock - coro 1: holding the lock - 
coro 2: waiting for lock - coro 1: releasing the lock - coro 2: holding the 
lock - coro 2: releasing the lock -"
+assert "coro 1: waiting for lock" in cor.res
+assert "coro 1: holding the lock" in cor.res
+assert "coro 1: releasing the lock" in cor.res
+assert "coro 2: waiting for lock" in cor.res
+assert "coro 2: holding the lock" in cor.res
+assert "coro 2: releasing the lock" in cor.res
+assert cor.res.find("coro 1: releasing the lock") < cor.res.find("coro 2: 
holding the lock") or \
+cor.res.find("coro 2: releasing the lock") < cor.res.find("coro 1: holding the 
lock")
         """
diff --git a/pypy/module/exceptions/__init__.py 
b/pypy/module/exceptions/__init__.py
--- a/pypy/module/exceptions/__init__.py
+++ b/pypy/module/exceptions/__init__.py
@@ -52,6 +52,7 @@
         'ResourceWarning'  : 'interp_exceptions.W_ResourceWarning',
         'RuntimeError' : 'interp_exceptions.W_RuntimeError',
         'RuntimeWarning' : 'interp_exceptions.W_RuntimeWarning',
+        'StopAsyncIteration' : 'interp_exceptions.W_StopAsyncIteration',
         'StopIteration' : 'interp_exceptions.W_StopIteration',
         'SyntaxError' : 'interp_exceptions.W_SyntaxError',
         'SyntaxWarning' : 'interp_exceptions.W_SyntaxWarning',
diff --git a/pypy/module/exceptions/interp_exceptions.py 
b/pypy/module/exceptions/interp_exceptions.py
--- a/pypy/module/exceptions/interp_exceptions.py
+++ b/pypy/module/exceptions/interp_exceptions.py
@@ -65,6 +65,7 @@
       +-- RuntimeError
       |    +-- NotImplementedError
       |    +-- RecursionError
+      +-- StopAsyncIteration
       +-- SyntaxError
       |    +-- IndentationError
       |         +-- TabError
@@ -834,6 +835,9 @@
 W_AssertionError = _new_exception('AssertionError', W_Exception,
                                   """Assertion failed.""")
 
+W_StopAsyncIteration = _new_exception('StopAsyncIteration', W_Exception,
+                                  """Signal the end from 
iterator.__anext__().""")
+
 class W_UnicodeDecodeError(W_UnicodeError):
     """Unicode decoding error."""
     w_encoding = None
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -298,7 +298,10 @@
         return w_iter
 
     def next(space, w_obj):
-        w_descr = space.lookup(w_obj, '__next__')
+        if space.type(w_obj).name == 'coroutine':
+            w_descr = space.lookup(w_obj, '__anext__')
+        else:
+            w_descr = space.lookup(w_obj, '__next__')
         if w_descr is None:
             raise oefmt(space.w_TypeError,
                         "'%T' object is not an iterator", w_obj)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to