Python Stopping a program at any point in an if command - python

I currently have a program that I am working on that requires the user to input some parameters, and then press a button to start the main part of the program.
After the start button is pressed, the if loop executes a sequential order of commands (around 20) and then stops.
I want to be able to stop this sequence of commands at any time during the code using a separate 'stop' button, but I am not sure how. I am more interested in a method of doing this than GUI syntax.
Any help is appreciated.
Example code:
if (start_button_is_pressed):
#do thing a
#do thing b
#do thing c
...
#do thing z
# i want to be able to stop from any point a-z

You can use a loop and break execution at any point. If you want only a single pass through the steps, add a final break at the end.
jump_out = False
while not jump_out:
step_1()
if (jump_out):
break
step_2()
if (jump_out):
break
# and so on
step_n()
break # add unconditional break for single-pass execution

you can use a break statement inside the loop. Set an event such that when the stop button is pressed, it triggers a certain value and this value alters the loop. Sample process below
stop = False
if stop_button_is_pressed:
stop = True
for a in b:
if stop == True:
break
print(a)
print("Stopped")

You could use multiprocessing.Process to terminate() the process/function my_process_function() whenever you please... Run it as script to get outputs.
import multiprocessing
def my_process_function():
for i in range (100):
print(i)
time.sleep(1)
print("my_process end")
if __name__ == "__main__":
x = multiprocessing.Process(target=my_process_function())
x.start()
print("Stop thread?")
a=input()
if (a=="y"):
x.terminate()

Related

Shorten a repeating exit flag for functions

I would like to exit a function by pressing a button using the return statement in the if statement. To write these lines again and again and again is not really what I like. That's why I am basically looking for a function that tells the parent function to return.
Obviously I can't use the return statement in a function and just execute the function where I want to check the variable, although that would be the nicest way I could imagine.
I want to explain it in a loop, but please keep in mind that's not where I want to use it. The usage is for automated processes which should have many exit points.
import keyboard, time
RedFlag = False
def set_RedFlag():
global RedFlag
RedFlag = True
keyboard.add_hotkey("end", set_RedFlag)
PauseFlag = False
def set_PauseFlag():
global PauseFlag
print(PauseFlag)
if PauseFlag == False:
PauseFlag = True
else:
PauseFlag = False
keyboard.add_hotkey("space", set_PauseFlag)
def task():
for i in range(30):
print("test",i)
time.sleep(1)
# Flags
if RedFlag == True: # exitpoint
return
while PauseFlag == True: # pause the script
time.sleep(1/6)
task()
Really relevant is the if statement after #Flags. Especially with the while statement I would have to repeat multiple lines. I would love to have this in one single word as if it was a function.
Edit:
More about the "what for?":
I would like to run a macro and later maybe other tasks. For example writing the odd numbers from 1 to 511. And I want to be able to stop or pause it at any given time.
I forgot to mention, that I tried using the multiprocessing module, since I could terminate the task there. Sadly it is not an option for me not only because the starting time of a process is a bit too long for me, also I am learning a bit about kivy and I know it get's complicated when I want to start another process while using kivy.

Python - Checking if there is an input from user without stopping the loop

I have a small script where I have a continuous loop. The loop runs and I expect that the user will give an input whenever he wants. I want to check if the user wrote something in the console, if yes, I will do something extra, if not, the loop continues.
The problem is that when I call the input() function, the program waits for user input.
The code that I will use here will be just a simple version of my code to show better what is my problem.
i=0
while True:
i+=1
if 'user wrote a number':
i+= 'user's input'
The objective is to not stop the loop if the user do not input anything. I believe this is a simple thing but I didn't find an answer for this problem.
Thank you for your time!
You can execute the background task (the while True) on a separate thread, and let the main thread handle the input.
import time
import threading
import sys
def background():
while True:
time.sleep(3)
print('background task')
def handling_input(inp):
print('Got {}'.format(inp))
t = threading.Thread(target=background)
t.daemon = True
t.start()
while True:
inp = input()
handling_input(inp)
if inp == 'q':
print('quitting')
sys.exit()
Sample execution (lines starting with >> are my inputs):
background task
>> a
Got a
>> b
Got b
background task
>> cc
Got cc
background task
background task
>> q
Got q
quitting
Process finished with exit code 0
The only caveat is if the user takes longer than 3 seconds to type (or whatever the value of time.sleep in background is) the input value will be truncated.
I'm don't think you can do that in one single process input(), because Python is a synchronous programming languaje,the execution will be stoped until input() receives a value.
As a final solution I'd recommend you to try implement your functions with parallel processing so that both 'functions' (input and loop) can get executed at the same time, then when the input function gets it's results, it sends the result to the other process (the loop) and finish the execution.

Schedule Python - Overlapping functions

I am trying to run 2 functions at different times, one after another.
The first function contains while loop in it (without break, since I want to keep it running until the next function comes)
However, when the next schedule comes, it doesn't run the second function and stuck in the 1st one.
I have tried to add sys.exit() but it doesn't even go into that function
import schedule
import sys
import time
def do_complete_automation():
while True:
print()
print("do_complete_automation()")
time.sleep(5)
def exit1():
print("exit")
sys.exit()
schedule.every().sunday.at('16:42').do(do_complete_automation)
schedule.every().sunday.at('16:42:30').do(exit1)
schedule.every().sunday.at('16:42:35').do(do_complete_automation)
while True:
schedule.run_pending()
time.sleep(1)
It should print "exit"

