diff --git a/giambio/_core.py b/giambio/_core.py index c0e2a4b..01f11c2 100644 --- a/giambio/_core.py +++ b/giambio/_core.py @@ -68,14 +68,12 @@ class AsyncScheduler: except BaseException as error: self.current_task.exc = error self.reschedule_parent(self.current_task) - raise # Maybe find a better way to propagate errors? if self.selector.get_map(): try: self.check_io() except BaseException as error: self.current_task.exc = error self.reschedule_parent(self.current_task) - raise # Maybe find a better way to propagate errors? while self.tasks: # While there are tasks to run self.current_task = self.tasks.popleft() # Sets the currently running task try: @@ -97,7 +95,6 @@ class AsyncScheduler: except BaseException as error: # Coroutine raised self.current_task.exc = error self.reschedule_parent(self.current_task) - raise # Maybe find a better way to propagate errors? def check_events(self): """Checks for ready or expired events and triggers them""" @@ -206,10 +203,18 @@ class AsyncScheduler: coroutine returns or, if an exception gets raised, the exception will get propagated inside the parent task""" - if child not in self.joined: - self.joined[child] = self.current_task + if child.cancelled: # Task was cancelled and is therefore dead + self.tasks.append(self.current_task) + elif child.exc: # Task raised an error, propagate it! + self.reschedule_parent(child) + raise child.exc + elif child.finished: + self.tasks.append(self.current_task) # Task has already finished else: - raise AlreadyJoinedError("Joining the same task multiple times is not allowed!") + if child not in self.joined: + self.joined[child] = self.current_task + else: + raise AlreadyJoinedError("Joining the same task multiple times is not allowed!") def sleep(self, seconds: int or float): """Puts the caller to sleep for a given amount of seconds""" diff --git a/giambio/_traps.py b/giambio/_traps.py index 74fe49a..8f8d5a9 100644 --- a/giambio/_traps.py +++ b/giambio/_traps.py @@ -14,7 +14,10 @@ See the License for the specific language governing permissions and limitations under the License. """ -"""Helper methods to interact with the event loop""" +# Helper methods to interact with the event loop +# These coroutines are the one and only way to interact +# with the event loop from the user's perspective, and +# the entire library is based on these traps import types import socket @@ -47,7 +50,8 @@ def join(task): :type task: class: Task """ - yield "join", task + res = yield "join", task + return task.result @types.coroutine @@ -89,12 +93,19 @@ def want_write(sock: socket.socket): @types.coroutine def event_set(event, value): + """Communicates to the loop that the given event object + must be set. This is important as the loop constantly + checks for active events to deliver them + """ yield "event_set", event, value @types.coroutine def event_wait(event): + """Notifies the event loop that the current task has to wait + for the event to trigger + """ msg = yield "event_wait", event return msg diff --git a/tests/count.py b/tests/count.py index c12dc2f..558eaea 100644 --- a/tests/count.py +++ b/tests/count.py @@ -7,7 +7,7 @@ async def countdown(n: int): n -= 1 await giambio.sleep(1) print("Countdown over") - + return 0 async def countup(stop: int, step: int = 1): x = 0 @@ -16,6 +16,7 @@ async def countup(stop: int, step: int = 1): x += 1 await giambio.sleep(step) print("Countup over") + return 1 async def main(): @@ -24,10 +25,11 @@ async def main(): print("Counters started, awaiting completion") await giambio.sleep(2) print("Slept 2 seconds, killing countup") - await cup.cancel() ## DOES NOT WORK!!! + await cup.cancel() print("Countup cancelled") - await cup.join() - await cdown.join() + up = await cup.join() + down = await cdown.join() + print(f"Countup returned: {up}\nCountdown returned: {down}") print("Task execution complete") if __name__ == "__main__":