From 47d1f72c353b0f63d7b61f86be6d231a7f4c3910 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 10:42:41 -0700 Subject: [PATCH 1/8] Apply PEP384 to _csv module --- Modules/_csv.c | 233 +++++++++++++++++++------------------------------ 1 file changed, 90 insertions(+), 143 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 4cc1f7c88d8779..8b727fbde7b9ac 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -45,9 +45,10 @@ _csv_free(void *m) _csv_clear((PyObject *)m); } -static struct PyModuleDef _csvmodule; +static struct PyModuleDef _csvmodule_def; +static PyObject *_csvmodule; -#define _csvstate_global ((_csvstate *)PyModule_GetState(PyState_FindModule(&_csvmodule))) +#define _csvstate_global ((_csvstate *)PyModule_GetState(PyState_FindModule(&_csvmodule_def))) typedef enum { START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD, @@ -86,8 +87,6 @@ typedef struct { } DialectObj; -static PyTypeObject Dialect_Type; - typedef struct { PyObject_HEAD @@ -104,10 +103,6 @@ typedef struct { unsigned long line_num; /* Source-file line number */ } ReaderObj; -static PyTypeObject Reader_Type; - -#define ReaderObject_Check(v) (Py_TYPE(v) == &Reader_Type) - typedef struct { PyObject_HEAD @@ -121,8 +116,6 @@ typedef struct { int num_fields; /* number of fields in record */ } WriterObj; -static PyTypeObject Writer_Type; - /* * DIALECT class */ @@ -365,7 +358,8 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) else Py_INCREF(dialect); /* Can we reuse this instance? */ - if (PyObject_TypeCheck(dialect, &Dialect_Type) && + PyObject *dialect_type = PyObject_GetAttrString(_csvmodule, "Dialect"); + if (PyObject_TypeCheck(dialect, (PyTypeObject *)dialect_type) && delimiter == NULL && doublequote == NULL && escapechar == NULL && @@ -462,47 +456,21 @@ PyDoc_STRVAR(Dialect_Type_doc, "\n" "The Dialect type records CSV parsing and generation options.\n"); -static PyTypeObject Dialect_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_csv.Dialect", /* tp_name */ - sizeof(DialectObj), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)Dialect_dealloc, /* tp_dealloc */ - (printfunc)0, /* tp_print */ - (getattrfunc)0, /* tp_getattr */ - (setattrfunc)0, /* tp_setattr */ - 0, /* tp_reserved */ - (reprfunc)0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc)0, /* tp_hash */ - (ternaryfunc)0, /* tp_call */ - (reprfunc)0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ - Dialect_Type_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - Dialect_memberlist, /* tp_members */ - Dialect_getsetlist, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - dialect_new, /* tp_new */ - 0, /* tp_free */ +static PyType_Slot Dialect_Type_slots[] = { + {Py_tp_dealloc, Dialect_dealloc}, + {Py_tp_doc, Dialect_Type_doc}, + {Py_tp_members, Dialect_memberlist}, + {Py_tp_getset, Dialect_getsetlist}, + {Py_tp_new, dialect_new}, + {0, 0}, +}; + +static PyType_Spec Dialect_Type_spec = { + "_csv.Dialect", + sizeof(DialectObj), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + Dialect_Type_slots }; /* @@ -512,7 +480,7 @@ static PyTypeObject Dialect_Type = { static PyObject * _call_dialect(PyObject *dialect_inst, PyObject *kwargs) { - PyObject *type = (PyObject *)&Dialect_Type; + PyObject *type = PyObject_GetAttrString(_csvmodule, "Dialect"); if (dialect_inst) { return _PyObject_FastCallDict(type, &dialect_inst, 1, kwargs); } @@ -894,48 +862,31 @@ static struct PyMemberDef Reader_memberlist[] = { { NULL } }; +static PyType_Slot Reader_Type_slots[] = { + {Py_tp_dealloc, Reader_dealloc}, + {Py_tp_doc, Reader_Type_doc}, + {Py_tp_traverse, Reader_traverse}, + {Py_tp_clear, Reader_clear}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, Reader_iternext}, + {Py_tp_methods, Reader_methods}, + {Py_tp_members, Reader_memberlist}, +}; -static PyTypeObject Reader_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_csv.reader", /*tp_name*/ - sizeof(ReaderObj), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)Reader_dealloc, /*tp_dealloc*/ - (printfunc)0, /*tp_print*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - 0, /*tp_reserved*/ - (reprfunc)0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)0, /*tp_hash*/ - (ternaryfunc)0, /*tp_call*/ - (reprfunc)0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - Reader_Type_doc, /*tp_doc*/ - (traverseproc)Reader_traverse, /*tp_traverse*/ - (inquiry)Reader_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - PyObject_SelfIter, /*tp_iter*/ - (getiterfunc)Reader_iternext, /*tp_iternext*/ - Reader_methods, /*tp_methods*/ - Reader_memberlist, /*tp_members*/ - 0, /*tp_getset*/ - +static PyType_Spec Reader_Type_spec = { + "_csv.reader", + sizeof(ReaderObj), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + Reader_Type_slots }; static PyObject * csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * iterator, * dialect = NULL; - ReaderObj * self = PyObject_GC_New(ReaderObj, &Reader_Type); + PyObject *reader_type = PyObject_GetAttrString(_csvmodule, "Reader"); + ReaderObj * self = PyObject_GC_New(ReaderObj, (PyTypeObject *)reader_type); if (!self) return NULL; @@ -1323,46 +1274,30 @@ PyDoc_STRVAR(Writer_Type_doc, "in CSV format from sequence input.\n" ); -static PyTypeObject Writer_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_csv.writer", /*tp_name*/ - sizeof(WriterObj), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)Writer_dealloc, /*tp_dealloc*/ - (printfunc)0, /*tp_print*/ - (getattrfunc)0, /*tp_getattr*/ - (setattrfunc)0, /*tp_setattr*/ - 0, /*tp_reserved*/ - (reprfunc)0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - (hashfunc)0, /*tp_hash*/ - (ternaryfunc)0, /*tp_call*/ - (reprfunc)0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, /*tp_flags*/ - Writer_Type_doc, - (traverseproc)Writer_traverse, /*tp_traverse*/ - (inquiry)Writer_clear, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - (getiterfunc)0, /*tp_iter*/ - (getiterfunc)0, /*tp_iternext*/ - Writer_methods, /*tp_methods*/ - Writer_memberlist, /*tp_members*/ - 0, /*tp_getset*/ +static PyType_Slot Writer_Type_slots[] = { + {Py_tp_dealloc, Writer_dealloc}, + {Py_tp_doc, Writer_Type_doc}, + {Py_tp_traverse, Writer_traverse}, + {Py_tp_clear, Writer_clear}, + {Py_tp_methods, Writer_methods}, + {Py_tp_members, Writer_memberlist}, + {0, 0}, +}; + +static PyType_Spec Writer_Type_spec = { + "_csv.writer", + sizeof(WriterObj), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + Writer_Type_slots }; static PyObject * csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * output_file, * dialect = NULL; - WriterObj * self = PyObject_GC_New(WriterObj, &Writer_Type); + PyObject *writer_type = PyObject_GetAttrString(_csvmodule, "Writer"); + WriterObj * self = PyObject_GC_New(WriterObj, (PyTypeObject*)writer_type); _Py_IDENTIFIER(write); if (!self) @@ -1600,7 +1535,7 @@ static struct PyMethodDef csv_methods[] = { { NULL, NULL } }; -static struct PyModuleDef _csvmodule = { +static struct PyModuleDef _csvmodule_def = { PyModuleDef_HEAD_INIT, "_csv", csv_module_doc, @@ -1615,57 +1550,69 @@ static struct PyModuleDef _csvmodule = { PyMODINIT_FUNC PyInit__csv(void) { - PyObject *module; const StyleDesc *style; - if (PyType_Ready(&Dialect_Type) < 0) + PyObject *dialect_type = PyType_FromSpec(&Dialect_Type_spec); + if (dialect_type == NULL) return NULL; - if (PyType_Ready(&Reader_Type) < 0) + PyObject *reader_type = PyType_FromSpec(&Reader_Type_spec); + if (reader_type == NULL) return NULL; - if (PyType_Ready(&Writer_Type) < 0) + PyObject *writer_type = PyType_FromSpec(&Writer_Type_spec); + if (writer_type == NULL) return NULL; /* Create the module and add the functions */ - module = PyModule_Create(&_csvmodule); - if (module == NULL) + _csvmodule = PyModule_Create(&_csvmodule_def); + if (_csvmodule == NULL) return NULL; /* Add version to the module. */ - if (PyModule_AddStringConstant(module, "__version__", + if (PyModule_AddStringConstant(_csvmodule, "__version__", MODULE_VERSION) == -1) return NULL; /* Set the field limit */ - _csvstate(module)->field_limit = 128 * 1024; + _csvstate(_csvmodule)->field_limit = 128 * 1024; /* Do I still need to add this var to the Module Dict? */ /* Add _dialects dictionary */ - _csvstate(module)->dialects = PyDict_New(); - if (_csvstate(module)->dialects == NULL) + _csvstate(_csvmodule)->dialects = PyDict_New(); + if (_csvstate(_csvmodule)->dialects == NULL) return NULL; - Py_INCREF(_csvstate(module)->dialects); - if (PyModule_AddObject(module, "_dialects", _csvstate(module)->dialects)) + Py_INCREF(_csvstate(_csvmodule)->dialects); + if (PyModule_AddObject(_csvmodule, "_dialects", _csvstate(_csvmodule)->dialects)) return NULL; /* Add quote styles into dictionary */ for (style = quote_styles; style->name; style++) { - if (PyModule_AddIntConstant(module, style->name, + if (PyModule_AddIntConstant(_csvmodule, style->name, style->style) == -1) return NULL; } /* Add the Dialect type */ - Py_INCREF(&Dialect_Type); - if (PyModule_AddObject(module, "Dialect", (PyObject *)&Dialect_Type)) + Py_INCREF(dialect_type); + if (PyModule_AddObject(_csvmodule, "Dialect", dialect_type)) + return NULL; + + /* Add the Reader type */ + Py_INCREF(reader_type); + if (PyModule_AddObject(_csvmodule, "Reader", reader_type)) + return NULL; + + /* Add the Writer type */ + Py_INCREF(writer_type); + if (PyModule_AddObject(_csvmodule, "Writer", writer_type)) return NULL; /* Add the CSV exception object to the module. */ - _csvstate(module)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL); - if (_csvstate(module)->error_obj == NULL) + _csvstate(_csvmodule)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL); + if (_csvstate(_csvmodule)->error_obj == NULL) return NULL; - Py_INCREF(_csvstate(module)->error_obj); - PyModule_AddObject(module, "Error", _csvstate(module)->error_obj); - return module; + Py_INCREF(_csvstate(_csvmodule)->error_obj); + PyModule_AddObject(_csvmodule, "Error", _csvstate(_csvmodule)->error_obj); + return _csvmodule; } From b41e84d9491777c380bb40e4065f4ba811d6c81b Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 10:47:04 -0700 Subject: [PATCH 2/8] Added News --- Misc/NEWS.d/next/C API/2018-08-28-10-46-55.bpo-34533.yko6kd.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/C API/2018-08-28-10-46-55.bpo-34533.yko6kd.rst diff --git a/Misc/NEWS.d/next/C API/2018-08-28-10-46-55.bpo-34533.yko6kd.rst b/Misc/NEWS.d/next/C API/2018-08-28-10-46-55.bpo-34533.yko6kd.rst new file mode 100644 index 00000000000000..cdc16516c5c13b --- /dev/null +++ b/Misc/NEWS.d/next/C API/2018-08-28-10-46-55.bpo-34533.yko6kd.rst @@ -0,0 +1 @@ +This applies the heap type refactoring from PEP 384 to the _csv module. From 9adcfe7154fd04fc519af92a4bd50e93b4496773 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 12:30:49 -0700 Subject: [PATCH 3/8] Fixed test and improves csv file --- Lib/test/test_csv.py | 2 +- Modules/_csv.c | 48 +++++++++++++++++++------------------------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 7a333139b5ea2c..2fdff6bbacab9a 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -454,7 +454,7 @@ def test_copy(self): def test_pickle(self): for name in csv.list_dialects(): dialect = csv.get_dialect(name) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): + for proto in range(2, pickle.HIGHEST_PROTOCOL + 1): self.assertRaises(TypeError, pickle.dumps, dialect, proto) class TestCsvBase(unittest.TestCase): diff --git a/Modules/_csv.c b/Modules/_csv.c index 8b727fbde7b9ac..8af717d668d299 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -87,6 +87,8 @@ typedef struct { } DialectObj; +static PyObject* Dialect_Type; + typedef struct { PyObject_HEAD @@ -103,6 +105,8 @@ typedef struct { unsigned long line_num; /* Source-file line number */ } ReaderObj; +static PyObject* Reader_Type; + typedef struct { PyObject_HEAD @@ -116,6 +120,8 @@ typedef struct { int num_fields; /* number of fields in record */ } WriterObj; +static PyObject* Writer_Type; + /* * DIALECT class */ @@ -358,8 +364,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) else Py_INCREF(dialect); /* Can we reuse this instance? */ - PyObject *dialect_type = PyObject_GetAttrString(_csvmodule, "Dialect"); - if (PyObject_TypeCheck(dialect, (PyTypeObject *)dialect_type) && + if (PyObject_TypeCheck(dialect, (PyTypeObject *)Dialect_Type) && delimiter == NULL && doublequote == NULL && escapechar == NULL && @@ -466,7 +471,7 @@ static PyType_Slot Dialect_Type_slots[] = { }; static PyType_Spec Dialect_Type_spec = { - "_csv.Dialect", + "Dialect", sizeof(DialectObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, @@ -871,10 +876,11 @@ static PyType_Slot Reader_Type_slots[] = { {Py_tp_iternext, Reader_iternext}, {Py_tp_methods, Reader_methods}, {Py_tp_members, Reader_memberlist}, + {0, 0}, }; static PyType_Spec Reader_Type_spec = { - "_csv.reader", + "reader", sizeof(ReaderObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, @@ -885,8 +891,7 @@ static PyObject * csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * iterator, * dialect = NULL; - PyObject *reader_type = PyObject_GetAttrString(_csvmodule, "Reader"); - ReaderObj * self = PyObject_GC_New(ReaderObj, (PyTypeObject *)reader_type); + ReaderObj * self = PyObject_GC_New(ReaderObj, (PyTypeObject *)Reader_Type); if (!self) return NULL; @@ -1285,7 +1290,7 @@ static PyType_Slot Writer_Type_slots[] = { }; static PyType_Spec Writer_Type_spec = { - "_csv.writer", + "writer", sizeof(WriterObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, @@ -1296,8 +1301,7 @@ static PyObject * csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * output_file, * dialect = NULL; - PyObject *writer_type = PyObject_GetAttrString(_csvmodule, "Writer"); - WriterObj * self = PyObject_GC_New(WriterObj, (PyTypeObject*)writer_type); + WriterObj * self = PyObject_GC_New(WriterObj, (PyTypeObject*)Writer_Type); _Py_IDENTIFIER(write); if (!self) @@ -1552,16 +1556,16 @@ PyInit__csv(void) { const StyleDesc *style; - PyObject *dialect_type = PyType_FromSpec(&Dialect_Type_spec); - if (dialect_type == NULL) + Dialect_Type = PyType_FromSpec(&Dialect_Type_spec); + if (Dialect_Type == NULL) return NULL; - PyObject *reader_type = PyType_FromSpec(&Reader_Type_spec); - if (reader_type == NULL) + Reader_Type = PyType_FromSpec(&Reader_Type_spec); + if (Reader_Type == NULL) return NULL; - PyObject *writer_type = PyType_FromSpec(&Writer_Type_spec); - if (writer_type == NULL) + Writer_Type = PyType_FromSpec(&Writer_Type_spec); + if (Writer_Type == NULL) return NULL; /* Create the module and add the functions */ @@ -1594,18 +1598,8 @@ PyInit__csv(void) } /* Add the Dialect type */ - Py_INCREF(dialect_type); - if (PyModule_AddObject(_csvmodule, "Dialect", dialect_type)) - return NULL; - - /* Add the Reader type */ - Py_INCREF(reader_type); - if (PyModule_AddObject(_csvmodule, "Reader", reader_type)) - return NULL; - - /* Add the Writer type */ - Py_INCREF(writer_type); - if (PyModule_AddObject(_csvmodule, "Writer", writer_type)) + Py_INCREF(Dialect_Type); + if (PyModule_AddObject(_csvmodule, "Dialect", Dialect_Type)) return NULL; /* Add the CSV exception object to the module. */ From f61164a5e9189486580012b31cbd99a024c53489 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 12:45:09 -0700 Subject: [PATCH 4/8] Added module name --- Modules/_csv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 8af717d668d299..490d3e626af28c 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -471,7 +471,7 @@ static PyType_Slot Dialect_Type_slots[] = { }; static PyType_Spec Dialect_Type_spec = { - "Dialect", + "_csv.Dialect", sizeof(DialectObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, @@ -880,7 +880,7 @@ static PyType_Slot Reader_Type_slots[] = { }; static PyType_Spec Reader_Type_spec = { - "reader", + "_csv.reader", sizeof(ReaderObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, @@ -1290,7 +1290,7 @@ static PyType_Slot Writer_Type_slots[] = { }; static PyType_Spec Writer_Type_spec = { - "writer", + "_csv.writer", sizeof(WriterObj), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, From 22af36affe9e97951934b57568e9c3203fd7d3aa Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 15:54:33 -0700 Subject: [PATCH 5/8] csv Fixes --- Lib/test/test_csv.py | 1 + Modules/_csv.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 2fdff6bbacab9a..46bfb9d629866b 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -1082,6 +1082,7 @@ def test_create_write(self): delta = rc-lastrc lastrc = rc # if csv.writer() leaks, last delta should be 3 or more + print(sys.getobjects(5)) self.assertLess(delta, 3) def test_read(self): diff --git a/Modules/_csv.c b/Modules/_csv.c index 490d3e626af28c..0bf862359f2874 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -310,8 +310,10 @@ static PyGetSetDef Dialect_getsetlist[] = { static void Dialect_dealloc(DialectObj *self) { + PyObject *tp = (PyObject *) Py_TYPE(self); Py_XDECREF(self->lineterminator); Py_TYPE(self)->tp_free((PyObject *)self); + Py_DECREF(tp); } static char *dialect_kws[] = { @@ -485,12 +487,11 @@ static PyType_Spec Dialect_Type_spec = { static PyObject * _call_dialect(PyObject *dialect_inst, PyObject *kwargs) { - PyObject *type = PyObject_GetAttrString(_csvmodule, "Dialect"); if (dialect_inst) { - return _PyObject_FastCallDict(type, &dialect_inst, 1, kwargs); + return _PyObject_FastCallDict(Dialect_Type, &dialect_inst, 1, kwargs); } else { - return _PyObject_FastCallDict(type, NULL, 0, kwargs); + return _PyObject_FastCallDict(Dialect_Type, NULL, 0, kwargs); } } @@ -822,12 +823,14 @@ Reader_iternext(ReaderObj *self) static void Reader_dealloc(ReaderObj *self) { + PyObject *tp = (PyObject *) Py_TYPE(self); PyObject_GC_UnTrack(self); Py_XDECREF(self->dialect); Py_XDECREF(self->input_iter); Py_XDECREF(self->fields); if (self->field != NULL) PyMem_Free(self->field); + Py_DECREF(tp); PyObject_GC_Del(self); } @@ -895,6 +898,7 @@ csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) if (!self) return NULL; + Py_INCREF(Reader_Type); self->dialect = NULL; self->fields = NULL; @@ -1248,11 +1252,13 @@ static struct PyMemberDef Writer_memberlist[] = { static void Writer_dealloc(WriterObj *self) { + PyObject *tp = (PyObject *) Py_TYPE(self); PyObject_GC_UnTrack(self); Py_XDECREF(self->dialect); Py_XDECREF(self->writeline); if (self->rec != NULL) PyMem_Free(self->rec); + Py_DECREF(tp); PyObject_GC_Del(self); } @@ -1306,6 +1312,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) if (!self) return NULL; + Py_INCREF(Writer_Type); self->dialect = NULL; self->writeline = NULL; @@ -1563,10 +1570,12 @@ PyInit__csv(void) Reader_Type = PyType_FromSpec(&Reader_Type_spec); if (Reader_Type == NULL) return NULL; + ((PyTypeObject *)Reader_Type)->tp_new = NULL; Writer_Type = PyType_FromSpec(&Writer_Type_spec); if (Writer_Type == NULL) return NULL; + ((PyTypeObject *)Writer_Type)->tp_new = NULL; /* Create the module and add the functions */ _csvmodule = PyModule_Create(&_csvmodule_def); @@ -1598,9 +1607,9 @@ PyInit__csv(void) } /* Add the Dialect type */ - Py_INCREF(Dialect_Type); if (PyModule_AddObject(_csvmodule, "Dialect", Dialect_Type)) return NULL; + Py_INCREF(Dialect_Type); /* Add the CSV exception object to the module. */ _csvstate(_csvmodule)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL); From 5eb802a762d155691485959b3d81eb572f4042c4 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Tue, 28 Aug 2018 16:00:06 -0700 Subject: [PATCH 6/8] Fix merge artifacts --- Lib/test/test_csv.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py index 46bfb9d629866b..2fdff6bbacab9a 100644 --- a/Lib/test/test_csv.py +++ b/Lib/test/test_csv.py @@ -1082,7 +1082,6 @@ def test_create_write(self): delta = rc-lastrc lastrc = rc # if csv.writer() leaks, last delta should be 3 or more - print(sys.getobjects(5)) self.assertLess(delta, 3) def test_read(self): From c04190fb2d53188de407735de74ef728e1d5a0b1 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Wed, 29 Aug 2018 08:58:27 -0700 Subject: [PATCH 7/8] Removed static module --- Modules/_csv.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 0bf862359f2874..918fc4d5ed2beb 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -45,10 +45,9 @@ _csv_free(void *m) _csv_clear((PyObject *)m); } -static struct PyModuleDef _csvmodule_def; -static PyObject *_csvmodule; +static struct PyModuleDef module_def; -#define _csvstate_global ((_csvstate *)PyModule_GetState(PyState_FindModule(&_csvmodule_def))) +#define _csvstate_global ((_csvstate *)PyModule_GetState(PyState_FindModule(&module_def))) typedef enum { START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD, @@ -1546,7 +1545,7 @@ static struct PyMethodDef csv_methods[] = { { NULL, NULL } }; -static struct PyModuleDef _csvmodule_def = { +static struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, "_csv", csv_module_doc, @@ -1561,6 +1560,7 @@ static struct PyModuleDef _csvmodule_def = { PyMODINIT_FUNC PyInit__csv(void) { + PyObject *module; const StyleDesc *style; Dialect_Type = PyType_FromSpec(&Dialect_Type_spec); @@ -1578,44 +1578,44 @@ PyInit__csv(void) ((PyTypeObject *)Writer_Type)->tp_new = NULL; /* Create the module and add the functions */ - _csvmodule = PyModule_Create(&_csvmodule_def); - if (_csvmodule == NULL) + module = PyModule_Create(&module_def); + if (module == NULL) return NULL; /* Add version to the module. */ - if (PyModule_AddStringConstant(_csvmodule, "__version__", + if (PyModule_AddStringConstant(module, "__version__", MODULE_VERSION) == -1) return NULL; /* Set the field limit */ - _csvstate(_csvmodule)->field_limit = 128 * 1024; + _csvstate(module)->field_limit = 128 * 1024; /* Do I still need to add this var to the Module Dict? */ /* Add _dialects dictionary */ - _csvstate(_csvmodule)->dialects = PyDict_New(); - if (_csvstate(_csvmodule)->dialects == NULL) + _csvstate(module)->dialects = PyDict_New(); + if (_csvstate(module)->dialects == NULL) return NULL; - Py_INCREF(_csvstate(_csvmodule)->dialects); - if (PyModule_AddObject(_csvmodule, "_dialects", _csvstate(_csvmodule)->dialects)) + Py_INCREF(_csvstate(module)->dialects); + if (PyModule_AddObject(module, "_dialects", _csvstate(module)->dialects)) return NULL; /* Add quote styles into dictionary */ for (style = quote_styles; style->name; style++) { - if (PyModule_AddIntConstant(_csvmodule, style->name, + if (PyModule_AddIntConstant(module, style->name, style->style) == -1) return NULL; } /* Add the Dialect type */ - if (PyModule_AddObject(_csvmodule, "Dialect", Dialect_Type)) + if (PyModule_AddObject(module, "Dialect", Dialect_Type)) return NULL; Py_INCREF(Dialect_Type); /* Add the CSV exception object to the module. */ - _csvstate(_csvmodule)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL); - if (_csvstate(_csvmodule)->error_obj == NULL) + _csvstate(module)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL); + if (_csvstate(module)->error_obj == NULL) return NULL; - Py_INCREF(_csvstate(_csvmodule)->error_obj); - PyModule_AddObject(_csvmodule, "Error", _csvstate(_csvmodule)->error_obj); - return _csvmodule; + Py_INCREF(_csvstate(module)->error_obj); + PyModule_AddObject(module, "Error", _csvstate(module)->error_obj); + return module; } From cbd2085bd4df79d7c552a0adb0c1812172ddd9d6 Mon Sep 17 00:00:00 2001 From: Eddie Elizondo Date: Thu, 30 Aug 2018 10:10:51 -0700 Subject: [PATCH 8/8] Add subinterpreter support --- Modules/_csv.c | 55 ++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/Modules/_csv.c b/Modules/_csv.c index 918fc4d5ed2beb..89489b3996e680 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -19,6 +19,9 @@ typedef struct { PyObject *error_obj; /* CSV exception */ PyObject *dialects; /* Dialect registry */ long field_limit; /* max parsed field size */ + PyObject* Dialect_Type; + PyObject* Reader_Type; + PyObject* Writer_Type; } _csvstate; #define _csvstate(o) ((_csvstate *)PyModule_GetState(o)) @@ -28,6 +31,9 @@ _csv_clear(PyObject *m) { Py_CLEAR(_csvstate(m)->error_obj); Py_CLEAR(_csvstate(m)->dialects); + Py_CLEAR(_csvstate(m)->Dialect_Type); + Py_CLEAR(_csvstate(m)->Reader_Type); + Py_CLEAR(_csvstate(m)->Writer_Type); return 0; } @@ -36,6 +42,9 @@ _csv_traverse(PyObject *m, visitproc visit, void *arg) { Py_VISIT(_csvstate(m)->error_obj); Py_VISIT(_csvstate(m)->dialects); + Py_VISIT(_csvstate(m)->Dialect_Type); + Py_VISIT(_csvstate(m)->Reader_Type); + Py_VISIT(_csvstate(m)->Writer_Type); return 0; } @@ -86,8 +95,6 @@ typedef struct { } DialectObj; -static PyObject* Dialect_Type; - typedef struct { PyObject_HEAD @@ -104,8 +111,6 @@ typedef struct { unsigned long line_num; /* Source-file line number */ } ReaderObj; -static PyObject* Reader_Type; - typedef struct { PyObject_HEAD @@ -119,8 +124,6 @@ typedef struct { int num_fields; /* number of fields in record */ } WriterObj; -static PyObject* Writer_Type; - /* * DIALECT class */ @@ -365,7 +368,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) else Py_INCREF(dialect); /* Can we reuse this instance? */ - if (PyObject_TypeCheck(dialect, (PyTypeObject *)Dialect_Type) && + if (PyObject_TypeCheck(dialect, (PyTypeObject *)_csvstate_global->Dialect_Type) && delimiter == NULL && doublequote == NULL && escapechar == NULL && @@ -487,10 +490,10 @@ static PyObject * _call_dialect(PyObject *dialect_inst, PyObject *kwargs) { if (dialect_inst) { - return _PyObject_FastCallDict(Dialect_Type, &dialect_inst, 1, kwargs); + return _PyObject_FastCallDict(_csvstate_global->Dialect_Type, &dialect_inst, 1, kwargs); } else { - return _PyObject_FastCallDict(Dialect_Type, NULL, 0, kwargs); + return _PyObject_FastCallDict(_csvstate_global->Dialect_Type, NULL, 0, kwargs); } } @@ -893,11 +896,11 @@ static PyObject * csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * iterator, * dialect = NULL; - ReaderObj * self = PyObject_GC_New(ReaderObj, (PyTypeObject *)Reader_Type); + ReaderObj * self = PyObject_GC_New(ReaderObj, (PyTypeObject *)_csvstate_global->Reader_Type); if (!self) return NULL; - Py_INCREF(Reader_Type); + Py_INCREF(_csvstate_global->Reader_Type); self->dialect = NULL; self->fields = NULL; @@ -1306,12 +1309,12 @@ static PyObject * csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) { PyObject * output_file, * dialect = NULL; - WriterObj * self = PyObject_GC_New(WriterObj, (PyTypeObject*)Writer_Type); + WriterObj * self = PyObject_GC_New(WriterObj, (PyTypeObject*)_csvstate_global->Writer_Type); _Py_IDENTIFIER(write); if (!self) return NULL; - Py_INCREF(Writer_Type); + Py_INCREF(_csvstate_global->Writer_Type); self->dialect = NULL; self->writeline = NULL; @@ -1563,24 +1566,24 @@ PyInit__csv(void) PyObject *module; const StyleDesc *style; - Dialect_Type = PyType_FromSpec(&Dialect_Type_spec); - if (Dialect_Type == NULL) + /* Create the module and add the functions */ + module = PyModule_Create(&module_def); + if (module == NULL) return NULL; - Reader_Type = PyType_FromSpec(&Reader_Type_spec); - if (Reader_Type == NULL) + _csvstate(module)->Dialect_Type = PyType_FromSpec(&Dialect_Type_spec); + if (_csvstate(module)->Dialect_Type == NULL) return NULL; - ((PyTypeObject *)Reader_Type)->tp_new = NULL; - Writer_Type = PyType_FromSpec(&Writer_Type_spec); - if (Writer_Type == NULL) + _csvstate(module)->Reader_Type = PyType_FromSpec(&Reader_Type_spec); + if (_csvstate(module)->Reader_Type == NULL) return NULL; - ((PyTypeObject *)Writer_Type)->tp_new = NULL; + ((PyTypeObject *)_csvstate(module)->Reader_Type)->tp_new = NULL; - /* Create the module and add the functions */ - module = PyModule_Create(&module_def); - if (module == NULL) + _csvstate(module)->Writer_Type = PyType_FromSpec(&Writer_Type_spec); + if (_csvstate(module)->Writer_Type == NULL) return NULL; + ((PyTypeObject *)_csvstate(module)->Writer_Type)->tp_new = NULL; /* Add version to the module. */ if (PyModule_AddStringConstant(module, "__version__", @@ -1607,9 +1610,9 @@ PyInit__csv(void) } /* Add the Dialect type */ - if (PyModule_AddObject(module, "Dialect", Dialect_Type)) + if (PyModule_AddObject(module, "Dialect", _csvstate(module)->Dialect_Type)) return NULL; - Py_INCREF(Dialect_Type); + Py_INCREF(_csvstate(module)->Dialect_Type); /* Add the CSV exception object to the module. */ _csvstate(module)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL);