Stop python from closing on error - python

In python when running scripts is there a way to stop the console window from closing after spitting out the traceback?

You can register a top-level exception handler that keeps the application alive when an unhandled exception occurs:
def show_exception_and_exit(exc_type, exc_value, tb):
import traceback
traceback.print_exception(exc_type, exc_value, tb)
raw_input("Press key to exit.")
sys.exit(-1)
import sys
sys.excepthook = show_exception_and_exit
This is especially useful if you have exceptions occuring inside event handlers that are called from C code, which often do not propagate the errors.

If you doing this on a Windows OS, you can prefix the target of your shortcut with:
C:\WINDOWS\system32\cmd.exe /K <command>
This will prevent the window from closing when the command exits.

try:
#do some stuff
1/0 #stuff that generated the exception
except Exception as ex:
print ex
raw_input()

On UNIX systems (Windows has already been covered above...) you can change the interpreter argument to include the -i flag:
#!/usr/bin/python -i
From the man page:
-i
When a script is passed as first argument or the -c option is used, enter interactive mode after executing the script or the command. It does not read the $PYTHONSTARTUP file. This can be useful to inspect global variables or a stack trace when a script raises an exception.

You could have a second script, which imports/runs your main code. This script would catch all exceptions, and print a traceback (then wait for user input before ending)
Assuming your code is structured using the if __name__ == "__main__": main() idiom..
def myfunction():
pass
class Myclass():
pass
def main():
c = Myclass()
myfunction(c)
if __name__ == "__main__":
main()
..and the file is named "myscriptname.py" (obviously that can be changed), the following will work
from myscriptname import main as myscript_main
try:
myscript_main()
except Exception, errormsg:
print "Script errored!"
print "Error message: %s" % errormsg
print "Traceback:"
import traceback
traceback.print_exc()
print "Press return to exit.."
raw_input()
(Note that raw_input() has been replaced by input() in Python 3)
If you don't have a main() function, you would use put the import statement in the try: block:
try:
import myscriptname
except [...]
A better solution, one that requires no extra wrapper-scripts, is to run the script either from IDLE, or the command line..
On Windows, go to Start > Run, enter cmd and enter. Then enter something like..
cd "\Path\To Your\ Script\"
\Python\bin\python.exe myscriptname.py
(If you installed Python into C:\Python\)
On Linux/Mac OS X it's a bit easier, you just run cd /home/your/script/ then python myscriptname.py
The easiest way would be to use IDLE, launch IDLE, open the script and click the run button (F5 or Ctrl+F5 I think). When the script exits, the window will not close automatically, so you can see any errors
Also, as Chris Thornhill suggested, on Windows, you can create a shortcut to your script, and in it's Properties prefix the target with..
C:\WINDOWS\system32\cmd.exe /K [existing command]
From http://www.computerhope.com/cmd.htm:
/K command - Executes the specified command and continues running.

In windows instead of double clicking the py file you can drag it into an already open CMD window, and then hit enter. It stays open after an exception.
Dan

if you are using windows you could do this
import os
#code here
os.system('pause')

Take a look at answer of this question: How to find exit code or reason when atexit callback is called in Python?
You can just copy this ExitHooks class, then customize your own foo function then register it to atexit.
import atexit
import sys, os
class ExitHooks(object):
def __init__(self):
self.exit_code = None
self.exception = None
def hook(self):
self._orig_exit = sys.exit
sys.exit = self.exit
sys.excepthook = self.exc_handler
def exit(self, code=0):
self.exit_code = code
self._orig_exit(code)
def exc_handler(self, exc_type, exc, *args):
self.exception = exc
hooks = ExitHooks()
hooks.hook()
def goodbye():
if not (hooks.exit_code is None and hooks.exception is None):
os.system('pause')
# input("\nPress Enter key to exit.")
atexit.register(goodbye)

Your question is not very clear, but I assume that the python interpreter exits (and therefore the calling console window closes) when an exception happens.
You need to modify your python application to catch the exception and print it without exiting the interpreter. One way to do that is to print "press ENTER to exit" and then read some input from the console window, effectively waiting for the user to press Enter.

Related

Python misinterpret KeyboardInterrupt exception when using Lingoes

