A way to exit cleanly without the possibility of caller catching it

I have had multiple cases where i need to exit from the interpreter cleanly in its entirety (threads included).

the problem is critical errors (because they are not expectations, but is networking related) , that i cant catch, and if i sys.exit another module with catch it , because that specific module caches in every function it has.

i dont want to use os._exit() because that is not clean

would be even better if it would be backported to 3.8 and above

You are not in control of the application. Raise an exception; if the caller catches it, that’s clearly because they intend to handle it. And if they catch it and don’t handle it, that’s not your fault - it’s a buggy application.

On the other hand, if you’re in control of the application, and it’s doing this, then fix the application - it’s buggy.

How is this other module catching your exceptions?

What is the relationship between your module, the other module, and the main program running? Who owns the threads you want to kill?

The correct way to fail from a critical error in a module is to raise an exception. If the main application catches and suppresses that error, that’s not your business. If they call your module again, then if the error state persists, you raise the exception again. Its not your problem if the application keeps going.

Trying to kill the main application is rude and should only be allowed for the most severe failures that corrupt the entire program state, not just one module. E.g. if your module dumps me out of the interactive interpreter with no possibility of catching the exception, you better believe I’ll be dumping your module into the trash.

Can you be more specific about what it is about os._exit() you don’t like? If there are threads, it’s the only way to exit the program, “cleanly” or otherwise.

From the operating system’s perspective, os._exit() cleanly exits the process, freeing all memory and closing all file descriptors.

the module is a wss client module

the threads are mine, unless the main program makes one.

its not an exception, its an error that cant be handled because its a bug that wont be fixed on a remote server. im writing a lib that connects with that server. if the server runs into this bug, then that user cant continue running at all.

edit: here is a snipit to show the error that breaks the entire script

        elif listener == "__meowerbot__login":
            if status == "E:104 | Internal": # sever sends this when it cant kick a shadow client
                requests.post("https://webhooks.meower.org/post/home", json={"post": "ERROR: MeowerBot.py Webhooks Logging\n\n Account Softlocked.", 'username': self.username})
                print("CRITICAL ERROR! ACCOUNT SOFTLOCKED!!!!.", file=sys.__stdout__)
                sys.exit(1) # waiting for https://discuss.python.org/t/a-way-to-exit-cleanly-without-the-possibility-of-caller-catching-it/22442/2

from the docs of os.exit (“Exit the process with status n, without calling cleanup handlers, flushing stdio buffers, etc.”

i would prefer if it called cleanup handlers

what im trying to ask for is a way to cut through all threads, and raise an exception in the main program (what iv found, says that its impossible).

note: this spcific branch happens very rarely, but when it does, the server has to be restarted. i would consider that corrupted

Once you detect the error raise a exception so that the caller can decide what to do with the error.
Document what is happening so the caller has the background facts.

Why isn’t that sufficent?

im also in a thread by the wss library, so i cant raise an exception in the main thread

        def run(*args):
                    try:
                        self.callback_function["on_packet"](message)
                    except Exception as e:
                        
                        self.logging.error(f"Error on _on_packet_client: {e}")
                threading.Thread(target=run).start()

Not sure what you mean by a “client module”, but if you have a library that connects to a remote server, it is MINDBOGGLINGLY RUDE to terminate the entire process when you get a problem on that remote server. So if you’re going to do this, make sure you put a big warning at the top of your documentation:

CAUTION: This module will abruptly terminate YOUR ENTIRE APPLICATION if the account gets softlocked. Be sure to avoid using this module. Like, ever.

1 Like

You must have a way to return results to tbe caller from the worker thread.
Return an error status to the main thread and raise the exception when that error status is seen.

Ig I could do it in a super hacky way by setting a flag, and then closing wss. When the close callback gets called, if that flag is set raise the error. Probably not going to work because that’s caught too, and may be in a thread (il need to look at my wss src again)

I may be able to do above but in the start function. where I have full control of everything.