summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Objects/structseq.c99
1 files changed, 76 insertions, 23 deletions
diff --git a/Objects/structseq.c b/Objects/structseq.c
index e5f8e09..9228e0f 100644
--- a/Objects/structseq.c
+++ b/Objects/structseq.c
@@ -84,39 +84,79 @@ static PyObject *
structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *arg = NULL;
+ PyObject *dict = NULL;
+ PyObject *ob;
PyStructSequence *res = NULL;
- int len, required_len, i;
- static char *kwlist[] = {"sequence", 0};
- static char msgbuf[128];
+ int len, min_len, max_len, i;
+ static char *kwlist[] = {"sequence", "dict", 0};
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:structseq",
- kwlist, &arg))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
+ kwlist, &arg, &dict))
return NULL;
- if (!PySequence_Check(arg)) {
- PyErr_SetString(PyExc_TypeError,
- "constructor requires a sequence");
+ arg = PySequence_Fast(arg, "constructor requires a sequence");
+
+ if (!arg) {
return NULL;
}
- len = PySequence_Length(arg);
- required_len = REAL_SIZE_TP(type);
- if (len != required_len) {
- PyOS_snprintf(
- msgbuf, sizeof(msgbuf),
- "constructor takes exactly %d arguments (%d given)",
- required_len,
- len);
- PyErr_SetString(PyExc_TypeError, msgbuf);
+ if (dict && !PyDict_Check(dict)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.500s() takes a dict as second arg, if any",
+ type->tp_name);
+ Py_DECREF(arg);
return NULL;
}
+ len = PySequence_Fast_GET_SIZE(arg);
+ min_len = VISIBLE_SIZE_TP(type);
+ max_len = REAL_SIZE_TP(type);
+
+ if (min_len != max_len) {
+ if (len < min_len) {
+ PyErr_Format(PyExc_TypeError,
+ "%.500s() takes an at least %d-sequence (%d-sequence given)",
+ type->tp_name, min_len, len);
+ Py_DECREF(arg);
+ return NULL;
+ }
+
+ if (len > max_len) {
+ PyErr_Format(PyExc_TypeError,
+ "%.500s() takes an at most %d-sequence (%d-sequence given)",
+ type->tp_name, max_len, len);
+ Py_DECREF(arg);
+ return NULL;
+ }
+ }
+ else {
+ if (len != min_len) {
+ PyErr_Format(PyExc_TypeError,
+ "%.500s() takes a %d-sequence (%d-sequence given)",
+ type->tp_name, min_len, len);
+ Py_DECREF(arg);
+ return NULL;
+ }
+ }
+
res = (PyStructSequence*) PyStructSequence_New(type);
for (i = 0; i < len; ++i) {
- /* INCREF???? XXXX */
- res->ob_item[i] = PySequence_GetItem(arg, i);
+ PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
+ Py_INCREF(v);
+ res->ob_item[i] = v;
+ }
+ for (; i < max_len; ++i) {
+ if (dict && (ob = PyDict_GetItemString(
+ dict, type->tp_members[i].name))) {
+ }
+ else {
+ ob = Py_None;
+ }
+ Py_INCREF(ob);
+ res->ob_item[i] = ob;
}
+ Py_DECREF(arg);
return (PyObject*) res;
}
@@ -192,21 +232,34 @@ static PyObject *
structseq_reduce(PyStructSequence* self)
{
PyObject* tup;
- long n_fields;
+ PyObject* dict;
+ long n_fields, n_visible_fields;
int i;
n_fields = REAL_SIZE(self);
- tup = PyTuple_New(n_fields);
+ n_visible_fields = VISIBLE_SIZE(self);
+ tup = PyTuple_New(n_visible_fields);
if (!tup) {
return NULL;
}
- for (i = 0; i < n_fields; i++) {
+ dict = PyDict_New();
+ if (!dict) {
+ Py_DECREF(tup);
+ return NULL;
+ }
+
+ for (i = 0; i < n_visible_fields; i++) {
Py_INCREF(self->ob_item[i]);
PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
}
- return Py_BuildValue("(O(O))", self->ob_type, tup);
+ for (; i < n_fields; i++) {
+ PyDict_SetItemString(dict, self->ob_type->tp_members[i].name,
+ self->ob_item[i]);
+ }
+
+ return Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
}
static PySequenceMethods structseq_as_sequence = {