@@ -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
2353typedef 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)
544574static int
545575parse_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)
13531383static PyObject *
13541384csv_list_dialects (PyObject * module , PyObject * args )
13551385{
1356- return PyDict_Keys (dialects );
1386+ return PyDict_Keys (_csvstate_global -> dialects );
13571387}
13581388
13591389static 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)
13841414static PyObject *
13851415csv_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 *
14001430csv_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-
15551584static 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
15671596PyMODINIT_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