def test_observable_notify(): c = Observable() c.set(5) assert c.get() == 5 triggered = [False] def f(c): triggered[0] = True c.add_listener(f) c.set(10) assert triggered[0] triggered = [False] c.remove_listener(f) c.set(20) assert not triggered[0] c.add_listener(f) c.notify_all() assert triggered[0]
class CalibrationProgramThread(KillableThread): """ This thread is a calibration utility that takes many samples per second, and automatically switches through the grid points. """ def __init__(self, generator, fp): KillableThread.__init__(self) self.fp = fp self.fps = 10 self.generator = generator self.seconds_per_point = 10 self.seconds_between_points = 5 self._current_time = 0 self._currently_sampling = Observable() self._currently_sampling.set(False) self._time_when_sampling_started = 0 self._time_when_sampling_stopped = 0 def loop(self): if not self.dead: self._current_time += 1.0 / self.fps if self._currently_sampling.get(): # Stop sampling after a certain time twss = self._time_when_sampling_started if self._current_time - twss > self.seconds_per_point: # Disable sampling self.fp.forces_after_calibration.remove_listener( self.generator.take_sample) if not self.generator.grid.hasMorePoints: self.kill() self.generator.grid.next() self._time_when_sampling_stopped = self._current_time self._currently_sampling.set(False) else: # Start sampling after certain time twss = self._time_when_sampling_stopped if self._current_time - twss > self.seconds_between_points: # Enable sampling self.fp.forces_after_calibration.add_listener( self.generator.take_sample) self._time_when_sampling_started = self._current_time self._currently_sampling.set(True)
class PyGameThread(threading.Thread): """ Invoke a thread of drawing pygame graphics in a new window. """ options = pygame.HWSURFACE | pygame.DOUBLEBUF | pygame.RESIZABLE def __init__(self): threading.Thread.__init__(self) self.dead = False self.fps = 60 # This lock is necessary so that we do not close the pygame display while # the loop() method is running; doing so will result in a "video system not # initialized" error. # We also use the lock to prevent calling pygame.init() and pygame.quit() # concurrently. self.pygame_lock = threading.Lock() self._draw_tasks_lock = threading.Lock() self._draw_tasks = [] self.keypress = Observable() def kill(self): with self.pygame_lock: self.dead = True pygame.quit() def add_draw_task(self, t): with self._draw_tasks_lock: self._draw_tasks.append(t) @_exception_wrapper def run(self): with self.pygame_lock: pygame.init() self.screen = pygame.display.set_mode((500, 500), self.options) clock = pygame.time.Clock() pygame.display.set_caption( 'Six-Axis Force Sensors - Weighted Centre of Pressure') s = pygame.Surface((32, 32)) pygame.display.set_icon(s) while True: clock.tick(60) with self.pygame_lock: if self.dead: return self.loop() def loop(self): pygame.event.pump() for event in pygame.event.get(): if event.type == pygame.QUIT: self.pygame_lock.release() self.kill() return elif event.type == pygame.VIDEORESIZE: self.screen = pygame.display.set_mode(event.dict['size'], self.options) elif event.type == pygame.KEYDOWN: self.keypress.set(event.key) self.screen.fill((255, 255, 255)) width = self.screen.get_width() height = self.screen.get_height() # Do some drawing with self._draw_tasks_lock: for task in self._draw_tasks: task(width, height, self.screen, pygame) # Double buffer flip puts drawn graphics on the screen pygame.display.flip() @staticmethod def query_exceptions(): while not _exceptions.empty(): e, traceback = _exceptions.get() # One could replace this with a non-terminating utility, to print # multiple errors; otherwise there isn't much use for the queue. sys.stderr.write(traceback) raise e e.task_done()