Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
06fdd71
Add `strict` argument
nineteendo Jun 13, 2024
a7966f8
📜🤖 Added by blurb_it.
blurb-it[bot] Jun 13, 2024
89e25d9
Add tests
nineteendo Jun 13, 2024
a48ebcf
Update commented out code
nineteendo Jun 13, 2024
e4ee2fb
Update docs
nineteendo Jun 13, 2024
bdd0fcb
Fix `__reduce__()`
nineteendo Jun 13, 2024
91a8450
Revert `map_vectorcall()`
nineteendo Jun 14, 2024
2c7d524
Reduce diff
nineteendo Jun 14, 2024
5ad7eb2
Never set
nineteendo Jun 14, 2024
6d8584b
Reduce diff 2
nineteendo Jun 14, 2024
e436a2b
Fixed undefined variable
nineteendo Jun 14, 2024
f9a2a49
Apply suggestions from code review
nineteendo Jun 14, 2024
800ac10
Merge branch 'main' into strict-map
nineteendo Jun 19, 2024
301da5d
Update 2024-06-13-19-12-49.gh-issue-119793.FDVCDk.rst
nineteendo Jun 19, 2024
fb1c379
Update whatsnew
nineteendo Jun 19, 2024
255e3a2
Fix pr number
nineteendo Jun 19, 2024
d1c1769
Fix signature
nineteendo Jun 19, 2024
6d20976
Add comment
nineteendo Jun 19, 2024
c338c8f
Add comment 2
nineteendo Jun 19, 2024
99d9c75
Fix typo
nineteendo Jun 19, 2024
63522b3
Update Doc/library/functions.rst
nineteendo Jun 19, 2024
fcb438f
Match news entry of `zip()`
nineteendo Jun 19, 2024
6e97e31
Fix trailing whitespace
nineteendo Jun 19, 2024
54231e0
Update 2024-06-13-19-12-49.gh-issue-119793.FDVCDk.rst
nineteendo Jun 24, 2024
b5e8ac4
Update 2024-06-13-19-12-49.gh-issue-119793.FDVCDk.rst
nineteendo Jun 24, 2024
53f3f58
Remove pep reference
nineteendo Sep 4, 2024
a2fe008
Merge branch 'main' into strict-map
nineteendo Sep 28, 2024
9a2c0fd
Make tests more maintainable
nineteendo Oct 3, 2024
f75e511
Update Python/bltinmodule.c
nineteendo Oct 10, 2024
92134e7
Update Python/bltinmodule.c
nineteendo Oct 10, 2024
e74c3ff
Use correct variable
nineteendo Oct 10, 2024
bf7f350
Update Python/bltinmodule.c
nineteendo Oct 31, 2024
9cc41f2
Rename 2024-06-13-19-12-49.gh-issue-119793.FDVCDk.rst to 2024-06-13-1…
nineteendo Oct 31, 2024
f686101
Fix shadowed variable
nineteendo Oct 31, 2024
e524e17
Apply suggestions from code review
nineteendo Oct 31, 2024
91bdf2f
Rename 2024-06-13-19-12-49.gh-issue-119793.FDVCDk.rst to 2024-06-13-1…
nineteendo Oct 31, 2024
39c34f1
Use same message for news.d
nineteendo Oct 31, 2024
ea65b2c
Update Doc/whatsnew/3.14.rst
nineteendo Oct 31, 2024
45c2d0d
Apply suggestions from code review
nineteendo Oct 31, 2024
ad6c2a5
Sync with what's new
nineteendo Oct 31, 2024
9ebc398
Accept truthy value in setstate
nineteendo Oct 31, 2024
d829a17
Fix removed line
nineteendo Oct 31, 2024
d1d858f
Use stdbool
nineteendo Oct 31, 2024
f23caa5
Revert "Use stdbool"
nineteendo Oct 31, 2024
7e32e2c
Apply suggestions from code review
nineteendo Nov 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Lib/test/test_itertools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2140,10 +2140,10 @@ class subclass(cls):
subclass(*args, newarg=3)

for cls, args, result in testcases:
# Constructors of repeat, zip, compress accept keyword arguments.
# Constructors of repeat, zip, map, compress accept keyword arguments.
Comment thread
nineteendo marked this conversation as resolved.
# Their subclasses need overriding __new__ to support new
# keyword arguments.
if cls in [repeat, zip, compress]:
if cls in [repeat, zip, map, compress]:
continue
with self.subTest(cls):
class subclass_with_init(cls):
Expand Down
130 changes: 80 additions & 50 deletions Python/bltinmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,7 @@ typedef struct {
PyObject_HEAD
PyObject *iters;
PyObject *func;
int strict;
Comment thread
erlend-aasland marked this conversation as resolved.
} mapobject;

static PyObject *
Expand All @@ -1311,10 +1312,21 @@ map_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
PyObject *it, *iters, *func;
mapobject *lz;
Py_ssize_t numargs, i;
int strict = 0;

if ((type == &PyMap_Type || type->tp_init == PyMap_Type.tp_init) &&
!_PyArg_NoKeywords("map", kwds))
return NULL;
if (kwds) {
PyObject *empty = PyTuple_New(0);
if (empty == NULL) {
return NULL;
}
static char *kwlist[] = {"strict", NULL};
int parsed = PyArg_ParseTupleAndKeywords(
empty, kwds, "|$p:map", kwlist, &strict);
Py_DECREF(empty);
if (!parsed) {
return NULL;
}
}

numargs = PyTuple_Size(args);
if (numargs < 2) {
Expand Down Expand Up @@ -1346,47 +1358,7 @@ map_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
lz->iters = iters;
func = PyTuple_GET_ITEM(args, 0);
lz->func = Py_NewRef(func);

return (PyObject *)lz;
}

