Apply (my) patch:

[ 526072 ] pickling os.stat results round II

structseq's constructors can now take "invisible" fields in a dict.
Gave the constructors better error messages.
their __reduce__ method puts these fields in a dict.

(this is all in aid of getting os.stat_result's to pickle portably)

Also fixes

[ 526039 ] devious code can crash structseqs

Thought needed about how much of this counts as a bugfix.  Certainly
#526039 needs to be fixed.
This commit is contained in:
Michael W. Hudson 2002-03-06 17:07:49 +00:00
parent da8a6dd072
commit ce358e3015
1 changed files with 76 additions and 23 deletions

View File

@ -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 = {