mirror of https://github.com/python/cpython
gh-110235: Raise TypeError for duplicate/unknown fields in PyStructSequence constructor (GH-110258)
This commit is contained in:
parent
bf4bc36069
commit
9561648f4a
|
@ -1,6 +1,7 @@
|
||||||
import copy
|
import copy
|
||||||
import os
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
|
import re
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
@ -91,10 +92,69 @@ class StructSeqTest(unittest.TestCase):
|
||||||
self.assertRaises(TypeError, t, "123")
|
self.assertRaises(TypeError, t, "123")
|
||||||
self.assertRaises(TypeError, t, "123", dict={})
|
self.assertRaises(TypeError, t, "123", dict={})
|
||||||
self.assertRaises(TypeError, t, "123456789", dict=None)
|
self.assertRaises(TypeError, t, "123456789", dict=None)
|
||||||
|
self.assertRaises(TypeError, t, seq="123456789", dict={})
|
||||||
|
|
||||||
|
self.assertEqual(t("123456789"), tuple("123456789"))
|
||||||
|
self.assertEqual(t("123456789", {}), tuple("123456789"))
|
||||||
|
self.assertEqual(t("123456789", dict={}), tuple("123456789"))
|
||||||
|
self.assertEqual(t(sequence="123456789", dict={}), tuple("123456789"))
|
||||||
|
|
||||||
|
self.assertEqual(t("1234567890"), tuple("123456789"))
|
||||||
|
self.assertEqual(t("1234567890").tm_zone, "0")
|
||||||
|
self.assertEqual(t("123456789", {"tm_zone": "some zone"}), tuple("123456789"))
|
||||||
|
self.assertEqual(t("123456789", {"tm_zone": "some zone"}).tm_zone, "some zone")
|
||||||
|
|
||||||
s = "123456789"
|
s = "123456789"
|
||||||
self.assertEqual("".join(t(s)), s)
|
self.assertEqual("".join(t(s)), s)
|
||||||
|
|
||||||
|
def test_constructor_with_duplicate_fields(self):
|
||||||
|
t = time.struct_time
|
||||||
|
|
||||||
|
error_message = re.escape("got duplicate or unexpected field name(s)")
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("1234567890", dict={"tm_zone": "some zone"})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("1234567890", dict={"tm_zone": "some zone", "tm_mon": 1})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("1234567890", dict={"error": 0, "tm_zone": "some zone"})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("1234567890", dict={"error": 0, "tm_zone": "some zone", "tm_mon": 1})
|
||||||
|
|
||||||
|
def test_constructor_with_duplicate_unnamed_fields(self):
|
||||||
|
assert os.stat_result.n_unnamed_fields > 0
|
||||||
|
n_visible_fields = os.stat_result.n_sequence_fields
|
||||||
|
|
||||||
|
r = os.stat_result(range(n_visible_fields), {'st_atime': -1.0})
|
||||||
|
self.assertEqual(r.st_atime, -1.0)
|
||||||
|
self.assertEqual(r, tuple(range(n_visible_fields)))
|
||||||
|
|
||||||
|
r = os.stat_result((*range(n_visible_fields), -1.0))
|
||||||
|
self.assertEqual(r.st_atime, -1.0)
|
||||||
|
self.assertEqual(r, tuple(range(n_visible_fields)))
|
||||||
|
|
||||||
|
with self.assertRaisesRegex(TypeError,
|
||||||
|
re.escape("got duplicate or unexpected field name(s)")):
|
||||||
|
os.stat_result((*range(n_visible_fields), -1.0), {'st_atime': -1.0})
|
||||||
|
|
||||||
|
def test_constructor_with_unknown_fields(self):
|
||||||
|
t = time.struct_time
|
||||||
|
|
||||||
|
error_message = re.escape("got duplicate or unexpected field name(s)")
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"tm_year": 0})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"tm_year": 0, "tm_mon": 1})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"tm_zone": "some zone", "tm_mon": 1})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"tm_zone": "some zone", "error": 0})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"error": 0, "tm_zone": "some zone", "tm_mon": 1})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"error": 0})
|
||||||
|
with self.assertRaisesRegex(TypeError, error_message):
|
||||||
|
t("123456789", dict={"tm_zone": "some zone", "error": 0})
|
||||||
|
|
||||||
def test_eviltuple(self):
|
def test_eviltuple(self):
|
||||||
class Exc(Exception):
|
class Exc(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Raise :exc:`TypeError` for duplicate/unknown fields in ``PyStructSequence`` constructor.
|
||||||
|
Patched by Xuehai Pan.
|
|
@ -216,19 +216,34 @@ structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
|
||||||
res->ob_item[i] = Py_NewRef(v);
|
res->ob_item[i] = Py_NewRef(v);
|
||||||
}
|
}
|
||||||
Py_DECREF(arg);
|
Py_DECREF(arg);
|
||||||
for (; i < max_len; ++i) {
|
if (dict != NULL && PyDict_GET_SIZE(dict) > 0) {
|
||||||
PyObject *ob = NULL;
|
Py_ssize_t n_found_keys = 0;
|
||||||
if (dict != NULL) {
|
for (i = len; i < max_len; ++i) {
|
||||||
const char *name = type->tp_members[i-n_unnamed_fields].name;
|
PyObject *ob = NULL;
|
||||||
|
const char *name = type->tp_members[i - n_unnamed_fields].name;
|
||||||
if (PyDict_GetItemStringRef(dict, name, &ob) < 0) {
|
if (PyDict_GetItemStringRef(dict, name, &ob) < 0) {
|
||||||
Py_DECREF(res);
|
Py_DECREF(res);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (ob == NULL) {
|
||||||
|
ob = Py_NewRef(Py_None);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++n_found_keys;
|
||||||
|
}
|
||||||
|
res->ob_item[i] = ob;
|
||||||
}
|
}
|
||||||
if (ob == NULL) {
|
if (PyDict_GET_SIZE(dict) > n_found_keys) {
|
||||||
ob = Py_NewRef(Py_None);
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"%.500s() got duplicate or unexpected field name(s)",
|
||||||
|
type->tp_name);
|
||||||
|
Py_DECREF(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = len; i < max_len; ++i) {
|
||||||
|
res->ob_item[i] = Py_NewRef(Py_None);
|
||||||
}
|
}
|
||||||
res->ob_item[i] = ob;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_PyObject_GC_TRACK(res);
|
_PyObject_GC_TRACK(res);
|
||||||
|
|
Loading…
Reference in New Issue