def close(self, *, ensure_done: bool = True): """ Closes the event loop, terminating all tasks inside it and tearing down any extra machinery. If ensure_done equals False, the loop will cancel ALL running and scheduled tasks and then tear itself down. If ensure_done equals True, which is the default behavior, this method will raise a GiambioError exception if the loop hasn't finished running. The state of the event loop is reset so it can be reused with another run() call """ if ensure_done: self.cancel_all() elif not self.done(): raise GiambioError( "event loop not terminated, call this method with ensure_done=False to forcefully exit" ) self.shutdown() # We reset the event loop's state self.tasks = [] self.entry_point = None self.current_pool = None self.current_task = None self.paused = TimeQueue(self.clock) self.deadlines = DeadlinesQueue() self.run_ready = deque() self.suspended = deque()
def run(func: FunctionType, *args, **kwargs): """ Starts the event loop from a synchronous entry point """ if inspect.iscoroutine(func): raise GiambioError( "Looks like you tried to call giambio.run(your_func(arg1, arg2, ...)), that is wrong!" "\nWhat you wanna do, instead, is this: giambio.run(your_func, arg1, arg2, ...)" ) elif not inspect.iscoroutinefunction(func): raise GiambioError( "giambio.run() requires an async function as parameter!") new_event_loop(kwargs.get("debugger", None), kwargs.get("clock", default_timer)) get_event_loop().start(func, *args)
def reschedule_running(self): """ Reschedules the currently running task """ if self.current_task: self.run_ready.append(self.current_task) else: raise GiambioError("giambio is not running")
def get_event_loop(): """ Returns the event loop associated to the current thread """ try: return thread_local.loop except AttributeError: raise GiambioError("giambio is not running") from None
async def trigger(self, value: Optional[Any] = None): """ Sets the event, waking up all tasks that called pause() on it """ if self.set: raise GiambioError("The event has already been set") self.value = value await event_set(self, value)
async def create_task(coro: Callable[..., Coroutine[Any, Any, Any]], pool, *args): """ Spawns a new task in the current event loop from a bare coroutine function. All extra positional arguments are passed to the function This trap should *NOT* be used on its own, it is meant to be called from internal giambio machinery """ if inspect.iscoroutine(coro): raise GiambioError( "Looks like you tried to call giambio.run(your_func(arg1, arg2, ...)), that is wrong!" "\nWhat you wanna do, instead, is this: giambio.run(your_func, arg1, arg2, ...)" ) elif inspect.iscoroutinefunction(coro): return await create_trap("create_task", coro, pool, *args) else: raise TypeError("coro must be a coroutine function")
def new_event_loop(debugger: BaseDebugger, clock: FunctionType): """ Associates a new event loop to the current thread and deactivates the old one. This should not be called explicitly unless you know what you're doing. If an event loop is currently set and it is running, a GiambioError exception is raised """ try: loop = get_event_loop() except GiambioError: thread_local.loop = AsyncScheduler(clock, debugger) else: if not loop.done(): raise GiambioError("cannot change event loop while running") else: loop.close() thread_local.loop = AsyncScheduler(clock, debugger)