StringIO in 2.6 and beyond

B

Bill McClain

I've just installed 2.6, had been using 2.4.

This was working for me:

#! /usr/bin/env python
import StringIO
out = StringIO.StringIO()
print >> out, 'hello'

I used 2to3, and added import from future to get:

#! /usr/bin/env python
from __future__ import print_function
import io
out = io.StringIO()
print('hello', file=out)

....which gives an error:

Traceback (most recent call last):
File "./example.py", line 5, in <module>
print('hello', file=out)
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

....which has me stumped. Why can't it?

-Bill
 
B

Bill McClain

In this context 'str' means Python 3.0's str type, which is unicode in
2.x. Please report the misleading error message.

So this is an encoding problem? Can you give me a hint on how to correct in my
example? I see that io.StringIO() has an encoding parameter, but I'm unclear
what to specify.

-Bill
 
B

Bill McClain

So this is an encoding problem? Can you give me a hint on how to correct in my
example? I see that io.StringIO() has an encoding parameter, but I'm unclear
what to specify.

I still don't have this working. I've been specifying encodings without
success.

The StringIO example usage in the Python 3.0 documentation here:

http://docs.python.org/3.0/library/io.html#io.StringIO

gives me the same error on 2.6:

#! /usr/bin/env python

from __future__ import print_function
import io

output = io.StringIO()
output.write('First line.\n')
print('Second line.', file=output)

# Retrieve file contents -- this will be
# 'First line.\nSecond line.\n'
contents = output.getvalue()

# Close object and discard memory buffer --
# .getvalue() will now raise an exception.
output.close()

../stringio30.py
Traceback (most recent call last):
File "./stringio30.py", line 7, in <module>
output.write('First line.\n')
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

-Bill
 
P

pruebauno

I still don't have this working. I've been specifying encodings without
success.

The StringIO example usage in the Python 3.0 documentation here:

     http://docs.python.org/3.0/library/io.html#io.StringIO

gives me the same error on 2.6:

    #! /usr/bin/env python

    from __future__ import print_function
    import io

    output = io.StringIO()
    output.write('First line.\n')
    print('Second line.', file=output)

    # Retrieve file contents -- this will be
    # 'First line.\nSecond line.\n'
    contents = output.getvalue()

    # Close object and discard memory buffer --
    # .getvalue() will now raise an exception.
    output.close()

./stringio30.py
Traceback (most recent call last):
  File "./stringio30.py", line 7, in <module>
    output.write('First line.\n')
  File "/usr/local/lib/python2.6/io.py", line 1487, in write
    s.__class__.__name__)
TypeError: can't write str to text stream

-Bill

This puzzles me too. According to the documentation StringIO accepts
both byte strings and unicode strings. Try to replace
output.write('First line.\n')
with
output.write(unicode('First line.\n'))
or
output.write(str('First line.\n'))
and see if one of those works.
 
B

Bill McClain

This puzzles me too. According to the documentation StringIO accepts
both byte strings and unicode strings. Try to replace
output.write('First line.\n')
with
output.write(unicode('First line.\n'))
or
output.write(str('First line.\n'))
and see if one of those works.

This works:

output.write(unicode('First line.\n'))

...but this generates the error:

print(unicode('Second line.'), file=output)

-Bill
 
P

Peter Otten

Bill said:
I've just installed 2.6, had been using 2.4.

This was working for me:

#! /usr/bin/env python
import StringIO
out = StringIO.StringIO()
print >> out, 'hello'

I used 2to3, and added import from future to get:

#! /usr/bin/env python
from __future__ import print_function
import io
out = io.StringIO()
print('hello', file=out)

...which gives an error:

Traceback (most recent call last):
File "./example.py", line 5, in <module>
print('hello', file=out)
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

...which has me stumped. Why can't it?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

Seems io.StringIO() wants unicode. So let's feed it some:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

Still complaining? Let's have a look at the output so far:
u'hello'

Hmm, u"hello" was written. The complaint must be about the newline then.
u'hello\n'

Heureka. Let's try something else now:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.6/io.py", line 1487, in write
s.__class__.__name__)
TypeError: can't write str to text stream

Fixing is left as exercise ;)

