We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Coroutines & the Event Loop

Python's solution to async is the coroutine. A coroutine function (declared with async def) doesn't run when you call it – it hands you a coroutine object, a task the event loop can schedule later. While one coroutine is paused (e.g. waiting for I/O, a timer), the loop can give CPU time to something else, so your program never has to freeze.

Declaring a Coroutine

import asyncio
import random


async def dice_roll() -> str:
    await asyncio.sleep(1)  # pretend we're waiting on I/O
    if random.random() < 0.5:
        return "success!"
    raise Exception("failure!")

Calling dice_roll() returns a coroutine object immediately.

Awaiting a Coroutine

async def main() -> None:
    try:
        msg = await dice_roll()  # the event loop runs dice_roll() here
        print(msg)
    except Exception as err:
        print(f"oops: {err}")

await pauses main() and hands control back to the event loop until dice_roll() completes.

Assignment

In Jello, tasks finish at unpredictable times. We simulate this with an async delay so that all tests complete in roughly 2 seconds.

Complete the update_task_status coroutine. It takes the following arguments:

  • task_id: a string – the task ID
  • current_status: a string – e.g. "In Progress", "Blocked"
  • is_completed: a boolean – whether the task is marked as completed

Return based on the following rules:

Task TASKID has been completed successfully.
Task TASKID is still in progress and cannot be completed.
Task TASKID status updated to CURRENT_STATUS.

TASKID and CURRENT_STATUS must be replaced with the arguments passed into the function.