@@ -125,16 +125,40 @@ def __init__(self, obj, path_or_buf=None, sep=",", na_rep='',
125
125
126
126
def save (self ):
127
127
# create the writer & save
128
- encoding = self .encoding
129
- if encoding is None :
130
- encoding = 'ascii' if compat .PY2 else 'utf-8'
131
-
132
- f , handles = _get_handle (
133
- path_or_buf = self .path_or_buf ,
134
- mode = self .mode ,
135
- encoding = encoding ,
136
- compression = self .compression ,
137
- )
128
+ if self .encoding is None :
129
+ if compat .PY2 :
130
+ encoding = 'ascii'
131
+ else :
132
+ encoding = 'utf-8'
133
+ else :
134
+ encoding = self .encoding
135
+
136
+ # GH 21227 internal compression is not used when file-like passed.
137
+ if self .compression and hasattr (self .path_or_buf , 'write' ):
138
+ msg = ("compression has no effect when passing file-like "
139
+ "object as input." )
140
+ warnings .warn (msg , RuntimeWarning , stacklevel = 2 )
141
+
142
+ # when zip compression is called.
143
+ is_zip = isinstance (self .path_or_buf , ZipFile ) or (
144
+ not hasattr (self .path_or_buf , 'write' )
145
+ and self .compression == 'zip' )
146
+
147
+ if is_zip :
148
+ # zipfile doesn't support writing string to archive. uses string
149
+ # buffer to receive csv writing and dump into zip compression
150
+ # file handle. GH 21241, 21118
151
+ f = StringIO ()
152
+ close = False
153
+ elif hasattr (self .path_or_buf , 'write' ):
154
+ f = self .path_or_buf
155
+ close = False
156
+ else :
157
+ f , handles = _get_handle (self .path_or_buf , self .mode ,
158
+ encoding = encoding ,
159
+ compression = self .compression )
160
+ close = True
161
+
138
162
try :
139
163
writer_kwargs = dict (lineterminator = self .line_terminator ,
140
164
delimiter = self .sep , quoting = self .quoting ,
@@ -150,8 +174,21 @@ def save(self):
150
174
self ._save ()
151
175
152
176
finally :
153
- for handle in handles :
154
- handle .close ()
177
+ if is_zip :
178
+ # GH 17778 handles zip compression separately.
179
+ buf = f .getvalue ()
180
+ if hasattr (self .path_or_buf , 'write' ):
181
+ self .path_or_buf .write (buf )
182
+ else :
183
+ f , handles = _get_handle (self .path_or_buf , self .mode ,
184
+ encoding = encoding ,
185
+ compression = self .compression )
186
+ f .write (buf )
187
+ close = True
188
+ if close :
189
+ f .close ()
190
+ for _fh in handles :
191
+ _fh .close ()
155
192
156
193
def _save_header (self ):
157
194
0 commit comments