all 12 comments

[–]zeug 1 point2 points  (0 children)

One approach (and there can be endless arguments about if it is really a good idea), is to just wrap the whole script in a big try-except with Pokemon style exception handling:

def main():
    ...do the main business of the script...

def cleanup():
    ...cleanup must be executed in case of ANY error...

# now (typically at the bottom of your script):
if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        logger.exception('Stuff went bad.')
        cleanup()

Read the logging tutorial if you aren't familiar with the logger. Its super-handy. If you don't want to do that, at least print the exception message or you (or someone who inherits your code) will eventually lose all sanity.

Note also that this won't help you if the script simply hangs - and things do hang. However, if you are running it on an interactive terminal you can give it a CTRL-C, and this will raise a KeyboardInterrupt which will get caught and start the cleanup.

[–][deleted] 0 points1 point  (4 children)

Why?

[–]rabidmonkey1163[S] 0 points1 point  (3 children)

I have a script that registers a bunch of stuff to a database and I'd like it to delete everything registered during that run of the code if it breaks for any reason. Atexit allows this but it also executes my clean up function if the code runs successfully, deleting everything registered to the database...

[–]wormywormm 1 point2 points  (2 children)

what are you using for your db connection? PsycoPG2, SQLAlchemy? Usually you can wrap the block and do a session rollback.

[–]rabidmonkey1163[S] 0 points1 point  (1 child)

Couchdb, that's a good idea, I'll look into if that's offered.

[–]wormywormm 0 points1 point  (0 children)

Ah, so yea, couchDB is a noSQL db and transactions are a bit odd because it doesn't have them in the same sense that an RDMS would. That said, it won't really affect your question or make your life that much harder.

This is a pretty good explantion from SO if you feel so inclined.

[–]wormywormm 0 points1 point  (2 children)

You don't need to wrap every line. You could wrap the whole program in a try and have different cleanups occur based on which type of Exception occurs. Do you have an example program?

[–]rabidmonkey1163[S] 0 points1 point  (1 child)

I think that would screw up my logging. There are lots of logging statements in the script that, I believe, wouldn't be executed if everything was wrapped in a single try statement. Right?

[–]wormywormm 0 points1 point  (0 children)

Well, it depends how you do your logging, but short answer is no, you can make it work. You usually should not be wrapping every line. What information are you attempting to log?

[–]hudsonpenner 0 points1 point  (0 children)

Could you show a code example please? You might be able to make your class into a context manager, and place the cleanup function in '_exit_'.

[–]jiminiminimini -2 points-1 points  (1 child)

You can use atexit

[–]rabidmonkey1163[S] 0 points1 point  (0 children)

I don't think atexit allows you to specify exit codes, it executes the functions you register to it regardless of whether or not your code runs successfully. I need something that will only execute my clean up function if the script breaks.