From 8a5c08a6bcde96938ed92ee4996aafb6655c3688 Mon Sep 17 00:00:00 2001 From: Pablo Hoffman Date: Thu, 24 Mar 2011 13:15:52 -0300 Subject: [PATCH] added join_multivalued parameter to CsvItemExporter --- docs/topics/exporters.rst | 6 +++++- scrapy/contrib/exporter/__init__.py | 11 ++++++++++- scrapy/tests/test_contrib_exporter.py | 12 ++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/docs/topics/exporters.rst b/docs/topics/exporters.rst index 9c6d292b6..4090b4ed8 100644 --- a/docs/topics/exporters.rst +++ b/docs/topics/exporters.rst @@ -264,7 +264,7 @@ XmlItemExporter CsvItemExporter --------------- -.. class:: CsvItemExporter(file, include_headers_line=True, \**kwargs) +.. class:: CsvItemExporter(file, include_headers_line=True, join_multivalued=',', \**kwargs) Exports Items in CSV format to the given file-like object. If the :attr:`fields_to_export` attribute is set, it will be used to define the @@ -278,6 +278,10 @@ CsvItemExporter :attr:`BaseItemExporter.fields_to_export` or the first exported item fields. :type include_headers_line: boolean + :param join_multivalued: The char (or chars) that will be used for joining + multi-valued fields, if found. + :type include_headers_line: str + The additional keyword arguments of this constructor are passed to the :class:`BaseItemExporter` constructor, and the leftover arguments to the `csv.writer`_ constructor, so you can use any `csv.writer` constructor diff --git a/scrapy/contrib/exporter/__init__.py b/scrapy/contrib/exporter/__init__.py index b77c747cc..1d695eb9d 100644 --- a/scrapy/contrib/exporter/__init__.py +++ b/scrapy/contrib/exporter/__init__.py @@ -143,11 +143,20 @@ class XmlItemExporter(BaseItemExporter): class CsvItemExporter(BaseItemExporter): - def __init__(self, file, include_headers_line=True, **kwargs): + def __init__(self, file, include_headers_line=True, join_multivalued=',', **kwargs): self._configure(kwargs, dont_fail=True) self.include_headers_line = include_headers_line self.csv_writer = csv.writer(file, **kwargs) self._headers_not_written = True + self._join_multivalued = join_multivalued + + def _to_str_if_unicode(self, value): + if isinstance(value, (list, tuple)): + try: + value = self._join_multivalued.join(value) + except TypeError: # list in value may not contain strings + pass + return super(CsvItemExporter, self)._to_str_if_unicode(value) def export_item(self, item): if self._headers_not_written: diff --git a/scrapy/tests/test_contrib_exporter.py b/scrapy/tests/test_contrib_exporter.py index 8b776f587..974174c42 100644 --- a/scrapy/tests/test_contrib_exporter.py +++ b/scrapy/tests/test_contrib_exporter.py @@ -127,6 +127,18 @@ class CsvItemExporterTest(BaseItemExporterTest): ie.finish_exporting() self.assertEqual(output.getvalue(), '22,John\xc2\xa3\r\n') + def test_join_multivalue(self): + class TestItem2(Item): + name = Field() + friends = Field() + + i = TestItem2(name='John', friends=['Mary', 'Paul']) + output = StringIO() + ie = CsvItemExporter(output, include_headers_line=False) + ie.start_exporting() + ie.export_item(i) + ie.finish_exporting() + self.assertEqual(output.getvalue(), '"Mary,Paul",John\r\n') class XmlItemExporterTest(BaseItemExporterTest):