Terminate a Python script

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.

sys.exit

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")