Reputation: 2312
I would like to run a python script with IPython and be able to tell whether the script was successful (ran all the way through) or unsuccessful (an exception was raised).
Normally one can tell whether a command is successful by inspecting its return value, where the convention is 0 for success and some other integer for an error (the value indicating which error). This is the behaviour when running scripts with python script.py
, but when using ipython script.py
, IPython automatically captures the error and (unhelpfully) returns exit code 0.
How can I disable this behaviour when running the script with IPython?
Incidentally, I need to run the script in IPython instead of Python because the script has been generated from an IPython notebook (.ipynb) and contains some IPython magic commands.
Here is a minimal working example.
fail.py
#! /usr/bin/env python
mytext = 'Hello World!'
if __name__=="__main__":
print(missing_variable)
When running the script with IPython, the exception is printed to stdout and the return value is 1, correctly denoting failure of the script.
~$ python fail.py
Traceback (most recent call last):
File "fail.py", line 4, in <module>
print(missing_variable)
NameError: name 'missing_variable' is not defined
~$ echo $?
1
When running the script with IPython, the exception is caught and the traceback is printed to stdout, then IPython exits and returns 0 (which is not desirable, since the script did not succeed).
~$ ipython fail.py
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
~/fail.py in <module>()
2 mytext = 'Hello World!'
3 if __name__=="__main__":
----> 4 print(missing_variable)
NameError: name 'missing_variable' is not defined
~$ echo $?
0
Upvotes: 4
Views: 1976
Reputation: 2312
As @chrisaycock and @vrs helpfully pointed out, there is an issue discussing this problem on the ipython GitHub page.
Moreover, the issue was resolved and the fix merged into the ipython main code base, however the fix is too recent to be in any released versions of ipython. The latest released version of ipython at time of writing is v4.0.1, and the solution should be in the next release, v4.1.0.
For the time being, this can be resolved by installing the bleeding-edge version of ipython, as demonstrated here:
virtualenv --no-site-packages -p /usr/bin/python2.7 tmp-env
source tmp-env/bin/activate
pip install git+git://github.com/ipython/ipython.git@master
We can see the undesirable behaviour is now fixed:
(tmp-env)~$ pip freeze
argparse==1.2.1
decorator==4.0.6
ipython==4.1.0.dev0
ipython-genutils==0.1.0
path.py==8.1.2
pexpect==4.0.1
pickleshare==0.5
ptyprocess==0.5
simplegeneric==0.8.1
traitlets==4.0.0
wsgiref==0.1.2
(tmp-env)~$ ipython fail.py
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
~/fail.py in <module>()
2 mytext = 'Hello World!'
3 if __name__=="__main__":
----> 4 print(missing_variable)
NameError: name 'missing_variable' is not defined
(tmp-env)~$ echo $?
1
Upvotes: 2
Reputation: 1982
It seems that you cannot do that in IPython (see this discussion for more details). What you can do is to use try/except
and then set exit code needed with sys.exit(code_number)
. You can also use traceback
module to print out stack traces the way Python interpreter does it. So your code may look like this:
import sys, traceback
mytext = 'Hello World!'
if __name__=="__main__":
try:
print(missing_variable)
except:
traceback.print_exc(file=sys.stdout)
sys.exit(1)
Then running this:
~$ ipython fail.py
In theory should produce stack trace along with the exit code 1:
~$ echo $?
1
Upvotes: 1