How can a Python function be called on script exit reliably? - python

How do you register a function with all the correct handlers etc to be called when the Python script is exitted (successfully or not)?
I have tried:
#atexit.register
def finalise():
'''
Function handles program close
'''
print("Tidying up...")
...
print("Closing")
...but this does not get called when the user closes the command prompt window for example (because #atexit.register decorated functions do not get called when the exitcode is non zero)
I am looking for a way of guaranteeing finalise() is called on program exit, regardless of errors.
For context, my Python program is a continually looping service program that aims to run all the time.
Thanks in advance

I don't think it can be done in pure Python. From documentation:
Note: the functions registered via this module are not called when the
program is killed by a signal not handled by Python, when a Python
fatal internal error is detected, or when os._exit() is called.
I think you may find this useful: How to capture a command prompt window close event in python

Have you tried to just catch all kinds of exceptions in your main function or code block?

For context, my Python program is a continually looping service program that aims to run all the time.
This is very hard to get right (see How do you create a daemon in Python?). You should use a library like http://pypi.python.org/pypi/python-daemon/ instead.

This one should work
works both on Ctrl-C and when the assertion fails. Maybe you can use a similar construct and pack it as a decorator, or whatever.
def main():
print raw_input('> ')
# do all your stuff here
if __name__ == '__main__':
try:
main()
finally:
print 'Bye!'

atexit.register(func)
func = lambda x: x
Use http://docs.python.org/2/library/atexit.html

Related

How to have code executed on termination

I want a part of my code to only execute when I manually stop the program (like pressing stop button in pycharm). I thought finally statement could do it for me. Like this:
try:
do_sth()
finally:
print("you stopped the program")
but it doesn't work. I tried both finally and except but none of them worked. I thought when we stopped the program from running, a keyboard_intrrupt error occurred so finally must have worked.
Any idea?
You could use the atexit library.
From the documentation:
The atexit module defines functions to register and unregister cleanup functions. Functions thus registered are automatically executed upon normal interpreter termination.
This can be implemented like so:
#Rest of program...
def before_termination():
#Do something...
import atexit
atexit.register(before_termination)
However this is only called during normal program termination, not if keyboard interrupt occurs.

python simple threading won't ends without doing anything (maybe)

When i run the following code (using "sudo python servers.py") the process seem to just finish immediately with just printing "test".
why doesn't the functions "proxy_server" won't run ? or maybe they do but i do not realize that. (because the first line in proxy function doesn't print anything)
this is an impotent code, i didn't want to put unnecessary content, yet it still demonstrate my problem:
import os,sys,thread,socket,select,struct,time
HTTP_PORT = 80
FTP_PORT=21
FTP_DATA_PORT = 20
IP_IN = '10.0.1.3'
IP_OUT = '10.0.3.3'
sys_http = 'http_proxy'
sys_ftp = 'ftp_proxy'
sys_ftp_data = 'ftp_data_proxy'
def main():
try:
thread.start_new_thread(proxy_server, (HTTP_PORT, IP_IN,sys_http,http_handler))
thread.start_new_thread(proxy_server, (FTP_PORT, IP_IN,sys_ftp,http_handler))
thread.start_new_thread(proxy_server, (FTP_DATA_PORT, IP_OUT,sys_ftp_data,http_handler))
print "test"
except e:
print 'Error!'
sys.exit(1)
def proxy_server(host,port,fileName,handler):
print "Proxy Server Running on ",host,":",port
def http_handler(src,sock):
return ''
if __name__ == '__main__':
main()
What am i missing or doing wrong ?
First, you have indentation problems related to using mixed tabs and spaces for indentation. While they didn't cause your code to misbehave in this particular case, they will cause you problems later if you don't stick to consistently using one or the other. They've already broken the displayed indentation in your question; see the print "test" line in main, which looks misaligned.
Second, instead of the low-level thread module, you should be using threading. Your problem is occurring because, as documented in the thread module documentation,
When the main thread exits, it is system defined whether the other threads survive. On SGI IRIX using the native thread implementation, they survive. On most other systems, they are killed without executing try ... finally clauses or executing object destructors.
threading threads let you explicitly define whether other threads should survive the death of the main thread, and default to surviving. In general, threading is much easier to use correctly.

Block python's atexit during a crash?

I have a python script I've written which uses atexit.register() to run a function to persist a list of dictionaries when the program exits. However, this code is also running when the script exits due to a crash or runtime error. Usually, this results in the data becoming corrupted.
Is there any way to block it from running when the program exits abnormally?
EDIT: To clarify, this involves a program using flask, and I'm trying to prevent the data persistence code from running on an exit that results from an error being raised.
You don't want to use atexit with Flask. You want to use Flask signals. It sounds like you are specifically looking for the request_finished signal.
from flask import request_finished
def request_finished_handler(sender, response, **extra):
sender.logger.debug('Request context is about to close down. '
'Response: %s', response)
# do some fancy storage stuff.
request_finished.connect(request_finished_handler, app)
The benefit of request_finished is that it only fires after a successful response. That means that so long as there isn't an error in another signal, you should be good.
One way: at global level in main program:
abormal_termination = False
def your_cleanup_function():
# Add next two lines at the top
if abnormal_termination:
return
# ...
# At end of main program:
try:
# your original code goes here
except Exception: # replace according to what *you* consider "abnormal"
abnormal_termination = True # stop atexit handler
Not pretty, but straightforward ;-)

Performing an action upon unexpected exit python

I was wandering if there was a way to perform an action before the program closes. I am running a program over a long time and I do want to be able to close it and have the data be saved in a text file or something but there is no way of me interfering with the while True loop I have running, and simply saving the data each loop would be highly ineffective.
So is there a way that I can save data, say a list, when I hit the x or destroy the program? I have been looking at the atexit module but have had no luck, except when I set the program to finish at a certain point.
def saveFile(list):
print "Saving List"
with open("file.txt", "a") as test_file:
test_file.write(str(list[-1]))
atexit.register(saveFile(list))
That is my whole atexit part of the code and like I said, it runs fine when I set it to close through the while loop.
Is this possible, to save something when the application is terminated?
Your atexit usage is wrong. It expects a function and its arguments, but you're just calling your function right away and passing the result to atexit.register(). Try:
atexit.register(saveFile, list)
Be aware that this uses the list reference as it exists at the time you call atexit.register(), so if you assign to list afterwards, those changes will not be picked up. Modifying the list itself without reassigning should be fine, though.
You could use the handle_exit context manager from this ActiveState recipe:
http://code.activestate.com/recipes/577997-handle-exit-context-manager/
It handles SystemExit, KeyboardInterrupt, SIGINT, and SIGTERM, with a simple interface:
def cleanup():
print 'do some cleanup here'
def main():
print 'do something'
if __name__ == '__main__':
with handle_exit(cleanup):
main()
There's nothing you can in reaction to a SIGKILL. It kills your process immediately, without any allowed cleanup.
Catch the SystemExit exception at the top of your application, then rethrow it.
There are a a couple of approaches to this. As some have commented you could used signal handling ... your [Ctrl]+[C] from the terminal where this is running in the foreground is dispatching a SIGHUP signal to your process (from the terminal's drivers).
Another approach would be to use a non-blocking os.read() on sys.stdin.fileno such that you're polling your keyboard one during every loop to see if an "exit" keystroke or sequence has been entered.
A similarly non-blocking polling approach can be implemented using the select module's functionality. I've see that used with the termios and tty modules. (Seems inelegant that it needs all those to save, set changes to, and restore the terminal settings, and I've also seen some examples using os and fcntl; and I'm not sure when or why one would prefer one over the other if os.isatty(sys.stdin.fileno())).
Yet another approach would be to use the curses module with window.nodelay() or window.timeout() to set your desired input behavior and then either window.getch() or window.getkey() to poll for any input.

Python: How to quit CLI when stuck in blocking raw_input?

I have a GUI program which should also be controllable via CLI (for monitoring). The CLI is implemented in a while loop using raw_input.
If I quit the program via a GUI close button, it hangs in raw_input and does not quit until it gets an input.
How can I immediately abort raw_input without entering an input?
I run it on WinXP but I want it to be platform independent, it should also work within Eclipse since it is a developer tool. Python version is 2.6.
I searched stackoverflow for hours and I know there are many answers to that topic, but is there really no platform independent solution to have a non-blocking CLI reader?
If not, what would be the best way to overcome this problem?
Thanks
That's not maybe the best solution but you could use the thread module which has a function thread.interrupt_main(). So can run two thread : one with your raw_input method and one which can give the interruption signal. The upper level thread raise a KeyboardInterrupt exception.
import thread
import time
def main():
try:
m = thread.start_new_thread(killable_input, tuple())
while 1:
time.sleep(0.1)
except KeyboardInterrupt:
print "exception"
def killable_input():
w = thread.start_new_thread(normal_input, tuple())
i = thread.start_new_thread(wait_sometime, tuple())
def normal_input():
s = raw_input("input:")
def wait_sometime():
time.sleep(4) # or any other condition to kill the thread
print "too slow, killing imput"
thread.interrupt_main()
if __name__ == '__main__':
main()
Depending on what GUI toolkit you're using, find a way to hook up an event listener to the close window action and make it call win32api.TerminateProcess(-1, 0).
For reference, on Linux calling sys.exit() works.

Categories