How to run 2 loops side by side in python? - python

I have tried both of these solutions
from multiprocessing import Process
def loop_a():
while 1:
print("a")
def loop_b():
while 1:
print("b")
if __name__ == '__main__':
Process(target=loop_a).start()
Process(target=loop_b).start()
and the second solution
import threading
import time
def infiniteloop1():
while True:
print('Loop 1')
time.sleep(1)
def infiniteloop2():
while True:
print('Loop 2')
time.sleep(1)
thread1 = threading.Thread(target=infiniteloop1)
thread1.start()
thread2 = threading.Thread(target=infiniteloop2)
thread2.start()
but both of these dont work whichever loop is above like in the second case infiniteloop1 is above so infiniteloop1 will run then after it ends infiniteloop2 will run and i want BOTH of them to run at the same time what i think that the problem is that both the loops will take input from user in some kind like in the first loop it will take voice input and in the second loop it will see if a mouse button is pressed. so while one loop is taking input the other wont run something like that is happening from what i think
this is the code of my loops
loop 1
def screen_display():
white = (255, 255, 255)
screen = pygame.display.set_mode((320, 600))
pygame.display.set_caption("Assistant")
screen.fill(white)
exit_button = pygame.image.load('cross.png').convert_alpha()
set_height = exit_button.get_height()
set_width = exit_button.get_width()
exit_button_rect = exit_button.get_rect(center=(230, 545))
settings_button = pygame.image.load('settings.png').convert_alpha()
pygame.transform.scale(settings_button, (set_height, set_width))
settings_button_rect = settings_button.get_rect(center=(67, 545))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
mousepos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if is_over(settings_button_rect, mousepos):
print(1)
if is_over(exit_button_rect, mousepos):
print(2)
loop 2
while True:
# Exception handling to handle
# exceptions at the runtime
try:
# use the microphone as source for input.
global source2
with sr.Microphone() as source2:
# wait for a second to let the recognizer
# adjust the energy threshold based on
# the surrounding noise level
settings()
print("say the command after the beep")
SpeakText("What do you want me to do?")
MyText = speech_text()
turn_text_to_sense(MyText)
if 'your name' in MyText:
print("You can change my name say 'help' for help")
except sr.RequestError as e:
SpeakText("Could not request results please check your internet connection; {0}".format(e))
except sr.UnknownValueError:
SpeakText("Couldn't understand what you said, say 'help' for info about commands")
there is some more code of other functions but i dont think that they are important

You'd better use threading
import threading
def loop_a():
while 1:
print("a")
def loop_b():
while 1:
print("b")
if __name__ == '__main__':
threadings = []
threadings.append(threading.Thread(target = loop_a))
threadings.append(threading.Thread(target = loop_b))
for thread_item in threadings:
thread_item.start()
for thread_item in threadings:
thread_item.join()

Related

Toggle key to run a thread then stop the thread when pressed again?

