Python 3.14.8 urllib: poll a Sume job with only the stdlib
Python 3.14.8 shipped 30 September 2026. A urllib-only loop for GET /v1/jobs/:id/status with a 20-minute client deadline and no third-party packages.

Short answer
You do not need requests to poll Sume. urllib.request with a timeout, a while loop bounded by time.monotonic(), and time.sleep(next_poll_after_seconds) covers it. The Python 3.14.8 page gives 30 September 2026 as the release date and describes around 354 bugfixes, build improvements and documentation changes since 3.14.7.
The same page says the release addressed nine security vulnerabilities, naming SSL context handling, tarfile extraction filters, zipfile decompression and urllib credential management among them. That is a reason to keep a small poller on a current patch release rather than to pin an old interpreter.
What the 3.14.8 page says
Only the security note is relevant to a stdlib HTTP client. The rest is general maintenance.
| Item | Detail |
|---|---|
| Release date | 30 September 2026 |
| Size | around 354 changes from 142 contributors since 3.14.7 |
| Security | nine vulnerabilities addressed, including urllib credential management |
| Bundled | Expat 2.8.5; OpenSSL 3.5.9 for certain platforms |
A loop with a client-side deadline
Sume's docs call this the official equivalent of a client subscribe(): submit with async, poll the status, read the result only when it completed. The deadline lives in your process and can be minutes, because it is not an HTTP hold. Run SUME_API_KEY=... python3 poll.py job_123.
import json, os, sys, time, urllib.request
def get(url):
req = urllib.request.Request(
url, headers={"Authorization": "Bearer " + os.environ["SUME_API_KEY"]})
with urllib.request.urlopen(req, timeout=20) as res:
return json.load(res)["data"]
base = f"https://api.sume.com/v1/jobs/{sys.argv[1]}"
deadline = time.monotonic() + 20 * 60
while time.monotonic() < deadline:
s = get(base + "/status")
if s["terminal"]:
break
time.sleep(s.get("next_poll_after_seconds") or 2)
else:
raise SystemExit("deadline passed; the job is still running and still billing")
if s["sume_status"] == "completed":
print(json.dumps(get(base + "/result"), indent=2))
else:
print("terminal:", s["sume_status"])Failure paths worth handling
urllib raises HTTPError on a non-2xx answer, so a 429 surfaces as an exception with a Retry-After header, and a 404 not_found means the job belongs to another workspace or another member's key. Catch HTTPError around get if you want to sleep and continue on 429 instead of exiting.
GET /v1/jobs/:id/result answers 409 job_not_completed for a failed or canceled job, which is why the script branches on sume_status before calling it.
What Sume does and does not do
Sume keeps the job running and billing after your deadline passes, and exposes POST /v1/jobs/:id/cancel for a job that has not started generation. After generation starts the cancel route answers 409 job_generation_already_started and the job runs to completion.
The Developer API has no streaming transport, so a loop like this one, or a webhook, is the way to learn the outcome.
Sources
Related posts
More in Developers
- Python 3.15 json array_hook: freeze a Sume job result
Python 3.15 adds array_hook to json.load and json.loads. Pair it with frozendict to hold a completed Sume job result as deeply immutable data you can share.
- Python 3.15 lazy import in a Sume webhook handler: what to defer
Python 3.15 adds the lazy import keyword. In a Sume webhook receiver with a 10-second attempt budget, defer only the modules the signature check does not need.
- Python 3.15 UTF-8 default: still verify Sume webhooks on raw bytes
Python 3.15 makes UTF-8 the default for open() without an encoding. It does not change that a Sume signature covers raw body bytes, so verify before any parse.
- Python: list Sume video models that accept a video input
A 20-line Python script reads GET /v1/videos/models and prints every model whose supported_input_references include video_url, with its duration range.
Written by Sume