From a45739f8b30c151be4409a72d02c9ef7d7788f06 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 18 Jun 2020 19:04:36 +0900 Subject: [PATCH 1/9] bpo-40077: Convert _bz2 module to use PyType_FromSpec --- Lib/test/test_bz2.py | 6 +- .../2020-06-18-19-04-30.bpo-40077._yI-ax.rst | 1 + Modules/_bz2module.c | 294 +++++++++++------- Modules/clinic/_bz2module.c.h | 73 +---- 4 files changed, 181 insertions(+), 193 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-06-18-19-04-30.bpo-40077._yI-ax.rst diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index 91ccff2d0c07f8..91c32dedadb9a5 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -666,7 +666,8 @@ def testCompress4G(self, size): data = None def testPickle(self): - for proto in range(pickle.HIGHEST_PROTOCOL + 1): + # Why? + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(TypeError): pickle.dumps(BZ2Compressor(), proto) @@ -724,7 +725,8 @@ def testDecompress4G(self, size): decompressed = None def testPickle(self): - for proto in range(pickle.HIGHEST_PROTOCOL + 1): + # Why? + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(TypeError): pickle.dumps(BZ2Decompressor(), proto) diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-18-19-04-30.bpo-40077._yI-ax.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-18-19-04-30.bpo-40077._yI-ax.rst new file mode 100644 index 00000000000000..2e0258a7b369d2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-18-19-04-30.bpo-40077._yI-ax.rst @@ -0,0 +1 @@ +Convert :mod:`_bz2` to use :c:func:`PyType_FromSpec`. diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 880632c62349f1..2455359a6bc915 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -28,6 +28,19 @@ #define RELEASE_LOCK(obj) PyThread_release_lock((obj)->lock) +typedef struct { + PyTypeObject *bz2_compressor_type; + PyTypeObject *bz2_decompressor_type; +} _bz2_state; + +static inline _bz2_state* +get_bz2_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_bz2_state *)state; +} + typedef struct { PyObject_HEAD bz_stream bzs; @@ -51,9 +64,6 @@ typedef struct { PyThread_type_lock lock; } BZ2Decompressor; -static PyTypeObject BZ2Compressor_Type; -static PyTypeObject BZ2Decompressor_Type; - /* Helper functions. */ static int @@ -280,21 +290,9 @@ BZ2_Free(void* ctx, void *ptr) PyMem_RawFree(ptr); } -/*[clinic input] -_bz2.BZ2Compressor.__init__ - - compresslevel: int = 9 - Compression level, as a number between 1 and 9. - / - -Create a compressor object for compressing data incrementally. - -For one-shot compression, use the compress() function instead. -[clinic start generated code]*/ - +// TODO: Convert it to clinic static int _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) -/*[clinic end generated code: output=c4e6adfd02963827 input=4e1ff7b8394b6e9a]*/ { int bzerror; @@ -325,13 +323,56 @@ _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) return -1; } +PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, +"BZ2Compressor(compresslevel=9, /)\n" +"--\n" +"\n" +"Create a compressor object for compressing data incrementally.\n" +"\n" +" compresslevel\n" +" Compression level, as a number between 1 and 9.\n" +"\n" +"For one-shot compression, use the compress() function instead."); + +static int +_bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + int compresslevel = 9; + _bz2_state *state = PyType_GetModuleState(Py_TYPE(self)); + assert(state != NULL); + + if (Py_IS_TYPE(self, state->bz2_compressor_type) && + !_PyArg_NoKeywords("BZ2Compressor", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) { + goto exit; + } + if (PyTuple_GET_SIZE(args) < 1) { + goto skip_optional; + } + compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); + if (compresslevel == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: + return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel); + +exit: + return return_value; +} + static void BZ2Compressor_dealloc(BZ2Compressor *self) { BZ2_bzCompressEnd(&self->bzs); - if (self->lock != NULL) + if (self->lock != NULL) { PyThread_free_lock(self->lock); - Py_TYPE(self)->tp_free((PyObject *)self); + } + PyTypeObject *tp = Py_TYPE(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyMethodDef BZ2Compressor_methods[] = { @@ -340,48 +381,24 @@ static PyMethodDef BZ2Compressor_methods[] = { {NULL} }; - -static PyTypeObject BZ2Compressor_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_bz2.BZ2Compressor", /* tp_name */ - sizeof(BZ2Compressor), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)BZ2Compressor_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - _bz2_BZ2Compressor___init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - BZ2Compressor_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - _bz2_BZ2Compressor___init__, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot bz2_compressor_type_slots[] = { + {Py_tp_dealloc, BZ2Compressor_dealloc}, + {Py_tp_methods, BZ2Compressor_methods}, + {Py_tp_init, _bz2_BZ2Compressor___init__}, + {Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__}, + {0, 0} }; +static PyType_Spec bz2_compressor_type_spec = { + .name = "_bz2.BZ2Compressor", + .basicsize = sizeof(BZ2Compressor), + // Calling PyType_GetModuleState() on a subclass is not safe. + // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag + // which prevents to create a subclass. + // So calling PyType_GetModuleState() in this file is always safe. + .flags = Py_TPFLAGS_DEFAULT, + .slots = bz2_compressor_type_slots, +}; /* BZ2Decompressor class. */ @@ -601,17 +618,9 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, return result; } -/*[clinic input] -_bz2.BZ2Decompressor.__init__ - -Create a decompressor object for decompressing data incrementally. - -For one-shot decompression, use the decompress() function instead. -[clinic start generated code]*/ - +// TODO: Convert it to clinic static int _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) -/*[clinic end generated code: output=e4d2b9bb866ab8f1 input=95f6500dcda60088]*/ { int bzerror; @@ -646,16 +655,50 @@ _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) return -1; } +static int +_bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + _bz2_state *state = PyType_GetModuleState(Py_TYPE(self)); + assert(state != NULL); + + if (Py_IS_TYPE(self, state->bz2_decompressor_type) && + !_PyArg_NoPositional("BZ2Decompressor", args)) { + goto exit; + } + if (Py_IS_TYPE(self, state->bz2_decompressor_type) && + !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) { + goto exit; + } + return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); + +exit: + return return_value; +} + +PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, +"BZ2Decompressor()\n" +"--\n" +"\n" +"Create a decompressor object for decompressing data incrementally.\n" +"\n" +"For one-shot decompression, use the decompress() function instead."); + static void BZ2Decompressor_dealloc(BZ2Decompressor *self) { - if(self->input_buffer != NULL) + if(self->input_buffer != NULL) { PyMem_Free(self->input_buffer); + } BZ2_bzDecompressEnd(&self->bzs); Py_CLEAR(self->unused_data); - if (self->lock != NULL) + if (self->lock != NULL) { PyThread_free_lock(self->lock); - Py_TYPE(self)->tp_free((PyObject *)self); + } + + PyTypeObject *tp = Py_TYPE(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyMethodDef BZ2Decompressor_methods[] = { @@ -682,64 +725,79 @@ static PyMemberDef BZ2Decompressor_members[] = { {NULL} }; -static PyTypeObject BZ2Decompressor_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_bz2.BZ2Decompressor", /* tp_name */ - sizeof(BZ2Decompressor), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)BZ2Decompressor_dealloc,/* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - _bz2_BZ2Decompressor___init____doc__, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - BZ2Decompressor_methods, /* tp_methods */ - BZ2Decompressor_members, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - _bz2_BZ2Decompressor___init__, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot bz2_decompressor_type_slots[] = { + {Py_tp_dealloc, BZ2Decompressor_dealloc}, + {Py_tp_methods, BZ2Decompressor_methods}, + {Py_tp_init, _bz2_BZ2Decompressor___init__}, + {Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__}, + {Py_tp_members, BZ2Decompressor_members}, + {0, 0} }; +static PyType_Spec bz2_decompressor_type_spec = { + .name = "_bz2.BZ2Decompressor", + .basicsize = sizeof(BZ2Decompressor), + // Calling PyType_GetModuleState() on a subclass is not safe. + // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag + // which prevents to create a subclass. + // So calling PyType_GetModuleState() in this file is always safe. + .flags = Py_TPFLAGS_DEFAULT, + .slots = bz2_decompressor_type_slots, +}; /* Module initialization. */ static int _bz2_exec(PyObject *module) { - if (PyModule_AddType(module, &BZ2Compressor_Type) < 0) { + _bz2_state *state = get_bz2_state(module); + state->bz2_compressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, + &bz2_compressor_type_spec, NULL); + if (state->bz2_compressor_type == NULL) { + return -1; + } + + if (PyModule_AddType(module, state->bz2_compressor_type) < 0) { + return -1; + } + + state->bz2_decompressor_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, + &bz2_decompressor_type_spec, NULL); + if (state->bz2_decompressor_type == NULL) { return -1; } - if (PyModule_AddType(module, &BZ2Decompressor_Type) < 0) { + if (PyModule_AddType(module, state->bz2_decompressor_type) < 0) { return -1; } return 0; } +static int +_bz2_traverse(PyObject *module, visitproc visit, void *arg) +{ + _bz2_state *state = get_bz2_state(module); + Py_VISIT(state->bz2_compressor_type); + Py_VISIT(state->bz2_decompressor_type); + return 0; +} + +static int +_bz2_clear(PyObject *module) +{ + _bz2_state *state = get_bz2_state(module); + Py_CLEAR(state->bz2_compressor_type); + Py_CLEAR(state->bz2_decompressor_type); + return 0; +} + +static void +_bz2_free(void *module) +{ + _bz2_clear((PyObject *)module); +} + static struct PyModuleDef_Slot _bz2_slots[] = { {Py_mod_exec, _bz2_exec}, {0, NULL} @@ -747,14 +805,12 @@ static struct PyModuleDef_Slot _bz2_slots[] = { static struct PyModuleDef _bz2module = { PyModuleDef_HEAD_INIT, - "_bz2", - NULL, - 0, - NULL, - _bz2_slots, - NULL, - NULL, - NULL + .m_name = "_bz2", + .m_size = sizeof(_bz2_state), + .m_slots = _bz2_slots, + .m_traverse = _bz2_traverse, + .m_clear = _bz2_clear, + .m_free = _bz2_free, }; PyMODINIT_FUNC diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h index 466020787449e9..71ad0b135718a9 100644 --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -65,47 +65,6 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) return _bz2_BZ2Compressor_flush_impl(self); } -PyDoc_STRVAR(_bz2_BZ2Compressor___init____doc__, -"BZ2Compressor(compresslevel=9, /)\n" -"--\n" -"\n" -"Create a compressor object for compressing data incrementally.\n" -"\n" -" compresslevel\n" -" Compression level, as a number between 1 and 9.\n" -"\n" -"For one-shot compression, use the compress() function instead."); - -static int -_bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel); - -static int -_bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - int compresslevel = 9; - - if (Py_IS_TYPE(self, &BZ2Compressor_Type) && - !_PyArg_NoKeywords("BZ2Compressor", kwargs)) { - goto exit; - } - if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) { - goto exit; - } - if (PyTuple_GET_SIZE(args) < 1) { - goto skip_optional; - } - compresslevel = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); - if (compresslevel == -1 && PyErr_Occurred()) { - goto exit; - } -skip_optional: - return_value = _bz2_BZ2Compressor___init___impl((BZ2Compressor *)self, compresslevel); - -exit: - return return_value; -} - PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, "decompress($self, /, data, max_length=-1)\n" "--\n" @@ -180,34 +139,4 @@ _bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *const *args, Py return return_value; } - -PyDoc_STRVAR(_bz2_BZ2Decompressor___init____doc__, -"BZ2Decompressor()\n" -"--\n" -"\n" -"Create a decompressor object for decompressing data incrementally.\n" -"\n" -"For one-shot decompression, use the decompress() function instead."); - -static int -_bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self); - -static int -_bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) -{ - int return_value = -1; - - if (Py_IS_TYPE(self, &BZ2Decompressor_Type) && - !_PyArg_NoPositional("BZ2Decompressor", args)) { - goto exit; - } - if (Py_IS_TYPE(self, &BZ2Decompressor_Type) && - !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) { - goto exit; - } - return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); - -exit: - return return_value; -} -/*[clinic end generated code: output=b49102ee26928a28 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ed10705d7a9fd598 input=a9049054013a1b77]*/ From fcc972667e81c59fccc36c193d0d0c0f7418f741 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 01:57:57 +0900 Subject: [PATCH 2/9] bpo-40077: Re-enable pickle test --- Lib/test/test_bz2.py | 4 +--- Modules/_bz2module.c | 36 ++++++++++++++++++++++++++++++++++- Modules/clinic/_bz2module.c.h | 36 ++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index 91c32dedadb9a5..ac06eb1ef7f10a 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -666,8 +666,7 @@ def testCompress4G(self, size): data = None def testPickle(self): - # Why? - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(TypeError): pickle.dumps(BZ2Compressor(), proto) @@ -725,7 +724,6 @@ def testDecompress4G(self, size): decompressed = None def testPickle(self): - # Why? for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(TypeError): pickle.dumps(BZ2Decompressor(), proto) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 2455359a6bc915..8d5a8b46ea849f 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -272,6 +272,21 @@ _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) return result; } +/*[clinic input] +_bz2.BZ2Compressor.__reduce__ as _bz2_compressor_reduce + +[clinic start generated code]*/ + +static PyObject * +_bz2_compressor_reduce_impl(BZ2Compressor *self) +/*[clinic end generated code: output=8b4e32a4a405409b input=598cfb30699bd0ee]*/ +{ + PyErr_Format(PyExc_TypeError, + "cannot pickle %s object", + Py_TYPE(self)->tp_name); + return NULL; +} + static void* BZ2_Malloc(void* ctx, int items, int size) { @@ -378,6 +393,7 @@ BZ2Compressor_dealloc(BZ2Compressor *self) static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF + _BZ2_COMPRESSOR_REDUCE_METHODDEF {NULL} }; @@ -385,6 +401,7 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_dealloc, BZ2Compressor_dealloc}, {Py_tp_methods, BZ2Compressor_methods}, {Py_tp_init, _bz2_BZ2Compressor___init__}, + {Py_tp_new, PyType_GenericNew}, {Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__}, {0, 0} }; @@ -396,7 +413,7 @@ static PyType_Spec bz2_compressor_type_spec = { // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. - .flags = Py_TPFLAGS_DEFAULT, + .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE, .slots = bz2_compressor_type_slots, }; @@ -618,6 +635,21 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, return result; } +/*[clinic input] +_bz2.BZ2Decompressor.__reduce__ as _bz2_decompressor_reduce + +[clinic start generated code]*/ + +static PyObject * +_bz2_decompressor_reduce_impl(BZ2Decompressor *self) +/*[clinic end generated code: output=c79772d813bf4271 input=486b9c8c0205e116]*/ +{ + PyErr_Format(PyExc_TypeError, + "cannot pickle %s object", + Py_TYPE(self)->tp_name); + return NULL; +} + // TODO: Convert it to clinic static int _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) @@ -703,6 +735,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self) static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF + _BZ2_DECOMPRESSOR_REDUCE_METHODDEF {NULL} }; @@ -731,6 +764,7 @@ static PyType_Slot bz2_decompressor_type_slots[] = { {Py_tp_init, _bz2_BZ2Decompressor___init__}, {Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__}, {Py_tp_members, BZ2Decompressor_members}, + {Py_tp_new, PyType_GenericNew}, {0, 0} }; diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h index 71ad0b135718a9..879e81925da225 100644 --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -65,6 +65,23 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) return _bz2_BZ2Compressor_flush_impl(self); } +PyDoc_STRVAR(_bz2_compressor_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define _BZ2_COMPRESSOR_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)_bz2_compressor_reduce, METH_NOARGS, _bz2_compressor_reduce__doc__}, + +static PyObject * +_bz2_compressor_reduce_impl(BZ2Compressor *self); + +static PyObject * +_bz2_compressor_reduce(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) +{ + return _bz2_compressor_reduce_impl(self); +} + PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, "decompress($self, /, data, max_length=-1)\n" "--\n" @@ -139,4 +156,21 @@ _bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *const *args, Py return return_value; } -/*[clinic end generated code: output=ed10705d7a9fd598 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_bz2_decompressor_reduce__doc__, +"__reduce__($self, /)\n" +"--\n" +"\n"); + +#define _BZ2_DECOMPRESSOR_REDUCE_METHODDEF \ + {"__reduce__", (PyCFunction)_bz2_decompressor_reduce, METH_NOARGS, _bz2_decompressor_reduce__doc__}, + +static PyObject * +_bz2_decompressor_reduce_impl(BZ2Decompressor *self); + +static PyObject * +_bz2_decompressor_reduce(BZ2Decompressor *self, PyObject *Py_UNUSED(ignored)) +{ + return _bz2_decompressor_reduce_impl(self); +} +/*[clinic end generated code: output=afbb47be9b4b4283 input=a9049054013a1b77]*/ From e1e4c4ad53b49532cc720a45a6c8cd99b4416af0 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 02:02:50 +0900 Subject: [PATCH 3/9] bpo-40077: nit fix --- Modules/_bz2module.c | 16 ++++++++-------- Modules/clinic/_bz2module.c.h | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 8d5a8b46ea849f..042fe19ef5c03d 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -273,13 +273,13 @@ _bz2_BZ2Compressor_flush_impl(BZ2Compressor *self) } /*[clinic input] -_bz2.BZ2Compressor.__reduce__ as _bz2_compressor_reduce +_bz2.BZ2Compressor.__reduce__ [clinic start generated code]*/ static PyObject * -_bz2_compressor_reduce_impl(BZ2Compressor *self) -/*[clinic end generated code: output=8b4e32a4a405409b input=598cfb30699bd0ee]*/ +_bz2_BZ2Compressor___reduce___impl(BZ2Compressor *self) +/*[clinic end generated code: output=d13db66ae043e141 input=e09bccef0e6731b2]*/ { PyErr_Format(PyExc_TypeError, "cannot pickle %s object", @@ -393,7 +393,7 @@ BZ2Compressor_dealloc(BZ2Compressor *self) static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF - _BZ2_COMPRESSOR_REDUCE_METHODDEF + _BZ2_BZ2COMPRESSOR___REDUCE___METHODDEF {NULL} }; @@ -636,13 +636,13 @@ _bz2_BZ2Decompressor_decompress_impl(BZ2Decompressor *self, Py_buffer *data, } /*[clinic input] -_bz2.BZ2Decompressor.__reduce__ as _bz2_decompressor_reduce +_bz2.BZ2Decompressor.__reduce__ [clinic start generated code]*/ static PyObject * -_bz2_decompressor_reduce_impl(BZ2Decompressor *self) -/*[clinic end generated code: output=c79772d813bf4271 input=486b9c8c0205e116]*/ +_bz2_BZ2Decompressor___reduce___impl(BZ2Decompressor *self) +/*[clinic end generated code: output=f6a40650813f482e input=8db9175a609fdd43]*/ { PyErr_Format(PyExc_TypeError, "cannot pickle %s object", @@ -735,7 +735,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self) static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF - _BZ2_DECOMPRESSOR_REDUCE_METHODDEF + _BZ2_BZ2DECOMPRESSOR___REDUCE___METHODDEF {NULL} }; diff --git a/Modules/clinic/_bz2module.c.h b/Modules/clinic/_bz2module.c.h index 879e81925da225..ff67d34155dfdf 100644 --- a/Modules/clinic/_bz2module.c.h +++ b/Modules/clinic/_bz2module.c.h @@ -65,21 +65,21 @@ _bz2_BZ2Compressor_flush(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) return _bz2_BZ2Compressor_flush_impl(self); } -PyDoc_STRVAR(_bz2_compressor_reduce__doc__, +PyDoc_STRVAR(_bz2_BZ2Compressor___reduce____doc__, "__reduce__($self, /)\n" "--\n" "\n"); -#define _BZ2_COMPRESSOR_REDUCE_METHODDEF \ - {"__reduce__", (PyCFunction)_bz2_compressor_reduce, METH_NOARGS, _bz2_compressor_reduce__doc__}, +#define _BZ2_BZ2COMPRESSOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)_bz2_BZ2Compressor___reduce__, METH_NOARGS, _bz2_BZ2Compressor___reduce____doc__}, static PyObject * -_bz2_compressor_reduce_impl(BZ2Compressor *self); +_bz2_BZ2Compressor___reduce___impl(BZ2Compressor *self); static PyObject * -_bz2_compressor_reduce(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) +_bz2_BZ2Compressor___reduce__(BZ2Compressor *self, PyObject *Py_UNUSED(ignored)) { - return _bz2_compressor_reduce_impl(self); + return _bz2_BZ2Compressor___reduce___impl(self); } PyDoc_STRVAR(_bz2_BZ2Decompressor_decompress__doc__, @@ -157,20 +157,20 @@ _bz2_BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *const *args, Py return return_value; } -PyDoc_STRVAR(_bz2_decompressor_reduce__doc__, +PyDoc_STRVAR(_bz2_BZ2Decompressor___reduce____doc__, "__reduce__($self, /)\n" "--\n" "\n"); -#define _BZ2_DECOMPRESSOR_REDUCE_METHODDEF \ - {"__reduce__", (PyCFunction)_bz2_decompressor_reduce, METH_NOARGS, _bz2_decompressor_reduce__doc__}, +#define _BZ2_BZ2DECOMPRESSOR___REDUCE___METHODDEF \ + {"__reduce__", (PyCFunction)_bz2_BZ2Decompressor___reduce__, METH_NOARGS, _bz2_BZ2Decompressor___reduce____doc__}, static PyObject * -_bz2_decompressor_reduce_impl(BZ2Decompressor *self); +_bz2_BZ2Decompressor___reduce___impl(BZ2Decompressor *self); static PyObject * -_bz2_decompressor_reduce(BZ2Decompressor *self, PyObject *Py_UNUSED(ignored)) +_bz2_BZ2Decompressor___reduce__(BZ2Decompressor *self, PyObject *Py_UNUSED(ignored)) { - return _bz2_decompressor_reduce_impl(self); + return _bz2_BZ2Decompressor___reduce___impl(self); } -/*[clinic end generated code: output=afbb47be9b4b4283 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=001f31fdacb4cb01 input=a9049054013a1b77]*/ From 54d233c5f52b190357adabe655dc6fc6de025265 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 02:03:41 +0900 Subject: [PATCH 4/9] bpo-40077: Apply code review --- Modules/_bz2module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 042fe19ef5c03d..3746620d35628c 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -413,7 +413,7 @@ static PyType_Spec bz2_compressor_type_spec = { // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. - .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE, + .flags = Py_TPFLAGS_DEFAULT, .slots = bz2_compressor_type_slots, }; From 498b4534908a233ec04ad0a9a0254b3ed052a3bd Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 02:05:44 +0900 Subject: [PATCH 5/9] bpo-40077: fix --- Lib/test/test_bz2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py index ac06eb1ef7f10a..91ccff2d0c07f8 100644 --- a/Lib/test/test_bz2.py +++ b/Lib/test/test_bz2.py @@ -724,7 +724,7 @@ def testDecompress4G(self, size): decompressed = None def testPickle(self): - for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): + for proto in range(pickle.HIGHEST_PROTOCOL + 1): with self.assertRaises(TypeError): pickle.dumps(BZ2Decompressor(), proto) From 09944c9a1db4d63c18f6de47ebc312e601e0131e Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 22:23:53 +0900 Subject: [PATCH 6/9] bpo-40077: Apply Victor's review --- Modules/_bz2module.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 3746620d35628c..7a7a2747f8d50c 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -354,11 +354,8 @@ _bz2_BZ2Compressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; int compresslevel = 9; - _bz2_state *state = PyType_GetModuleState(Py_TYPE(self)); - assert(state != NULL); - if (Py_IS_TYPE(self, state->bz2_compressor_type) && - !_PyArg_NoKeywords("BZ2Compressor", kwargs)) { + if (!_PyArg_NoKeywords("BZ2Compressor", kwargs)) { goto exit; } if (!_PyArg_CheckPositional("BZ2Compressor", PyTuple_GET_SIZE(args), 0, 1)) { @@ -691,15 +688,11 @@ static int _bz2_BZ2Decompressor___init__(PyObject *self, PyObject *args, PyObject *kwargs) { int return_value = -1; - _bz2_state *state = PyType_GetModuleState(Py_TYPE(self)); - assert(state != NULL); - if (Py_IS_TYPE(self, state->bz2_decompressor_type) && - !_PyArg_NoPositional("BZ2Decompressor", args)) { + if (!_PyArg_NoPositional("BZ2Decompressor", args)) { goto exit; } - if (Py_IS_TYPE(self, state->bz2_decompressor_type) && - !_PyArg_NoKeywords("BZ2Decompressor", kwargs)) { + if (!_PyArg_NoKeywords("BZ2Decompressor", kwargs)) { goto exit; } return_value = _bz2_BZ2Decompressor___init___impl((BZ2Decompressor *)self); From 58073f6b15f8b7b4a3c3a89472ff594570d2a75f Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 23:17:00 +0900 Subject: [PATCH 7/9] bpo-40077: Add Py_tp_traverse --- Modules/_bz2module.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 7a7a2747f8d50c..c61e0bd5359d8a 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -387,6 +387,13 @@ BZ2Compressor_dealloc(BZ2Compressor *self) Py_DECREF(tp); } +static int +BZ2Compressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef BZ2Compressor_methods[] = { _BZ2_BZ2COMPRESSOR_COMPRESS_METHODDEF _BZ2_BZ2COMPRESSOR_FLUSH_METHODDEF @@ -400,6 +407,7 @@ static PyType_Slot bz2_compressor_type_slots[] = { {Py_tp_init, _bz2_BZ2Compressor___init__}, {Py_tp_new, PyType_GenericNew}, {Py_tp_doc, (char *)_bz2_BZ2Compressor___init____doc__}, + {Py_tp_traverse, BZ2Compressor_traverse}, {0, 0} }; @@ -726,6 +734,13 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self) Py_DECREF(tp); } +static int +BZ2Decompressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + static PyMethodDef BZ2Decompressor_methods[] = { _BZ2_BZ2DECOMPRESSOR_DECOMPRESS_METHODDEF _BZ2_BZ2DECOMPRESSOR___REDUCE___METHODDEF @@ -758,6 +773,7 @@ static PyType_Slot bz2_decompressor_type_slots[] = { {Py_tp_doc, (char *)_bz2_BZ2Decompressor___init____doc__}, {Py_tp_members, BZ2Decompressor_members}, {Py_tp_new, PyType_GenericNew}, + {Py_tp_traverse, BZ2Decompressor_traverse}, {0, 0} }; From 043590bd2be245df102bcb32c6d572a3d006dd69 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 23:19:11 +0900 Subject: [PATCH 8/9] bpo-40077: fix --- Modules/_bz2module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index c61e0bd5359d8a..6a336cffb5528b 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -735,7 +735,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self) } static int -BZ2Decompressor_traverse(BZ2Compressor *self, visitproc visit, void *arg) +BZ2Decompressor_traverse(BZ2Decompressor *self, visitproc visit, void *arg) { Py_VISIT(Py_TYPE(self)); return 0; From 89ecd25b3b88a78f01bea72bc573621d6f7bd322 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 19 Jun 2020 23:53:15 +0900 Subject: [PATCH 9/9] bpo-40077: Apply Victor's review --- Modules/_bz2module.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c index 6a336cffb5528b..effb0de2e65369 100644 --- a/Modules/_bz2module.c +++ b/Modules/_bz2module.c @@ -305,7 +305,9 @@ BZ2_Free(void* ctx, void *ptr) PyMem_RawFree(ptr); } -// TODO: Convert it to clinic + +/* Argument Clinic is not used since the Argument Clinic always want to + check the type which would be wrong here */ static int _bz2_BZ2Compressor___init___impl(BZ2Compressor *self, int compresslevel) { @@ -415,7 +417,7 @@ static PyType_Spec bz2_compressor_type_spec = { .name = "_bz2.BZ2Compressor", .basicsize = sizeof(BZ2Compressor), // Calling PyType_GetModuleState() on a subclass is not safe. - // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag + // bz2_compressor_type_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. .flags = Py_TPFLAGS_DEFAULT, @@ -655,7 +657,8 @@ _bz2_BZ2Decompressor___reduce___impl(BZ2Decompressor *self) return NULL; } -// TODO: Convert it to clinic +/* Argument Clinic is not used since the Argument Clinic always want to + check the type which would be wrong here */ static int _bz2_BZ2Decompressor___init___impl(BZ2Decompressor *self) { @@ -781,7 +784,7 @@ static PyType_Spec bz2_decompressor_type_spec = { .name = "_bz2.BZ2Decompressor", .basicsize = sizeof(BZ2Decompressor), // Calling PyType_GetModuleState() on a subclass is not safe. - // dbmtype_spec does not have Py_TPFLAGS_BASETYPE flag + // bz2_decompressor_type_spec does not have Py_TPFLAGS_BASETYPE flag // which prevents to create a subclass. // So calling PyType_GetModuleState() in this file is always safe. .flags = Py_TPFLAGS_DEFAULT,