Search code examples
pythonhttp-redirectexecstdiostringio

python 2.7 / exec / what is wrong?


I have this code which runs fine in Python 2.5 but not in 2.7:

import sys
import traceback
try:
    from io import StringIO
except:
    from StringIO import StringIO

def CaptureExec(stmt):
    oldio = (sys.stdin, sys.stdout, sys.stderr)
    sio = StringIO()
    sys.stdout = sys.stderr = sio
    try:
        exec(stmt, globals(), globals())
        out = sio.getvalue()
    except Exception, e:
        out = str(e) + "\n" + traceback.format_exc()
    sys.stdin, sys.stdout, sys.stderr = oldio
    return out

print "%s" % CaptureExec("""
import random
print "hello world"
""")

And I get:

string argument expected, got 'str'
Traceback (most recent call last):
  File "D:\3.py", line 13, in CaptureExec
    exec(stmt, globals(), globals())
  File "", line 3, in 
TypeError: string argument expected, got 'str'

Solution

  • io.StringIO is confusing in Python 2.7 because it's backported from the 3.x bytes/string world. This code gets the same error as yours:

    from io import StringIO
    sio = StringIO()
    sio.write("Hello\n")
    

    causes:

    Traceback (most recent call last):
      File "so2.py", line 3, in <module>
        sio.write("Hello\n")
    TypeError: string argument expected, got 'str'
    

    If you are only using Python 2.x, then skip the io module altogether, and stick with StringIO. If you really want to use io, change your import to:

    from io import BytesIO as StringIO