I have a few classes that rely on time.perf_counter() to timestamp events and do things after a certain amount of time passes, like this:
class Alarm:
def setAlarm(self):
self.alarmed = False
self._saved = time.perf_counter()
def runStep(self):
now = time.perf_counter()
if now - self._saved > 1000.0 and self._saved != -1:
self.alarmed = True
self._saved = -1
I would like to test the class Alarm using a fake clock, it does not necessary to be a call to time.perf_counter() (though it would be more elegant if it does, I guess). I want that the fake clock does not increment by itself, but rather upon my command, like this:
alarm = Alarm()
alarm.setAlarm()
clock.increment(999.0)
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.increment(1.1) # tick another second
alarm.runStep()
self.assertTrue(alarm.alarmed)
Could you please advise on how to mock time.perf_counter() or mock my class for it, and what kind of tool should be used for this kind of job?
You can use unittest.mock.
For example:
import time
import unittest
import unittest.mock
class Alarm:
def setAlarm(self):
self.alarmed = False
self._saved = time.perf_counter()
def runStep(self):
now = time.perf_counter()
if now - self._saved > 1000.0 and self._saved != -1:
self.alarmed = True
self._saved = -1
class MockPerfCounter:
def __init__(self):
self.t = 0
def increment(self, n):
self.t += n
def perf_counter(self):
return self.t
class TestAlarm(unittest.TestCase):
def test_foo(self):
clock = MockPerfCounter()
with unittest.mock.patch('time.perf_counter', clock.perf_counter):
alarm = Alarm()
alarm.setAlarm()
clock.increment(999.0)
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.increment(1.1) # tick another second
alarm.runStep()
self.assertTrue(alarm.alarmed)
if __name__ == '__main__':
unittest.main()
Alterantively, instead of manual MockPerfCounter, you can also use unittest.mock.Mock:
class TestAlarm(unittest.TestCase):
def test_foo(self):
clock = unittest.mock.Mock()
clock.t = 0
with unittest.mock.patch('time.perf_counter', lambda: clock.t):
alarm = Alarm()
alarm.setAlarm()
clock.t += 999.0
alarm.runStep()
self.assertFalse(alarm.alarmed)
clock.t += 1.1
alarm.runStep()
self.assertTrue(alarm.alarmed)
Related
Hi :) I am programming an independent multi-metronome and need to run the funciont beat() on a while loop for every instances of my class Metronome(), starting at the same time.
import time
import mido
from numpy import interp
from IPython.display import clear_output
inport = mido.open_input() #my MIDI is a KORG nanoKontrol 2
class Metronome():
#A dict for my MIDI controller
metronomes_controls = {
'inst_number':[n + 0 for n in range(0,7)],
'vol_slide':[n + 0 for n in range(0,7)],
'tempo_knob': [n + 16 for n in range(0,7)],
'play_stop': [n + 32 for n in range(0,7)],
'sync_selected': [n + 48 for n in range(0,7)],
'tap_button': [n + 64 for n in range(0,7)]}
def __init__(self, inport, inst_number = 0, tempo=60, active=True,
on_off_list = ['ON','OFF','ON','OFF'], selector = 0):
self.inport = inport
self.inst_number = inst_number
self.tempo = tempo
self.active = active
self.on_off_list = on_off_list #The controller is not so precise
self.selector = selector
self.controls = dict(zip(list(metronomes_controls.keys()),
[val[self.inst_number] for val in metronomes_controls.values()]))
def beat(self):
if self.active == True:
print('Tick', self.tempo) #this is going to be a sound
time.sleep(int(round(60/self.tempo)))
clear_output()
self.update()
else:
self.update()
def update(self):
msg = self.inport.receive(block=False)
for msg in inport.iter_pending():
if msg.control == self.controls['tempo_knob']:
self.tempo = int(interp(msg.value,[0,127],[20,99]))
if msg.control == self.controls['play_stop']:
self.selector += 1
if self.selector >3:
self.selector = 0
if 'ON' in self.on_off_list[self.selector]:
print('ON')
self.active = True
if 'OFF' in self.on_off_list[self.selector]:
print('OFF')
self.active = False
#Creating two instances of my class
m0 = Metronome(inport = inport, inst_number = 0)
m1 = Metronome(inport = inport,inst_number = 1)
m2 = Metronome(inport = inport,inst_number = 1)
m3 = Metronome(inport = inport,inst_number = 1)
#They run on a while loop. All should start at the same time.
while True:
m0.beat()
m1.beat()
m2.beat()
m3.beat()
I read about threading but it seems to create some starting delay. Then I got into barries, but I couldn't imagine how to implement it :/ or maybe should I try something with multiprocess? I got really lost! Any advice is highly appreciated
Thanks for the help!!!
Create one thread per metronome and start them at (almost) the same time:
from threading import Thread
# Previous code...
...
def create_thread(inport, inst_number):
# The function the thread is going to execute
def inner():
m = Metronome(inport, inst_number)
m.beat()
return Thread(target=inner)
if __name__ == "__main__":
inport = mido.open_input()
# Create the threads
threads = [
create_thread(inport, i) for i in (0, 1, 1, 1)
]
# Start them at (almost) the same time
for t in threads:
t.start()
# Wait for them to finish execution
for t in threads:
t.join()
how do I invoke an error if the start timer class function is invoke twice ? Thanks
import time
class Timer(object):
def __init__(self):
self._startTime = None
self._endTime = None
def start(self):
self._startTime = time.time() if self._startTime is None else print('Started')
def end(self):
self._endTime = time.time()
print('seconds',self._endTime - self._startTime)
t = Timer()
t.start()
t.start() # should give an error
You can create a instance variable (if you want 1 invocation per class instance) or class variable (only 1 invocation in entire lifecycle as class variable is shared by all instances of class) to keep count of number of invocations and when count exceeds some threshold (In your case it's 1), you can raise an exception. Something like this:
import time
class Timer(object):
def __init__(self):
self._startTime = None
self._endTime = None
self.count = 0 # Instance variable, which allows 1 invocation per instance of this class
def start(self):
self.count+=1
if self.count == 2: # Threshold is 2 here
raise Exception # You custom exception here
self._startTime = time.time() if self._startTime is None else print('Started')
def end(self):
self._endTime = time.time()
print('seconds',self._endTime - self._startTime)
Refer this for more details about class variables vs instance variable in Python.
I am running a flask application which shall call a function getSomething(input) every day at the same time. This function returns a string. I can not return a print() because I need to pass the string to another function.
When using the Timer function
t = Timer(secs, getSomething, args=[input])
I do not know how to aces the return value of the getSomething function.
example:
from datetime import datetime, timedelta
from threading import Timer
# This shall trigger something at a certain time^
x = datetime.today()
y = x + timedelta(seconds=5)
delta_t = y - x
secs = delta_t.seconds + 1
def getSomething(a):
b = a + " Hello World"
return b
s = "Test"
t = Timer(secs, getSomething, args=[s])
t.start()
I know the very same question has been asked here before. But I am not able to adapt it to my problem though I think i can not avoid the return.
The problem can be solved the following way:
from datetime import datetime, timedelta
from threading import Timer
d = [] # use list, dictionary, some class or queue.Queue to store data
def getSomething(a):
global d
d.append(a + " Hello World")
if __name__ == "__main__":
# This shall trigger something at a certain time^
x = datetime.today()
y = x + timedelta(seconds=5)
delta_t = y - x
secs = delta_t.seconds + 1
s = "Test"
t = Timer(secs, getSomething, args=[s])
t.start()
t.join() # need to wait until thread is finished to get new d value
print(d[0])
Another exmple how you can get data from another thread:
from threading import Thread
import time
class Storage:
def __init__(self):
self.storage = ""
class MyThread(Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None):
super().__init__(group=group, target=target, name=name, daemon=daemon)
self.args = args
self.kwargs = kwargs
def run(self):
self.args[0].storage += "Hello!"
if __name__ == "__main__":
s = Storage()
branch = MyThread(args=(s,),)
branch.start()
time.sleep(1) # need some time to wait for another thread
print(s.storage)
I have a problem with my code. I'm running this code with thread, then I need to ask about variables SPEED, etc., but I don't know how. I'm still trying to do this, but I'm getting errors with thread.
BTW, I want to make a script that generates fake car data, and I need to fill a database, and then make some diagrams.
import time
import thread
class Test:
def __init__(self):
self.speed = 0
self.dist = 0
self.maxSpeed = 150
self.time = 6
self.fuel = 100
self.distance = 100
self.start = time.time()
self.elapsed = 0
def jazda(self):
while True:
self.speed += 1
if self.speed < self.maxSpeed:
time.sleep(1)
else:
time.sleep(60)
self.elapsed = time.time() - self.start
self.dist = (self.speed * self.elapsed) / 3600
print "Distance: ", self.dist
print "Speed: ", self.speed
print "Time: ", self.elapsed
if self.elapsed > self.time:
break
return 0
def SPEED(self):
return self.speed
and second script:
import test
import thread
import time
class Data:
def __init__(self):
self.test = test.Test()
def get_speed(self):
while True:
return self.test.SPEED()
time.sleep(2)
thread.start_new_thread( test.Test().jazda(), () )
thread.start_new_thread( obdData().get_speed, () )
The error I'm getting is:
thread.start_new_thread( Test().jazda(), () )
TypeError: first arg must be callable
I believe the problem is that the thread.start_new_thread method is expecting a method reference and not a method invocation i.e. test.Test().jazda is a method reference i.e. callable; however, test.Test().jazda() will return the result of the method (0 in this case) not a callable. Your start method should look like thread.start_new_thread(test.Test().jazda, ())
I am trying to write a method that counts down to a given time and unless a restart command is given, it will execute the task. But I don't think Python threading.Timer class allows for timer to be cancelable.
import threading
def countdown(action):
def printText():
print 'hello!'
t = threading.Timer(5.0, printText)
if (action == 'reset'):
t.cancel()
t.start()
I know the above code is wrong somehow. Would appreciate some kind guidance over here.
You would call the cancel method after you start the timer:
import time
import threading
def hello():
print "hello, world"
time.sleep(2)
t = threading.Timer(3.0, hello)
t.start()
var = 'something'
if var == 'something':
t.cancel()
You might consider using a while-loop on a Thread, instead of using a Timer.
Here is an example appropriated from Nikolaus Gradwohl's answer to another question:
import threading
import time
class TimerClass(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.event = threading.Event()
self.count = 10
def run(self):
while self.count > 0 and not self.event.is_set():
print self.count
self.count -= 1
self.event.wait(1)
def stop(self):
self.event.set()
tmr = TimerClass()
tmr.start()
time.sleep(3)
tmr.stop()
I'm not sure if I understand correctly. Do you want to write something like in this example?
>>> import threading
>>> t = None
>>>
>>> def sayHello():
... global t
... print "Hello!"
... t = threading.Timer(0.5, sayHello)
... t.start()
...
>>> sayHello()
Hello!
Hello!
Hello!
Hello!
Hello!
>>> t.cancel()
>>>
The threading.Timer class does have a cancel method, and although it won't cancel the thread, it will stop the timer from actually firing. What actually happens is that the cancel method sets a threading.Event, and the thread actually executing the threading.Timer will check that event after it's done waiting and before it actually executes the callback.
That said, timers are usually implemented without using a separate thread for each one. The best way to do it depends on what your program is actually doing (while waiting for this timer), but anything with an event loop, like GUI and network frameworks, all have ways to request a timer that is hooked into the eventloop.
Im not sure if best option but for me is woking like this:
t = timer_mgr(.....) append to list "timers.append(t)" and then after all created you can call:
for tm in timers:#threading.enumerate():
print "********", tm.cancel()
my timer_mgr() class is this:
class timer_mgr():
def __init__(self, st, t, hFunction, id, name):
self.is_list = (type(st) is list)
self.st = st
self.t = t
self.id = id
self.hFunction = hFunction
self.thread = threading.Timer(t, self.handle_function, [id])
self.thread.name = name
def handle_function(self, id):
if self.is_list:
print "run_at_time:", datetime.now()
self.hFunction(id)
dt = schedule_fixed_times(datetime.now(), self.st)
print "next:", dt
self.t = (dt-datetime.now()).total_seconds()
else:
self.t = self.st
print "run_every", self.t, datetime.now()
self.hFunction(id)
self.thread = threading.Timer(self.t, self.handle_function, [id])
self.thread.start()
def start(self):
self.thread.start()
def cancel(self):
self.thread.cancel()
Inspired by above post.
Cancelable and Resetting Timer in Python. It uses thread.
Features: Start, Stop, Restart, callback function.
Input: Timeout, sleep_chunk values, and callback_function.
Can use or inherit this class in any other program. Can also pass arguments to the callback function.
Timer should respond in middle also. Not just after completion of full sleep time. So instead of using one full sleep, using small chunks of sleep and kept checking event object in loop.
import threading
import time
class TimerThread(threading.Thread):
def __init__(self, timeout=3, sleep_chunk=0.25, callback=None, *args):
threading.Thread.__init__(self)
self.timeout = timeout
self.sleep_chunk = sleep_chunk
if callback == None:
self.callback = None
else:
self.callback = callback
self.callback_args = args
self.terminate_event = threading.Event()
self.start_event = threading.Event()
self.reset_event = threading.Event()
self.count = self.timeout/self.sleep_chunk
def run(self):
while not self.terminate_event.is_set():
while self.count > 0 and self.start_event.is_set():
# print self.count
# time.sleep(self.sleep_chunk)
# if self.reset_event.is_set():
if self.reset_event.wait(self.sleep_chunk): # wait for a small chunk of timeout
self.reset_event.clear()
self.count = self.timeout/self.sleep_chunk # reset
self.count -= 1
if self.count <= 0:
self.start_event.clear()
#print 'timeout. calling function...'
self.callback(*self.callback_args)
self.count = self.timeout/self.sleep_chunk #reset
def start_timer(self):
self.start_event.set()
def stop_timer(self):
self.start_event.clear()
self.count = self.timeout / self.sleep_chunk # reset
def restart_timer(self):
# reset only if timer is running. otherwise start timer afresh
if self.start_event.is_set():
self.reset_event.set()
else:
self.start_event.set()
def terminate(self):
self.terminate_event.set()
#=================================================================
def my_callback_function():
print 'timeout, do this...'
timeout = 6 # sec
sleep_chunk = .25 # sec
tmr = TimerThread(timeout, sleep_chunk, my_callback_function)
tmr.start()
quit = '0'
while True:
quit = raw_input("Proceed or quit: ")
if quit == 'q':
tmr.terminate()
tmr.join()
break
tmr.start_timer()
if raw_input("Stop ? : ") == 's':
tmr.stop_timer()
if raw_input("Restart ? : ") == 'r':
tmr.restart_timer()