Consider the following (Python 3.2 under Windows):
>>> import io
>>> import csv
>>> output = io.StringIO() # default parameter newline=None
>>> csvdata = [1, 'a', 'Whoa!\nNewlines!']
>>> writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
>>> writer.writerow(csvdata)
25
>>> output.getvalue()
'1,"a","Whoa!\nNewlines!"\r\n'
Why is there a single \n – shouldn’t it have been converted to \r\n since universal newlines mode is enabled?
With this enabled, on input, the lines endings
\n,\r, or\r\n
are translated to\nbefore being returned to the caller.
Conversely, on output,\nis translated to the system default line
separator,os.linesep.
The “single”
\noccurs as a data character inside the third field. Consequently that field is quoted so that a csv reader will treat it as part of the data. It is NOT a “line terminator” (should be called a row separator) or part thereof. To get a better appreciation of the quoting, remove thequoting=csv.QUOTE_NONNUMERIC.The
\r\nis produced because csv terminates rows with thedialect.lineterminatorwhose default is\r\n. In other words, the “universal newlines” setting is ignored.Update
The 2.7 and 3.2 docs for
io.StringIOare virtually identical as far as the newline arg is concerned.We’ll examine the first sentence below. The second sentence is true for output, depending on your interpretation of “default” and “newline translation”.
TextIOWrapper docs:
Python 3.2 on Windows:
Line 0 shows that the “default” that you get with no
newlinearg involves no translation of\n(or any other character). It is certainly NOT converting'\n'toos.linesepLine 1 shows that what you get with
newline=None(should be the same as line 0, shouldn’t it??) is in effect INPUT universal newlines translation — bizarre!Line 2:
newline=''does no change, like line 0. It is certainly NOT converting'\n'to''.Lines 3, 4, and 5: as the docs say,
'\n'is converted to the value of thenewlinearg.The equivalent Python 2.X code produces equivalent results with Python 2.7.2.
Update 2 For consistency with built-in
open(), the default should beos.linesep, as documented. To get the no-translation-on-output behaviour, usenewline=''. Note: theopen()docs are much clearer. I’ll submit a bug report tomorrow.