diff --git a/doc/source/release.rst b/doc/source/release.rst index 74ac180a7d121..69647939ab0d0 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -315,6 +315,7 @@ See :ref:`Internal Refactoring` - Fix some inconsistencies with ``Index.rename`` and ``MultiIndex.rename``, etc. (:issue:`4718`, :issue:`4628`) - Bug in using ``iloc/loc`` with a cross-sectional and duplicate indicies (:issue:`4726`) + - Bug with using ``QUOTE_NONE`` with ``to_csv`` causing ``Exception``. (:issue:`4328`) pandas 0.12 =========== diff --git a/pandas/core/format.py b/pandas/core/format.py index 8077254de47ff..978b82aed22d9 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -787,7 +787,7 @@ def __init__(self, obj, path_or_buf, sep=",", na_rep='', float_format=None, cols=None, header=True, index=True, index_label=None, mode='w', nanRep=None, encoding=None, quoting=None, line_terminator='\n', chunksize=None, engine=None, - tupleize_cols=True): + tupleize_cols=True, quotechar='"'): self.engine = engine # remove for 0.13 self.obj = obj @@ -807,6 +807,11 @@ def __init__(self, obj, path_or_buf, sep=",", na_rep='', float_format=None, quoting = csv.QUOTE_MINIMAL self.quoting = quoting + if quoting == csv.QUOTE_NONE: + # prevents crash in _csv + quotechar = None + self.quotechar = quotechar + self.line_terminator = line_terminator #GH3457 @@ -950,13 +955,14 @@ def save(self): close = True try: + writer_kwargs = dict(lineterminator=self.line_terminator, + delimiter=self.sep, quoting=self.quoting, + quotechar=self.quotechar) if self.encoding is not None: - self.writer = com.UnicodeWriter(f, lineterminator=self.line_terminator, - delimiter=self.sep, encoding=self.encoding, - quoting=self.quoting) + writer_kwargs['encoding'] = self.encoding + self.writer = com.UnicodeWriter(f, **writer_kwargs) else: - self.writer = csv.writer(f, lineterminator=self.line_terminator, - delimiter=self.sep, quoting=self.quoting) + self.writer = csv.writer(f, **writer_kwargs) if self.engine == 'python': # to be removed in 0.13 diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index b992b2d60a08d..d72c379919e93 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -6,6 +6,7 @@ from datetime import datetime, timedelta, time import operator import re +import csv import unittest import nose @@ -5465,8 +5466,6 @@ def test_to_csv_float_format(self): assert_frame_equal(rs, xp) def test_to_csv_quoting(self): - import csv - df = DataFrame({'A': [1, 2, 3], 'B': ['foo', 'bar', 'baz']}) buf = StringIO() @@ -5489,8 +5488,6 @@ def test_to_csv_quoting(self): self.assertEqual(buf.getvalue(), text) def test_to_csv_unicodewriter_quoting(self): - import csv - df = DataFrame({'A': [1, 2, 3], 'B': ['foo', 'bar', 'baz']}) buf = StringIO() @@ -5505,6 +5502,17 @@ def test_to_csv_unicodewriter_quoting(self): self.assertEqual(result, expected) + def test_to_csv_quote_none(self): + # GH4328 + df = DataFrame({'A': ['hello', '{"hello"}']}) + for encoding in (None, 'utf-8'): + buf = StringIO() + df.to_csv(buf, quoting=csv.QUOTE_NONE, + encoding=encoding, index=False) + result = buf.getvalue() + expected = 'A\nhello\n{"hello"}\n' + self.assertEqual(result, expected) + def test_to_csv_index_no_leading_comma(self): df = DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6]}, index=['one', 'two', 'three'])