Forgive me if I am missing something obvious but how do I terminate a Python script early, say in the case of an exception, and return to the calling program? I have tried return, breaks, cancel but none of those work.
import sys
...
sys.exit("some error message")
If you want to exit with a custom error MSG and a specific exit code, you can do something like:
import sys
print("Exiting", file=sys.stderr)
sys.exit(99)
If you simply donât do anything with an exception, it will be reported on the console, and the script terminated. This is usually what you want for simple scripts; just because an exception can happen, that doesnât mean you need try/except around it.
Unfortunately sys.exit() terminates the whole program, all I want to do is terminate the currently running script and continue with the calling program.
Hmm, you may need to post your code, both the calling program and the âcurrently running scriptâ, to explain how they interact.
My crystal ball tells me that youâre running another script by importing it. If so, I would recommend putting most of the code inside a function, which you can then call in the normal way.
Yes for the purposes of testing I am currently using âimportâ to run the script. However the real code actually uses exec() to run the script.
If you want the calling program to keep running, youâll need a try-except:
try:
import it # The module that uses exec
except Exception as e:
print("Error:", e)
print("keep on running")
Same if you put the code in a function you call:
import it
try:
it.do_it()
except Exception as e:
print("Error:", e)
print("keep on running")
If you donât want the code to keep running, having no try-except is okay.
Ok so now trying to do this using a Custom Exception but whatever I do I canât seem to get the code to revert to the caller and continue:
Controller.py:
class NotAuthorised(Exception):
pass
print("Controller.py: 1")
try:
import Script
except NotAuthorised:
pass
print("Controller.py: 2")
Script.py:
print("running script: 1")
raise NotAuthorised("User authentication failed (script)")
print("running script: 2")
And what happens with that?
Are you sure you arenât getting a NameError from Script.py rather than a NotAuthorised?
lonnieh@dupree:/tmp$ python Controller.py
Controller.py: 1
running script: 1
Traceback (most recent call last):
File "/tmp/Controller.py", line 7, in <module>
import Script
File "/tmp/Script.py", line 3, in <module>
raise NotAuthorised("User authentication failed (script)")
^^^^^^^^^^^^^
NameError: name 'NotAuthorised' is not defined
Is there a reason you need to use exec() rather than calling a function directly? exec() is not usually the best tool for the job.
The problem is that the script module doesnât know NotAuthorised. It canât see things defined in the code that imported it.
If you use a built-in exception type, itâll work. For example, try replacing NotAuthorised with Exception or RuntimeError.
If you still want to use NotAuthorised and run the code by importing the module, my recommendation is to create a third module where both the runner code and the exec module can see NotAuthorised:
Controller.py
from Shared import NotAuthorised
print("Controller.py: 1")
try:
import Script
except NotAuthorised:
pass
print("Controller.py: 2")
Script.py
from Shared import NotAuthorised
print("running script: 1")
raise NotAuthorised("User authentication failed (script)")
print("running script: 2")
Shared.py
class NotAuthorised(Exception):
pass
(You canât just copy the definition into Script.py because theyâll be seen as different)
If you can reorganize your code you can also put the exception definition in Script.py:
Controller.py
import Script
print("Controller.py: 1")
try:
Script.run()
except Script.NotAuthorised:
pass
print("Controller.py: 2")
Script.py
class NotAuthorised(Exception):
pass
def run():
print("running script: 1")
raise NotAuthorised("User authentication failed (script)")
print("running script: 2")