1

I'm writing a small IDE for myself in Python at the moment and want to execute the text of my editor as Python code. I get the text of my editor as a string. I want to execute the code, save the ouput & errors in string-variables (o and e) and then I render the output in my IDE.

It works fine as long as I don't have any errors (my_code). Once I execute code containing an error (my_code_with_error - commented below), it seems as if the code is not returning and "silently" crashing. In fact I even get Process finished with exit code 0 in Pycharm - probably because I switched sys.stdout for my own StringIO instance.

How can I execute the code-string, even if it has errors and then save the error / normal output in a variable as a String?

import sys
from io import StringIO

# create file-like string to capture output
codeOut = StringIO()
codeErr = StringIO()
print("Start")

my_code = """
print("Hello World!")
"""

my_code_with_error = """
print("Hello world!")
print(avfsd)  # error -> printing a variable that does not exist.
"""

print("Executing code...")
# capture output and errors
sys.stdout = codeOut
sys.stderr = codeErr

exec(my_code )  # this works fine
# exec(my_code_with_error)  # as soon as there is an error, it crashes silently.

# restore stdout and stderr
sys.stdout = sys.__stdout__
sys.stderr = sys.__stderr__
print("Finished code execution.")

e = codeErr.getvalue()
o = codeOut.getvalue()
print("Error: " + e)
print("Output: " + o)

codeOut.close()
codeErr.close()

PS: There was a really old question from 2009 where I got some of my code, but can't find any more recent questions concerning this topic. (How do I execute a string containing Python code in Python?)

2
  • You likely want to spawn a child process, so you can have better control over the input and output channels. Commented Oct 11, 2020 at 18:23
  • Take a look at the code module in the stdlib (which is what IDLE uses). It's mostly written in pure python, so the source code should be instructive. Commented Oct 11, 2020 at 18:38

2 Answers 2

2

Try surrounding the execution code in a try/except block.

try:
    exec(my_code)
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise
Sign up to request clarification or add additional context in comments.

5 Comments

This works great! I love that I even get the class of the error with sys.exc_info. I have one problem though - if I have a correct print statement in front of my error-line, I don't get the output of that one, I only get the error back. Is it possible to get the "correct" output leading up to the error as well?
You can place the string and the error output in 2 seperate print statements. print("Unexpected error: ") print(sys.exc_info()[0])
Ah, I think you misunderstood me - I edited my question: The my_code_with_error contains two statements. The first one is working, the second one throws the error. If I would execute the two statements in Pycharm, I first get the output Hello world! and then it throws an error. In your solution, I only get the error from sys.exc_info()
If you want the error-free code to run before the exception is thrown, you would have to split the commands into separate strings and call try: exec() for each string.
I just realized your code already does what I want... sorry, my bad. The problem was EOL-errors (no quote-ending) are thrown before anything is executed so I didn't realize it is what I need. Thanks :D
2

You can do that by catching the exceptions :

try:
    exec(my_code_with_error)
except Exception as e:
    print(e)

Raymond posted a similar answer as I was writting mine. Raymond's answer works in Python 2 also (see https://wiki.python.org/moin/HandlingExceptions, "General Error Handling" in "Questions") and has the advantage of outputing the error class too.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.