We use finally blocks in ``__aiter__`` like this: ``` class AsyncFinallyIterator: def __aiter__(self): for i in range(10): try: yield i finally: print('FINALLY') ``` Attached is a test for both iterators and async iterators. The tests pass on Python 3.6, but only the non-async iterator test pass under Python 3.7. Thanks for your attention! This worked perfectly well in Python 3.6, but stopped working in Python 3.7. I also verified that Iterator supports the same construct (and this works in both Python 3.6 and 3.7): ``` class FinallyIterator: def __iter__(self): for i in range(10): try: yield i finally: print('FINALLY') ```
The attached script fails on master too. On bisecting could this be possibly caused due to 41e5ec377b (bpo-34769) ? Tagging Ned since it was introduced from 3.7.1rc2 and also backported to 3.6 . ➜ cpython git:(41e5ec377b) git checkout 41e5ec377b && make -s -j4 > /dev/null HEAD is now at 41e5ec377bbpo-34769: Thread safety for _asyncgen_finalizer_hook(). (GH-9716) ➜ cpython git:(41e5ec377b) ./python.exe ../backups/bpo36403.py F. ====================================================================== FAIL: test_main (__main__.TestAsyncIteratorFinally) ---------------------------------------------------------------------- Traceback (most recent call last): File "../backups/bpo36403.py", line 30, in test_main self.assertTrue(it.finally_executed) AssertionError: False is not true ---------------------------------------------------------------------- Ran 2 tests in 0.002s FAILED (failures=1) ➜ cpython git:(41e5ec377b) git checkout 41e5ec377b~1 && make -s -j4 > /dev/null Previous HEAD position was 41e5ec377bbpo-34769: Thread safety for _asyncgen_finalizer_hook(). (GH-9716) HEAD is now at 0ce31d340bbpo-32962: Fix test_gdb failure in debug build with -mcet -fcf-protection -O0 (GH-9656) ➜ cpython git:(0ce31d340b) ./python.exe ../backups/bpo36403.py .. ---------------------------------------------------------------------- Ran 2 tests in 0.003s OK
Ah, so the extra call_soon means it needs a: [code] loop.run_until_complete(asyncio.sleep(0))``` [/code] before the self.assertTrue(it.finally_executed) to finish executing agen.close(). Why is create_task different? Does it execute an iteration of the generator immediately? Seems good for this behavior to be consistent, but not sure how difficult that would be.
Perhaps we could add a self._finally to the event loop itself? Like loop._ready, but a list of callbacks run_until_complete will call before returning?
From my understanding yield inside __aiter__ is a forbidden construction. Even if parser allows it the statement doesn't make any sense. I'm very interested to hear Yuri opinion.
I note this is marked as a 3.7regression and still open. Since the cutoff for the final 3.7 bugfix mode release is in a few days, I'm assuming this means that 3.7 users will have to live with this regression. If you feel that is a problem, speak up now.