mirror of https://github.com/python/cpython
bpo-46527: allow calling enumerate(iterable=...) again (GH-30904)
This commit is contained in:
parent
1e8a3a5579
commit
ac0c6e128c
|
@ -128,6 +128,18 @@ class EnumerateTestCase(unittest.TestCase, PickleTest):
|
||||||
self.assertRaises(TypeError, self.enum, 'abc', 'a') # wrong type
|
self.assertRaises(TypeError, self.enum, 'abc', 'a') # wrong type
|
||||||
self.assertRaises(TypeError, self.enum, 'abc', 2, 3) # too many arguments
|
self.assertRaises(TypeError, self.enum, 'abc', 2, 3) # too many arguments
|
||||||
|
|
||||||
|
def test_kwargs(self):
|
||||||
|
self.assertEqual(list(self.enum(iterable=Ig(self.seq))), self.res)
|
||||||
|
expected = list(self.enum(Ig(self.seq), 0))
|
||||||
|
self.assertEqual(list(self.enum(iterable=Ig(self.seq), start=0)),
|
||||||
|
expected)
|
||||||
|
self.assertEqual(list(self.enum(start=0, iterable=Ig(self.seq))),
|
||||||
|
expected)
|
||||||
|
self.assertRaises(TypeError, self.enum, iterable=[], x=3)
|
||||||
|
self.assertRaises(TypeError, self.enum, start=0, x=3)
|
||||||
|
self.assertRaises(TypeError, self.enum, x=0, y=3)
|
||||||
|
self.assertRaises(TypeError, self.enum, x=0)
|
||||||
|
|
||||||
@support.cpython_only
|
@support.cpython_only
|
||||||
def test_tuple_reuse(self):
|
def test_tuple_reuse(self):
|
||||||
# Tests an implementation detail where tuple is reused
|
# Tests an implementation detail where tuple is reused
|
||||||
|
@ -266,14 +278,16 @@ class EnumerateStartTestCase(EnumerateTestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestStart(EnumerateStartTestCase):
|
class TestStart(EnumerateStartTestCase):
|
||||||
|
def enum(self, iterable, start=11):
|
||||||
|
return enumerate(iterable, start=start)
|
||||||
|
|
||||||
enum = lambda self, i: enumerate(i, start=11)
|
|
||||||
seq, res = 'abc', [(11, 'a'), (12, 'b'), (13, 'c')]
|
seq, res = 'abc', [(11, 'a'), (12, 'b'), (13, 'c')]
|
||||||
|
|
||||||
|
|
||||||
class TestLongStart(EnumerateStartTestCase):
|
class TestLongStart(EnumerateStartTestCase):
|
||||||
|
def enum(self, iterable, start=sys.maxsize + 1):
|
||||||
|
return enumerate(iterable, start=start)
|
||||||
|
|
||||||
enum = lambda self, i: enumerate(i, start=sys.maxsize+1)
|
|
||||||
seq, res = 'abc', [(sys.maxsize+1,'a'), (sys.maxsize+2,'b'),
|
seq, res = 'abc', [(sys.maxsize+1,'a'), (sys.maxsize+2,'b'),
|
||||||
(sys.maxsize+3,'c')]
|
(sys.maxsize+3,'c')]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Allow passing ``iterable`` as a keyword argument to :func:`enumerate` again.
|
||||||
|
Patch by Jelle Zijlstra.
|
|
@ -83,6 +83,18 @@ enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start)
|
||||||
return (PyObject *)en;
|
return (PyObject *)en;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_keyword(PyObject *kwnames, int index,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
PyObject *kw = PyTuple_GET_ITEM(kwnames, index);
|
||||||
|
if (!_PyUnicode_EqualToASCIIString(kw, name)) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"'%S' is an invalid keyword argument for enumerate()", kw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Use AC when bpo-43447 is supported
|
// TODO: Use AC when bpo-43447 is supported
|
||||||
static PyObject *
|
static PyObject *
|
||||||
enumerate_vectorcall(PyObject *type, PyObject *const *args,
|
enumerate_vectorcall(PyObject *type, PyObject *const *args,
|
||||||
|
@ -91,31 +103,46 @@ enumerate_vectorcall(PyObject *type, PyObject *const *args,
|
||||||
PyTypeObject *tp = _PyType_CAST(type);
|
PyTypeObject *tp = _PyType_CAST(type);
|
||||||
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
Py_ssize_t nkwargs = 0;
|
Py_ssize_t nkwargs = 0;
|
||||||
if (nargs == 0) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"enumerate() missing required argument 'iterable'");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (kwnames != NULL) {
|
if (kwnames != NULL) {
|
||||||
nkwargs = PyTuple_GET_SIZE(kwnames);
|
nkwargs = PyTuple_GET_SIZE(kwnames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manually implement enumerate(iterable, start=...)
|
||||||
if (nargs + nkwargs == 2) {
|
if (nargs + nkwargs == 2) {
|
||||||
if (nkwargs == 1) {
|
if (nkwargs == 1) {
|
||||||
PyObject *kw = PyTuple_GET_ITEM(kwnames, 0);
|
if (!check_keyword(kwnames, 0, "start")) {
|
||||||
if (!_PyUnicode_EqualToASCIIString(kw, "start")) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"'%S' is an invalid keyword argument for enumerate()", kw);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
} else if (nkwargs == 2) {
|
||||||
|
PyObject *kw0 = PyTuple_GET_ITEM(kwnames, 0);
|
||||||
|
if (_PyUnicode_EqualToASCIIString(kw0, "start")) {
|
||||||
|
if (!check_keyword(kwnames, 1, "iterable")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return enum_new_impl(tp, args[1], args[0]);
|
||||||
|
}
|
||||||
|
if (!check_keyword(kwnames, 0, "iterable") ||
|
||||||
|
!check_keyword(kwnames, 1, "start")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return enum_new_impl(tp, args[0], args[1]);
|
return enum_new_impl(tp, args[0], args[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nargs == 1 && nkwargs == 0) {
|
if (nargs + nkwargs == 1) {
|
||||||
|
if (nkwargs == 1 && !check_keyword(kwnames, 0, "iterable")) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return enum_new_impl(tp, args[0], NULL);
|
return enum_new_impl(tp, args[0], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nargs == 0) {
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"enumerate() missing required argument 'iterable'");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"enumerate() takes at most 2 arguments (%d given)", nargs + nkwargs);
|
"enumerate() takes at most 2 arguments (%d given)", nargs + nkwargs);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
Loading…
Reference in New Issue