Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e7672d3

Browse files
committed
Issue #14732: The _csv module now uses PEP 3121 module initialization.
Patch by Robin Schreiber.
1 parent adbda17 commit e7672d3

3 files changed

Lines changed: 74 additions & 35 deletions

File tree

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ Ralf Schmitt
919919
Michael Schneider
920920
Peter Schneider-Kamp
921921
Arvin Schnell
922+
Robin Schreiber
922923
Chad J. Schroeder
923924
Sam Schulenburg
924925
Stefan Schwarzer

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Core and Builtins
3434
Library
3535
-------
3636

37+
- Issue #14732: The _csv module now uses PEP 3121 module initialization.
38+
Patch by Robin Schreiber.
39+
3740
- Issue #14809: Add HTTP status codes introduced by RFC 6585 to http.server
3841
and http.client. Patch by EungJun Yi.
3942

Modules/_csv.c

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,39 @@ module instead.
1616
#define IS_BASESTRING(o) \
1717
PyUnicode_Check(o)
1818

19-
static PyObject *error_obj; /* CSV exception */
20-
static PyObject *dialects; /* Dialect registry */
21-
static long field_limit = 128 * 1024; /* max parsed field size */
19+
typedef struct {
20+
PyObject *error_obj; /* CSV exception */
21+
PyObject *dialects; /* Dialect registry */
22+
long field_limit; /* max parsed field size */
23+
} _csvstate;
24+
25+
#define _csvstate(o) ((_csvstate *)PyModule_GetState(o))
26+
27+
static int
28+
_csv_clear(PyObject *m)
29+
{
30+
Py_CLEAR(_csvstate(m)->error_obj);
31+
Py_CLEAR(_csvstate(m)->dialects);
32+
return 0;
33+
}
34+
35+
static int
36+
_csv_traverse(PyObject *m, visitproc visit, void *arg)
37+
{
38+
Py_VISIT(_csvstate(m)->error_obj);
39+
Py_VISIT(_csvstate(m)->dialects);
40+
return 0;
41+
}
42+
43+
static void
44+
_csv_free(void *m)
45+
{
46+
_csv_clear((PyObject *)m);
47+
}
48+
49+
static struct PyModuleDef _csvmodule;
50+
51+
#define _csvstate_global ((_csvstate *)PyModule_GetState(PyState_FindModule(&_csvmodule)))
2252

