I would like to use sys.exit() within a function my_func(), how do I use it?
def my_func():
try:
some_method()
except:
print('Error')
sys.exit()
if __name__ == "__main__":
my_func()
You need to import sys before you can use it. Just add it to the top of your script:
import sys
def my_func():
try:
some_method()
except:
print('Error')
sys.exit()
if __name__ == "__main__":
my_func()
I see three programming issues. Besides the missing import sys, you flag an error but simply call sys.exit() which exits with a zero indicating success to the invoker -- it needs to exit non-zero to indicate error. Finally you print the error message to sys.stdout when it really should go to sys.stderr. A rework of your code:
import sys
def my_func():
try:
some_method()
except:
print('Error', file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
my_func()
Fortunately, Python allows us to combine these last two issues by instead doing:
import sys
def my_func():
try:
some_method()
except:
sys.exit('Error')
if __name__ == "__main__":
my_func()
This will exit non-zero and print the message to sys.stderr.
Related
In the example below, when I run y_file.py, I need 5 printed and Hello not printed.
How to stop the execution of an imported python script x_file.py without exiting the python altogether? sys.exit() seems to exit python altogether.
x_file.py
import sys
x = 5
if __name__ != '__main__':
pass
# stop executing x.py, but do not exit python
# sys.exit() # this line exits python
print("Hello")
y_file.py
import x_file
print(x_file.x)
As jvx8ss suggested, you can fix this by putting the print inside a if __name__ == "__main__": conditional. Note the equality "==" instead of inequality "!=".
Final code:
import sys
x = 5
if __name__ == "__main__":
# stop executing x.py, but do not exit python
# sys.exit() # this line exits python
print("Hello")
You should place your code you don't want to run in the import inside an if __name__ == "__main__" however, there is an extremely bad way to do what you want that I can think of using Exception
# x_file.py
x = 5
if __name__ != '__main__':
raise Exception(x)
print("Hello")
# y_file.py
try:
import x_file
except Exception as e:
print(e.args[0])
I'm using click in Python to create a CLI for my program. I want to execute a function (below represented through the placeholder do_something()) if an exception occurs, but only if a certain argument is passed through the CLI (here: --verbose or -v).
I know that I can access command line input via sys.argv. This is my conceptual minimal working example using this approach:
#filename: my_app.py
import click
#click.group()
#click.option('--verbose', '-v', is_flag=True)
def cli():
pass
#click.command()
def greeting():
print('hello world')
raise Exception
#cli.command()
def spam():
print('SPAM')
raise Exception
def do_something():
print('Doing something...')
if __name__ == '__main__':
try:
main()
except e:
if '--verbose' in sys.argv or '-v' in sys.argv:
do_something()
raise e
To be as exact as I can be: In case of an exception in any of the subcommands, I want the program to do_something() when the --verbose flag is on, but not if it's off. E.g. for the greeting subcommand the CLI should behave like this:
~$ python my_app.py --verbose greeting
hello world
Doing something...
Exception
~$ python my_app.py greeting
hello world
Exception
While the sys.argv solution shown above works, it would be nice if I could refer to the command line option with click's internal name (which is 'verbose' in this case). I.e., I would like to do something like this here:
...
if __name__ == '__main__':
try:
main()
except e:
if 'verbose' in click.argv:
do_something()
raise e
Is this a feature that click provides?
Correct me if I'm wrong, but it seems to me like you'd like to be able to output more information/clean up something in the case of an exception.
There are a few options you could try:
Move the try/except logic inside the greeting method that leverages the verbose flag, and call do_something there
Consider looking at callbacks and see if you can leverage these to do what you want. Without more context into do_something, I can't tell for sure whether it would be a good use case for callbacks.
The closest thing to your question is to have a global scope variable _verbose like in the example below:
import click
global _verbose
_verbose = False
def do_something():
print(f'Doing something')
#click.group()
def cli():
pass
#cli.command()
#click.option('--verbose', '-v', is_flag=True)
def greeting():
global _verbose
_verbose = verbose
if verbose:
print('hello world')
raise Exception("Test")
else:
print('hello')
#cli.command()
#click.option('--count', '-c')
def spam(count):
print(count * 'SPAM')
if __name__ == '__main__':
try:
cli()
except Exception as e:
if _verbose:
do_something()
raise e
I've updated my answer with a working snippet that doesn't rely on globals to do this, but instead leverages Python's pass-by-reference and click's advanced context examples
import click
def do_something():
print(f'Doing something')
#click.group()
#click.option('--verbose', '-v', is_flag=True)
#click.pass_context
def cli(ctx, verbose):
ctx.obj['verbose'] = verbose
pass
#cli.command()
#click.pass_context
def greeting(ctx):
if ctx.obj['verbose']:
print('hello world')
raise Exception("Test")
else:
print('hello')
#cli.command()
#click.option('--count', '-c')
def spam(count):
print(count * 'SPAM')
if __name__ == '__main__':
flags = {}
try:
cli(obj=flags)
except Exception as e:
if flags['verbose']:
do_something()
raise e
#checkapi.py
import time
def add(a,b):
return a + b
def loop():
while True:
time.sleep(10)
print("loop running")
loop()
#apicheck.py
import checkapi
print(checkapi.add(5, 6))
output
------
apicheck.py showing "loop running"
please check out this. Why this happening.
Q. How to call a running method and get it's return value ?.
Modify checkapi.py in following way:
#checkapi.py
import time
def add(a,b):
return a + b
def loop():
while True:
time.sleep(10)
print("loop running")
if __name__ == '__main__':
loop()
this will solve your issue. if __name__ == '__main__' says Python to run loop() function only if you execute script itself like python checkapi.py, but if you import it from other module through import checkapi then loop() is not executed and you can use this module without trouble.
I have a script main.py which called a function fun from a library.
I want to exit only from fun continuing the script main.py, using for this purpose another script kill_fun.py.
I tried to use different bash commands (using os.system) with ps, but the pid it gives me is referred only to main.py.
Example:
-main.py
from lib import fun
if __name__ == '__main__':
try:
fun()
except:
do_something
do_something_else
-lib.py
def fun():
do_something_of_long_time
-kill_fun.py
if __name__ == '__main__':
kill_only_fun
You can do so by run fun in a different process.
from time import sleep
from multiprocessing import Process
from lib import fun
def my_fun():
tmp = 0
for i in range(1000000):
sleep(1)
tmp += 1
print('fun')
return tmp
def should_i_kill_fun():
try:
with open('./kill.txt','r') as f:
read = f.readline().strip()
#print(read)
return read == 'Y'
except Exception as e:
return False
if __name__ == '__main__':
try:
p = Process(target=my_fun, args=())
p.start()
while p.is_alive():
sleep(1)
if should_i_kill_fun():
p.terminate()
except Exception as e:
print("do sth",e)
print("do sth other thing")
to kill fun, simply echo 'Y' > kill.txt
or you can write a python script to write the file as well.
Explain
The idea is to start fun in a different process. p is a process handler that you can control. And then, we put a loop to check file kill.txt to see if kill command 'Y' is in there. If yes, then it call p.terminate(). The process will then get killed and continue to do next things.
Hope this helps.
I am using
if __name__ == "__main__":
to run my defined functions.
However as an error catching measure I am trying to implement a way to ensure that file paths have been entered correctly into the .bat file my script is ran from, the file names are passed in as arguments.
What I am doing is defining a function to define whether certain arguments are "valid", things such as
.endswith("\\")
or
.endswith(".txt")
however because they are within an if block (if __name__ == "main"`) I am struggling to work out how to stop the script there.
I basically want to apply my validation function to all the arguments and if any return False then to stop the __main__ function and show an error message in such a way:
print len(invalid_args), " arguments are invalid, please check input"
However using a break here is showing as "Break is outside of loop" in pycharm.
How can I stop the rest of my script running if validation returns False and it is all contained in the if __name__ == "__main__" block?
Here is a representation of my code, but without the unnecessary detail:
def clean():
do_something()
def merge():
do_something_else()
def valid()
if valid:
return True
if not valid:
return False
if __name__ == "__main__":
if not valid():
"Stop script here" # This is the part I don't know how to do
if valid():
try:
clear()
except Exception a e:
print e + "Something Went Wrong"
try:
merge()
except Exception as e:
print e + "Something Went Wrong"
break is used to break out of a loop (as PyCharm has told you).
Instead you could have the following code which will run your tests and if true not allow the rest of the content to proceed.
# Your code ...
def some_function():
# Something function that runs your tests
# If your tests fail then return True, otherwise return False
if __name__ == '__main__':
if some_function():
print("Sorry but your .bat file must be broken!")
else:
# Run the rest of your code happily.
You could even raise an Exception as opposed to just printing a message.
if is not a "loop". You can only break from for or while (which are loops). To stop the program outside of a loop, you have a few options:
raise an error;
sys.exit the whole program; or
guard the rest of the code with another if.
For example:
if __name__ == "__main__":
valid_args, invalid_args = process(args)
if invalid_args:
# raise error or exit
# rest of code
or:
if __name__ == "__main__":
valid_args, invalid_args = process(args)
if invalid_args:
# print warning
else:
# rest of code
Within a function, you can also return:
def main():
valid_args, invalid_args = process(args)
if invalid_args:
return
# rest of code
if __name__ == "__main__":
main()
Move all of your logic under if __name__ == "__main__" into a separate function, and replace your if __name__ == "__main__" block with just
if __name__ == "__main__":
doMySetupStuff()
Inside your doMySetupStuff function, you can check the arguments and return if you find any of them are not valid.