66. Running the tests and making a change
66.1 How the tests are built
pytest tests/test_requests.py -q -k "redirect" -x
pytest tests/ --cov=requests --cov-report=term-missing -q
# tests/test_requests.py (a typical test: real HTTP against a local httpbin)
def test_HTTP_302_ALLOW_REDIRECT_GET(self, httpbin):
r = requests.get(httpbin("redirect", "1"))
assert r.status_code == 200
assert r.history[0].status_code == 302
assert r.history[0].is_redirect
The httpbin fixture (from pytest-httpbin, wrapped in
tests/conftest.py) starts a local server and returns a URL builder. The
tests exercise the full stack, through urllib3 and real sockets on
127.0.0.1, which is why they catch integration bugs that mocks would
miss. test_lowlevel.py goes further: it runs a raw socket server
(tests/testserver/server.py) that sends hand-written, sometimes
malformed, HTTP responses to test edge cases like broken chunked encoding.
66.2 Exercise: add a feature in your fork
Add a default_timeout to your local copy, so a session can set one
timeout for every request:
- Write the failing test first (Ch 20):
# tests/test_default_timeout.py
import pytest
import requests
def test_session_default_timeout(httpbin):
s = requests.Session()
s.default_timeout = 0.5
with pytest.raises(requests.exceptions.ReadTimeout):
s.get(httpbin("delay", "2")) # httpbin waits 2 s before answering
def test_explicit_timeout_wins(httpbin):
s = requests.Session()
s.default_timeout = 0.5
assert s.get(httpbin("delay", "1"), timeout=3).status_code == 200
- Implement it in
Session.__init__(self.default_timeout = None) and inSession.request(if timeout is None: timeout = self.default_timeout). - Run the whole suite,
ruff check, and readHISTORY.mdto see how changes are recorded.
Then read how the ecosystem solved the same problem without changing
requests: a custom HTTPAdapter subclass whose send sets a timeout when
none is given. Compare the two designs: which one keeps the library's API
smaller?
66.3 Contributing to open source, in general
- Read
CONTRIBUTING.mdand the code of conduct; find the issue tracker's "good first issue" label. - Comment on an issue before writing a large change; maintainers may already have a plan, or a reason not to.
- Keep pull requests small, with a test that fails before and passes after, and a description of why.
- Documentation fixes, reproductions of reported bugs, and triage are real contributions, and the fastest way to learn a codebase.
Next codebases to read, in rough order of size: httpx (async and sync
from one codebase), click (decorators and composition, Ch 14), rich
(the data model and rendering), pydantic (metaclasses and a Rust core,
Ch 30–31), fastapi (introspection, Ch 30.4), and Karpathy's nanoGPT
(PyTorch training in about 300 lines, the companion to
AI Ch 41).