I'm currently working on a program and setup a toggle key that starts a thread when it's first clicked, and I want it to stop the thread when the key is pressed again. Currently I've tried this piece of code, but it came out with an error.
def on_press(key):
try: k = key.char
except: k = key.name
if key == (KeyCode(char='e')):
print("Key Pressed")
clicker = threading.Thread(target=run)
if running == False:
print("Starting")
clicker.start()
else:
print("Stopping")
clicker.join()
lis = keyboard.Listener(on_press=on_press)
lis.start() # start to listen on a separate thread
lis.join() # no this if main thread is polling self.keys
The error I get is:
raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started**
You should check what you have in variable running - ie. print(running)- because it decides when to execute code inif/elseand it runsclick.join()directly after creatingThreadbefore you runclicker.start()`
As for me you should create therad inside if running == False
You should also use global to assing values to external variable - now you create local clicker which will be removed when it exits on_press and you will not have access to this thread. You should also change value running when you started thead`
BTW:
For True/False you should rather use is instead of ==
You can also use more readable if not running instead of if running is False:
I didn't test it
# from ... import ...
# --- functions ---
def on_press(key):
global running # inform function that it has to assign value to external variable
global clicker
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == KeyCode(char='e'):
print("Key Pressed")
if not running: # the same as `if running == False:`
print("Starting")
clicker = threading.Thread(target=run)
clicker.start()
running = True
else:
print("Stopping")
clicker.join()
running = False
# --- main ---
running = False # default value at start
lis = keyboard.Listener(on_press=on_press)
lis.start()
lis.join()
if you don't use running in other places in code then you could use clicker = None to control if thread is running.
# from ... import ...
# --- functions ---
def on_press(key):
global clicker # inform function that it has to assign value to external variable
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == KeyCode(char='e'):
print("Key Pressed")
if not clicker:
print("Starting")
clicker = threading.Thread(target=run)
clicker.start()
else:
print("Stopping")
clicker.join()
clicker = None
# --- main ---
clicker = None # default value at start
lis = keyboard.Listener(on_press=on_press)
lis.start()
lis.join()
BTW:
If thread is running then join() waits for its end - but it doesn't kill it so you may wait forever.
You should use value running also inside run() to stop it.
def run():
while running:
#... code ...
or
def run():
while True:
#... code ...
if not running:
return
#... code ...
and then you have to set running before start() and join()
if not running:
print("Starting")
clicker = threading.Thread(target=run)
running = True # it has to be before `start()`
clicker.start()
else:
print("Stopping")
running = False # it has to be before `join()`
clicker.join()
EDIT:
Minimal working code - I tested it.
from pynput import keyboard
import datetime
import time
import threading
# --- functions ---
def run():
print('Running thread')
while running:
print(datetime.datetime.now())
time.sleep(1)
print('Exiting thread')
def on_press(key):
global running # inform function that it has to assign value to external variable
global clicker
try: # PEP8: don't put it in one line - it make code unreadable for human
k = key.char
except:
k = key.name
if key == keyboard.KeyCode(char='e'):
print("Key Pressed")
if not running: # the same as `if running == False:`
print("Starting thread")
clicker = threading.Thread(target=run)
running = True # it has to be before `start()`
clicker.start()
else:
print("Stopping thread")
running = False # it has to be before `join()`
clicker.join()
# press `q` to exit
if key == keyboard.KeyCode(char='q'):
return False
# --- main ---
running = False # default value at start
try:
print("Starting program")
print("- press E to start/stop thread")
print("- press Q to exit")
print("- press Ctrl+C to exit")
lis = keyboard.Listener(on_press=on_press)
lis.start()
print("Listening ...")
lis.join()
print("Exiting program")
except KeyboardInterrupt:
print("Stoped by Ctrl+C")
else:
print("Stoped by Q")
finally:
if running:
running = False
clicker.join()
If the key pressed is the same as the start_stop_key, stop clicking if the running flag is set to true in the thread otherwise start it. If the key pressed is the exit key, call the exit method in the thread and stop the listener
start_stop_key = KeyCode(char='s')
exit_key = KeyCode(char='e')
...............
def on_press(key):
if key == start_stop_key:
if click_thread.running:
click_thread.stop_clicking()
else:
click_thread.start_clicking()
elif key == exit_key:
click_thread.exit()
listener.stop()

Python script not stopping on sys.exit() [duplicate]

