I need to say first and foremost, I am just learning Python.
I am making a simple python program that has a menu option for exiting the program by using a function I called exit. I have tried making the exit function just call break, but I am getting an error when the exit function is called.
Any help would be greatly appreciated.
Sorry for not posting code earlier....
def exit():
break
evade = evade_fw()
# Main program running dialogue
def main(): # menu goes here
opt_list = [xsl_file,
basic_loud_scan,
fw_main,
exit
]
Just forget about your own exit() function. You can simply do:
from sys import exit
And the exit() function from sys module will do the job.
It's also worth to know what happens under the hood. Function sys.exit() actually throws a special exception. You can do it as well explicitly and without importing anything:
raise SystemExit()
break is for breaking out of for or while loops, but it must be called from within the loop. I'm guessing that you expect the break to break out of your program's main event loop from an event handler, and that is not going to work because, as aforementioned, the break must be within the loop itself.
Instead your exit function can clean up any resources, e.g. open files, database connections, etc. then call [sys.exit()][1] which will cause the Python interpreter to terminate. You can optionally pass a status code to sys.exit() which will be the system exit status available to shell scripts and batch files.
import sys
def exit():
# clean up resources
sys.exit() # defaults to status 0 == success
Related
I have the following Python program running in a Docker container.
Basically, if the Python process exits gracefully (ex. when I manually stop the container) or if the Python process crashes (while inside some_other_module.do_work()) then I need to do some cleanup and ping my DB telling it that process has exited.
What's the best way to accomplish this? I saw one answer where they did a try catch on main(), but that seems a bit odd.
My code:
def main():
some_other_module.do_work()
if __name__ == '__main__':
main()
I assume that the additional cleanup will be done by a different process, since the main process has likely crashed in a not recoverable way (I understood the question in this way).
The simplest way would be that the main process sets a flag somewhere (maybe creates a file in a specified location, or a column value in a database table; could also include the PID of the main process that sets the flag) when it starts and removes (or un-sets) that same flag if it finishes gracefully.
The cleanup process just needs to check the flag:
if the flag is set but the main process has ended already (the flag could contain the PID of the main process, so the cleanup process uses that to find if the main process is still running or not), then a cleanup is in order.
if the flag is set and the main process is running, then nothing is to be done.
if the flag is not set, then nothing is to be done.
Try-catch on main seems simplest, but doesn't/may not work for most things (please see comments below). You can always except specific exceptions:
def main():
some_other_module.do_work()
if __name__ == '__main__':
try:
main()
except Exception as e:
if e == "<INSERT GRACEFUL INTERRUPT HERE>":
# finished gracefully
else:
print(e)
# crash
Use a try/except
def thing_that_crashes():
exit()
try:
thing_that_crashes()
except:
print('oh and by the way, that thing tried to kill me')
I think it is impossible to catch a process with advanced suicidal behaviour (I don't know sending a SYGKILL to itself or something) so if you need your main process to live whatever happens, maybe run the other one in a subprocess.
You could wrap your script with another subprocess script and check the returncode. Inspired by this Relevant question.
from subprocess import Popen
script = Popen("python abspath/to/your/script.py")
script.communicate()
if script.returncode <> 0:
# something went wrong
# do something about it
I have got a GUI aplication which includes five python scripts.
I have already found an error in the IO data, and then I'd like to include a escape condition to quit the python script and show a QT message but stay the GUI application.
one of the scripts
if len(Numero_Unidades) != 1:
quit()
else:
pass
block
but it quits python
and I want to stay in the GUI application, maintaining the main window open.
if self.ui.radioButton3.isChecked()== True:
myscript.myscript()
QtGui.QMessageBox.information(self,'message')
How can I do that?
You can start another python process to launch your script
By using os.system("script.py")
Assuming that the quit() function is the built-in quit, you can monkey-patch it and raise an error instead of quitting the whole appliaction:
import myscript
import __builtin__
def myquit():
raise RuntimeError('script quit!')
__builtin__.quit = myquit
try:
myscript.myscript()
except RuntimeError as exception:
print(exception)
else:
print('keep calm and carry on')
I have a thread that monitors user input which looks like this:
def keyboard_monitor(temp): #temp is sys.stdin
global flag_exit
while True:
keyin = temp.readline().rstrip().lower()
if keyin == "exit":
flag_exit = True
print("Stopping...")
if flag_exit == True:
break
If I type exit the flag is properly set and all the other threads terminate. If another one of my threads sets the flag, this thread refuses to finish because it's hanging on the user input. I have to input something to get it to finish. How do I change this code so that the program finishes when the flag is set externally?
Its hard to tell exactly what is going wrong without more of your code, but as an easy solution you could rather exit() which is a python built in. This should reliably terminate the application, also sys.exit()
From wim's comment:
You can use the atexit module to register clean up handlers
import atexit
def cleanup():
pass
# TODO cleanup
atexit.register(cleanup)
I need help with controlling a python script. I want to run a script that controls two robots. A routine consists of a series of motions which either move the arm or move the gripper. The form of the code is as follows:
def robot_exec():
# List of robot arm poses:
*many_many_lines_of_position_vectors*
# List of robot gripper poses:
*open position*
*close position*
while 1:
*Call a function that moves the robot arm(s) to a position on the list*
*Call a function that moves the robot gripper(s) to a position on the list*
*continue calling functions many times until the desired routine is complete*
n = raw_input("Restart the routine? (Y/N)")
if n.strip() == 'n' or 'N':
break
elif n.strip() == 'y' or 'Y':
continue
else:
print "Invalid input. Exiting..."
break
If the routine is complete (i.e. every function was called), it asks if I want to restart, and if I choose yes, behaves as normal, which is good.
But, if I press ctrl-C in the middle of the routine, the message "Restart the routine?" still pops up and asks for input, and I don't want that. What I want is either one of the following:
if and only if the user presses ctrl-C, completely exit everything, no questions asked.
if and only if the user presses ctrl-C, return the robots to home position (defined in that list of arm poses) and then completely exit everything.
My main question is, how does ctrl-C actually work? I thought it would just exit the script but in actuality it still prints stuff and asks for input. A subset of that broad question is, how can I just get the desired behavior (completely exit everything when pressing ctrl-C)?
I realize this is a clunky way of doing what I need the robots to do, but it is the best way I can think of with my limited knowledge of python.
Thank you,
-Adrian
The comments/answers about signals are technically correct (on UNIX), but in Python the CTRL+C handling is neatly wrapped away from you. What happens in a Python program is that at the point where you press CTRL+C, a KeyboardInterrupt exception is raised.
Now, your problem seems to be in the code that you have removed from the listing, i.e., in the "calling robot routines" part. That code catches the KeyboardInterrupt.
I guess either your code or library code that you call does something like:
try:
# some long running code
# ...
except:
# something, or just pass
Note the naked except:. Naked excepts are almost always a bad thing. Instead you or the library should do:
try:
# some long running code
# ...
except Exception:
# something to fix the situation
Using except Exception: does not catch the KeyboardInterrupt exception, which will let you handle it appropriately, or just let the program exit. Have a look at the Exception class hierarchy.
What exactly happens when user presses Ctrl-C?
A signal is raised.
how can I just get the desired behavior
>>> import signal
>>> def handler(sig, stack_frame):
... print "Handled"
...
>>> signal.signal(signal.SIGINT, handler)
<built-in function default_int_handler>
^C # <--- typed ctrl-c here
>>> Handled
See the doc of signal for details.
Please note: on Linux I use signal.SIGINT. On Windows, maybe it is signal.CTRL_C_EVENT instead.
you can handle Ctrl_C with this code :
#!/usr/bin/env python
import signal
import sys
def signal_handler(signal, frame):
#write your command here for example i write print below :
print('You pressed Ctrl+C!')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()
I have a problem in managing a infinite while loop in Python, in which I would insert a timer as a sort of "watchdog". I try to explain better: the script has to listen on a serial channel and wait for messages coming from sensors connected on the other side of the channel.
I do this with a while True loop because the script must catch all the signals that are passing. However, even if it's probably unnecessary, i would like to insert a timer which is always reset every loop. So, if (for example) the loop get stuck for some reason, the timer will end and will exit the program. I thought i could do this in this way:
def periodicUpdate():
exitTimer = threading.Timer(60.0, sys.exit())
while True:
exitTimer.start()
readData()
exitTimer.cancel()
Now, the problem is that when i start the script it immediatly exit. It seems that it reads sys.exit() before all the rest, and it doesn't respect the construct of the timer, but simply when periodicUpdate is called it exits. Why this happen?! I tried changing the syntax, putting sys.exit in an other function and call that function, i tried other solutions but always it behave in two ways: it exits or it behave as the timer doesn't exists. Can someone help me? Thanks very much
Remove the parentheses. If you use sys.exit(), it will fire straight away. When you use sys.exit, it will pass the function as Timer's second argument.
I think your approach is not the best one, instead of running a timer that exits the application, why not simply timeout the function that reads the data:
Timeout on a function call
It seems that it reads sys.exit() before all the rest
Sure it does. The second argument of threadint.Timer is a function that will be called. What you do is you actually call sys.exit and supply its return value (which is undefined, by the way, since the call terminates the program) as a function to be called. That's an error, since sys.exit's return value is not a function, but that doesn't matter, as the program is terminated anyway.
What you want to do is
exitTimer = threading.Timer(60.0, sys.exit) # note: no brackets
But that actually will not work, as sys.exit in the thread will terminate only that thread. In short, you can't use a watchdog to terminate a stuck while-loop if this loops is in your main thread. In your particular situation you should investigate the function you are using to read data, most likely it lets you set a read timeout.
It seems to me that none of the solutions proposed here actually works. This is an example of code. Would be great to know how to fix it. Also, please try it before answering.
import time, threading, sys
def _exit():
print 'exiting'
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(2.0, _exit)
while True:
exitTimer.start()
print 'go'
time.sleep(5)
exitTimer.cancel()
periodicUpdate()
The actual output is:
$python test.py
go
exiting
RuntimeError: threads can only be started once
exitTimer = threading.Timer(60.0, sys.exit)
Remove the () from sys.exit in timer call
def _exit()
sys.exit()
def periodicUpdate():
exitTimer = threading.Timer(60.0, _exit)
while True:
exitTimer.start()
readData()
exitTimer.cancel()
In you put the () the interpreter call this function if not the interpreter get a reference for this function.
Have fun :)
Edit: Use of _exit
threading.Timer(60.0, os._exit, [0])
def periodicUpdate():
exitTimer = sys.exit(60.0, sys.exit())
while sys.exit():
sys.exit()
readData()
sys.exit()
if __name__ == "__main__":
sys.exit()
Don't forget to import sys.