-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Description
Tip
Want to skip the background? Jump to How to test or What feedback we need.
Motivation
Requests has notably been without inline type annotations since type hints entered the Python ecosystem. We've had aspirations of bringing Requests up to par with community standards for a few years but have been unable to properly express the typing contract. This change doesn't solve all of those gaps, but does make progress towards that goal.
The maintainers of typeshed have provided an incredibly useful alternative for Requests typing for quite a while. There are some limitations of type stubs that can't fully express the Requests API though. Cases like iter_content having different return typing based on input, or PreparedRequests needing to be state checked can't be easily expressed. Inline annotations let us own the type contract alongside the code and should help drive better development decisions in the future.
For most use cases, the public API should be accurately typed. There are some internals that are currently suppressed because they need discussion, but the package passes pyright strict mode without errors. We've flagged where the sharp edges are and can refine those over time.
The main goal is to start this migration with community input to make sure we're covering all usage. The "magic" of Requests is that it's very flexible, which also means people use it in creative ways the maintainers don't always anticipate. We want to identify those edge cases early in this process before the types ship in a release.
What's changed
- Every class, function, method, and module-level variable in
src/requests/is annotated - No public API changes
- Passes typechecking with pyright strict mode
- New internal
_types.pymodule for shared type aliases and Protocols from __future__ import annotationsapplied everywhere- There are some minor bug fixes included, but they address legitimate defects in Requests that resulted in unhandled runtime exceptions.
Design philosophy
Types should describe the code, not change behavior. This was the primary goal in this process, not adding new constraints.
Where typing forced a choice between runtime strictness and backward compatibility, we chose backward compatibility. That's the lens I'd view this through when things may differ from expectations.
How to test
Install from the branch:
python -m pip install git+https://github.com/psf/requests.git@inline_types_rfc
or
uv pip install git+https://github.com/psf/requests.git@inline_types_rfc
Then:
- Run your existing test suite
- Run pyright or mypy against your code that uses Requests
- Try your usual Requests patterns and see if anything doesn't typecheck
What feedback we're looking for
Important
We want feedback from people who actively maintain projects that depend on Requests or use it heavily. Please share your real experience testing this against your code.
Comments that are clearly AI-generated will be hidden or removed. This is a library written "for Humans". The conversation is between maintainers and users, not a prompt.
If you do find issues, we want to hear about it. Specifically:
- Compatibility: Does this break anything in your project? Especially if you're doing something unusual with Requests internals.
- Type accuracy: Do the types match how you actually use the API? Are return types too narrow or too wide?
- Missing coverage: Is there a pattern you use that we're not covering?
We're not looking for style opinions on the annotations themselves or nitpicks on suppression comments. Those are tracked on the PR.
Known limitations
str | bytesURL handling: Requests has historically accepted bothstrandbytesfor URLs. The typing currently declaresstronly. This is a known gap we're still working through.- urllib3 stub gaps: Some
type: ignorecomments exist because urllib3's type stubs don't fully cover all the methods we use. - Optional dependency typing: chardet/charset_normalizer detection is imperfect under strict mode since these are optional imports.
RequestsCookieJarandMutableMapping: The RequestsCookieJar's conformance toMutableMappinghas some known mismatches (extended method signatures,__iter__yieldingCookieobjects instead of strings) that date back to when the class was first written against the Python 2.6 ABC contract. The current types don't fix that, but should be clearer about what the class does. Future work may be able to refine this further.
For more details and rationale, see the PR.