This question already has answers here:
Why does sys.exit() not exit when called inside a thread in Python?
(6 answers)
Closed 1 year ago.
I wrote a script that can draw polylines (it over on github) from ScalableVectorGraphics(.svg) by moving the Mouse accordingly.
When you are handing the control over your mouse to a script, a killswitch is certainly necessary, so I found an example for a Keyboard listener somwhere on the Internet:
def on_press(key):
try:
sys.exit()
print('alphanumeric key {0} pressed'.format(key.char))
print('adsfadfsa')
except AttributeError:
print('special key {0} pressed'.format(
key))
def main():
listener = keyboard.Listener( #TODO fix sys.exit()
on_press=on_press)
listener.start()
if __name__ == '__main__':
main()
It seems to be working: If i add a a print statement before the sys.exit() it is instantly executed properly.
But with sys.exit() it keeps moving my mouse and the python interpreter is still on Taskmanager. I don't know why it keeps executing.
Thank you in advance for your suggestions.
MrSmoer
Solution was: os._exit(1)
Full Sourcecode:
from pynput import mouse as ms
from pynput import keyboard
from pynput.mouse import Button, Controller
import threading
import time
from xml.dom import minidom
import re
sys.path.append('/Users/MrSmoer/Desktop/linedraw-master')
mouse = ms.Controller()
tlc = None
brc = None
brc_available = threading.Event()
biggestY = 0
biggestX = 0
drwblCnvsX = 0
drwblCnvsY = 0
def on_click(x, y, button, pressed):
if not pressed:
# Stop listener
return False
def on_press(key):
try:
sys.exit()
print('alphanumeric key {0} pressed'.format(key.char))
print('adsfadfsa')
except AttributeError:
print('special key {0} pressed'.format(
key))
def initialize():
print("Please select your programm and then click at the two corners of the canvas. Press any key to cancel.")
with ms.Listener(
on_click=on_click) as listener:
listener.join()
print('please middleclick, when you are on top left corner of canvas')
with ms.Listener(
on_click=on_click) as listener:
listener.join()
global tlc
tlc = mouse.position
print('please middleclick, when you are on bottom left corner of canvas')
with ms.Listener(
on_click=on_click) as listener:
listener.join()
global brc
brc = mouse.position
mouse.position = tlc
print('thread finished')
brc_available.set()
def getDrawabableCanvasSize(polylines):
global biggestX
global biggestY
for i in range(len(polylines)): # goes throug all polylines
points = hyphen_split(polylines[i]) # Splits polylines to individual points
for c in range(len(points)): # goes throug all points on polyline
cord = points[c].split(',') # splits points in x and y axis
if float(cord[0]) > (biggestX - 5):
biggestX = float(cord[0]) + 5
if float(cord[1]) > (biggestY - 5):
biggestY = float(cord[1]) + 5
print('TLC: ', tlc)
print('bigX: ', biggestX)
print('bigY: ', biggestY)
cnvswidth = tuple(map(lambda i, j: i - j, brc, tlc))[0]
cnvsheight = tuple(map(lambda i, j: i - j, brc, tlc))[1]
cnvsapr = cnvswidth / cnvsheight
print('Canvasaspr: ', cnvsapr)
drwblcnvaspr = biggestX / biggestY
print('drwnble aspr: ', drwblcnvaspr)
if drwblcnvaspr < cnvsapr: # es mus h vertikal saugend
print('es mus h vertikal saugend')
finalheight = cnvsheight
finalwidth = finalheight * drwblcnvaspr
else: # es muss horizontal saugend, oder aspect ratio ist eh gleich
print('es muss horizontal saugend, oder aspect ratio ist eh gleich')
finalwidth = cnvswidth
scalefactor = finalwidth / biggestX
print(scalefactor)
return scalefactor
def drawPolyline(polyline, scalefactor):
points = hyphen_split(polyline)
#print(points)
beginpoint = tlc
for c in range(len(points)): # goes throug all points on polyline
beginpoint = formatPoint(points[c], scalefactor)
if len(points) > c + 1:
destpoint = formatPoint(points[c + 1], scalefactor)
mouse.position = beginpoint
time.sleep(0.001)
mouse.press(Button.left)
# time.sleep(0.01)
mouse.position = destpoint
# time.sleep(0.01)
mouse.release(Button.left)
else:
destpoint = tlc
#print("finished line")
mouse.release(Button.left)
def formatPoint(p, scale):
strcord = p.split(',')
#print(scale)
#print(tlc)
x = float(strcord[0]) * scale + tlc[0] # + drwblCnvsX/2
y = float(strcord[1]) * scale + tlc[1] # + drwblCnvsY/2
#print('x: ', x)
#print('y: ', y)
thistuple = (int(x), int(y))
return thistuple
def hyphen_split(a):
return re.findall("[^,]+\,[^,]+", a)
# ['id|tag1', 'id|tag2', 'id|tag3', 'id|tag4']
def main():
listener = keyboard.Listener( #TODO fix sys.exit()
on_press=on_press)
listener.start()
thread = threading.Thread(target=initialize()) #waits for initializing function (two dots)
thread.start()
brc_available.wait()
# print(sys.argv[1])
doc = minidom.parse('/Users/MrSmoer/Desktop/linedraw-master/output/out.svg') # parseString also exists
try:
if sys.argv[1] == '-ip':
doc = minidom.parse(sys.argv[2])
except IndexError:
print('Somethings incorrect1')
polylines = NotImplemented
try:
doc = minidom.parse('/Users/MrSmoer/Desktop/linedraw-master/output/out.svg') # parseString also exists
# /Users/MrSmoer/Desktop/linedraw-master/output/output2.svg
#doc = minidom.parse('/Users/MrSmoer/Desktop/Test.svg')
polylines = [path.getAttribute('points') for path
in doc.getElementsByTagName('polyline')]
doc.unlink()
except:
print('Somethings incorrect3')
# print(polylines)
scalefactor = getDrawabableCanvasSize(polylines)
for i in range(len(polylines)):
drawPolyline(polylines[i], scalefactor)
if __name__ == '__main__':
main()
Sometimes, when writing a multithreadded app, raise SystemExit and sys.exit() both kills only the running thread. On the other hand, os._exit() exits the whole process.
While you should generally prefer sys.exit because it is more "friendly" to other code, all it actually does is raise an exception.
If you are sure that you need to exit a process immediately, and you might be inside of some exception handler which would catch SystemExit, there is another function - os._exit - which terminates immediately at the C level and does not perform any of the normal tear-down of the interpreter
A simple way to terminate a Python script early is to use the built-in quit() function. There is no need to import any library, and it is efficient and simple.
Example:
#do stuff
if this == that:
quit()
You may try these options!!
Hope it works fine!! If not tell us, we will try more solutions!
That sys.exit() ends up killing the thread that it's executing it, but you program seems to take advantage of multiple threads.
You will need to kill all the threads of the program including the main one if you want to exit.

