def _debug(self, message: str) -> None: """ Write a debug message to the transcript. :param message: The message to write. :return: None """ thread_meeting.transcribe(message, ti_type=thread_meeting.TranscriptType.Debug)
def execute_meeting(*args) -> None: """ Launch all workers and wait for them to complete. The first exception found is raised, if any. :param args: Zero or more Worker-based objects to launch. :return Nothing. """ if 0 == len(args): # A meeting with nobody in it. Cancel it. thread_meeting.transcribe("Canceled meeting with no attendees.") return workers = args with concurrent.futures.ThreadPoolExecutor( max_workers=len(args)) as executor: # We MUST have the starting baton before creating workers, # otherwise they WILL keep us from getting it. baton = thread_meeting.primary_baton() if not baton: # Should NEVER happen! raise RuntimeError("Could not get starting baton!") try: futures = list() workers_are_idle = True for worker in workers: # Start the worker worker.meeting_members = workers futures.append(executor.submit(worker.thread_entry)) # Wait for the worker to hit IDLE. for i in range(30): state = worker.state if state == WorkerState.IDLE: break time.sleep(0.3) if not WorkerState.IDLE == state: # If initialization takes more than 9 seconds, assume # something is wrong. The Worker has likely generated # an exception. We will catch it below. raise RuntimeError( "Created worker did not reach IDLE state") if workers_are_idle: baton.post(Message.START.value, None) # OK, let's go! # Now nothing to do but wait for workers to end. If they 'raise' # then future.result() here will also raise. for future in concurrent.futures.as_completed(futures): future.result() except BaseException as e: thread_meeting.transcribe("Exception in primary thread") baton.post(Message.QUIT.value, None) raise
def state(self) -> WorkerState: if not self._attendee: new_state = WorkerState.FINAL if self._state else WorkerState.INIT elif self._fad.func == self.on_idle: new_state = WorkerState.IDLE else: new_state = WorkerState.BUSY if new_state != self._state: thread_meeting.transcribe(new_state.value, thread_meeting.TranscriptType.State) self._state = new_state return self._state
def _wrapper(*args, **kwargs): attendee = meeting.me() with attendee.request_baton() as baton: if baton is None: meeting.transcribe("Failed to acquire baton", ti_type=meeting.TranscriptType.Debug) if message is not None: time.sleep(0.1) attendee.note(message.value, payload) return None modified_kwargs = {k: v for k, v in kwargs.items()} result = func(*args, baton=baton, **modified_kwargs) return result
def test_transcribe_returns_item_with_transcriber(self): message = "Message will be returned" with thread_meeting.transcriber() as transcriber: self.assertIsNotNone(transcriber) item = transcribe(message) self.assertIsNotNone(item) self.assertEqual(item.message, message) expected = (TI('Transcript', TT.Enter), TI(message, TT.Custom), TI('Transcript', TT.Exit)) self.verify_transcript_items(transcriber, *expected)
def _wrapper(*args, **kwargs): current_state = state_object.state name = func.__name__ # if not hasattr(func, 'name') else func.name message = "Method:{}()".format(name) try: meeting.transcribe(message, meeting.TranscriptType.Enter) result = func(*args, **kwargs) except Interruption: meeting.transcribe("Interrupted", meeting.TranscriptType.Custom) result = None finally: meeting.transcribe(message, meeting.TranscriptType.Exit) return result
def test_transcribe_returns_none_without_transcriber(self): message = "Message will be dropped" item = transcribe(message) self.assertEqual(item, None)
def test_transcribe_can_succeed(self): transcribe("Hello")
def test_transcribe_requires_valid_transcript_type(self): with self.assertRaises(TypeError) as context: transcribe("Hello", 1) self.assertTrue( "incompatible function arguments" in str(context.exception), str(context.exception))