diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2015-03-30 06:09:54 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2015-03-30 06:09:54 (GMT) |
commit | 7901b48a1f89b9bfa9d111ae3725400b466a9baa (patch) | |
tree | 4cebbcaeeb7b1f29f5440c7762f55bf3a57c0c54 /Modules | |
parent | a695f83f0de060a77352174be8a5c6f6500ab98a (diff) | |
download | cpython-7901b48a1f89b9bfa9d111ae3725400b466a9baa.zip cpython-7901b48a1f89b9bfa9d111ae3725400b466a9baa.tar.gz cpython-7901b48a1f89b9bfa9d111ae3725400b466a9baa.tar.bz2 |
Issue #23171: csv.Writer.writerow() now supports arbitrary iterables.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_csv.c | 79 |
1 files changed, 39 insertions, 40 deletions
diff --git a/Modules/_csv.c b/Modules/_csv.c index ade35e5..eb88626 100644 --- a/Modules/_csv.c +++ b/Modules/_csv.c @@ -1009,7 +1009,7 @@ join_reset(WriterObj *self) */ static Py_ssize_t join_append_data(WriterObj *self, unsigned int field_kind, void *field_data, - Py_ssize_t field_len, int quote_empty, int *quoted, + Py_ssize_t field_len, int *quoted, int copy_phase) { DialectObj *dialect = self->dialect; @@ -1071,18 +1071,6 @@ join_append_data(WriterObj *self, unsigned int field_kind, void *field_data, ADDCH(c); } - /* If field is empty check if it needs to be quoted. - */ - if (i == 0 && quote_empty) { - if (dialect->quoting == QUOTE_NONE) { - PyErr_Format(_csvstate_global->error_obj, - "single empty field record must be quoted"); - return -1; - } - else - *quoted = 1; - } - if (*quoted) { if (copy_phase) ADDCH(dialect->quotechar); @@ -1126,7 +1114,7 @@ join_check_rec_size(WriterObj *self, Py_ssize_t rec_len) } static int -join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty) +join_append(WriterObj *self, PyObject *field, int quoted) { unsigned int field_kind = -1; void *field_data = NULL; @@ -1141,7 +1129,7 @@ join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty) field_len = PyUnicode_GET_LENGTH(field); } rec_len = join_append_data(self, field_kind, field_data, field_len, - quote_empty, quoted, 0); + "ed, 0); if (rec_len < 0) return 0; @@ -1150,7 +1138,7 @@ join_append(WriterObj *self, PyObject *field, int *quoted, int quote_empty) return 0; self->rec_len = join_append_data(self, field_kind, field_data, field_len, - quote_empty, quoted, 1); + "ed, 1); self->num_fields++; return 1; @@ -1181,37 +1169,30 @@ join_append_lineterminator(WriterObj *self) } PyDoc_STRVAR(csv_writerow_doc, -"writerow(sequence)\n" +"writerow(iterable)\n" "\n" -"Construct and write a CSV record from a sequence of fields. Non-string\n" +"Construct and write a CSV record from an iterable of fields. Non-string\n" "elements will be converted to string."); static PyObject * csv_writerow(WriterObj *self, PyObject *seq) { DialectObj *dialect = self->dialect; - Py_ssize_t len, i; - PyObject *line, *result; + PyObject *iter, *field, *line, *result; - if (!PySequence_Check(seq)) - return PyErr_Format(_csvstate_global->error_obj, "sequence expected"); - - len = PySequence_Length(seq); - if (len < 0) - return NULL; + iter = PyObject_GetIter(seq); + if (iter == NULL) + return PyErr_Format(_csvstate_global->error_obj, + "iterable expected, not %.200s", + seq->ob_type->tp_name); /* Join all fields in internal buffer. */ join_reset(self); - for (i = 0; i < len; i++) { - PyObject *field; + while ((field = PyIter_Next(iter))) { int append_ok; int quoted; - field = PySequence_GetItem(seq, i); - if (field == NULL) - return NULL; - switch (dialect->quoting) { case QUOTE_NONNUMERIC: quoted = !PyNumber_Check(field); @@ -1225,11 +1206,11 @@ csv_writerow(WriterObj *self, PyObject *seq) } if (PyUnicode_Check(field)) { - append_ok = join_append(self, field, "ed, len == 1); + append_ok = join_append(self, field, quoted); Py_DECREF(field); } else if (field == Py_None) { - append_ok = join_append(self, NULL, "ed, len == 1); + append_ok = join_append(self, NULL, quoted); Py_DECREF(field); } else { @@ -1237,19 +1218,37 @@ csv_writerow(WriterObj *self, PyObject *seq) str = PyObject_Str(field); Py_DECREF(field); - if (str == NULL) + if (str == NULL) { + Py_DECREF(iter); return NULL; - append_ok = join_append(self, str, "ed, len == 1); + } + append_ok = join_append(self, str, quoted); Py_DECREF(str); } - if (!append_ok) + if (!append_ok) { + Py_DECREF(iter); + return NULL; + } + } + Py_DECREF(iter); + if (PyErr_Occurred()) + return NULL; + + if (self->num_fields > 0 && self->rec_size == 0) { + if (dialect->quoting == QUOTE_NONE) { + PyErr_Format(_csvstate_global->error_obj, + "single empty field record must be quoted"); + return NULL; + } + self->num_fields--; + if (!join_append(self, NULL, 1)) return NULL; } /* Add line terminator. */ if (!join_append_lineterminator(self)) - return 0; + return NULL; line = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, (void *) self->rec, self->rec_len); @@ -1261,9 +1260,9 @@ csv_writerow(WriterObj *self, PyObject *seq) } PyDoc_STRVAR(csv_writerows_doc, -"writerows(sequence of sequences)\n" +"writerows(iterable of iterables)\n" "\n" -"Construct and write a series of sequences to a csv file. Non-string\n" +"Construct and write a series of iterables to a csv file. Non-string\n" "elements will be converted to string."); static PyObject * |