How to stop or pause pyautogui at any moment that I want?

I am building some macro program using pyautogui.
Unfortunately I am not able to stop for-loop so sometimes it takes too much time until for-loop end.
Is there any way to stop the program at any moment I want? or I just wait until program end.
below is my code
CURRENT_DIR = os.getcwd()
list = os.path.join(CURRENT_DIR,'BOM_list.xlsx')
df = pd.read_excel(list)
for i in df['MLFB'].index:
MLFB = df.loc[i, 'MLFB']
print(MLFB)
a = pyautogui.locateCenterOnScreen('a_material.png')
print(a)
pyautogui.moveTo(a)
pyautogui.moveRel(350, 0)
pyautogui.click()
pyautogui.keyDown('ctrl')
pyautogui.press('a')
pyautogui.keyUp('ctrl')
pyautogui.typewrite(MLFB)
b = pyautogui.locateCenterOnScreen('b_execute.png')
print(b)
pyautogui.moveTo(b)
pyautogui.click()
time.sleep(2.5)
pyautogui.keyDown('alt')
pyautogui.press('y')
pyautogui.press('t')
pyautogui.press('a')
pyautogui.press('i')
pyautogui.keyUp('alt')
time.sleep(2)
pyautogui.press('down')
pyautogui.typewrite(['enter'])
time.sleep(2)
c = pyautogui.locateCenterOnScreen('c_Directory.png')
pyautogui.moveTo(c)
pyautogui.moveRel(350, 0)
pyautogui.click()
pyautogui.keyDown('ctrl')
pyautogui.press('a')
pyautogui.keyUp('ctrl')
pyautogui.typewrite(CURRENT_DIR)
pyautogui.click()
time.sleep(1.5)
d = pyautogui.locateCenterOnScreen('d_Filename.png')
pyautogui.moveTo(d)
pyautogui.moveRel(350, 0)
pyautogui.click()
pyautogui.keyDown('ctrl')
pyautogui.press('left')
pyautogui.keyUp('ctrl')
pyautogui.typewrite(MLFB)
time.sleep(0.5)
pyautogui.typewrite(['enter'])
time.sleep(2)
e = pyautogui.locateCenterOnScreen('e_go_back.png')
pyautogui.moveTo(e)
pyautogui.click()
time.sleep(2)
PyAutoGUI has a built in failsafe to terminate the program at any time. Just move your mouse to the top left corner of your main monitor where your x, y values would be 0, 0.
Typing print(pyautogui.FAILSAFE) should return True, telling us the failsafe is on. You could also disable it if it's getting in the way of your program by setting it to pyautogui.FAILSAFE = False
Looking through your code, you could save some space by using hotkey() when you want to press more than one key at a time:
pyautogui.keyDown('ctrl')
pyautogui.press('a')
pyautogui.keyUp('ctrl')
Is the same as:
pyautogui.hotkey('ctrl', 'a')
You could also check out threading which allows you to run more than one process at a time.
The following code will have an example main program running and when the Esc key is pressed, the main program will pause and the user is prompted if they want to continue or not.
import time
from threading import Thread
from pynput import keyboard
def exit_program():
def on_press(key):
if str(key) == 'Key.esc':
main.status = 'pause'
user_input = input('Program paused, would you like to continue? (y/n) ')
while user_input != 'y' and user_input != 'n':
user_input = input('Incorrect input, try either "y" or "n" ')
if user_input == 'y':
main.status = 'run'
elif user_input == 'n':
main.status = 'exit'
exit()
with keyboard.Listener(on_press=on_press) as listener:
listener.join()
def main():
main.status = 'run'
while True:
print('running')
time.sleep(1)
while main.status == 'pause':
time.sleep(1)
if main.status == 'exit':
print('Main program closing')
break
Thread(target=main).start()
Thread(target=exit_program).start()