I want to write a python program (run.py) that always runs and only stops running when Ctr-C is pressed. This is how I implement it:
wrapper.py:
import subprocess
import signal
def sig_handler(signum, frame):
res = input("Ctrl-c was pressed. Do you really want to exit? y/n ")
if res == 'y':
exit(1)
signal.signal(signal.SIGINT, sig_handler)
while(True):
p = None
p = subprocess.Popen("python run.py", shell=True)
stdout, stderr = p.communicate()
run.py:
print('aaaaa')
print('bbbbb')
However, when I hold left-mouse and select text in the terminal that is running wrapper.py, this event is understood incorrectly as Ctr-C then the wrapper.py stop running run.py. My question is how to prevent reading mouse events as KeyboardInterrupt in python (Unix). Thanks!
Terminal
Instead of using a module like signal to achieve this you could opt to use exceptions since it is a pretty exceptional case that your program will receive a keyboard interrupt.
#!/usr/bin/env python3
import sys
def main() -> int:
try:
while True:
print(sys.argv)
except KeyboardInterrupt as e:
return 0
if __name__ == '__main__':
try:
sys.exit(main())
except Exception as e:
print(f'Error: {e}', file=sys.stderr)
sys.exit(1)
The source code has no problem. The problem is caused by dictionary software. The software has a feature of selecting word to translate. By somehow it converts the mouse event (selecting word) to Ctr-C then the program above exits. When I turn off the dictionary software, the problem disappears. I will close the thread here

python windows: exit a loop when cmd window closes

I run the following code in a cmd window. Many different exceptions may occur within the try loop, this is why I generalize to except all exceptions. But: If I close the cmd window the code runs in, how do I stop the code from keep running even though the cmd window is closed.
while True:
try:
print('test') # in actual code more complicateed task with many possible exceptions
except Exception:
pass
Right now, I can only quit this code via a restart.
EDIT: I tried to catch the exception but the log file only says "log works"
import sys
from time import sleep
import logging
logging.basicConfig(filename="logtest.log",
filemode='a',
format='%(asctime)s,%(msecs)d %(name)s %
(levelname)s %(message)s',
datefmt='%H:%M:%S',
level=logging.DEBUG)
logging.info("log works")
while True:
try:
print('test')
sleep(1)
except Exception as e:
logging.info(e)
logging.info(str(e))
This is because in your try statement you need to set a condition where the execution breaks for example below:
x = 0
while True:
try:
if (x == 10):
break
else:
# in actual code more complicated task with many possible exceptions
print('test')
x += 1
except Exception as e:
print(e.printStackTrace())
Another method can be using a keyword to force break out of the while loop for example below we are using q to end the loop execution:
'''
from time import sleep
import re
input_text= ""
while True:
try:
# in actual code more complicateed task with many possible exceptions
input_text = input("Enter your selection .....")
print(input_text)
if re.search('q' , input_text , re.IGNORECASE):
break
except Exception as e:
print(e.printStackTrace())
'''
Well, your script never received any exception, it was just killed without any possibility to log anything.
We are not in the Unix world where a shell just kindly telss its child that it is exiting with a SIGHUP signal letting them know where they want to die or not. We are in a MS/DOS inheritance: when a console ends, every process attached to the console dies.
So unless you have detached the process from its console it is over. You can easily control it with Windows task manager (start it with Ctrl Alt Del)

Threading program in python running successfully on IDLE but not on shell, command line

I am using python 3.8 on windows 10. I am able to run threading programs succesfully on IDLE but, the same programs do not start on command line or when I double click them. The shell pops up and exits quickly even when threads are not started. I even tried to catch any runtime errors and any errors using except but I got neither on IDLE and the program was still terminating abruptly on shell.
Here is an example -
import threading
import time
try:
def func():
for i in range(10):
print(i)
time.sleep(0.1)
t1 = threading.Thread(target = func)
t1.start()
#t1.join() # i tried this also
while t1.is_alive():
time.sleep(0.1) #trying to return back, i added this when the threads were not working
input() #waiting for the user to press any key before exit
except RuntimeError:
print('runtime error')
input()
except: # any error
print('Some error')
input()
I found that I had made a file by the name 'threading.py' in the directory. This file was causing Attribute Error of python because it has the same name as the 'threading' module of python. I renamed it and my programs are working jolly good!

Python click command exit flow

