Skip to content
Advertisement

How to check what lineending a StringIO file is using?

I had a method that detects line endings

def getLineEnding(filename):
    ret = "rn"
    with  open(filename, 'r') as f:
        f.readline()
        ret = f.newlines
    return ret

In order to be able to test it without using real files, I changed it to:

def getLineEnding(filehandle):
    filehandle.readline()
    return filehandle.newlines

And this works fine with files. But when I do this:

f = StringIO()
f.write('testrn')
f.seek(0)
f.readline()
print(f.newlines)

I get None

The reason I’m checking the file ending is that I’m writing a program that process a text file, and I want to keep the original line endings.

Advertisement

Answer

To answer your question, the default value of the newline parameter is different for io.StringIO than for io.TextIOWrapper (which is returned by open(..., 'r')). For StringIO the default is 'n' while for TextIOWrapper the default is None. The documentation explains the behavior:

newline controls how line endings are handled. It can be None, '', 'n', 'r', and 'rn'. It works as follows:

  • When reading input from the stream, if newline is None, universal newlines mode is enabled. Lines in the input can end in 'n', 'r', or 'rn', and these are translated into 'n' before being returned to the caller. If newline is '', universal newlines mode is enabled, but line endings are returned to the caller untranslated. If newline has any of the other legal values, input lines are only terminated by the given string, and the line ending is returned to the caller untranslated.
  • […]

So that means that TextIOWrapper will translate the line endings while StringIO will not, by default. Then the documentation of the newlines attribute is:

A string, a tuple of strings, or None, indicating the newlines translated so far. […]

Hence, if no translation is performed, this attribute will not be set (which is the case for StringIO).

The solution is to construct the StringIO object by passing newline=None, i.e.

f = StringIO(newline=None)

Then the behavior w.r.t. line endings will be similar to TextIOWrapper.

However, if the goal is to have line endings unchanged, one can use newline='' directly to return the line endings untranslated, as explained in the above quote from the docs.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement