Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6af4757

Browse files
committed
Add support of PyStructSequence in copy.replace()
1 parent 6139bf5 commit 6af4757

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

Objects/structseq.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include "Python.h"
11+
#include "pycore_dict.h" // _PyDict_Pop(()
1112
#include "pycore_tuple.h" // _PyTuple_FromArray()
1213
#include "pycore_object.h" // _PyObject_GC_TRACK()
1314

@@ -365,9 +366,99 @@ structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored))
365366
return NULL;
366367
}
367368

369+
370+
static PyObject *
371+
structseq_replace(PyStructSequence *self, PyObject *args, PyObject *kwargs)
372+
{
373+
PyObject *tup = NULL;
374+
PyObject *dict = NULL;
375+
PyObject *result;
376+
Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
377+
378+
if (!_PyArg_NoPositional("__replace__", args)) {
379+
return NULL;
380+
}
381+
382+
n_fields = REAL_SIZE(self);
383+
if (n_fields < 0) {
384+
return NULL;
385+
}
386+
n_visible_fields = VISIBLE_SIZE(self);
387+
n_unnamed_fields = UNNAMED_FIELDS(self);
388+
if (n_unnamed_fields < 0) {
389+
return NULL;
390+
}
391+
tup = _PyTuple_FromArray(self->ob_item, n_visible_fields);
392+
if (!tup) {
393+
goto error;
394+
}
395+
396+
dict = PyDict_New();
397+
if (!dict) {
398+
goto error;
399+
}
400+
401+
if (kwargs != NULL) {
402+
for (i = 0; i < n_visible_fields; i++) {
403+
const char *name = Py_TYPE(self)->tp_members[i].name;
404+
PyObject *key = PyUnicode_FromString(name);
405+
if (!key) {
406+
goto error;
407+
}
408+
PyObject *ob = _PyDict_Pop(kwargs, key, self->ob_item[i]);
409+
Py_DECREF(key);
410+
if (!ob) {
411+
goto error;
412+
}
413+
PyTuple_SetItem(tup, i, ob);
414+
}
415+
for (i = n_visible_fields; i < n_fields; i++) {
416+
const char *name = Py_TYPE(self)->tp_members[i - n_unnamed_fields].name;
417+
PyObject *key = PyUnicode_FromString(name);
418+
if (!key) {
419+
goto error;
420+
}
421+
PyObject *ob = _PyDict_Pop(kwargs, key, self->ob_item[i]);
422+
if (PyDict_SetItem(dict, key, ob) < 0) {
423+
goto error;
424+
}
425+
}
426+
if (PyDict_Size(kwargs) > 0) {
427+
PyObject *names = PyDict_Keys(kwargs);
428+
if (names) {
429+
PyErr_Format(PyExc_ValueError, "Got unexpected field name(s): %R", names);
430+
Py_DECREF(names);
431+
}
432+
goto error;
433+
}
434+
}
435+
else
436+
{
437+
for (i = n_visible_fields; i < n_fields; i++) {
438+
const char *name = Py_TYPE(self)->tp_members[i - n_unnamed_fields].name;
439+
if (PyDict_SetItemString(dict, name, self->ob_item[i]) < 0) {
440+
goto error;
441+
}
442+
}
443+
}
444+
445+
result = structseq_new_impl(Py_TYPE(self), tup, dict);
446+
447+
Py_DECREF(tup);
448+
Py_DECREF(dict);
449+
450+
return result;
451+
452+
error:
453+
Py_XDECREF(tup);
454+
Py_XDECREF(dict);
455+
return NULL;
456+
}
457+
368458
static PyMethodDef structseq_methods[] = {
369459
{"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
370-
{NULL, NULL}
460+
{"__replace__", _PyCFunction_CAST(structseq_replace), METH_VARARGS | METH_KEYWORDS, NULL},
461+
{NULL, NULL} // sentinel
371462
};
372463

373464
static Py_ssize_t

0 commit comments

Comments
 (0)