How to pause and resume a while loop in Python?

I want to have a loop running that will print "Hello" and when I press "K" it stops printing but it doesn't end the program, then when I press "K" again it starts printing again.
I tried this(using the keyboard module):
import keyboard
running = True
while running == True:
print("hello")
if keyboard.is_pressed("k"):
if running == True:
running = False
else:
running = True
but when I press the button it just ends the program and that's not what I'm trying to do. I understand why it ends but I don't know how to make it not end. How can I do that?
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("k"):
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
print("not")
Maybe something like that:
import keyboard
running = True
stop = False
while !stop:
if keyboard.is_pressed("k"):
running = !running # Stops "hello" while
if keyboard.is_pressed("q"):
stop = !stop # Stops general while
if running:
print("hello")
You could use a handler for the keypress, which sets an event that the main thread can then test for periodically, and wait if required.
(Note that there are two types of events here, the keypress event and the setting of the running, so these should not be confused.)
from threading import Event
from time import sleep
import keyboard
hotkey = 'k'
running = Event()
running.set() # at the start, it is running
def handle_key_event(event):
if event.event_type == 'down':
# toggle value of 'running'
if running.is_set():
running.clear()
else:
running.set()
# make it so that handle_key_event is called when k is pressed; this will
# be in a separate thread from the main execution
keyboard.hook_key(hotkey, handle_key_event)
while True:
if not running.is_set():
running.wait() # wait until running is set
sleep(0.1)
print('hello')
import sys
import keyboard
from time import sleep
running = True
while running:
if keyboard.is_pressed("k"):
sleep(1)
elif keyboard.is_presed('Esc'):
sys.exit()
else:
print("hello")
I didnt test it, so please give me feedback
I think the right way is flushing the buffer, because the previous solutions may print more. This works for windows, for Linux, you should refer to Python read a single character from the user
import time
import subprocess
import sys
import msvcrt
printing = True
while (1):
# Try to flush the buffer
while not msvcrt.kbhit() and printing:
print("hello")
doit = msvcrt.getch().decode('utf-8')
if doit=="k":
printing = not printing
print("stop/start")
if doit == 'q':
break
This is the output of this code:
Please note that, if you add print("stop/start") in Adrian Melon's program, you can see his program prints several time "hello" after 'k' is pressed until the buffer will be empty.
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("k"):
print("stop/start")
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
pass
This is the output of #Adrian-Melon program:
import keyboard
running = True
display = True
block = False
while running:
if keyboard.is_pressed("space"):
if block == False:
display = not display
block = True
else:
block = False
if display:
print("hello")
else:
input("Press Enter to continue...")
if block == False:
display = not display
block = True
You can use this to stop and start again.

