mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-112358: Fix Python 3.12 regression with subclassing struct.Struct. (#112424)
Revert commit c8c0afc713 (PR #94532),
which moved `struct.Struct` initialisation from `Struct.__init__` to `Struct.__new__`.
This caused issues with code in the wild that subclasses `struct.Struct`.
			
			
This commit is contained in:
		
							parent
							
								
									3faf8e586d
								
							
						
					
					
						commit
						9fe60340d7
					
				
					 4 changed files with 52 additions and 48 deletions
				
			
		|  | @ -700,20 +700,6 @@ def test__struct_types_immutable(self): | |||
|                 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,15 @@ def test_error_propagation(fmt_str): | |||
|         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') | ||||
| 
 | ||||
|     def test_repr(self): | ||||
|         s = struct.Struct('=i2H') | ||||
|         self.assertEqual(repr(s), f'Struct({s.format!r})') | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| Revert change to :class:`struct.Struct` initialization that broke some cases | ||||
| of subclassing. | ||||
|  | @ -1553,9 +1553,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 | ||||
| 
 | ||||
|  | @ -1567,24 +1586,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); | ||||
|  | @ -1592,24 +1603,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) | ||||
| { | ||||
|  | @ -2219,8 +2225,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}, | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										16
									
								
								Modules/clinic/_struct.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								Modules/clinic/_struct.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -9,7 +9,7 @@ preserve | |||
| #include "pycore_abstract.h"      // _PyNumber_Index() | ||||
| #include "pycore_modsupport.h"    // _PyArg_UnpackKeywords() | ||||
| 
 | ||||
| PyDoc_STRVAR(Struct__doc__, | ||||
| PyDoc_STRVAR(Struct___init____doc__, | ||||
| "Struct(format)\n" | ||||
| "--\n" | ||||
| "\n" | ||||
|  | @ -20,13 +20,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 | ||||
|  | @ -62,7 +62,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; | ||||
|  | @ -436,4 +436,4 @@ exit: | |||
| 
 | ||||
|     return return_value; | ||||
| } | ||||
| /*[clinic end generated code: output=6a20e87f9b298b14 input=a9049054013a1b77]*/ | ||||
| /*[clinic end generated code: output=67bd299e5d72fee0 input=a9049054013a1b77]*/ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Dickinson
						Mark Dickinson