# Testing signals — psf/requests

> Canonical page: https://codevetter.com/unpack/requests/testing-signals

# Testing signals — psf/requests

Scanned commit 611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60 (2026-09-21). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Testing is pytest-only, concentrated in one 108 KB file: `tests/test_requests.py` holds 237 of the ~347 test functions, with `tests/test_utils.py` (64) and `tests/test_lowlevel.py` (13) next. Integration tests run against a real local `httpbin` via the `pytest-httpbin` fixture (wrapped by `conftest.prepare_url` to guarantee a trailing slash), while wire-level behaviour uses a hand-rolled socket `Server` thread in `tests/testserver/server.py`. TLS behaviour is covered by checked-in fixture certificates (`tests/certs/{valid,expired,mtls}`) plus a `trustme`-generated no-SAN server fixture. Doctests in the library modules are executed by `--doctest-modules`. Gaps: `adapters.py` — the single most security-relevant module — has a one-test dedicated file, and there is no coverage threshold enforced anywhere.
- The framework is pytest with `minversion = 6.2`, `testpaths = ["tests"]`, and `--doctest-modules` plus `NORMALIZE_WHITESPACE ELLIPSIS` optionflags, so module docstring examples are part of the suite. — [pyproject.toml#L100-L104](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/pyproject.toml#L100-L104)
- Test distribution is extremely lopsided: `tests/test_requests.py` defines 237 `test_` functions across 7 classes (`TestRequests`, `TestCaseInsensitiveDict`, `TestMorselToCookieExpires`, `TestMorselToCookieMaxAge`, `TestTimeout`, `RedirectSession`, `TestPreparingURLs`), versus 64 in `test_utils.py` and 13 in `test_lowlevel.py`. — [tests/test_requests.py#L84-L2760](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_requests.py#L84-L2760) [tests/test_utils.py](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_utils.py) [tests/test_lowlevel.py](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_lowlevel.py)
- An autouse fixture `clean_proxy_environ` monkeypatches away `http_proxy`, `https_proxy`, `no_proxy`, `ftp_proxy` and `all_proxy` (both cases) for every test, so proxy tests must set env vars explicitly. — [tests/conftest.py#L25-L32](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/conftest.py#L25-L32)
- Integration coverage runs against a live httpbin server through the `httpbin`/`httpbin_secure` fixtures, pinned via `pytest-httpbin==2.1.0` and `httpbin~=0.10.0` in the `test` dependency group. — [tests/conftest.py#L14-L41](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/conftest.py#L14-L41) [pyproject.toml#L57-L66](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/pyproject.toml#L57-L66)
- Wire-level tests use a purpose-built threaded socket server with `text_response_server` / `basic_response_server` helpers, exercising chunked upload, conflicting Content-Length, RFC 1808 non-ASCII redirects and fragment handling. — [tests/testserver/server.py#L27-L70](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/testserver/server.py#L27-L70) [tests/test_lowlevel.py#L24-L106](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_lowlevel.py#L24-L106) [tests/test_lowlevel.py#L308-L406](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_lowlevel.py#L308-L406)
- Digest auth is covered at the socket level by three dedicated tests: `test_digestauth_401_count_reset_on_redirect`, `test_digestauth_401_only_sent_once`, and `test_digestauth_only_on_4xx`. — [tests/test_lowlevel.py#L127-L289](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_lowlevel.py#L127-L289) [src/requests/auth.py#L268-L319](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/auth.py#L268-L319)
- TLS paths are tested with committed fixture certs — expired server cert, valid server cert, and an mTLS client cert — including `test_different_connection_pool_for_mtls_settings` verifying pool-key separation. — [tests/certs/README.md](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/certs/README.md) [tests/test_requests.py#L2940-L3055](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_requests.py#L2940-L3055)
- A `nosan_server` fixture mints a CA and a commonName-only (no subjectAltName) certificate at runtime using `trustme`, backing the SNI/SAN warning tests. — [tests/conftest.py#L44-L66](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/conftest.py#L44-L66) [tests/test_requests.py#L1030-L1040](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_requests.py#L1030-L1040)
- `test_response_iter_lines_reentrant` is marked `@pytest.mark.xfail` and documents a known defect: `Response.iter_lines()` is not reentrant-safe, matching the docstring note on the method itself. — [tests/test_requests.py#L2200-L2208](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_requests.py#L2200-L2208) [src/requests/models.py#L1005-L1015](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/models.py#L1005-L1015)
- Behaviour differences between urllib3 1.x and 2.x are handled by skips keyed on `is_urllib3_1`, e.g. `test_content_length_for_string_data_counts_bytes` skips on 1.x because it encodes strings as latin-1 rather than utf-8. — [tests/test_requests.py#L3073-L3086](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_requests.py#L3073-L3086) [src/requests/compat.py#L21-L27](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/compat.py#L21-L27) [src/requests/utils.py#L163-L167](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/utils.py#L163-L167)
- `adapters.py` has a single dedicated regression test (`test_request_url_handles_leading_path_separators`); the rest of the adapter is exercised only indirectly through `test_requests.py`. — [tests/test_adapters.py](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/tests/test_adapters.py) [src/requests/adapters.py#L565-L598](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/src/requests/adapters.py#L565-L598)
- CI runs `make ci` (`pytest tests --junitxml=report.xml`) across 8 Python versions × 3 OSes, plus two special jobs: `no_chardet` uninstalls both detection libraries, and `urllib3` pins `urllib3<2`. — [.github/workflows/run-tests.yml#L10-L95](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.github/workflows/run-tests.yml#L10-L95) [Makefile#L5-L8](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/Makefile#L5-L8)
- Typechecking is enforced in CI as a separate gate: pyright in `strict` mode over `include = ["src/requests"]`, run on Python 3.10 and 3.14 — note `tests/` is deliberately outside the typechecked surface. — [pyproject.toml#L106-L113](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/pyproject.toml#L106-L113) [.github/workflows/typecheck.yml#L24-L32](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.github/workflows/typecheck.yml#L24-L32)
- Coverage is available locally via `make coverage` with a `.coveragerc` whose only directive omits `requests/packages/*` — a stale path given the package now lives under `src/requests/`; no minimum threshold is configured and no workflow uploads coverage. — [.coveragerc](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.coveragerc) [Makefile#L13-L14](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/Makefile#L13-L14) [.github/workflows/run-tests.yml](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.github/workflows/run-tests.yml)
- Lint runs as its own workflow executing pre-commit (`ruff-check --fix`, `ruff-format`, plus whitespace/merge-conflict hooks), with `tests/test_lowlevel.py` explicitly excluded from `ruff-format`. — [.pre-commit-config.yaml#L1-L23](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.pre-commit-config.yaml#L1-L23) [.github/workflows/lint.yml](https://github.com/psf/requests/blob/611c6162cbc4ac2020a2f91c7cfa4f3abf9bbb60/.github/workflows/lint.yml)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