Threading with Python

complete python newbie...
I'm working with the Arduino pyfirmata package and Im trying to do something quite simple.
Depending on a user input to python, I want an LED to flash or not.
My problem is that the python program only asks for the user input once but I would like it to always ask for the input so the user can change function at any time.
I have tried using the threading package but no success... Perhaps there is a simpler way, but I am totally new to coding so I do not know of any other. Open to suggestions!!
Here is my code,
import pyfirmata
import threading
import time
board = pyfirmata.Arduino('/dev/cu.usbmodem14101')
def flash():
for i in range(1000):
board.digital[13].write(1)
time.sleep(1)
board.digital[13].write(0)
time.sleep(1)
def stop():
board.digital[13].write(0)
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
x = threading.Thread(target=flash(), args=(1,))
x.start()
# x.join()
elif runMode == "Stop":
x = threading.Thread(target=stop(), args=(1,))
x.start()
#x.join()
You can do it in an object-oriented way by creating your own Thread subclass something like the Flasher class below.
One of the advantages to this approach is that it would be relatively easy to extend the Flasher class and make it control LEDs connected to different outputs, or to allow the delay between flashes to be specified at creation time. Doing the former would allow multiple instances to be running at the same time.
import pyfirmata
import threading
import time
OFF, ON = False, True
class Flasher(threading.Thread):
DELAY = 1
def __init__(self):
super().__init__()
self.daemon = True
self.board = pyfirmata.Arduino('/dev/cu.usbmodem14101')
self.flashing = False
self.LED_state = OFF
def turn_LED_on(self):
self.board.digital[13].write(1)
self.LED_state = ON
def turn_LED_off(self):
self.board.digital[13].write(0)
self.LED_state = OFF
def run(self):
while True:
if self.flashing:
if self.LED_state == ON:
self.turn_LED_off()
else:
self.turn_LED_on()
time.sleep(self.DELAY)
def start_flashing(self):
if self.LED_state == OFF:
self.turn_LED_on()
self.flashing = True
def stop_flashing(self):
if self.LED_state == ON:
self.turn_LED_off()
self.flashing = False
flasher = Flasher()
flasher.start()
while True:
runMode = input("Run or Stop? ").strip().lower()
if runMode == "run":
flasher.start_flashing()
elif runMode == "stop":
flasher.stop_flashing()
else:
print('Unknown response ignored')
If your looking to just kill the thread you could use mulitiprocessing
which a multiprocessing.Process can p.terminate()
p = Process(target=flash, args=(,))
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
p.start()
elif runMode == "Stop":
p.terminate()
However this is not recommended to just kill threads as it can cause errors if the process is handling critical resources or dependant on other threads see here for a better explanation Is there any way to kill a Thread?
A better option as described here is to use flags to handle your flashing, they allow a simple communication between threads
from threading import Event
e = event()
def check_for_stop(e):
while not e.isSet():
flash()
print("Flashing Ended")
while True:
runMode = input("Run or Stop? ")
if runMode == "Run":
x = threading.Thread(target=check_for_stop, args=(e,))
x.start()
# x.join()
elif runMode == "Stop":
e.set() #set flag true
e.clear() #reset flag
here is the documentation for more info on event objects https://docs.python.org/2.0/lib/event-objects.html
I havent tested this code is just an example so apologies if it doesnt work straight away
Edit: Just looking at your function again you would want to check for the flag during the flashing thats my mistake aplogies so your flash function would look like
def flash():
while e.isSet():
board.digital[13].write(1)
time.sleep(1)
board.digital[13].write(0)
time.sleep(1)
and you would pass this into the thread as you have before
x = threading.Thread(target=flash(), args=(1,))
x.start()
You got an error in the code.
You should create the thread via:
x = threading.Thread(target=flash)
Note: You gave the entered 'flash()' therefore executing the method in the main thread. And also your method doesn't have any arguments therefore you can remove the args values

Categories

Resources