I have this python click CLI design (wificli.py). At the end of command execution, it prints only respective print messages.
For example, when executed command python3.7 wificli.py png, it prints only png and when executed command python3.7 wificli.py terminal it prints only terminal.
As I have shown, I am expecting that it would also print End of start function and End of the main function but it is not. The idea is that to do clean up of resources only at one place rather than at each exit point of the respective command.
import click
#click.group()
#click.option('--ssid', help='WiFi network name.')
#click.option('--security', type=click.Choice(['WEP', 'WPA', '']))
#click.option('--password', help='WiFi password.')
#click.pass_context
def main(ctx, ssid: str, security: str = '', password: str = ''):
ctx.obj['ssid'] = ssid
ctx.obj['security'] = security
ctx.obj['password'] = password
#main.command()
#click.pass_context
def terminal(ctx):
print('terminal')
#main.command()
#click.option('--filename', help='full path to the png file')
#click.pass_context
def png(ctx, filename, scale: int = 10):
print('png')
def start():
main(obj={})
print('End of start function')
if __name__ == '__main__':
start()
print('End of main function')
When executed
As you've not asked a specific question, I can only post what worked for me with the reasoning behind it, and if this is not what you are looking for, I apologize in advance.
#main.resultcallback()
def process_result(result, **kwargs):
print('End of start function')
click.get_current_context().obj['callback']()
def start():
main(obj={'callback': lambda: print('End of main function')})
So, the resultcallback seems to be the suggested way of handling the termination of the group, and the invoked command. In our case, it prints End of start function, because at that point, the start function has finished executing, so we are wrapping up before terminating main. Then, it retrieves the callback passed in via the context, and executes that.
I am not sure if this is the idiomatic way of doing it, but it seems to have the intended behaviour.
For the result callback, a similar question was answered here
As to what exactly is causing this behaviour, and this is only a guess based on some quick experimentation with placing yield in the group or the command, I suspect some kind of thread/processor is spawned to handle the execution of the group and its command.
Hope this helps!
click's main() always raises a SystemExit. Quoting the documentation:
This will always terminate the application after a call. If this is not wanted, SystemExit needs to be caught.
In your example, change start() to:
def start():
try:
main(obj={})
except SystemExit as err:
# re-raise unless main() finished without an error
if err.code:
raise
print('End of start function')
See the click docs here also this answer here
# Main Runtime call at bottom of your code
start(standalone_mode=False)
# or e.g
main(standalone_mode=False)

How to prevent running the __main__ guard when using execfile?

The BDFL posted in 2003 an article about how to write a Python main function. His example is this:
import sys
import getopt
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "h", ["help"])
except getopt.error, msg:
raise Usage(msg)
# more code, unchanged
except Usage, err:
print >>sys.stderr, err.msg
print >>sys.stderr, "for help use --help"
return 2
if __name__ == "__main__":
sys.exit(main())
The reason for the optional argument argv to main() is, "We change main() to take an optional argv argument, which allows us to call it from the interactive Python prompt."
He explains the last line of his code like this:
Now the sys.exit() calls are annoying: when main() calls sys.exit(),
your interactive Python interpreter will exit! The remedy is to let
main()'s return value specify the exit status. Thus, the code at the
very end becomes
if __name__ == "__main__":
sys.exit(main())
and the calls to sys.exit(n) inside main() all become return n.
However, when I run Guido's code in a Spyder console, it kills the interpreter. What am I missing here? Is the intention that I only import modules that have this type of main(), never just executing them with execfile or runfile? That's not how I tend to do interactive development, especially given that it would require me to remember to switch back and forth between import foo and reload(foo).
I know I can catch the SystemExit from getopt or try to use some black magic to detect whether Python is running interactively, but I assume neither of those is the BDFL's intent.
Your options are to not use execfile or to pass in a different __name__ value as a global:
execfile('test.py', {'__name__': 'test'})
The default is to run the file as a script, which means that __name__ is set to __main__.
The article you cite only applies to import.
Another way to handle it, which I alluded to briefly in the question, is to try to detect if you're in an interactive context. I don't believe this can be done portably, but here it is in case it's helpful to someone:
if __name__ == "__main__":
if 'PYTHONSTARTUP' in os.environ:
try:
main() # Or whatever you want to do here
except SystemExit as se:
logging.exception("")
else:
sys.exit(main())

Categories

Resources