mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-110222: Add support of PyStructSequence in copy.replace() (GH-110223)
This commit is contained in:
parent
9561648f4a
commit
3bbe3b7c82
3 changed files with 155 additions and 1 deletions
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "Python.h"
|
||||
#include "pycore_dict.h" // _PyDict_Pop()
|
||||
#include "pycore_tuple.h" // _PyTuple_FromArray()
|
||||
#include "pycore_object.h" // _PyObject_GC_TRACK()
|
||||
|
||||
|
@ -380,9 +381,82 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
structseq_replace(PyStructSequence *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
PyStructSequence *result = NULL;
|
||||
Py_ssize_t n_fields, n_unnamed_fields, i;
|
||||
|
||||
if (!_PyArg_NoPositional("__replace__", args)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
n_fields = REAL_SIZE(self);
|
||||
if (n_fields < 0) {
|
||||
return NULL;
|
||||
}
|
||||
n_unnamed_fields = UNNAMED_FIELDS(self);
|
||||
if (n_unnamed_fields < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (n_unnamed_fields > 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__replace__() is not supported for %.500s "
|
||||
"because it has unnamed field(s)",
|
||||
Py_TYPE(self)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = (PyStructSequence *) PyStructSequence_New(Py_TYPE(self));
|
||||
if (!result) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (kwargs != NULL) {
|
||||
// We do not support types with unnamed fields, so we can iterate over
|
||||
// i >= n_visible_fields case without slicing with (i - n_unnamed_fields).
|
||||
for (i = 0; i < n_fields; ++i) {
|
||||
PyObject *key = PyUnicode_FromString(Py_TYPE(self)->tp_members[i].name);
|
||||
if (!key) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *ob = _PyDict_Pop(kwargs, key, self->ob_item[i]);
|
||||
Py_DECREF(key);
|
||||
if (!ob) {
|
||||
goto error;
|
||||
}
|
||||
result->ob_item[i] = ob;
|
||||
}
|
||||
// Check if there are any unexpected fields.
|
||||
if (PyDict_GET_SIZE(kwargs) > 0) {
|
||||
PyObject *names = PyDict_Keys(kwargs);
|
||||
if (names) {
|
||||
PyErr_Format(PyExc_TypeError, "Got unexpected field name(s): %R", names);
|
||||
Py_DECREF(names);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just create a copy of the original.
|
||||
for (i = 0; i < n_fields; ++i) {
|
||||
result->ob_item[i] = Py_NewRef(self->ob_item[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject *)result;
|
||||
|
||||
error:
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyMethodDef structseq_methods[] = {
|
||||
{"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
|
||||
{NULL, NULL}
|
||||
{"__replace__", _PyCFunction_CAST(structseq_replace), METH_VARARGS | METH_KEYWORDS, NULL},
|
||||
{NULL, NULL} // sentinel
|
||||
};
|
||||
|
||||
static Py_ssize_t
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue