I am trying to replicate ES6 events behavior in python, so I wrote the following code:
from threading import Thread
from time import sleep
class Event:
def __init__(self, action):
self.action= action
self.flag = False
self.__watchFlag()
def triggerAction(self):
self.flag = True
def __watchFlag(self):
if self.flag:
self.action()
self.flag = False
Thread(target=self.__watchFlag).start()
def action():
print("Event triggered action.")
my_event = Event(action)
my_event.triggerAction()
Which works just fine except when I try to trigger the action two times consecutively, i.e:
my_event.triggerAction()
my_event.triggerAction()
Only 1 event is triggered, but if I add a sleep(1/10) in between each trigger, works well. So I am assuming there is a delay somewhere in the process, any ideas?
NOTE: PLS DON'T RECOMMEND ANY EVENTS LIBRARIES ALREADY EXISTING IN PYTHON, I KNOW THEM, THIS IS NOT MY END GOAL, THX.
If you change your code to:
def triggerAction(self):
print("setting to true")
self.flag = True
when you have:
my_event.triggerAction()
my_event.triggerAction()
you get the following output:
setting to true
setting to true
Event triggered action.
But if you have :
my_event.triggerAction()
sleep(1/10)
my_event.triggerAction()
you got:
setting to true
Event triggered action.
setting to true
Event triggered action.
So in the first case you set flag to true immediately, so you don't given enough time for the context switch to kick in.
Related
I have a running variable which is responsible for whether the program is running or not. There is also a loop that runs as long as running == True. This loop contains many functions, each of which takes, say, 1 second to complete.
Thus, if during the iteration of the loop the value of running is changed to False until the iteration is completely completed, the actions will be performed.
It is necessary for me that as soon as the value of running becomes False, the cycle is interrupted immediately (well, or almost immediately).
I have this solution:
running = True
while running:
do_something1(time_length=1)
if not running:
break
do_something2(time_length=1)
if not running:
break
do_something3(time_length=1)
if not running:
break
do_something4(time_length=1)
if not running:
break
do_something5(time_length=1)
if not running:
break
do_something6(time_length=1)
if not running:
break
# etc.
However, this option looks very clumsy and takes up a lot of space. Is it possible not to prescribe a condition before each action, but to prescribe it, say, only at the beginning?
UPD 1:
Due to the fact that I did not fully show the code, the answers do not quite suit me, as I understand it.
All variables and functions are inside the class. The code itself looks like this.
from threading import Thread
class SomeClass:
def __init__(self):
self.running = True
def toggle_running_flag(self):
# this function toggles self.running by user input
self.running = not self.running
if self.running:
Thread(target=self.do_all_of_this).start()
def do_something1(self):
# do something
pass
def do_something2(self):
# do something
pass
def do_something3(self):
# do something
pass
def do_all_of_this(self):
while self.running:
self.do_something1()
if not self.running:
break
self.do_something2()
if not self.running:
break
self.do_something3()
Instead of that flag variable, you could use an exception. Note that exceptions aren't just for "bad stuff", for example the StopIteration exception is how iterators signal that they're done.
Demo:
from contextlib import suppress
class StopRunning(Exception):
pass
def do_something1():
print('do_something1')
raise StopRunning
def do_something2():
print('do_something2')
with suppress(StopRunning):
while True:
do_something1()
do_something2()
print('done')
Output:
do_something1
done
Try it online!
The is a way you can do that. You can create a function that will loop indefinitely between the functions you have to execute:
from itertools import cycle
class SomeClass:
def __init__(self):
self.running = True
def toggle_running_flag(self):
# this function toggles self.running by user input
self.running = True
Thread(target=self.do_all_of_this).start()
def do_all_of_this(self):
self.work = [self.do_something1, self.do_something2, self.do_something3]
for func in cycle(self.work):
func()
if not self.running:
return
After every iteration check if your program should still be running. If not return (Stop iteration)
Are the various do_somethings setting running = False? Relying on globals isn't a great pattern.
One alternative to updating a global flag is to have do_somethingN throw an exception to stop execution:
from do_things import StopRunning, do_something1, do_something2, # etc
try:
while True:
do_something1(time_length=1)
do_something2(time_length=1)
do_something3(time_length=1)
do_something4(time_length=1)
do_something5(time_length=1)
do_something6(time_length=1)
except StopRunning:
pass
Elsewhere:
# do_things.py
class StopRunning(Exception):
pass
def do_something1(time_length):
if time_length > 42:
raise StopRunning
# etc
I'm trying to use pynput to make an autoclicker as my first project, but I'm having a tough time understanding why my code won't work. The code is meant to start/stop clicking when I hit "ctrl + alt + i" and click once every 1 second. Here is my current code. I can't really understand why it doesn't work, but what I have made work so far is that "click_thread.running" is changing from true to false, python listens to my keyboard, and the clicking works ONLY WHEN I set the "self.running" in the "ClickMouse" class to true. The output I get from printing "click_thread.running" seems to change from true to false, but if that's happening then why doesn't the clicking start? I would imagine it has something to do with how it's a subclass of "threading.Thread"? Or maybe I made the class wrong? Either way I've been working on it for a few days now and I feel like I have hit a wall trying to figure it out alone. Any help greatly appreciated!
import time
import threading
from pynput.mouse import Button, Controller
from pynput import keyboard
delay = 1
button = Button.left
class ClickMouse(threading.Thread):
def __init__(self, delay, button):
super().__init__()
self.delay = delay
self.button = button
self.running = False
def run(self):
while self.running == True:
mouse.click(self.button)
time.sleep(self.delay)
def start_clicking(self):
self.running = True
def stop_clicking(self):
self.running = False
mouse = Controller()
click_thread = ClickMouse(delay, button)
click_thread.start()
def on_activate_i():
print('<ctrl>+<alt>+i pressed')
if click_thread.running == False:
click_thread.start_clicking()
else:
click_thread.stop_clicking()
print(click_thread.running)
with keyboard.GlobalHotKeys({'<ctrl>+<alt>+i': on_activate_i,}) as h:
h.join()
As soon as you call click_thread.start(), the start handler is going to call your run function in the new thread. At that point, self.running is False. Thus, your while loop will immediately exit, and the thread will end.
So, set running=True as the default, and don't create the thread until on_activate_i.
Where are you clicking? At random?
I'm using the threading.Timer package to execute a method after x seconds. However, in some cases I want to execute this method earlier and cancel the timer (so it isn't called twice). How do I unit test this?
I want to know if the timer has stopped so that the method is not called anymore. I am now using the following code, unfortunately the is_alive still returns True
from threading import Timer
Class X():
def __init__(self, timeout):
self.timer = Timer(timeout, self.some_method)
self.timer.start()
def some_method(self):
# Do something
def other_method(self):
self.timer.cancel()
self.some_method()
import unittest
Class TestX(unittest.TestCase):
def test_cancel_timer(self):
x = X(1000)
x.other_method()
self.assertFalse(x.timer.is_alive())
Form the documentation the is_alive method returns True during the run operation;
Return whether the thread is alive.
This method returns True just before the run() method starts until just after the run() method terminates. The module function enumerate() returns a list of all alive threads.
The documentation on the cancel method says the following;
Stop the timer, and cancel the execution of the timer’s action. This will only work if the timer is still in its waiting stage.
Does this mean that the cancel method does not stop the run action? Or is is still in the grey area after the run method and returns True for that reason?
With timer.is_alive() you are just checking if the timer-thread itself is alive, so if you want to "check if timer.cancel() was called", you're testing for the wrong thing.
Does this mean that the cancel method does not stop the run action?
It does not stop the run()-function, right. timer.cancel() just sets a flag in an Event-object which gets checked by run. You can test if the flag is set with:
self.assertTrue(x.timer.finished.is_set())
Unfortunately, checking for cancellation is not enough to prevent repeated execution, since run can have already crossed the check like you can see in the source code:
# threading.py (Python 3.7.1):
class Timer(Thread):
"""Call a function after a specified number of seconds:
t = Timer(30.0, f, args=None, kwargs=None)
t.start()
t.cancel() # stop the timer's action if it's still waiting
"""
def __init__(self, interval, function, args=None, kwargs=None):
Thread.__init__(self)
self.interval = interval
self.function = function
self.args = args if args is not None else []
self.kwargs = kwargs if kwargs is not None else {}
self.finished = Event()
def cancel(self):
"""Stop the timer if it hasn't finished yet."""
self.finished.set()
def run(self):
self.finished.wait(self.interval)
if not self.finished.is_set():
self.function(*self.args, **self.kwargs)
self.finished.set()
Some more effort is needed to ensure unique execution. I've written up a possible solution to this in my answer here.
I am trying to spawn a python thread which perform a particular operation repeatedly based on a certain condition. If the condition doesn't met then the thread should exit. I have written the following code, but its running indefinitely.
class dummy(object):
def __init__(self):
# if the flag is set to False,the thread should exit
self.flag = True
def print_hello(self):
while self.flag:
print "Hello!! current Flag value: %s" % self.flag
time.sleep(0.5)
def execute(self):
t = threading.Thread(target=self.print_hello())
t.daemon = True # set daemon to True, to run thread in background
t.start()
if __name__ == "__main__":
obj = dummy()
obj.execute()
#Some other functions calls
#time.sleep(2)
print "Executed" # This line is never executed
obj.flag = False
I am new to python threading module. I have gone through some articles suggesting the use of threading.Timer() function, but this is not what I need.
The problem line is t = threading.Thread(target=self.print_hello()), more specifically target=self.print_hello(). This sets target to the results of self.print_hello(), and since this function never ends it will never be set. What you need to do is set it to the function itself with t = threading.Thread(target=self.print_hello).
I wrote an pyqt gui and used threading to run code which needs a long time to be executed, but I want to have the choice to stop the execution safely. I dont want to use the get_thread.terminate() method. I want to stop the code by a special function (maybe del()). My problem is that, I wrote the code in a own class and just want to abort the class without changing a lot of syntax.
Edit: It was mentioned that one has to pass a flag to the class, which has to be checked constantly. How do I send this flag to the class? Because the flag has to change the value, when one presses the stop button.
Edit 2: My solution so far is, to declerate a global variable with the name running_global. I changed self.get_thread.terminate() to running_global = False and I check constantly in my long_running_prog if the variable has been set False. I think this solution is ugly, so I would be pretty happy if someone has a better idea.
This is my code for the dialog where I start the thread:
class SomeDialog(QtGui.QDialog,
userinterface_status.Ui_status_window):
finished = QtCore.pyqtSignal(bool)
def __init__(self):
"""
:param raster: Coordinates which are going to be scanned.
"""
super(self.__class__, self).__init__() # old version, used in python 2.
self.setupUi(self) # It sets up layout and widgets that are defined
self.get_thread = SomeThread()
# Conencting the buttons
self.start_button.clicked.connect(self.start)
self.stop_button.clicked.connect(self.stop)
self.close_button.clicked.connect(self.return_main)
# Connecting other signals
self.connect(self.get_thread, QtCore.SIGNAL("stop()"), self.stop)
self.connect(self.get_thread, QtCore.SIGNAL("update_status_bar()"), self.update_status_bar)
def return_main(self):
"""
Function is excecuted, when close button is clicked.
"""
print("return main")
self.get_thread.terminate()
self.close()
def start(self):
"""
Starts the thread, which means that the run method of the thread is started.
"""
self.start_button.setEnabled(False)
self.get_thread.start()
def stop(self):
print("Stop programm.")
self.start_button.setEnabled(True)
self.get_thread.quit()
def end(self):
QtGui.QMessageBox.information(self, "Done!", "Programm finished")
def closeEvent(self, event):
"""
This method is called, when the window is closed and will send a signal to the main window to activaete the
window again.
:param event:
"""
self.finished.emit(True)
# close window
event.accept()
In the following class is the code for the thread:
class SomeThread(QtCore.QThread):
finished = QtCore.pyqtSignal(bool)
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
print("del")
self.wait()
def run(self):
self.prog = long_running_prog(self.emit) # Sending from the prog signals
self.prog.run()
self.prog.closeSystem() # Leaving the programm in a safe way.
So if one presses the stop button, the programm should instantly shut down in a save way. Is there a way to abort the class in a save way? For example can I pass a variable to the long_running_prog class which turns True, when one presses the stop button? If somethin like this is possible, could one tell me how?
Thanks for your help in advance
I hope you understand my problem.
Greetings
Hizzy
This is impossible to do unless prog.run(self) would periodically inspect a value of a flag to break out of its loop. Once you implement it, __del__(self) on the thread should set the flag and only then wait.