@@ -1009,7 +1009,7 @@ join_reset(WriterObj *self)
10091009 */
10101010static Py_ssize_t
10111011join_append_data (WriterObj * self , unsigned int field_kind , void * field_data ,
1012- Py_ssize_t field_len , int quote_empty , int * quoted ,
1012+ Py_ssize_t field_len , int * quoted ,
10131013 int copy_phase )
10141014{
10151015 DialectObj * dialect = self -> dialect ;
@@ -1071,18 +1071,6 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data,
10711071 ADDCH (c );
10721072 }
10731073
1074- /* If field is empty check if it needs to be quoted.
1075- */
1076- if (i == 0 && quote_empty ) {
1077- if (dialect -> quoting == QUOTE_NONE ) {
1078- PyErr_Format (_csvstate_global -> error_obj ,
1079- "single empty field record must be quoted" );
1080- return -1 ;
1081- }
1082- else
1083- * quoted = 1 ;
1084- }
1085-
10861074 if (* quoted ) {
10871075 if (copy_phase )
10881076 ADDCH (dialect -> quotechar );
@@ -1126,7 +1114,7 @@ join_check_rec_size(WriterObj *self, Py_ssize_t rec_len)
11261114}
11271115
11281116static int
1129- join_append (WriterObj * self , PyObject * field , int * quoted , int quote_empty )
1117+ join_append (WriterObj * self , PyObject * field , int quoted )
11301118{
11311119 unsigned int field_kind = -1 ;
11321120 void * field_data = NULL ;
@@ -1141,7 +1129,7 @@ join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty)
11411129 field_len = PyUnicode_GET_LENGTH (field );
11421130 }
11431131 rec_len = join_append_data (self , field_kind , field_data , field_len ,
1144- quote_empty , quoted , 0 );
1132+ & quoted , 0 );
11451133 if (rec_len < 0 )
11461134 return 0 ;
11471135
@@ -1150,7 +1138,7 @@ join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty)
11501138 return 0 ;
11511139
11521140 self -> rec_len = join_append_data (self , field_kind , field_data , field_len ,
1153- quote_empty , quoted , 1 );
1141+ & quoted , 1 );
11541142 self -> num_fields ++ ;
11551143
11561144 return 1 ;
@@ -1181,37 +1169,30 @@ join_append_lineterminator(WriterObj *self)
11811169}
11821170
11831171PyDoc_STRVAR (csv_writerow_doc ,
1184- "writerow(sequence )\n"
1172+ "writerow(iterable )\n"
11851173"\n"
1186- "Construct and write a CSV record from a sequence of fields. Non-string\n"
1174+ "Construct and write a CSV record from an iterable of fields. Non-string\n"
11871175"elements will be converted to string." );
11881176
11891177static PyObject *
11901178csv_writerow (WriterObj * self , PyObject * seq )
11911179{
11921180 DialectObj * dialect = self -> dialect ;
1193- Py_ssize_t len , i ;
1194- PyObject * line , * result ;
1181+ PyObject * iter , * field , * line , * result ;
11951182
1196- if (!PySequence_Check (seq ))
1197- return PyErr_Format (_csvstate_global -> error_obj , "sequence expected" );
1198-
1199- len = PySequence_Length (seq );
1200- if (len < 0 )
1201- return NULL ;
1183+ iter = PyObject_GetIter (seq );
1184+ if (iter == NULL )
1185+ return PyErr_Format (_csvstate_global -> error_obj ,
1186+ "iterable expected, not %.200s" ,
1187+ seq -> ob_type -> tp_name );
12021188
12031189 /* Join all fields in internal buffer.
12041190 */
12051191 join_reset (self );
1206- for (i = 0 ; i < len ; i ++ ) {
1207- PyObject * field ;
1192+ while ((field = PyIter_Next (iter ))) {
12081193 int append_ok ;
12091194 int quoted ;
12101195
1211- field = PySequence_GetItem (seq , i );
1212- if (field == NULL )
1213- return NULL ;
1214-
12151196 switch (dialect -> quoting ) {
12161197 case QUOTE_NONNUMERIC :
12171198 quoted = !PyNumber_Check (field );
@@ -1225,31 +1206,49 @@ csv_writerow(WriterObj *self, PyObject *seq)
12251206 }
12261207
12271208 if (PyUnicode_Check (field )) {
1228- append_ok = join_append (self , field , & quoted , len == 1 );
1209+ append_ok = join_append (self , field , quoted );
12291210 Py_DECREF (field );
12301211 }
12311212 else if (field == Py_None ) {
1232- append_ok = join_append (self , NULL , & quoted , len == 1 );
1213+ append_ok = join_append (self , NULL , quoted );
12331214 Py_DECREF (field );
12341215 }
12351216 else {
12361217 PyObject * str ;
12371218
12381219 str = PyObject_Str (field );
12391220 Py_DECREF (field );
1240- if (str == NULL )
1221+ if (str == NULL ) {
1222+ Py_DECREF (iter );
12411223 return NULL ;
1242- append_ok = join_append (self , str , & quoted , len == 1 );
1224+ }
1225+ append_ok = join_append (self , str , quoted );
12431226 Py_DECREF (str );
12441227 }
1245- if (!append_ok )
1228+ if (!append_ok ) {
1229+ Py_DECREF (iter );
1230+ return NULL ;
1231+ }
1232+ }
1233+ Py_DECREF (iter );
1234+ if (PyErr_Occurred ())
1235+ return NULL ;
1236+
1237+ if (self -> num_fields > 0 && self -> rec_size == 0 ) {
1238+ if (dialect -> quoting == QUOTE_NONE ) {
1239+ PyErr_Format (_csvstate_global -> error_obj ,
1240+ "single empty field record must be quoted" );
1241+ return NULL ;
1242+ }
1243+ self -> num_fields -- ;
1244+ if (!join_append (self , NULL , 1 ))
12461245 return NULL ;
12471246 }
12481247
12491248 /* Add line terminator.
12501249 */
12511250 if (!join_append_lineterminator (self ))
1252- return 0 ;
1251+ return NULL ;
12531252
12541253 line = PyUnicode_FromKindAndData (PyUnicode_4BYTE_KIND ,
12551254 (void * ) self -> rec , self -> rec_len );
@@ -1261,9 +1260,9 @@ csv_writerow(WriterObj *self, PyObject *seq)
12611260}
12621261
12631262PyDoc_STRVAR (csv_writerows_doc ,
1264- "writerows(sequence of sequences )\n"
1263+ "writerows(iterable of iterables )\n"
12651264"\n"
1266- "Construct and write a series of sequences to a csv file. Non-string\n"
1265+ "Construct and write a series of iterables to a csv file. Non-string\n"
12671266"elements will be converted to string." );
12681267
12691268static PyObject *
0 commit comments