Commit 314d2c4d authored by Stefan Behnel's avatar Stefan Behnel

remove support for the pre-Py3.5.2 aiter protocol that slows down the overall implementation

parent d41842dc
......@@ -9571,13 +9571,6 @@ class AwaitExprNode(_YieldDelegationExprNode):
return "__Pyx_Coroutine_Yield_From"
class AIterAwaitExprNode(AwaitExprNode):
# 'await' expression node used in async-for loops to support the pre-Py3.5.2 'aiter' protocol
def yield_from_func(self, code):
code.globalstate.use_utility_code(UtilityCode.load_cached("CoroutineAIterYieldFrom", "Coroutine.c"))
return "__Pyx_Coroutine_AIter_Yield_From"
class AwaitIterNextExprNode(AwaitExprNode):
# 'await' expression node as part of 'async for' iteration
#
......
......@@ -6315,12 +6315,11 @@ class AsyncForStatNode(_ForInStatNode):
is_async = True
def __init__(self, pos, iterator, **kw):
def __init__(self, pos, **kw):
assert 'item' not in kw
from . import ExprNodes
# AwaitExprNodes must appear before running MarkClosureVisitor
kw['iterator'] = ExprNodes.AIterAwaitExprNode(iterator.pos, arg=iterator)
kw['item'] = ExprNodes.AwaitIterNextExprNode(iterator.pos, arg=None)
kw['item'] = ExprNodes.AwaitIterNextExprNode(kw['iterator'].pos, arg=None)
_ForInStatNode.__init__(self, pos, **kw)
def _create_item_node(self):
......
......@@ -45,44 +45,18 @@ static CYTHON_INLINE PyObject* __Pyx_Generator_Yield_From(__pyx_CoroutineObject
//////////////////// CoroutineYieldFrom.proto ////////////////////
#define __Pyx_Coroutine_Yield_From(gen, source) __Pyx__Coroutine_Yield_From(gen, source, 0)
static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source, int warn);
static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source);
//////////////////// CoroutineYieldFrom ////////////////////
//@requires: Coroutine
//@requires: GetAwaitIter
static int __Pyx_WarnAIterDeprecation(CYTHON_UNUSED PyObject *aiter) {
int result;
#if PY_MAJOR_VERSION >= 3
result = PyErr_WarnFormat(
PyExc_DeprecationWarning, 1,
"'%.100s' implements legacy __aiter__ protocol; "
"__aiter__ should return an asynchronous "
"iterator, not awaitable",
Py_TYPE(aiter)->tp_name);
#else
result = PyErr_WarnEx(
PyExc_DeprecationWarning,
"object implements legacy __aiter__ protocol; "
"__aiter__ should return an asynchronous "
"iterator, not awaitable",
1);
#endif
return result != 0;
}
static PyObject* __Pyx__Coroutine_Yield_From_Generic(__pyx_CoroutineObject *gen, PyObject *source, int warn) {
static PyObject* __Pyx__Coroutine_Yield_From_Generic(__pyx_CoroutineObject *gen, PyObject *source) {
PyObject *retval;
PyObject *source_gen = __Pyx__Coroutine_GetAwaitableIter(source);
if (unlikely(!source_gen)) {
return NULL;
}
if (warn && unlikely(__Pyx_WarnAIterDeprecation(source))) {
/* Warning was converted to an error. */
Py_DECREF(source_gen);
return NULL;
}
// source_gen is now the iterator, make the first next() call
if (__Pyx_Coroutine_CheckExact(source_gen)) {
retval = __Pyx_Generator_Next(source_gen);
......@@ -97,13 +71,9 @@ static PyObject* __Pyx__Coroutine_Yield_From_Generic(__pyx_CoroutineObject *gen,
return NULL;
}
static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source, int warn) {
static CYTHON_INLINE PyObject* __Pyx_Coroutine_Yield_From(__pyx_CoroutineObject *gen, PyObject *source) {
PyObject *retval;
if (__Pyx_Coroutine_CheckExact(source)) {
if (warn && unlikely(__Pyx_WarnAIterDeprecation(source))) {
/* Warning was converted to an error. */
return NULL;
}
if (unlikely(((__pyx_CoroutineObject*)source)->yieldfrom)) {
PyErr_SetString(
PyExc_RuntimeError,
......@@ -128,63 +98,7 @@ static CYTHON_INLINE PyObject* __Pyx__Coroutine_Yield_From(__pyx_CoroutineObject
}
#endif
} else {
return __Pyx__Coroutine_Yield_From_Generic(gen, source, warn);
}
return NULL;
}
//////////////////// CoroutineAIterYieldFrom.proto ////////////////////
static CYTHON_INLINE PyObject* __Pyx_Coroutine_AIter_Yield_From(__pyx_CoroutineObject *gen, PyObject *source);
//////////////////// CoroutineAIterYieldFrom ////////////////////
//@requires: CoroutineYieldFrom
static CYTHON_INLINE PyObject* __Pyx_Coroutine_AIter_Yield_From(__pyx_CoroutineObject *gen, PyObject *source) {
#if CYTHON_USE_ASYNC_SLOTS
__Pyx_PyAsyncMethodsStruct* am = __Pyx_PyType_AsAsync(source);
if (likely(am && am->am_anext)) {
// 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 return it directly as StopIteration result,
// which avoids yielding.
//
// See http://bugs.python.org/issue27243 for more
// details.
goto store_result;
}
#endif
#if PY_VERSION_HEX < 0x030500B2
if (!__Pyx_PyType_AsAsync(source)) {
#ifdef __Pyx_Coroutine_USED
if (!__Pyx_Coroutine_CheckExact(source)) /* quickly rule out a likely case */
#endif
{
// same as above in slow
PyObject *method = __Pyx_PyObject_GetAttrStr(source, PYIDENT("__anext__"));
if (method) {
Py_DECREF(method);
goto store_result;
}
PyErr_Clear();
}
}
#endif
return __Pyx__Coroutine_Yield_From(gen, source, 1);
store_result:
if (unlikely(PyTuple_Check(source) || __Pyx_TypeCheck(source, (PyTypeObject*)PyExc_StopIteration))) {
PyObject *t = PyTuple_Pack(1, source);
if (unlikely(!t)) return NULL;
PyErr_SetObject(PyExc_StopIteration, t);
Py_DECREF(t);
} else {
PyErr_SetObject(PyExc_StopIteration, source);
return __Pyx__Coroutine_Yield_From_Generic(gen, source);
}
return NULL;
}
......
......@@ -279,9 +279,10 @@ def test_with_for():
print(I[0])
cdef class AI_old:
async def __aiter__(self):
1/0
# old-style pre-3.5.2 AIter protocol - no longer supported
#cdef class AI_old:
# async def __aiter__(self):
# 1/0
cdef class AI_new:
......@@ -291,9 +292,9 @@ cdef class AI_new:
def test_aiter_raises(AI):
"""
>>> test_aiter_raises(AI_old)
RAISED
0
#>>> test_aiter_raises(AI_old)
#RAISED
#0
>>> test_aiter_raises(AI_new)
RAISED
0
......
......@@ -1789,7 +1789,8 @@ class CoroutineTest(unittest.TestCase):
run_async(foo())
self.assertEqual(CNT, 1)
def test_for_1(self):
# old-style pre-Py3.5.2 protocol - no longer supported
def __test_for_1(self):
aiter_calls = 0
class AsyncIter(object):
......@@ -2029,7 +2030,8 @@ class CoroutineTest(unittest.TestCase):
run_async(main())
self.assertEqual(I, 20555255)
def test_for_7(self):
# old-style pre-Py3.5.2 protocol - no longer supported
def __test_for_7(self):
CNT = 0
class AI(object):
async def __aiter__(self):
......@@ -2063,8 +2065,9 @@ class CoroutineTest(unittest.TestCase):
run_async(foo())
self.assertEqual(CNT, 0)
# old-style pre-Py3.5.2 protocol - no longer supported
@min_py27
def test_for_9(self):
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.)
......@@ -2080,8 +2083,9 @@ class CoroutineTest(unittest.TestCase):
warnings.simplefilter("error")
run_async(foo())
# old-style pre-Py3.5.2 protocol - no longer supported
@min_py27
def test_for_10(self):
def __test_for_10(self):
# Test that DeprecationWarning can safely be converted into
# an exception.
class AI(object):
......@@ -2120,7 +2124,8 @@ class CoroutineTest(unittest.TestCase):
err = c.exception
self.assertIsInstance(err.__cause__, ZeroDivisionError)
def test_for_12(self):
# old-style pre-Py3.5.2 protocol - no longer supported
def __test_for_12(self):
class F(object):
def __aiter__(self):
return self
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment