One useful idea
An HTTP client connects your code to an external service. A GET asks for data; a status code describes the response. The URL identifies the resource, query parameters describe the request, and the body contains data. A successful status is not enough: the body must also satisfy your contract.
Here you use HTTPX, but every supplied request goes through MockTransport. Its handler receives a real HTTPX request and returns an invented response without connecting to the fictional example.invalid host. The handler is injected: tests can exercise success, rate limits and broken responses without an account, key or paid call. There is no live-provider switch.
A Client owns transport resources. Its stream context manager closes the response when the with block finishes, including when validation raises. Separate the fixed provider URL from params. Refuse invalid IDs and unknown providers before requesting anything; IDs are 1–64 ASCII letters, digits, underscores or hyphens. Explicitly set follow_redirects=False and connect 2s, read/write/pool 5s timeouts. These are phase inactivity limits, not a total deadline; mock tests inspect configuration and inject failures, not real socket timing.
This small policy declares 429, 500, 502, 503, 504, timeout and network failures transient. Other statuses, redirects and malformed responses are permanent; undeclared protocol/programming errors propagate. Retry-After supports only integer seconds 0–60. Refuse dates, invalid or larger values instead of guessing a shorter wait. Require identity content encoding, application/json, strict UTF-8 and a root object; reject duplicate keys, nonfinite numbers, integers over 64 digits and accumulated body bytes above 65,536. That bounds your buffer, not all process memory or a caller that already buffered data.
Refresh first: HTTPX environment setup, Narrow expected failures, Typed JSON data.
Trace a finished example
import httpx
from provider_tools.core import fetch_job
from provider_tools.errors import ResponseError, TransientError
for status in (200, 429, 503, 404):
def handle(request):
return httpx.Response(status, json={"job_id": "job_1", "state": "done"})
with httpx.Client(transport=httpx.MockTransport(handle), trust_env=False) as client:
try:
result = fetch_job(client, "job_1")
except TransientError as error:
print(status, error.reason)
except ResponseError as error:
print(status, error.code)
else:
print(status, "object")Each iteration supplies one invented status. The 200 response becomes a dictionary; 429/503 become controlled transient reasons; 404 is a permanent refusal. Both context managers close their resources. The loop observes expected failures rather than pretending every request succeeded.
The finished implementation is in provider_tools/core.py. Reading it is guided practice, not independent evidence.
Predict the refusal
Should a 200 HTML page become an empty successful job?
Compare your answer · self-reviewed
No. Require application/json and valid object data. A success status alone is not a usable job.
Find the timeout claim
Does read=5 mean the whole request must finish within five seconds?
Compare your answer · self-reviewed
No. It is an inactivity limit for a read phase. Total deadlines require a separate policy, and MockTransport does not prove real elapsed socket timing.
Recall the boundary
Should a TypeError from the handler become a network retry?
Compare your answer · self-reviewed
No. Catch only declared timeout/network errors. A programming mistake must remain visible instead of triggering more requests.
Change it, then build your own
One controlled change
Change job_1 to a new canonical ID and inspect request.url.path and request.url.params in the handler. Then return a 502 response, a redirect and a 200 malformed body. Predict each category before running.
Your independent task
Implement fetch_job in practice.py. You may reuse the reviewed core.validate_job_id, retry_after_seconds and strict JSON hooks _object, _constant, _integer and _float; disclose those supports. Write your own request/stream/status/buffer logic, reject inputs before callbacks, close on every path and catch only the declared HTTPX error families. Do not return canned jobs or accept arbitrary URLs. The caller owns the injected client; replacing the supplied mock transport is outside this safe fixture workflow.
What success looks like
The build1 group passes success, timeout/network/status, invalid-ID, redirect, stream-close and strict bounded-JSON cases. A reference run or mock timeout test is not an independent live API integration. Keep controlled errors; never retain raw headers, URLs, bodies or exception messages in retry logs.
Hint 1 · a question
List the failure categories and validate ID/provider before using the client. Which errors should not reach a retry loop?
Hint 2 · a concept cue
Within client.stream, classify status before reading. Enforce media/encoding and bound each added chunk. Keep JSON parsing errors inside a separate narrow boundary.
Hint 3 · a localized example
A transient status can raise TransientError("server_error"). This is a controlled category, not the raw body. The complete request and parser still need their own implementation.
Need the complete worked solution?
Open provider_tools/core.py from the kit. Trace it, close it, then try fresh inputs in your own files. Treat the attempt as guided; seeing the solution does not award a practical pass.
Course help is guidance, not independent evidence. With JavaScript, opening help records guidance locally; otherwise note it in your README. Reset does not erase that history.
Repair a failed check
If MockTransport says StreamConsumed, trace whether the response was already buffered. The reference uses iter_bytes with identity encoding enforced first. If later retries hide a bug, narrow the catch. If a redirect follows the client default, explicitly override follow_redirects. If an oversized body passes, count actual accumulated bytes rather than trusting Content-Length.
NotImplementedError means a practice stub is still unfinished. Read the failing test name and the last error line. Change one behavior, rerun that build, then rerun all implemented builds.
Show it works on new inputs
Author a changed-ID fixture with 200 object, 429, 502, malformed UTF-8 and unexpected RuntimeError outcomes. Explain response closure, input refusal before requests and what the mock cannot prove about real network timing.
Self-review: name the input, result, refused case and reason. Your local test output and explanation are separate from a quiz score; this page does not certify a pass.
Keep the idea
Safe reads preserve failure meaning. A mocked response teaches client behavior without inventing production-provider evidence.