2353
typedef enum {
2454
START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD,
@@ -103,10 +133,10 @@ get_dialect_from_registry(PyObject * name_obj)
103133
{
104134
PyObject *dialect_obj;
105135

106-
dialect_obj = PyDict_GetItem(dialects, name_obj);
136+
dialect_obj = PyDict_GetItem(_csvstate_global->dialects, name_obj);
107137
if (dialect_obj == NULL) {
108138
if (!PyErr_Occurred())
109-
PyErr_Format(error_obj, "unknown dialect");
139+
PyErr_Format(_csvstate_global->error_obj, "unknown dialect");
110140
}
111141
else
112142
Py_INCREF(dialect_obj);
@@ -544,9 +574,9 @@ parse_grow_buff(ReaderObj *self)
544574
static int
545575
parse_add_char(ReaderObj *self, Py_UCS4 c)
546576
{
547-
if (self->field_len >= field_limit) {
548-
PyErr_Format(error_obj, "field larger than field limit (%ld)",
549-
field_limit);
577+
if (self->field_len >= _csvstate_global->field_limit) {
578+
PyErr_Format(_csvstate_global->error_obj, "field larger than field limit (%ld)",
579+
_csvstate_global->field_limit);
550580
return -1;
551581
}
552582
if (self->field_len == self->field_size && !parse_grow_buff(self))
@@ -703,7 +733,7 @@ parse_process_char(ReaderObj *self, Py_UCS4 c)
703733
}
704734
else {
705735
/* illegal */
706-
PyErr_Format(error_obj, "'%c' expected after '%c'",
736+
PyErr_Format(_csvstate_global->error_obj, "'%c' expected after '%c'",
707737
dialect->delimiter,
708738
dialect->quotechar);
709739
return -1;
@@ -716,7 +746,7 @@ parse_process_char(ReaderObj *self, Py_UCS4 c)
716746
else if (c == '\0')
717747
self->state = START_RECORD;
718748
else {
719-
PyErr_Format(error_obj, "new-line character seen in unquoted field - do you need to open the file in universal-newline mode?");
749+
PyErr_Format(_csvstate_global->error_obj, "new-line character seen in unquoted field - do you need to open the file in universal-newline mode?");
720750
return -1;
721751
}
722752
break;
@@ -755,12 +785,12 @@ Reader_iternext(ReaderObj *self)
755785
if (lineobj == NULL) {
756786
/* End of input OR exception */
757787
if (!PyErr_Occurred() && self->field_len != 0)
758-
PyErr_Format(error_obj,
788+
PyErr_Format(_csvstate_global->error_obj,
759789
"newline inside string");
760790
return NULL;
761791
}
762792
if (!PyUnicode_Check(lineobj)) {
763-
PyErr_Format(error_obj,
793+
PyErr_Format(_csvstate_global->error_obj,
764794
"iterator should return strings, "
765795
"not %.200s "
766796
"(did you open the file in text mode?)",
@@ -778,7 +808,7 @@ Reader_iternext(ReaderObj *self)
778808
c = PyUnicode_READ(kind, data, pos);
779809
if (c == '\0') {
780810
Py_DECREF(lineobj);
781-
PyErr_Format(error_obj,
811+
PyErr_Format(_csvstate_global->error_obj,
782812
"line contains NULL byte");
783813
goto err;
784814
}
@@ -994,7 +1024,7 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data,
9941024
}
9951025
if (want_escape) {
9961026
if (!dialect->escapechar) {
997-
PyErr_Format(error_obj,
1027+
PyErr_Format(_csvstate_global->error_obj,
9981028
"need to escape, but no escapechar set");
9991029
return -1;
10001030
}
@@ -1010,7 +1040,7 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data,
10101040
*/
10111041
if (i == 0 && quote_empty) {
10121042
if (dialect->quoting == QUOTE_NONE) {
1013-
PyErr_Format(error_obj,
1043+
PyErr_Format(_csvstate_global->error_obj,
10141044
"single empty field record must be quoted");
10151045
return -1;
10161046
}
@@ -1127,7 +1157,7 @@ csv_writerow(WriterObj *self, PyObject *seq)
11271157
PyObject *line, *result;
11281158

11291159
if (!PySequence_Check(seq))
1130-
return PyErr_Format(error_obj, "sequence expected");
1160+
return PyErr_Format(_csvstate_global->error_obj, "sequence expected");
11311161

11321162
len = PySequence_Length(seq);
11331163
if (len < 0)
@@ -1353,7 +1383,7 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
13531383
static PyObject *
13541384
csv_list_dialects(PyObject *module, PyObject *args)
13551385
{
1356-
return PyDict_Keys(dialects);
1386+
return PyDict_Keys(_csvstate_global->dialects);
13571387
}
13581388

13591389
static PyObject *
@@ -1372,7 +1402,7 @@ csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
13721402
dialect = _call_dialect(dialect_obj, kwargs);
13731403
if (dialect == NULL)
13741404
return NULL;
1375-
if (PyDict_SetItem(dialects, name_obj, dialect) < 0) {
1405+
if (PyDict_SetItem(_csvstate_global->dialects, name_obj, dialect) < 0) {
13761406
Py_DECREF(dialect);
13771407
return NULL;
13781408
}
@@ -1384,8 +1414,8 @@ csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs)
13841414
static PyObject *
13851415
csv_unregister_dialect(PyObject *module, PyObject *name_obj)
13861416
{
1387-
if (PyDict_DelItem(dialects, name_obj) < 0)
1388-
return PyErr_Format(error_obj, "unknown dialect");
1417+
if (PyDict_DelItem(_csvstate_global->dialects, name_obj) < 0)
1418+
return PyErr_Format(_csvstate_global->error_obj, "unknown dialect");
13891419
Py_INCREF(Py_None);
13901420
return Py_None;
13911421
}
@@ -1400,7 +1430,7 @@ static PyObject *
14001430
csv_field_size_limit(PyObject *module, PyObject *args)
14011431
{
14021432
PyObject *new_limit = NULL;
1403-
long old_limit = field_limit;
1433+
long old_limit = _csvstate_global->field_limit;
14041434

14051435
if (!PyArg_UnpackTuple(args, "field_size_limit", 0, 1, &new_limit))
14061436
return NULL;
@@ -1410,9 +1440,9 @@ csv_field_size_limit(PyObject *module, PyObject *args)
14101440
"limit must be an integer");
14111441
return NULL;
14121442
}
1413-
field_limit = PyLong_AsLong(new_limit);
1414-
if (field_limit == -1 && PyErr_Occurred()) {
1415-
field_limit = old_limit;
1443+
_csvstate_global->field_limit = PyLong_AsLong(new_limit);
1444+
if (_csvstate_global->field_limit == -1 && PyErr_Occurred()) {
1445+
_csvstate_global->field_limit = old_limit;
14161446
return NULL;
14171447
}
14181448
}
@@ -1551,17 +1581,16 @@ static struct PyMethodDef csv_methods[] = {
15511581
{ NULL, NULL }
15521582
};
15531583

1554-
15551584
static struct PyModuleDef _csvmodule = {
15561585
PyModuleDef_HEAD_INIT,
15571586
"_csv",
15581587
csv_module_doc,
1559-
-1,
1588+
sizeof(_csvstate),
15601589
csv_methods,
15611590
NULL,
1562-
NULL,
1563-
NULL,
1564-
NULL
1591+
_csv_traverse,
1592+
_csv_clear,
1593+
_csv_free
15651594
};
15661595

15671596
PyMODINIT_FUNC
@@ -1589,11 +1618,16 @@ PyInit__csv(void)
15891618
MODULE_VERSION) == -1)
15901619
return NULL;
15911620

1621+
/* Set the field limit */
1622+
_csvstate(module)->field_limit = 128 * 1024;
1623+
/* Do I still need to add this var to the Module Dict? */
1624+
15921625
/* Add _dialects dictionary */
1593-
dialects = PyDict_New();
1594-
if (dialects == NULL)
1626+
_csvstate(module)->dialects = PyDict_New();
1627+
if (_csvstate(module)->dialects == NULL)
15951628
return NULL;
1596-
if (PyModule_AddObject(module, "_dialects", dialects))
1629+
Py_INCREF(_csvstate(module)->dialects);
1630+
if (PyModule_AddObject(module, "_dialects", _csvstate(module)->dialects))
15971631
return NULL;
15981632

15991633
/* Add quote styles into dictionary */
@@ -1609,9 +1643,10 @@ PyInit__csv(void)
16091643
return NULL;
16101644

16111645
/* Add the CSV exception object to the module. */
1612-
error_obj = PyErr_NewException("_csv.Error", NULL, NULL);
1613-
if (error_obj == NULL)
1646+
_csvstate(module)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL);
1647+
if (_csvstate(module)->error_obj == NULL)
16141648
return NULL;
1615-
PyModule_AddObject(module, "Error", error_obj);
1649+
Py_INCREF(_csvstate(module)->error_obj);
1650+
PyModule_AddObject(module, "Error", _csvstate(module)->error_obj);
16161651
return module;
16171652
}

0 commit comments

Comments
 (0)