def test_wait_for_one_with_error_and_completed(): def raise_error(): raise DummyTestError() task1 = Task(raise_error).start() time.sleep(0.1) with pytest.raises(DummyTestError): Task.wait_for_one([task1], timeout=1)
def call_method(*args, **kwargs): task = Task( fun, use_daemon_thread=use_daemon_thread, thread_name=thread_name, event_name=event_name, use_async_loop=use_async_loop, ) task.start(*args, **kwargs) return task
def test_wait_for_one(): def coro(t): time.sleep(t) return "test" task1 = Task(coro).start(0.1) task2 = Task(coro).start(0.2) Task.wait_for_one([task1, task2], timeout=1) assert not task1.is_running and task2.is_running, "Failed to wait for task"
def test_wait_for_events_with_error(): def send_event(): time.sleep(0.1) raise DummyExcpetion() task = Task(send_event).start() with pytest.raises(DummyExcpetion): task.wait_for_events(lambda sender, name, *args: name == "test_event", [task], timeout=1)
def test_wait_for_all(): def coro(t): time.sleep(t) return "test" task1 = Task(coro).start(0.1) task2 = Task(coro).start(0.2) task3 = Task(coro).start(0.3) Task.wait_for_all([task1, task2, task3]) assert not task1.is_running and not task2.is_running and not task3.is_running, "Failed to wait for task"
def test_wait_for_some(): def coro(t): time.sleep(t) return "test" task1 = Task(coro).start(0.1) task2 = Task(coro).start(0.2) task3 = Task(coro).start(0.3) Task.wait_for_some([task1, task2, task3], timeout=1, wait_count=2) assert not task1.is_running and not task2.is_running and task3.is_running, "Failed to wait for task"
def test_threaded_waiter(): waiter = ThreadingWaiter(is_asyncio=False) def release(): sleep(3) waiter.release() rtask = Task(release).start() waiter.wait(1)
def test_wait_for_events_none(): hndl = events.EventHandler() def send_event(): time.sleep(0.1) hndl.emit("test_event") Task(send_event).start() rslt = hndl.wait_for_events(None, [hndl], timeout=1) assert rslt[0] is hndl, "Did not return correct handler"
def test_wait_for_self(): hndl = events.EventHandler() def send_event(): time.sleep(0.1) hndl.emit("test_event") # asyncio will not work here :) Task(send_event).start() hndl.wait_for("test_event", timeout=1)
def test_wait_for_events_predict(): hndl = events.EventHandler() def send_event(): time.sleep(0.1) hndl.emit("test_event") Task(send_event).start() rslt = hndl.wait_for_events( lambda sender, event: event.name == "test_event", [hndl], timeout=1) assert rslt[0] is hndl, "Did not return correct handler"
async def test_events_stream_in_corutine_asyncio(): hndl = events.EventHandler() strm = hndl.stream(timeout=0.1, use_async_loop=True) async def send_event(): hndl.emit("test_event") hndl.stop_all_streams() Task(send_event).start() await asyncio.sleep(0.01) # allow the other task to execute. assert (await strm.__anext__()).name == "test_event"
def test_wait_for_events(): hndl = events.EventHandler() def send_event(): time.sleep(0.1) hndl.emit("test_event") # asyncio will not work here :) Task(send_event).start() rslt = hndl.wait_for_events("test_event", [hndl], timeout=1) assert rslt[0] is hndl, "Did not return correct handler"
def __init__( self, parent, fun, on_error: str = None, use_daemon_thread: bool = True, ignore_waiting_calls_timeout: Union[timedelta, float] = None, ): super().__init__() thread_name = f"ccc_async::{fun.__module__}::{fun.__qualname__}" if parent is not None: thread_name = f"{thread_name} (oid: {id(parent)})" self.task = Task(fun, thread_name=thread_name, use_daemon_thread=use_daemon_thread) self.is_waiting_on_call = False self.was_triggered = False self.parent = parent self.invoke_error: Callable = None self.last_executed = None self.ignore_waiting_calls_timeout: timedelta = ( None if ignore_waiting_calls_timeout is None else ( ignore_waiting_calls_timeout if isinstance(ignore_waiting_calls_timeout, timedelta) else timedelta(ignore_waiting_calls_timeout) ) ) if isinstance(on_error, str): assert parent is not None, ValueError("Cannot assign on_error as string to a non class method") assert hasattr(parent, on_error), ValueError( f"Error method not found in {parent.__class__.__name__}.{on_error}" ) self.invoke_error = getattr(parent, on_error) elif on_error is not None: assert callable(on_error), ValueError("On error must be a callable or a string") self.invoke_error = on_error self.task.on(self.task.error_event_name, lambda task, ex: self.on_error(ex)) self.task.on(self.task.event_name, lambda *args, **kwargs: self.on_done())
def test_wait_for_self_emit_error(): parent = events.EventHandler() child = events.EventHandler() parent.pipe(child) def send_event(): time.sleep(0.1) parent.emit_error(DummyExcpetion("from parent")) Task(send_event).start() with pytest.raises(DummyExcpetion): child.wait_for("test_event", timeout=1)
async def test_events_stream_stop_asyncio(): hndl = events.EventHandler() async def send_event(): await asyncio.sleep(0.01) hndl.stop_all_streams() # asyncio will not work here :) Task(send_event).start() strm = hndl.stream(timeout=1) for v in strm: pass
def test_wait_for_self_emit_error_no_raise(): parent = events.EventHandler() child = events.EventHandler() parent.pipe(child) def send_event(): time.sleep(0.1) parent.emit_error(DummyExcpetion("from parent")) Task(send_event).start() rsp = child.wait_for("test_event", timeout=1, raise_errors=False) assert isinstance(rsp, DummyExcpetion)
def test_wait_for_self_with_predict_error(): hndl = events.EventHandler() def send_event(): time.sleep(0.1) hndl.emit("test_event") def predict(sender: events.EventHandler, event: events.Event): raise DummyExcpetion("error") # asyncio will not work here :) Task(send_event).start() with pytest.raises(DummyExcpetion): hndl.wait_for(predict, timeout=1)
def test_events_streams_using_threads(): hndl = events.EventHandler() def do_emit(): for i in range(0, 4): hndl.emit("test") time.sleep(0.001) hndl.stop_all_streams() event_stream = hndl.stream("test") Task(do_emit).start() col = [] for ev in event_stream: col.append(ev) assert len(col) == 4
def test_wait_for_self_predict(): parent = events.EventHandler() child = events.EventHandler() parent.pipe(child) def send_event(): time.sleep(0.1) parent.emit("test_event", 22) def predict(sender: events.EventHandler, event: events.Event): assert sender != event.sender assert event.name == "test_event" return True # asyncio will not work here :) Task(send_event).start() child.wait_for(predict=predict, timeout=1)
from random import random from time import sleep from zthreading.tasks import Task # A task is an EventHandler, and has the # on method as well. task: Task = None def invoke_timed_events(): sleep(1) for i in range(1, 10): sleep(random() / 10) task.emit("test", f"loop index {i}") task.stop_all_streams() task = Task(invoke_timed_events).start() for ev in task.stream("test"): print(f"{ev.name}, {ev.args[0]}")
def test_return_value_using_thread(): def return_something(): return "test" assert Task(return_something).start().join() == "test"
def test_return_value_using_asyncio(): async def return_something(): return "test" assert Task(return_something, use_async_loop=True).start().join() == "test"
def test_already_running(): async def coro(): await asyncio.sleep(0.1) return "test" task1 = Task(coro, use_async_loop=True) task2 = Task(coro, use_async_loop=True) def start_task(task): task.start() main_task_1 = Task(start_task, use_async_loop=False).start(task1) main_task_2 = Task(start_task, use_async_loop=False).start(task2) time.sleep(0.01) task1.join() task2.join() main_task_1.join() main_task_2.join()
handler.emit("test", "the message") from zthreading.events import EventHandler from zthreading.tasks import Task handler = EventHandler() def handle_test_event(msg: str): print("The event messge: " + msg) def run_in_a_different_thread(msg): handler.emit("test", msg) handler.on("test", handle_test_event) Task(run_in_a_different_thread).start("A message from a thread").join() from zthreading.decorators import collect_consecutive_calls_async @collect_consecutive_calls_async() def consecutive_calls_action(): # Like save this to file.. for example. # should be printed twice, once for the first call, and another for the last call. print("consecutive called action") for i in range(1, 20): consecutive_calls_action()