Peter
 
B

Bill McClain

u'hello\n'

That has the benefit of working. Thank you!

That can't be the intended behavior of print(), can it? Insering non-unicode
spaces and line terminators? I thought all text was unicode now. Or is that
only in 3.0?

-Bill
 
M

MRAB

Bill said:
That has the benefit of working. Thank you!

That can't be the intended behavior of print(), can it? Insering non-unicode
spaces and line terminators? I thought all text was unicode now. Or is that
only in 3.0?
In Python 2.x unmarked string literals are bytestrings. In Python 3.x
they're Unicode. The intention is to make the transition from 2.x to 3.x
easier by adding some features of 3.x to 2.x, but without breaking
backwards compatibility (not entirely successfully!).
 
B

Bill McClain

In Python 2.x unmarked string literals are bytestrings. In Python 3.x
they're Unicode. The intention is to make the transition from 2.x to 3.x
easier by adding some features of 3.x to 2.x, but without breaking
backwards compatibility (not entirely successfully!).

It is a bit ugly. In 2.6 StringIO won't take bytestrings, so I apply u'x'. But
in 3.0 u'x' will be gone and I'll have to change the code again.

It's a small effort for what I am working on, but frustrating trying to puzzle
this out from the docs, which I couldn't do.

-Bill
 
P

Peter Otten

Bill said:
That has the benefit of working. Thank you!

That can't be the intended behavior of print(), can it? Insering
non-unicode spaces and line terminators? I thought all text was unicode
now. Or is that only in 3.0?

Yes it's 3.0 only. I have no clear idea of the implications of using the
print() function in 2.6 yet; maybe changing the defaults for end/sep to
unicode would suffice to make it work smoothly. I will probably defer the
transition from statement to function until I move to 3.x.

One benefit of the function is that you can do things like

from functools import partial
print = partial(print, sep=u" ", end=u"\n")

Peter
 
A

ajaksu

It is a bit ugly. In 2.6 StringIO won't take bytestrings, so I apply u'x'.. But
in 3.0 u'x' will be gone and I'll have to change the code again.

Try:

from __future__ import unicode_literals
 
B

Bill McClain

from __future__ import unicode_literals

That works for:

output.write('First line.\n')

....but not for:

print('Second line.', file=output)

Maybe a combination of this and functools.partial as was suggested before. At
least the necessary edits would be at the top of the program.

-Bill
 
P

pruebauno

That works for:

    output.write('First line.\n')

...but not for:

   print('Second line.', file=output)

Maybe a combination of this and functools.partial as was suggested before.. At
least the necessary edits would be at the top of the program.

-Bill

I think this combination might do the trick (I don't have 2.6 to test
it right now):

from __future__ import print_function
from __future__ import unicode_literals
from functools import partial
import io
print = partial(print, sep=" ", end="\n")
out = io.StringIO()
print("hello", file=out)

What puzzles me is the documentation in 2.6 and 3.0:
In 2.6 it says: "The StringIO object can accept either Unicode or 8-
bit strings". Why does it fail with old str objects then?
Why is there no documentation for StringIO in 3.0?
 
P

pruebauno

I think this combination might do the trick (I don't have 2.6 to test
it right now):

from __future__ import print_function
from __future__ import unicode_literals
from functools import partial
import io
print = partial(print, sep=" ", end="\n")
out = io.StringIO()
print("hello", file=out)

What puzzles me is the documentation in 2.6 and 3.0:
In 2.6 it says: "The StringIO object can accept either Unicode or 8-
bit strings". Why does it fail with old str objects then?
Why is there no documentation for StringIO in 3.0?

OK I found StringIO it is called io.StringIO now.
 
B

Bill McClain

I think this combination might do the trick (I don't have 2.6 to test
it right now):
from __future__ import print_function
from __future__ import unicode_literals
from functools import partial
import io
print = partial(print, sep=" ", end="\n")
out = io.StringIO()
print("hello", file=out)

The example works, but unicode_literals causes problems elsewhere, in optparse
for example. I didn't look into it too closely. I'll probably give up trying
to anticipate 3.0 with 2.6 too closely.

-Bill
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,126
Latest member
FastBurnketoIngredients
Top