static PyObject *
map_vectorcall(PyObject *type, PyObject * const*args,
Comment thread
nineteendo marked this conversation as resolved.
size_t nargsf, PyObject *kwnames)
{
PyTypeObject *tp = _PyType_CAST(type);
if (tp == &PyMap_Type && !_PyArg_NoKwnames("map", kwnames)) {
return NULL;
}

Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (nargs < 2) {
PyErr_SetString(PyExc_TypeError,
"map() must have at least two arguments.");
return NULL;
}

PyObject *iters = PyTuple_New(nargs-1);
if (iters == NULL) {
return NULL;
}

for (int i=1; i<nargs; i++) {
PyObject *it = PyObject_GetIter(args[i]);
if (it == NULL) {
Py_DECREF(iters);
return NULL;
}
PyTuple_SET_ITEM(iters, i-1, it);
}

mapobject *lz = (mapobject *)tp->tp_alloc(tp, 0);
if (lz == NULL) {
Py_DECREF(iters);
return NULL;
}
lz->iters = iters;
lz->func = Py_NewRef(args[0]);
lz->strict = strict;

return (PyObject *)lz;
}
Expand All @@ -1411,6 +1383,7 @@ map_traverse(mapobject *lz, visitproc visit, void *arg)
static PyObject *
map_next(mapobject *lz)
{
Py_ssize_t i;
Comment thread
picnixz marked this conversation as resolved.
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
PyObject **stack;
PyObject *result = NULL;
Expand All @@ -1429,10 +1402,13 @@ map_next(mapobject *lz)
}

Py_ssize_t nargs = 0;
for (Py_ssize_t i=0; i < niters; i++) {
for (i=0; i < niters; i++) {
Comment thread
rhettinger marked this conversation as resolved.
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
PyObject *val = Py_TYPE(it)->tp_iternext(it);
if (val == NULL) {
if (lz->strict) {
goto check;
}
goto exit;
}
stack[i] = val;
Expand All @@ -1449,6 +1425,43 @@ map_next(mapobject *lz)
PyMem_Free(stack);
}
return result;
check:
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
Comment thread
erlend-aasland marked this conversation as resolved.
return NULL;
}
PyErr_Clear();
}
if (i) {
// ValueError: map() argument 2 is shorter than argument 1
// ValueError: map() argument 3 is shorter than arguments 1-2
Comment thread
encukou marked this conversation as resolved.
const char* plural = i == 1 ? " " : "s 1-";
Comment thread
erlend-aasland marked this conversation as resolved.
return PyErr_Format(PyExc_ValueError,
"map() argument %d is shorter than argument%s%d",
i + 1, plural, i);
}
for (i = 1; i < niters; i++) {
PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
PyObject *val = (*Py_TYPE(it)->tp_iternext)(it);
if (val) {
Py_DECREF(val);
const char* plural = i == 1 ? " " : "s 1-";
return PyErr_Format(PyExc_ValueError,
"map() argument %d is longer than argument%s%d",
i + 1, plural, i);
}
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(PyExc_StopIteration)) {
// next() on argument i raised an exception (not StopIteration)
return NULL;
}
PyErr_Clear();
}
// Argument i is exhausted. So far so good...
}
// All arguments are exhausted. Success!
goto exit; // Cleanup
Comment thread
nineteendo marked this conversation as resolved.
Outdated
}

static PyObject *
Expand All @@ -1465,21 +1478,41 @@ map_reduce(mapobject *lz, PyObject *Py_UNUSED(ignored))
PyTuple_SET_ITEM(args, i+1, Py_NewRef(it));
}

if (lz->strict) {
Py_BuildValue("ONO", Py_TYPE(lz), args, Py_True);
}
return Py_BuildValue("ON", Py_TYPE(lz), args);
}

PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");

static PyObject *
map_setstate(mapobject *lz, PyObject *state)
{
int strict = PyObject_IsTrue(state);
Comment thread
nineteendo marked this conversation as resolved.
if (strict < 0) {
return NULL;
}
lz->strict = strict;
Py_RETURN_NONE;
}

static PyMethodDef map_methods[] = {
{"__reduce__", _PyCFunction_CAST(map_reduce), METH_NOARGS, reduce_doc},
{"__setstate__", (PyCFunction)map_setstate, METH_O, setstate_doc},
Comment thread
nineteendo marked this conversation as resolved.
Outdated
{NULL, NULL} /* sentinel */
};


PyDoc_STRVAR(map_doc,
"map(function, /, *iterables)\n\
"map(function, /, *iterables, strict=False)\n\
--\n\
\n\
Make an iterator that computes the function using arguments from\n\
each of the iterables. Stops when the shortest iterable is exhausted.");
each of the iterables. Stops when the shortest iterable is exhausted.\n\
\n\
If strict is true and one of the arguments is exhausted before the others,\n\
raise a ValueError.");

PyTypeObject PyMap_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
Expand Down Expand Up @@ -1523,7 +1556,6 @@ PyTypeObject PyMap_Type = {
PyType_GenericAlloc, /* tp_alloc */
map_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
.tp_vectorcall = (vectorcallfunc)map_vectorcall
};


Expand Down Expand Up @@ -2974,8 +3006,6 @@ zip_reduce(zipobject *lz, PyObject *Py_UNUSED(ignored))
return PyTuple_Pack(2, Py_TYPE(lz), lz->ittuple);
}

PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");

static PyObject *
zip_setstate(zipobject *lz, PyObject *state)
{
Expand Down