From 805739eb2eebb71126efed5ebb961d6b20f00dd3 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 15:03:06 +0100 Subject: [PATCH 01/19] implement closed attribute for PY2 --- pandas/io/common.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pandas/io/common.py b/pandas/io/common.py index a492b7c0b8e8e..3fd4c9ddb9dbc 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -445,6 +445,13 @@ def __init__(self, file, mode, compression=zipfile.ZIP_DEFLATED, **kwargs): def write(self, data): super(BytesZipFile, self).writestr(self.filename, data) + @property + def closed(self): + if compat.PY2: + return self.fp is None + else: + return super(BytesZipFile, self).closed + class MMapWrapper(BaseIterator): """ From 1185281619256a07170a4c52ee207edabffe70ed Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 15:04:04 +0100 Subject: [PATCH 02/19] revert PR 21249 --- pandas/core/frame.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 02c86d2f4dcc8..a5dfbcc2a3142 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1690,7 +1690,8 @@ def to_csv(self, path_or_buf=None, sep=",", na_rep='', float_format=None, defaults to 'ascii' on Python 2 and 'utf-8' on Python 3. compression : string, optional A string representing the compression to use in the output file. - Allowed values are 'gzip', 'bz2', 'zip', 'xz'. + Allowed values are 'gzip', 'bz2', 'zip', 'xz'. This input is only + used when the first argument is a filename. line_terminator : string, default ``'\n'`` The newline character or character sequence to use in the output file From 5e66ee21d6c0de40f94e732754175fb08cd008ec Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 15:04:33 +0100 Subject: [PATCH 03/19] revert PR 21249 --- pandas/core/series.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 0450f28087f66..23c4bbe082f28 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -3790,7 +3790,8 @@ def to_csv(self, path=None, index=True, sep=",", na_rep='', non-ascii, for python versions prior to 3 compression : string, optional A string representing the compression to use in the output file. - Allowed values are 'gzip', 'bz2', 'zip', 'xz'. + Allowed values are 'gzip', 'bz2', 'zip', 'xz'. This input is only + used when the first argument is a filename. date_format: string, default None Format string for datetime objects. decimal: string, default '.' From d11dcae13ac866a771823939ee41c530211038c5 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 16:03:46 +0100 Subject: [PATCH 04/19] use _get_handle to produce a handle --- pandas/tests/test_common.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 7034e9ac2e0c8..ed066fe179269 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -11,6 +11,7 @@ from pandas.compat import range, lmap import pandas.core.common as com from pandas.core import ops +from pandas.io.common import _get_handle import pandas.util.testing as tm @@ -246,19 +247,19 @@ def test_compression_size(obj, method, compression_only): [12.32112, 123123.2, 321321.2]], columns=['X', 'Y', 'Z']), Series(100 * [0.123456, 0.234567, 0.567567], name='X')]) -@pytest.mark.parametrize('method', ['to_csv']) +@pytest.mark.parametrize('method', ['to_csv', 'to_json']) def test_compression_size_fh(obj, method, compression_only): with tm.ensure_clean() as filename: - with open(filename, 'w') as fh: - getattr(obj, method)(fh, compression=compression_only) - assert not fh.closed - assert fh.closed + f, _handles = _get_handle(filename, 'w', compression=compression_only) + with f: + getattr(obj, method)(f) + assert not f.closed compressed = os.path.getsize(filename) with tm.ensure_clean() as filename: - with open(filename, 'w') as fh: - getattr(obj, method)(fh, compression=None) - assert not fh.closed - assert fh.closed + f, _handles = _get_handle(filename, 'w', compression=None) + with f: + getattr(obj, method)(f) + assert not f.closed uncompressed = os.path.getsize(filename) assert uncompressed > compressed From d3dac82832f5c88fa373454b0bc0298b47df93e0 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 16:05:44 +0100 Subject: [PATCH 05/19] use _get_handle to produce file handle --- pandas/tests/frame/test_to_csv.py | 17 ++++++++++------- pandas/tests/series/test_io.py | 13 +++++++------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/pandas/tests/frame/test_to_csv.py b/pandas/tests/frame/test_to_csv.py index 60dc336a85388..1b5dae222ed70 100644 --- a/pandas/tests/frame/test_to_csv.py +++ b/pandas/tests/frame/test_to_csv.py @@ -9,6 +9,7 @@ import numpy as np from pandas.compat import (lmap, range, lrange, StringIO, u) +from pandas.io.common import _get_handle import pandas.core.common as com from pandas.errors import ParserError from pandas import (DataFrame, Index, Series, MultiIndex, Timestamp, @@ -935,17 +936,19 @@ def test_to_csv_compression(self, df, encoding, compression): with ensure_clean() as filename: df.to_csv(filename, compression=compression, encoding=encoding) - # test the round trip - to_csv -> read_csv result = read_csv(filename, compression=compression, index_col=0, encoding=encoding) - - with open(filename, 'w') as fh: - df.to_csv(fh, compression=compression, encoding=encoding) - - result_fh = read_csv(filename, compression=compression, - index_col=0, encoding=encoding) assert_frame_equal(df, result) + + # test the round trip using file handle - to_csv -> read_csv + f, _handles = _get_handle(filename, 'w', compression=compression, + encoding=encoding) + with f: + df.to_csv(f, encoding=encoding) + result_fh = pd.read_csv(filename, compression=compression, + encoding=encoding, index_col=0, + squeeze=True) assert_frame_equal(df, result_fh) # explicitly make sure file is compressed diff --git a/pandas/tests/series/test_io.py b/pandas/tests/series/test_io.py index f98962685ad9a..5870b8895ecf4 100644 --- a/pandas/tests/series/test_io.py +++ b/pandas/tests/series/test_io.py @@ -11,6 +11,7 @@ from pandas import Series, DataFrame from pandas.compat import StringIO, u +from pandas.io.common import _get_handle from pandas.util.testing import (assert_series_equal, assert_almost_equal, assert_frame_equal, ensure_clean) import pandas.util.testing as tm @@ -151,19 +152,19 @@ def test_to_csv_compression(self, s, encoding, compression): s.to_csv(filename, compression=compression, encoding=encoding, header=True) - # test the round trip - to_csv -> read_csv result = pd.read_csv(filename, compression=compression, encoding=encoding, index_col=0, squeeze=True) + assert_series_equal(s, result) - with open(filename, 'w') as fh: - s.to_csv(fh, compression=compression, encoding=encoding, - header=True) - + # test the round trip using file handle - to_csv -> read_csv + f, _handles = _get_handle(filename, 'w', compression=compression, + encoding=encoding) + with f: + s.to_csv(f, encoding=encoding, header=True) result_fh = pd.read_csv(filename, compression=compression, encoding=encoding, index_col=0, squeeze=True) - assert_series_equal(s, result) assert_series_equal(s, result_fh) # explicitly ensure file was compressed From 9567900f3b9e632b78f77503ed1173be1a9010fa Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 17:56:24 +0100 Subject: [PATCH 06/19] regression to 0.22 and add zipfile support --- pandas/io/formats/csvs.py | 62 +++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index 7f660e2644fa4..4106958738326 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -9,7 +9,6 @@ import numpy as np from pandas.core.dtypes.missing import notna -from pandas.core.dtypes.inference import is_file_like from pandas.core.index import Index, MultiIndex from pandas import compat from pandas.compat import (StringIO, range, zip) @@ -128,19 +127,26 @@ def save(self): else: encoding = self.encoding - # PR 21300 uses string buffer to receive csv writing and dump into - # file-like output with compression as option. GH 21241, 21118 - f = StringIO() - if not is_file_like(self.path_or_buf): - # path_or_buf is path - path_or_buf = self.path_or_buf - elif hasattr(self.path_or_buf, 'name'): - # path_or_buf is file handle - path_or_buf = self.path_or_buf.name + if (not hasattr(self.path_or_buf, 'write') and + self.compression == 'zip'): + is_zip = True else: - # path_or_buf is file-like IO objects. + is_zip = False + + if is_zip: + # zipfile doesn't support writing string to archive. uses string + # buffer to receive csv writing and dump into zip compression + # file handle. GH 21241, 21118 + f = StringIO() + close = False + elif hasattr(self.path_or_buf, 'write'): f = self.path_or_buf - path_or_buf = None + close = False + else: + f, handles = _get_handle(self.path_or_buf, self.mode, + encoding=encoding, + compression=self.compression) + close = True try: writer_kwargs = dict(lineterminator=self.line_terminator, @@ -157,17 +163,35 @@ def save(self): self._save() finally: - # GH 17778 handles zip compression for byte strings separately. - buf = f.getvalue() - if path_or_buf: - f, handles = _get_handle(path_or_buf, self.mode, - encoding=encoding, - compression=self.compression) - f.write(buf) + if is_zip: + # GH 17778 handles zip compression separately. + buf = f.getvalue() + try: + self.path_or_buf.write(buf) + except AttributeError: + f, handles = _get_handle(self.path_or_buf, self.mode, + encoding=encoding, + compression=self.compression) + f.write(buf) + close = True + if close: f.close() for _fh in handles: _fh.close() + # GH 17778 handles zip compression for byte strings separately. + # if path is not None: + # buf = f.getvalue() + # f, handles = _get_handle(path, self.mode, + # encoding=encoding, + # compression=self.compression) + # f.write(buf) + # + # if not py2zip: + # f.close() + # for _fh in handles: + # _fh.close() + def _save_header(self): writer = self.writer From 6accf04a216c9a8f8e677d29151472b30835072c Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 18:25:08 +0100 Subject: [PATCH 07/19] add warning when passing file handle with compression flag --- pandas/io/formats/csvs.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index 4106958738326..e8e5815c77292 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -142,6 +142,11 @@ def save(self): elif hasattr(self.path_or_buf, 'write'): f = self.path_or_buf close = False + if self.compression: + import warnings + msg = ("compression has no effect when passing file-like " + "object as input.") + warnings.warn(msg, RuntimeWarning, stacklevel=2) else: f, handles = _get_handle(self.path_or_buf, self.mode, encoding=encoding, @@ -179,19 +184,6 @@ def save(self): for _fh in handles: _fh.close() - # GH 17778 handles zip compression for byte strings separately. - # if path is not None: - # buf = f.getvalue() - # f, handles = _get_handle(path, self.mode, - # encoding=encoding, - # compression=self.compression) - # f.write(buf) - # - # if not py2zip: - # f.close() - # for _fh in handles: - # _fh.close() - def _save_header(self): writer = self.writer From d5d976ea3b954a30fd46a25336fb0ca31d0d66fb Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 19:17:15 +0100 Subject: [PATCH 08/19] catch zip --- pandas/io/formats/csvs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index e8e5815c77292..d68b55b241d6a 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -6,6 +6,7 @@ from __future__ import print_function import csv as csvlib +from zipfile import ZipFile import numpy as np from pandas.core.dtypes.missing import notna @@ -127,7 +128,7 @@ def save(self): else: encoding = self.encoding - if (not hasattr(self.path_or_buf, 'write') and + if (isinstance(self.path_or_buf, ZipFile) or self.compression == 'zip'): is_zip = True else: From 05bbd81df8675d6ddc35bf7f3953582a08ac3000 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 19:35:14 +0100 Subject: [PATCH 09/19] add warnings when passing file-object and compression parameter --- pandas/io/formats/csvs.py | 11 ++++++----- pandas/tests/test_common.py | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index d68b55b241d6a..ca9deb12a9a0c 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -128,6 +128,12 @@ def save(self): else: encoding = self.encoding + if self.compression and hasattr(self.path_or_buf, 'write'): + import warnings + msg = ("compression has no effect when passing file-like " + "object as input.") + warnings.warn(msg, RuntimeWarning, stacklevel=2) + if (isinstance(self.path_or_buf, ZipFile) or self.compression == 'zip'): is_zip = True @@ -143,11 +149,6 @@ def save(self): elif hasattr(self.path_or_buf, 'write'): f = self.path_or_buf close = False - if self.compression: - import warnings - msg = ("compression has no effect when passing file-like " - "object as input.") - warnings.warn(msg, RuntimeWarning, stacklevel=2) else: f, handles = _get_handle(self.path_or_buf, self.mode, encoding=encoding, diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index ed066fe179269..9ccbf87205846 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -263,3 +263,15 @@ def test_compression_size_fh(obj, method, compression_only): assert not f.closed uncompressed = os.path.getsize(filename) assert uncompressed > compressed + + +def test_compression_warning(compression_only): + df = DataFrame(100 * [[0.123456, 0.234567, 0.567567], + [12.32112, 123123.2, 321321.2]], + columns=['X', 'Y', 'Z']) + with tm.ensure_clean() as filename: + f, _handles = _get_handle(filename, 'w', compression=compression_only) + with tm.assert_produces_warning(RuntimeWarning, + check_stacklevel=False): + with f: + df.to_csv(f, compression=compression_only) From 6f5bcf167cf46294e0b01600c2a69a7eae1b2e59 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Thu, 14 Jun 2018 19:49:17 +0100 Subject: [PATCH 10/19] catch file-handle and zip at the same time. --- pandas/io/formats/csvs.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index ca9deb12a9a0c..eb97e09b3c285 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -134,8 +134,9 @@ def save(self): "object as input.") warnings.warn(msg, RuntimeWarning, stacklevel=2) - if (isinstance(self.path_or_buf, ZipFile) or - self.compression == 'zip'): + if isinstance(self.path_or_buf, ZipFile) or ( + not hasattr(self.path_or_buf, 'write') + and self.compression == 'zip'): is_zip = True else: is_zip = False From c75432942a23b93070548f86a515e46e62a52041 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 10:40:43 +0100 Subject: [PATCH 11/19] add whatsnew --- doc/source/whatsnew/v0.23.2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.2.txt b/doc/source/whatsnew/v0.23.2.txt index 3e4326dea2ecc..8a94620e55bd1 100644 --- a/doc/source/whatsnew/v0.23.2.txt +++ b/doc/source/whatsnew/v0.23.2.txt @@ -56,7 +56,7 @@ Bug Fixes **I/O** -- +- Bug in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`) - **Plotting** From 23317afe9b7713684dcd47c9282dea3f813ef371 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 20:05:16 +0100 Subject: [PATCH 12/19] move section in whatsnew --- doc/source/whatsnew/v0.23.2.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v0.23.2.txt b/doc/source/whatsnew/v0.23.2.txt index 8a94620e55bd1..40d6a5afe44f1 100644 --- a/doc/source/whatsnew/v0.23.2.txt +++ b/doc/source/whatsnew/v0.23.2.txt @@ -16,7 +16,7 @@ and bug fixes. We recommend that all users upgrade to this version. Fixed Regressions ~~~~~~~~~~~~~~~~~ -- +- Fixed Regression in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`) - .. _whatsnew_0232.performance: @@ -56,7 +56,7 @@ Bug Fixes **I/O** -- Bug in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`) +- - **Plotting** From ab37993a4def0cbff5c5404449f5b6c2e6d58af2 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 20:06:44 +0100 Subject: [PATCH 13/19] move import to the top --- pandas/io/formats/csvs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index eb97e09b3c285..79d9e515113cf 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -5,6 +5,8 @@ from __future__ import print_function +import warnings + import csv as csvlib from zipfile import ZipFile import numpy as np @@ -129,7 +131,6 @@ def save(self): encoding = self.encoding if self.compression and hasattr(self.path_or_buf, 'write'): - import warnings msg = ("compression has no effect when passing file-like " "object as input.") warnings.warn(msg, RuntimeWarning, stacklevel=2) From 5392bcc61389e2f14c7cac4f0cd4cc83f6179c3f Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 20:31:14 +0100 Subject: [PATCH 14/19] rename variables --- pandas/tests/frame/test_to_csv.py | 7 +++---- pandas/tests/series/test_io.py | 7 +++---- pandas/tests/test_common.py | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pandas/tests/frame/test_to_csv.py b/pandas/tests/frame/test_to_csv.py index 1b5dae222ed70..3ad25ae73109e 100644 --- a/pandas/tests/frame/test_to_csv.py +++ b/pandas/tests/frame/test_to_csv.py @@ -946,10 +946,9 @@ def test_to_csv_compression(self, df, encoding, compression): encoding=encoding) with f: df.to_csv(f, encoding=encoding) - result_fh = pd.read_csv(filename, compression=compression, - encoding=encoding, index_col=0, - squeeze=True) - assert_frame_equal(df, result_fh) + result = pd.read_csv(filename, compression=compression, + encoding=encoding, index_col=0, squeeze=True) + assert_frame_equal(df, result) # explicitly make sure file is compressed with tm.decompress_file(filename, compression) as fh: diff --git a/pandas/tests/series/test_io.py b/pandas/tests/series/test_io.py index 5870b8895ecf4..814d794d45c18 100644 --- a/pandas/tests/series/test_io.py +++ b/pandas/tests/series/test_io.py @@ -162,10 +162,9 @@ def test_to_csv_compression(self, s, encoding, compression): encoding=encoding) with f: s.to_csv(f, encoding=encoding, header=True) - result_fh = pd.read_csv(filename, compression=compression, - encoding=encoding, index_col=0, - squeeze=True) - assert_series_equal(s, result_fh) + result = pd.read_csv(filename, compression=compression, + encoding=encoding, index_col=0, squeeze=True) + assert_series_equal(s, result) # explicitly ensure file was compressed with tm.decompress_file(filename, compression) as fh: diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 9ccbf87205846..63002f49da662 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -265,6 +265,7 @@ def test_compression_size_fh(obj, method, compression_only): assert uncompressed > compressed +# GH 21227 def test_compression_warning(compression_only): df = DataFrame(100 * [[0.123456, 0.234567, 0.567567], [12.32112, 123123.2, 321321.2]], From f34ab4ea5a5765ace3119b1d018fdbcf1e11ad66 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 20:31:35 +0100 Subject: [PATCH 15/19] comments --- pandas/io/formats/csvs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index 79d9e515113cf..7506ebb0b7a07 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -130,17 +130,16 @@ def save(self): else: encoding = self.encoding + # GH 21227 internal compression is not used when file-like passed. if self.compression and hasattr(self.path_or_buf, 'write'): msg = ("compression has no effect when passing file-like " "object as input.") warnings.warn(msg, RuntimeWarning, stacklevel=2) - if isinstance(self.path_or_buf, ZipFile) or ( - not hasattr(self.path_or_buf, 'write') - and self.compression == 'zip'): - is_zip = True - else: - is_zip = False + # when zip compression is called. + is_zip = isinstance(self.path_or_buf, ZipFile) or ( + not hasattr(self.path_or_buf, 'write') + and self.compression == 'zip') if is_zip: # zipfile doesn't support writing string to archive. uses string @@ -178,6 +177,7 @@ def save(self): try: self.path_or_buf.write(buf) except AttributeError: + # when path_or_buf is not file-like, create handle. f, handles = _get_handle(self.path_or_buf, self.mode, encoding=encoding, compression=self.compression) From 08f897258934dab65999258e4c8b16e115cd23bb Mon Sep 17 00:00:00 2001 From: Ming Li Date: Fri, 15 Jun 2018 20:35:28 +0100 Subject: [PATCH 16/19] pep8 --- pandas/io/formats/csvs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index 7506ebb0b7a07..29132553f1e4e 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -138,8 +138,8 @@ def save(self): # when zip compression is called. is_zip = isinstance(self.path_or_buf, ZipFile) or ( - not hasattr(self.path_or_buf, 'write') - and self.compression == 'zip') + not hasattr(self.path_or_buf, 'write') + and self.compression == 'zip') if is_zip: # zipfile doesn't support writing string to archive. uses string From 689f01116dad23198a8e057f8257a3e2afdf3a78 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 16 Jun 2018 10:24:54 +0100 Subject: [PATCH 17/19] minor styling --- doc/source/whatsnew/v0.23.2.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v0.23.2.txt b/doc/source/whatsnew/v0.23.2.txt index 40d6a5afe44f1..f562e782debda 100644 --- a/doc/source/whatsnew/v0.23.2.txt +++ b/doc/source/whatsnew/v0.23.2.txt @@ -16,7 +16,7 @@ and bug fixes. We recommend that all users upgrade to this version. Fixed Regressions ~~~~~~~~~~~~~~~~~ -- Fixed Regression in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`) +- Fixed regression in :meth:`to_csv` when handling file-like object incorrectly (:issue:`21471`) - .. _whatsnew_0232.performance: From c472a5b7a4b653fd33fb747ca92bafe395915e14 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 16 Jun 2018 10:35:28 +0100 Subject: [PATCH 18/19] repeat same pattern for simplicity --- pandas/io/formats/csvs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pandas/io/formats/csvs.py b/pandas/io/formats/csvs.py index 29132553f1e4e..60518f596e9af 100644 --- a/pandas/io/formats/csvs.py +++ b/pandas/io/formats/csvs.py @@ -174,10 +174,9 @@ def save(self): if is_zip: # GH 17778 handles zip compression separately. buf = f.getvalue() - try: + if hasattr(self.path_or_buf, 'write'): self.path_or_buf.write(buf) - except AttributeError: - # when path_or_buf is not file-like, create handle. + else: f, handles = _get_handle(self.path_or_buf, self.mode, encoding=encoding, compression=self.compression) From cf3afac666582ea760e7381ac0ee217dbe591c79 Mon Sep 17 00:00:00 2001 From: Ming Li Date: Sat, 16 Jun 2018 14:39:33 +0100 Subject: [PATCH 19/19] consistent closed attribtue --- pandas/io/common.py | 5 +---- pandas/tests/test_common.py | 2 ++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pandas/io/common.py b/pandas/io/common.py index 3fd4c9ddb9dbc..ac9077f2db50e 100644 --- a/pandas/io/common.py +++ b/pandas/io/common.py @@ -447,10 +447,7 @@ def write(self, data): @property def closed(self): - if compat.PY2: - return self.fp is None - else: - return super(BytesZipFile, self).closed + return self.fp is None class MMapWrapper(BaseIterator): diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 63002f49da662..ef5f13bfa504a 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -255,12 +255,14 @@ def test_compression_size_fh(obj, method, compression_only): with f: getattr(obj, method)(f) assert not f.closed + assert f.closed compressed = os.path.getsize(filename) with tm.ensure_clean() as filename: f, _handles = _get_handle(filename, 'w', compression=None) with f: getattr(obj, method)(f) assert not f.closed + assert f.closed uncompressed = os.path.getsize(filename) assert uncompressed > compressed