@@ -235,6 +235,97 @@ If installed, we now require:
235235| scipy | 0.18.1 | |
236236+-----------------+-----------------+----------+
237237
238+ .. _whatsnew_0240.api_breaking.csv_line_terminator:
239+
240+ `os.linesep` is used for ``line_terminator`` of ``DataFrame.to_csv``
241+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
242+
243+ :func:`DataFrame.to_csv` now uses :func:`os.linesep` rather than ``'\n'``
244+ for the default line terminator (:issue:`20353`).
245+ This change only affects when running on Windows, where ``'\r\n'`` was used for line terminator
246+ even when ``'\n'`` was passed in ``line_terminator``.
247+
248+ Previous Behavior on Windows:
249+
250+ .. code-block:: ipython
251+
252+ In [1]: data = pd.DataFrame({
253+ ...: "string_with_lf": ["a\nbc"],
254+ ...: "string_with_crlf": ["a\r\nbc"]
255+ ...: })
256+
257+ In [2]: # When passing file PATH to to_csv, line_terminator does not work, and csv is saved with '\r\n'.
258+ ...: # Also, this converts all '\n's in the data to '\r\n'.
259+ ...: data.to_csv("test.csv", index=False, line_terminator='\n')
260+
261+ In [3]: with open("test.csv", mode='rb') as f:
262+ ...: print(f.read())
263+ b'string_with_lf,string_with_crlf\r\n"a\r\nbc","a\r\r\nbc"\r\n'
264+
265+ In [4]: # When passing file OBJECT with newline option to to_csv, line_terminator works.
266+ ...: with open("test2.csv", mode='w', newline='\n') as f:
267+ ...: data.to_csv(f, index=False, line_terminator='\n')
268+
269+ In [5]: with open("test2.csv", mode='rb') as f:
270+ ...: print(f.read())
271+ b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n'
272+
273+
274+ New Behavior on Windows:
275+
276+ - By passing ``line_terminator`` explicitly, line terminator is set to that character.
277+ - The value of ``line_terminator`` only affects the line terminator of CSV,
278+ so it does not change the value inside the data.
279+
280+ .. code-block:: ipython
281+
282+ In [1]: data = pd.DataFrame({
283+ ...: "string_with_lf": ["a\nbc"],
284+ ...: "string_with_crlf": ["a\r\nbc"]
285+ ...: })
286+
287+ In [2]: data.to_csv("test.csv", index=False, line_terminator='\n')
288+
289+ In [3]: with open("test.csv", mode='rb') as f:
290+ ...: print(f.read())
291+ b'string_with_lf,string_with_crlf\n"a\nbc","a\r\nbc"\n'
292+
293+
294+ - On Windows, the value of ``os.linesep`` is ``'\r\n'``,
295+ so if ``line_terminator`` is not set, ``'\r\n'`` is used for line terminator.
296+ - Again, it does not affect the value inside the data.
297+
298+ .. code-block:: ipython
299+
300+ In [1]: data = pd.DataFrame({
301+ ...: "string_with_lf": ["a\nbc"],
302+ ...: "string_with_crlf": ["a\r\nbc"]
303+ ...: })
304+
305+ In [2]: data.to_csv("test.csv", index=False)
306+
307+ In [3]: with open("test.csv", mode='rb') as f:
308+ ...: print(f.read())
309+ b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n'
310+
311+
312+ - For files objects, specifying ``newline`` is not sufficient to set the line terminator.
313+ You must pass in the ``line_terminator`` explicitly, even in this case.
314+
315+ .. code-block:: ipython
316+
317+ In [1]: data = pd.DataFrame({
318+ ...: "string_with_lf": ["a\nbc"],
319+ ...: "string_with_crlf": ["a\r\nbc"]
320+ ...: })
321+
322+ In [2]: with open("test2.csv", mode='w', newline='\n') as f:
323+ ...: data.to_csv(f, index=False)
324+
325+ In [3]: with open("test2.csv", mode='rb') as f:
326+ ...: print(f.read())
327+ b'string_with_lf,string_with_crlf\r\n"a\nbc","a\r\nbc"\r\n'
328+
238329.. _whatsnew_0240.api_breaking.interval_values:
239330
240331``IntervalIndex.values`` is now an ``IntervalArray``
0 commit comments