Fix mutability issues with headers input types#7431
Conversation
| method: str | None | ||
| url: _t.UriType | None | ||
| headers: CaseInsensitiveDict[str] | Mapping[str, str | bytes] | None | ||
| headers: MutableMapping[str, str | bytes] |
There was a problem hiding this comment.
Why not headerstype here too?
There was a problem hiding this comment.
None was wrong. We always fallback to {} when you pass None into the constructor. The *Type aliases are all mapping input from the public API, this is representing what we store.
Otherwise you need to both validate headers is not None and Mutable. I made a similar change for status_code on Response.
There was a problem hiding this comment.
I guess as a tangent to that, | None being baked into the types was an opinion. I don't feel super strongly about that, it was just for terseness and keeping the None requirement grouped. We could do HeadersType | None everywhere it's used now. That applies to most of the *Types.
|
This has caused the same issue as #7426 # foo.py
import requests
requests.get("http://localhost", headers={"X-Foo": "bar"})$ ty check foo.py
All checks passed!# foo.py
import requests
headers={"X-Foo": "bar"}
requests.get("http://localhost", headers=headers)$ ty check foo.py
error[invalid-argument-type]: Argument to function `get` is incorrect
--> foo.py:4:34
|
4 | requests.get("http://localhost", headers=headers)
| ^^^^^^^^^^^^^^^ Expected `MutableMapping[str, str | bytes] | None`, found `dict[str, str]`
|
info: type `dict[str, str]` is not assignable to any element of the union `MutableMapping[str, str | bytes] | None`
info: ├── element `bytes` of union `str | bytes` is not assignable to `str`
info: └── ... omitted 1 union element without additional context
info: Function defined here
--> /path/to/venv/lib/python3.14/site-packages/requests/api.py:74:5
|
74 | def get(
| _____^^^-
75 | | url: _t.UriType, params: _t.ParamsType = None, **kwargs: Unpack[_t.GetKwargs]
76 | | ) -> Response:
| |_- Parameter declared here
|
Found 1 diagnostic |
|
There's some tension here in usage that I'm a bit at a loss for how to address. I saw this in
Once we pass |
|
Typeshed got around this issue by just labeling headers on Request as We either need to lie about what we accept with The input case is probably where we need to be overly permissive because the new failure is significantly more common than the |
We already got a helpful email, lack of header mutability in the typing contract is creating friction for some code bases. I think we'd started to go down this route but it got lost in the cleanup. I'm going to stage this as a known issue for a 2.34.1 but we'll likely wait a day or two before cutting another release to see what other feedback we missed.