Python match on a Sume /v1/videos poll: five statuses, one handler
Python 3.10 structural matching on the poll dict: wait on pending and in_progress, return on completed, raise on failed or cancelled. Runs under asyncio.run.

Python's match statement fits the Sume video poll well, because the response is a dict with a status string and a few optional keys. One match can route the five statuses, pull unsigned_urls only when it exists, and make a typo in a status name visible, since an unknown value falls into the final case.
The statuses
The poll on /v1/videos uses pending, in_progress, completed, failed and cancelled. The jobs surface at /v1/jobs/{id}/status uses queued, processing, completed, failed and canceled, so match on the spelling that belongs to the route you poll.
| Status | Loop action |
|---|---|
| pending | sleep and poll again |
| in_progress | sleep and poll again |
| completed | return unsigned_urls[0] |
| failed | raise with the error string |
| cancelled | raise a cancelled error |
An async loop
The code uses httpx with a 60-second request timeout and sleeps 30 seconds between polls, as the docs suggest. It runs under asyncio.run. The case {"status": "completed", "unsigned_urls": [first, *_]} pattern both checks the status and binds the first URL; if the key is missing, the case simply does not match and the final case raises.
import asyncio
import os
import httpx
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
async def wait(client: httpx.AsyncClient, polling_url: str) -> str:
while True:
poll = (await client.get(polling_url, headers=H)).json()
match poll:
case {"status": "pending" | "in_progress"}:
await asyncio.sleep(30)
case {"status": "completed", "unsigned_urls": [first, *_]}:
return first
case {"status": "failed", "error": str(msg)}:
raise RuntimeError(f"failed: {msg}")
case {"status": "failed" | "cancelled" as s}:
raise RuntimeError(s)
case _:
raise RuntimeError(f"unexpected poll: {poll}")
async def main() -> None:
async with httpx.AsyncClient(timeout=60) as client:
print(await wait(client, os.environ["POLLING_URL"]))
asyncio.run(main())Testing the handler without the network
Because wait takes the client as an argument, you can pass an httpx.AsyncClient built on httpx.MockTransport that returns a scripted list of poll bodies: pending, in_progress, then completed with one URL. Patch asyncio.sleep to return at once, and the test finishes in milliseconds. Add one case per status and one for a body with no status key, and every branch of the match is covered.
That is a better use of a test than hitting the real API, which would reserve funds for every run.
Why the last case matters
Sume maps any status it does not know to failed on this route, so an unknown value should not reach you in practice. The case _ branch protects against the other kind of surprise: a proxy page, an error envelope, or a body missing status. In those cases the right behaviour is to stop and log, not to loop forever.
Add a deadline around the whole loop with asyncio.timeout, because the poll itself never ends on its own when a job stays pending. See the wait-for-job read budget for the matching numbers on the SDK.
- Python 3.10 or later is required for
match. - Keep the sleep at 30 seconds unless you have measured that you need less.
- Handle
cancelledseparately if users can cancel from your UI.
Sources
Related posts
More in Developers
- Parse Retry-After as seconds or HTTP-date before retrying a Sume 429
A 21-line Python helper that reads retry-after as integer seconds or an HTTP-date, caps the wait, and falls back to exponential delay when the header is absent.
- Save a Sume job's result artifacts in Python by content type
Fetch GET /v1/jobs/:id/result and save each artifact with an extension from content_type, not the URL. Standard library only, with a text-result guard.
- Python: submit, poll and download one Omni Flash clip (v1/videos)
A short Python script that submits a Gemini Omni Flash 1.1 request to Sume's /v1/videos, polls the job until it completes and saves the MP4.
- Python urllib: retry a Sume video submit on 429 and 503, no requests
A standard-library Python function that retries a Sume video submit on 429 and 503, reusing one Idempotency-Key and reading Retry-After. Tested on a stub.
Written by Sume