Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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'
like image 356
Elias Bachaalany Avatar asked Aug 06 '10 12:08

Elias Bachaalany


People also ask

What does exec () do in Python?

Python's built-in exec() function allows you to execute arbitrary Python code from a string or compiled code input.

How do I open Python 2.7 in CMD?

The py Command The default Python interpreter is referenced on Windows using the command py. Using the Command Prompt, you can use the -V option to print out the version. You can also specify the version of Python you'd like to run. For Windows, you can just provide an option like -2.7 to run version 2.7.


2 Answers

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
like image 79
Ned Batchelder Avatar answered Oct 04 '22 03:10

Ned Batchelder


It's bad news

io.StringIO wants to work with unicode. You might think you can fix it by putting a u in front of the string you want to print like this

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

however print is really broken for this as it causes 2 writes to the StringIO. The first one is u"hello world" which is fine, but then it follows with "\n"

so instead you need to write something like this

print "%s" % CaptureExec("""
import random
sys.stdout.write(u"hello world\n")
""")
like image 20
John La Rooy Avatar answered Oct 04 '22 03:10

John La Rooy