diff -r 8e3d359cc73b Include/genobject.h --- a/Include/genobject.h Tue Nov 08 19:59:57 2016 -0500 +++ b/Include/genobject.h Tue Nov 08 20:10:08 2016 -0500 @@ -55,9 +55,6 @@ PyAPI_DATA(PyTypeObject) PyCoro_Type; PyAPI_DATA(PyTypeObject) _PyCoroWrapper_Type; -PyAPI_DATA(PyTypeObject) _PyAIterWrapper_Type; -PyObject *_PyAIterWrapper_New(PyObject *aiter); - #define PyCoro_CheckExact(op) (Py_TYPE(op) == &PyCoro_Type) PyObject *_PyCoro_GetAwaitableIter(PyObject *o); PyAPI_FUNC(PyObject *) PyCoro_New(struct _frame *, diff -r 8e3d359cc73b Lib/asyncio/streams.py --- a/Lib/asyncio/streams.py Tue Nov 08 19:59:57 2016 -0500 +++ b/Lib/asyncio/streams.py Tue Nov 08 20:10:08 2016 -0500 @@ -676,20 +676,12 @@ self._maybe_resume_transport() return data - if compat.PY35: - @coroutine - def __aiter__(self): - return self + def __aiter__(self): + return self - @coroutine - def __anext__(self): - val = yield from self.readline() - if val == b'': - raise StopAsyncIteration - return val - - if compat.PY352: - # In Python 3.5.2 and greater, __aiter__ should return - # the asynchronous iterator directly. - def __aiter__(self): - return self + @coroutine + def __anext__(self): + val = yield from self.readline() + if val == b'': + raise StopAsyncIteration + return val diff -r 8e3d359cc73b Lib/test/test_coroutines.py --- a/Lib/test/test_coroutines.py Tue Nov 08 19:59:57 2016 -0500 +++ b/Lib/test/test_coroutines.py Tue Nov 08 20:10:08 2016 -0500 @@ -1379,7 +1379,7 @@ def __init__(self): self.i = 0 - async def __aiter__(self): + def __aiter__(self): nonlocal aiter_calls aiter_calls += 1 return self @@ -1398,9 +1398,8 @@ buffer = [] async def test1(): - with self.assertWarnsRegex(DeprecationWarning, "legacy"): - async for i1, i2 in AsyncIter(): - buffer.append(i1 + i2) + async for i1, i2 in AsyncIter(): + buffer.append(i1 + i2) yielded, _ = run_async(test1()) # Make sure that __aiter__ was called only once @@ -1412,13 +1411,12 @@ buffer = [] async def test2(): nonlocal buffer - with self.assertWarnsRegex(DeprecationWarning, "legacy"): - async for i in AsyncIter(): - buffer.append(i[0]) - if i[0] == 20: - break - else: - buffer.append('what?') + async for i in AsyncIter(): + buffer.append(i[0]) + if i[0] == 20: + break + else: + buffer.append('what?') buffer.append('end') yielded, _ = run_async(test2()) @@ -1431,13 +1429,12 @@ buffer = [] async def test3(): nonlocal buffer - with self.assertWarnsRegex(DeprecationWarning, "legacy"): - async for i in AsyncIter(): - if i[0] > 20: - continue - buffer.append(i[0]) - else: - buffer.append('what?') + async for i in AsyncIter(): + if i[0] > 20: + continue + buffer.append(i[0]) + else: + buffer.append('what?') buffer.append('end') yielded, _ = run_async(test3()) @@ -1476,7 +1473,7 @@ with self.assertRaisesRegex( TypeError, - r"async for' received an invalid object.*__aiter.*\: I"): + r"requires an iterator with __anext__"): run_async(foo()) @@ -1507,16 +1504,15 @@ def test_for_5(self): class I: - async def __aiter__(self): + def __aiter__(self): return self def __anext__(self): return 123 async def foo(): - with self.assertWarnsRegex(DeprecationWarning, "legacy"): - async for i in I(): - print('never going to happen') + async for i in I(): + print('never going to happen') with self.assertRaisesRegex( TypeError, @@ -1619,13 +1615,12 @@ def test_for_7(self): CNT = 0 class AI: - async def __aiter__(self): + def __aiter__(self): 1/0 async def foo(): nonlocal CNT - with self.assertWarnsRegex(DeprecationWarning, "legacy"): - async for i in AI(): - CNT += 1 + async for i in AI(): + CNT += 1 CNT += 10 with self.assertRaises(ZeroDivisionError): run_async(foo()) @@ -1649,37 +1644,6 @@ run_async(foo()) self.assertEqual(CNT, 0) - def test_for_9(self): - # Test that DeprecationWarning can safely be converted into - # an exception (__aiter__ should not have a chance to raise - # a ZeroDivisionError.) - class AI: - async def __aiter__(self): - 1/0 - async def foo(): - async for i in AI(): - pass - - with self.assertRaises(DeprecationWarning): - with warnings.catch_warnings(): - warnings.simplefilter("error") - run_async(foo()) - - def test_for_10(self): - # Test that DeprecationWarning can safely be converted into - # an exception. - class AI: - async def __aiter__(self): - pass - async def foo(): - async for i in AI(): - pass - - with self.assertRaises(DeprecationWarning): - with warnings.catch_warnings(): - warnings.simplefilter("error") - run_async(foo()) - def test_for_tuple(self): class Done(Exception): pass diff -r 8e3d359cc73b Objects/genobject.c --- a/Objects/genobject.c Tue Nov 08 19:59:57 2016 -0500 +++ b/Objects/genobject.c Tue Nov 08 20:10:08 2016 -0500 @@ -1133,100 +1133,6 @@ } -/* __aiter__ wrapper; see http://bugs.python.org/issue27243 for details. */ - -typedef struct { - PyObject_HEAD - PyObject *ags_aiter; -} PyAIterWrapper; - - -static PyObject * -aiter_wrapper_iternext(PyAIterWrapper *aw) -{ - _PyGen_SetStopIterationValue(aw->ags_aiter); - return NULL; -} - -static int -aiter_wrapper_traverse(PyAIterWrapper *aw, visitproc visit, void *arg) -{ - Py_VISIT((PyObject *)aw->ags_aiter); - return 0; -} - -static void -aiter_wrapper_dealloc(PyAIterWrapper *aw) -{ - _PyObject_GC_UNTRACK((PyObject *)aw); - Py_CLEAR(aw->ags_aiter); - PyObject_GC_Del(aw); -} - -static PyAsyncMethods aiter_wrapper_as_async = { - PyObject_SelfIter, /* am_await */ - 0, /* am_aiter */ - 0 /* am_anext */ -}; - -PyTypeObject _PyAIterWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "aiter_wrapper", - sizeof(PyAIterWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)aiter_wrapper_dealloc, /* destructor tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - &aiter_wrapper_as_async, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - "A wrapper object for __aiter__ bakwards compatibility.", - (traverseproc)aiter_wrapper_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)aiter_wrapper_iternext, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ -}; - - -PyObject * -_PyAIterWrapper_New(PyObject *aiter) -{ - PyAIterWrapper *aw = PyObject_GC_New(PyAIterWrapper, - &_PyAIterWrapper_Type); - if (aw == NULL) { - return NULL; - } - Py_INCREF(aiter); - aw->ags_aiter = aiter; - _PyObject_GC_TRACK(aw); - return (PyObject *)aw; -} - - /* ========= Asynchronous Generators ========= */ diff -r 8e3d359cc73b Python/ceval.c --- a/Python/ceval.c Tue Nov 08 19:59:57 2016 -0500 +++ b/Python/ceval.c Tue Nov 08 20:10:08 2016 -0500 @@ -1854,7 +1854,6 @@ TARGET(GET_AITER) { unaryfunc getter = NULL; PyObject *iter = NULL; - PyObject *awaitable = NULL; PyObject *obj = TOP(); PyTypeObject *type = Py_TYPE(obj); @@ -1881,57 +1880,7 @@ goto error; } - if (Py_TYPE(iter)->tp_as_async != NULL && - Py_TYPE(iter)->tp_as_async->am_anext != NULL) { - - /* Starting with CPython 3.5.2 __aiter__ should return - asynchronous iterators directly (not awaitables that - resolve to asynchronous iterators.) - - Therefore, we check if the object that was returned - from __aiter__ has an __anext__ method. If it does, - we wrap it in an awaitable that resolves to `iter`. - - See http://bugs.python.org/issue27243 for more - details. - */ - - PyObject *wrapper = _PyAIterWrapper_New(iter); - Py_DECREF(iter); - SET_TOP(wrapper); - DISPATCH(); - } - - awaitable = _PyCoro_GetAwaitableIter(iter); - if (awaitable == NULL) { - SET_TOP(NULL); - PyErr_Format( - PyExc_TypeError, - "'async for' received an invalid object " - "from __aiter__: %.100s", - Py_TYPE(iter)->tp_name); - - Py_DECREF(iter); - goto error; - } else { - Py_DECREF(iter); - - if (PyErr_WarnFormat( - PyExc_DeprecationWarning, 1, - "'%.100s' implements legacy __aiter__ protocol; " - "__aiter__ should return an asynchronous " - "iterator, not awaitable", - type->tp_name)) - { - /* Warning was converted to an error. */ - Py_DECREF(awaitable); - SET_TOP(NULL); - goto error; - } - } - - SET_TOP(awaitable); - PREDICT(LOAD_CONST); + SET_TOP(iter); DISPATCH(); } diff -r 8e3d359cc73b Python/compile.c --- a/Python/compile.c Tue Nov 08 19:59:57 2016 -0500 +++ b/Python/compile.c Tue Nov 08 20:10:08 2016 -0500 @@ -2205,8 +2205,6 @@ VISIT(c, expr, s->v.AsyncFor.iter); ADDOP(c, GET_AITER); - ADDOP_O(c, LOAD_CONST, Py_None, consts); - ADDOP(c, YIELD_FROM); compiler_use_next_block(c, try); @@ -3772,8 +3770,6 @@ /* Sub-iter - calculate on the fly */ VISIT(c, expr, gen->iter); ADDOP(c, GET_AITER); - ADDOP_O(c, LOAD_CONST, Py_None, consts); - ADDOP(c, YIELD_FROM); } compiler_use_next_block(c, try); @@ -3938,8 +3934,6 @@ if (outermost->is_async) { ADDOP(c, GET_AITER); - ADDOP_O(c, LOAD_CONST, Py_None, consts); - ADDOP(c, YIELD_FROM); } else { ADDOP(c, GET_ITER); }