From 5c45b25806362336d5c22a007f5414f4a186e435 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Fri, 5 Nov 2010 19:02:35 +0100 Subject: [PATCH] implement builtin next() to make it available in Py2 --- Cython/Compiler/Builtin.py | 37 +++++++++++++++++ tests/run/builtin_next.pyx | 85 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 tests/run/builtin_next.pyx diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index 096af2e8..bafccd04 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -39,6 +39,8 @@ builtin_function_table = [ #('map', "", "", ""), #('max', "", "", ""), #('min', "", "", ""), + ('next', "O", "O", "__Pyx_PyIter_Next"), # not available in Py2 => implemented here + ('next', "OO", "O", "__Pyx_PyIter_Next2"), # not available in Py2 => implemented here #('oct', "", "", ""), # Not worth doing open, when second argument would become mandatory #('open', "ss", "O", "PyFile_FromString"), @@ -158,6 +160,40 @@ proto = """ #define __Pyx_PyNumber_Power2(a, b) PyNumber_Power(a, b, Py_None) """) +iter_next_utility_code = UtilityCode( +proto = """ +#define __Pyx_PyIter_Next(obj) __Pyx_PyIter_Next2(obj, NULL); +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject *, PyObject *); /*proto*/ +""", +# copied from Py3's builtin_next() +impl = ''' +static CYTHON_INLINE PyObject *__Pyx_PyIter_Next2(PyObject* iterator, PyObject* defval) { + PyObject* next; + if (unlikely(!PyIter_Check(iterator))) { + PyErr_Format(PyExc_TypeError, + "%.200s object is not an iterator", iterator->ob_type->tp_name); + return NULL; + } + next = (*iterator->ob_type->tp_iternext)(iterator); + if (likely(next)) { + return next; + } else if (defval) { + if (PyErr_Occurred()) { + if(!PyErr_ExceptionMatches(PyExc_StopIteration)) + return NULL; + PyErr_Clear(); + } + Py_INCREF(defval); + return defval; + } else if (PyErr_Occurred()) { + return NULL; + } else { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } +} +''') + getattr3_utility_code = UtilityCode( proto = """ static PyObject *__Pyx_GetAttr3(PyObject *, PyObject *, PyObject *); /*proto*/ @@ -390,6 +426,7 @@ builtin_utility_code = { 'exec' : pyexec_utility_code, 'getattr3' : getattr3_utility_code, 'pow' : pow2_utility_code, + 'next' : iter_next_utility_code, 'intern' : intern_utility_code, 'set' : py23_set_utility_code, 'frozenset' : py23_set_utility_code, diff --git a/tests/run/builtin_next.pyx b/tests/run/builtin_next.pyx new file mode 100644 index 00000000..53a75cbd --- /dev/null +++ b/tests/run/builtin_next.pyx @@ -0,0 +1,85 @@ + +import sys +IS_PY3 = sys.version_info[0] >= 3 + +__doc__ = """ +>>> it = iter([1,2,3]) +>>> if not IS_PY3: +... next = type(it).next +>>> next(it) +1 +>>> next(it) +2 +>>> next(it) +3 + +>>> next(it) +Traceback (most recent call last): +StopIteration + +>>> next(it) +Traceback (most recent call last): +StopIteration + +>>> if IS_PY3: next(it, 123) +... else: print(123) +123 +""" + +def test_single_next(it): + """ + >>> it = iter([1,2,3]) + >>> test_single_next(it) + 1 + >>> test_single_next(it) + 2 + >>> test_single_next(it) + 3 + >>> test_single_next(it) + Traceback (most recent call last): + StopIteration + >>> test_single_next(it) + Traceback (most recent call last): + StopIteration + """ + return next(it) + +def test_default_next(it, default): + """ + >>> it = iter([1,2,3]) + >>> test_default_next(it, 99) + 1 + >>> test_default_next(it, 99) + 2 + >>> test_default_next(it, 99) + 3 + >>> test_default_next(it, 99) + 99 + >>> test_default_next(it, 99) + 99 + """ + return next(it, default) + +def test_next_not_iterable(it): + """ + >>> test_next_not_iterable(123) + Traceback (most recent call last): + TypeError: int object is not an iterator + """ + return next(it) + +def test_next_override(it): + """ + >>> it = iter([1,2,3]) + >>> test_next_override(it) + 1 + >>> test_next_override(it) + 1 + >>> test_next_override(it) + 1 + >>> test_next_override(it) + 1 + """ + def next(it): + return 1 + return next(it) -- 2.26.2