Breaking if __name__ when a condition is not met - python

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.

Related

How to stop the execution of an imported python script without exiting the python altogether?

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])

How to Fix: Main function is Unreachable - Python 3.5

I'm trying to make a dead-simple bot according to this video: https://www.youtube.com/watch?v=5Jwd69MRYwg
The main function that is supposed to be called when a part of the screen changes color simply is not being run at all.
I've tried ending the program with
"main()"
and
"if __name__ == '__main__':
main()"
respectively. Neither have allowed the code to run
def restart_game():
time.sleep(1)
pyautogui.click(Coordinates.replayBtn)
def image_grab():
box = (290, 465, 305, 487)
image = image_grab_lib.grab(box)
grey = ImageOps.grayscale(image)
a = array(grey.getcolors())
print(a.sum())
return a.sum()
def main():
restart_game()
print("blip")
if image_grab() != 577:
print("Jump")
press_space()
time.sleep(1)
restart_game()
if __name__ == '__main__':
main()
I expect the main function to run and give print "blip" and "jump", currently running all the other code and entirely skipping the main function.
shows what the warning looks like in PyCharm - image
Your code is unreachable because you have an infinite while loop before main() definition. It's a good practice in applications that require while loop to put it inside if name == 'main' condition after all variables are declared.
Like this:
if __name__ == '__main__':
while True:
do_something()

Exit from subfunction of function to main

#!/usr/bin/env python
class Functions() :
def A(self):
print "hey"
self.B()
return 1
def B(self):
print "hello"
exit(0)
func_obj = Functions()
def main() :
A = func_obj.A()
print A
print "awesome"
if __name__ == '__main__' :
main()
Above is my code. What I'm trying to do is that I want to call functionA from the main() function and when functionA executes functionB, I want functionB to raise error and exit back to the main() function without going back to functionA. How can I achieve this? Basically I want the main function to print "awesome" after functionB exits. I'm not sure what is the correct keyword to look it up.
What you're looking for are exceptions - they are actually designed to do just this: break the normal flow of execution and propagate up the call stack until someone take care of them (as a last resort, the runtime will catch them, display the error message and a full traceback, and exit).
There are two parts to the process: first raising the exception, then catching it at the right place. In your example it might look like:
# declare our own exception type so we can catch specifically this one
class MyOwnException(Exception):
pass
def a():
print("in a - before b")
b()
print("in a - after b (shouldn't see this)")
def b():
print("in b, before raise")
raise MyOwnException("hello houston ?")
print("in b, after raise (shouldn't see this)")
if __name__ == "__main__":
print("calling a")
try:
a()
print("after a (shouldn't see this)")
except MyOwnException as e:
print("caugth error {}".format(e))
FWIW, your example using exit() was really close since exit() actually works by raising a SysExit exception. The first and main use case for exception is of course error handling, but it's actually really a way to control the execution flow of your program (as an example the StopIteration exception is used to signal an exhausted iterator).
Hey so after someone pointed out my original answer didnt work i went searching! you can create custom exception classes to achieve what you're looking for!
class HaltException(Exception):
pass
class Functions():
def a(self):
print("hey")
self.b()
return "1"
def b(self):
print("hello")
raise HaltException("This is an exception error.")
def main():
func_obj = Functions()
try:
func_obj.a()
except HaltException as error:
print(error)
print("Awesome")
if __name__ == "__main__":
main()
This would then return the following when run :
hey
hello
This is an exception error.
Awesome

Python: how to terminate a function of a script from another script

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.

Python multiprocessing creates sub-process using wrong function

I'm trying to write code that create sub-process using another module(demo_2.py),
and exit program if i get wanted value on sub-processes.
But result looks like this.
It seems that demo_1 makes two sub-process that run demo_1 and load demo_2.
I want to make sub-process only runs demo_2.
What did i missed?
demo_1.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from multiprocessing import Process,Queue
import sys
import demo_2 as A
def multi_process():
print ("Function multi_process called!")
process_status_A = Queue()
process_status_B = Queue()
A_Process = Process(target = A.process_A, args = (process_status_A,))
B_Process = Process(target = A.process_A, args = (process_status_B,))
A_Process.start()
B_Process.start()
while True:
process_status_output_A = process_status_A.get()
process_status_output_B = process_status_B.get()
if process_status_output_A == 'exit' and process_status_output_B == 'exit':
print ("Success!")
break
process_status_A.close()
process_status_B.close()
A_Process.join()
B_Process.join()
sys.exit()
print ("demo_1 started")
if __name__ == "__main__":
multi_process()
demo_2.py
class process_A(object):
def __init__(self, process_status):
print ("demo_2 called!")
process_status.put('exit')
def call_exit(self):
pass
if process_status_A == 'exit' and process_status_B == 'exit':
should be
if process_status_A_output == 'exit' and process_status_B_output == 'exit':
Conclusion: The naming of variables is important.
Avoid long variable names which are almost the same (such as process_status_A and process_status_A_output).
Placing the distinguishing part of the variable name first helps clarify the meaning of the variable.
So instead of
process_status_A_output
process_status_B_output
perhaps use
output_A
output_B
Because Windows lacks os.fork,
on Windows every time a new subprocess is spawned, a new Python interpreter is started and the calling module is imported.
Therefore, code that you do not wish to be run in the spawned subprocess must be "protected" inside the if-statement (see in particular the section entitled "Safe importing of main module"):
Thus use
if __name__ == "__main__":
print ("demo_1 started")
multi_process()
to avoid printing the extra "demo_1 started" messages.

Categories

Resources