Ask input once then wait for response

I'm a total newbie and I have question about asking about input while the loop is working.
Lets pretend that i have simple loop.
x = 1
y = 1
while x == 1:
y += 1
print(y)
And now i want user input to stop this script but only if he types cancel and the loop is supposed to run while python is waiting for input.
As I mentioned in the comments you can achieve "running the loop while waiting for input" using threads from the threading module.
The idea is to have two threads that will run in parallel (ie at the same time) and each of them will do its own thing. The first one will do only one thing : wait for input. The second one will do the work that you would have put in the loop, and only check at the start of each loop if it should stop or not according to the information it gets from the first thread.
The following code illustrate this (note this requires python3):
from threading import Thread
import time
class Input_thread(Thread):
def __init__(self):
Thread.__init__(self)
self.keep_working = True
def run(self):
while True:
a = input("Type *cancel* and press Enter at anytime to cancel \n")
print("You typed "+a)
if a == "cancel":
self.keep_working = False
return
else:
pass
class Work_thread(Thread):
def __init__(self, other_thread):
Thread.__init__(self)
self.other_thread = other_thread
def run(self):
while True:
if self.other_thread.keep_working is True:
print("I'm working")
time.sleep(2)
else :
print("I'm done")
return
# Creating threads
input_thread = Input_thread()
work_thread = Work_thread(input_thread)
# Lanching threads
input_thread.start()
work_thread.start()
# Waiting for threads to end
input_thread.join()
work_thread.join()
As you can see using threading isn't trivial and requires some knowledge about classes.
A way of achieving something similar in a slightly simpler way would be to use the python's exception called KeyboardInterrupt. If you are not familiar with exceptions : there are python's way of handling errors in your code, that means if at some point in your code Python finds a line it can't run, it will raise an exception, and if nothing was planned to deal with that error (aka if you don't catch the exception with the try/except syntax), python stops running and display that exception and the traceback in the terminal window.
Now the thing is when you press Ctrl-c (same as the copy shortcut) in the terminal window while your program runs, it will automaticaly raise an exception called KeyboardInterupt in your program, and you can catch it to use it as way to send cancel to your program.
See that code for an example of how to do that :
import time
y=1
try:
while True:
y+=1
print(y)
time.sleep(1)
except KeyboardInterrupt:
print("User pressed Ctrl-c, I will now exit gracefully")
print("Done")

Python Curses: Exiting a program fast

What is the best way to quickly exit a Python program with an infinite loop that uses curses module?
I've tried adding nodelay() method coupled with this at the end of the loop:
if screen.getch() == ord('q'):
break
However, it takes 2-3 seconds to make all the function calls on one iteration of the loop. And because of the application, it doesn't make sense to run the loop more often than every 5 second. This means that in order for my way of exiting the program to work, I sometimes have to press and hold 'q' for 2-8 seconds.
My code looks like this:
import curses
import time
def main(screen):
refresh_rate = 5
screen.nodelay(1)
# Infinite loop. Displays information and updates it
# every (refresh_rate) # of seconds
while True:
# Makes several http requests
# and passes responses through multiple functions
# Escape infinite loop
if screen.getch() == ord('q'):
break
# Wait before going through the loop again
time.sleep(refresh_rate)
if __name__ == "__main__":
curses.wrapper(main)
My other solution was to replace while True with:
loop = 1
while loop:
#Loop code
if screen.getch() == ord('q'):
loop = -1
This way, there is no need to press and hold 'q' to exit the program. But it can still take up to 8 seconds to exit after pressing 'q' once.
For obvious reasons, this doesn't seem to be the best way of exiting the program. I am pretty sure there should be a better (faster) solution.
Other than that, the program works fine. It's 2 files with more than 300 lines, so I am posting just the relevant parts of the code with my attempted solutions.
Given that you have nodelay already, the usual approach is to use napms with a small (20-50 milliseconds) time, and addressing your 5-seconds goal, to run the functions after several (10-25) repetitions of the getch/napms loop.
Mixing curses and standard I/O doesn't really work well unless you take care to flush things when switching between the two.
What's probably happening is that your 'q' is coming in between the getch() and the sleep calls. Given that getch() takes a fraction of a second to execute and sleep locks the program for 5 seconds, it's very likely that any time you press a key you're going to wait.
The easiest way to exit any python script is to press Ctrl-C - it spawns a KeyBoardInterrupt exception that can be handled like:
try:
while True:
do_something()
except KeyboardInterrupt:
pass
Granted, if this is meant to be a user-facing application, that might not be sufficient. But it's also unlikely that any production application would operate without a full event loop and a UI that would allow them to exit.
Last, if you want another way of doing what you're already doing, you can use:
import sys
sys.stdin.read(1)
To read 1 bye of user input at a time. I'd go for the Ctrl-C route, if I were you.

Categories

Resources