summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2023-11-27 08:25:06 (GMT)
committerGitHub <noreply@github.com>2023-11-27 08:25:06 (GMT)
commit42df73652dba4937489e34a92dbf184a184c2d93 (patch)
tree850ff04e3ed9ed107c12f290e3151d9911584c93
parentd7a788332666eabade922bf5d976df8c362ecb14 (diff)
downloadcpython-42df73652dba4937489e34a92dbf184a184c2d93.zip
cpython-42df73652dba4937489e34a92dbf184a184c2d93.tar.gz
cpython-42df73652dba4937489e34a92dbf184a184c2d93.tar.bz2
[3.12] gh-112358: Fix Python 3.12 regression with subclassing struct.Struct (GH-112424) (#112426)
* [3.12] gh-112358: Fix Python 3.12 regression with subclassing struct.Struct. (GH-112424) Revert commit c8c0afc7137ab9f22bf59d591084948ca967c97c (PR GH-94532), which moved `struct.Struct` initialisation from `Struct.__init__` to `Struct.__new__`. This caused issues with code in the wild that subclasses `struct.Struct`.. (cherry picked from commit 9fe60340d7e8dc22b3aec205c557bc69a1b2d18c) Co-authored-by: Mark Dickinson <dickinsm@gmail.com> * Remove unrelated test
-rw-r--r--Lib/test/test_struct.py24
-rw-r--r--Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst2
-rw-r--r--Modules/_struct.c59
-rw-r--r--Modules/clinic/_struct.c.h16
4 files changed, 53 insertions, 48 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 6b1f22f..8d4b13a 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -700,20 +700,6 @@ class StructTest(unittest.TestCase):
with self.assertRaises(TypeError):
cls.x = 1
- @support.cpython_only
- def test__struct_Struct__new__initialized(self):
- # See https://github.com/python/cpython/issues/78724
-
- s = struct.Struct.__new__(struct.Struct, "b")
- s.unpack_from(b"abcd")
-
- @support.cpython_only
- def test__struct_Struct_subclassing(self):
- class Bob(struct.Struct):
- pass
-
- s = Bob("b")
- s.unpack_from(b"abcd")
def test_issue35714(self):
# Embedded null characters should not be allowed in format strings.
@@ -774,6 +760,16 @@ class StructTest(unittest.TestCase):
test_error_propagation('N')
test_error_propagation('n')
+ def test_struct_subclass_instantiation(self):
+ # Regression test for https://github.com/python/cpython/issues/112358
+ class MyStruct(struct.Struct):
+ def __init__(self):
+ super().__init__('>h')
+
+ my_struct = MyStruct()
+ self.assertEqual(my_struct.pack(12345), b'\x30\x39')
+
+
class UnpackIteratorTest(unittest.TestCase):
"""
Tests for iterative unpacking (struct.Struct.iter_unpack).
diff --git a/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst b/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst
new file mode 100644
index 0000000..e473ded
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-11-26-13-26-56.gh-issue-112358.smhaeZ.rst
@@ -0,0 +1,2 @@
+Revert change to :class:`struct.Struct` initialization that broke some cases
+of subclassing.
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 4f9478b..55efc0c 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1550,9 +1550,28 @@ prepare_s(PyStructObject *self)
return -1;
}
+static PyObject *
+s_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *self;
+
+ assert(type != NULL);
+ allocfunc alloc_func = PyType_GetSlot(type, Py_tp_alloc);
+ assert(alloc_func != NULL);
+
+ self = alloc_func(type, 0);
+ if (self != NULL) {
+ PyStructObject *s = (PyStructObject*)self;
+ s->s_format = Py_NewRef(Py_None);
+ s->s_codes = NULL;
+ s->s_size = -1;
+ s->s_len = -1;
+ }
+ return self;
+}
+
/*[clinic input]
-@classmethod
-Struct.__new__
+Struct.__init__
format: object
@@ -1564,24 +1583,16 @@ the format string.
See help(struct) for more on format strings.
[clinic start generated code]*/
-static PyObject *
-Struct_impl(PyTypeObject *type, PyObject *format)
-/*[clinic end generated code: output=49468b044e334308 input=8b91868eb1df0e28]*/
+static int
+Struct___init___impl(PyStructObject *self, PyObject *format)
+/*[clinic end generated code: output=b8e80862444e92d0 input=192a4575a3dde802]*/
{
- allocfunc alloc = PyType_GetSlot(type, Py_tp_alloc);
- assert(alloc != NULL);
- PyStructObject *self = (PyStructObject *)alloc(type, 0);
-
- if (self == NULL) {
- return NULL;
- }
+ int ret = 0;
if (PyUnicode_Check(format)) {
format = PyUnicode_AsASCIIString(format);
- if (format == NULL) {
- Py_DECREF(self);
- return NULL;
- }
+ if (format == NULL)
+ return -1;
}
else {
Py_INCREF(format);
@@ -1589,24 +1600,19 @@ Struct_impl(PyTypeObject *type, PyObject *format)
if (!PyBytes_Check(format)) {
Py_DECREF(format);
- Py_DECREF(self);
PyErr_Format(PyExc_TypeError,
"Struct() argument 1 must be a str or bytes object, "
"not %.200s",
_PyType_Name(Py_TYPE(format)));
- return NULL;
+ return -1;
}
- self->s_format = format;
+ Py_SETREF(self->s_format, format);
- if (prepare_s(self) < 0) {
- Py_DECREF(self);
- return NULL;
- }
- return (PyObject *)self;
+ ret = prepare_s(self);
+ return ret;
}
-
static int
s_clear(PyStructObject *s)
{
@@ -2202,8 +2208,9 @@ static PyType_Slot PyStructType_slots[] = {
{Py_tp_methods, s_methods},
{Py_tp_members, s_members},
{Py_tp_getset, s_getsetlist},
- {Py_tp_new, Struct},
+ {Py_tp_init, Struct___init__},
{Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_new, s_new},
{Py_tp_free, PyObject_GC_Del},
{0, 0},
};
diff --git a/Modules/clinic/_struct.c.h b/Modules/clinic/_struct.c.h
index c3cf179..b21d9ff 100644
--- a/Modules/clinic/_struct.c.h
+++ b/Modules/clinic/_struct.c.h
@@ -8,7 +8,7 @@ preserve
#endif
-PyDoc_STRVAR(Struct__doc__,
+PyDoc_STRVAR(Struct___init____doc__,
"Struct(format)\n"
"--\n"
"\n"
@@ -19,13 +19,13 @@ PyDoc_STRVAR(Struct__doc__,
"\n"
"See help(struct) for more on format strings.");
-static PyObject *
-Struct_impl(PyTypeObject *type, PyObject *format);
+static int
+Struct___init___impl(PyStructObject *self, PyObject *format);
-static PyObject *
-Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+static int
+Struct___init__(PyObject *self, PyObject *args, PyObject *kwargs)
{
- PyObject *return_value = NULL;
+ int return_value = -1;
#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
#define NUM_KEYWORDS 1
@@ -61,7 +61,7 @@ Struct(PyTypeObject *type, PyObject *args, PyObject *kwargs)
goto exit;
}
format = fastargs[0];
- return_value = Struct_impl(type, format);
+ return_value = Struct___init___impl((PyStructObject *)self, format);
exit:
return return_value;
@@ -451,4 +451,4 @@ exit:
return return_value;
}
-/*[clinic end generated code: output=f3d6e06f80368998 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=eca7df0e75f8919d input=a9049054013a1b77]*/