-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
requests
: Allow session headers to be of type None
#7773
requests
: Allow session headers to be of type None
#7773
Conversation
requests
: Allow session headers to be of type None
Currently many functions accept |
@Akuli does it make sense for headers to be in a session, |
session = requests.Session()
session.headers.update({"Content-Type": "application/json"})
# request with content type
session.get("http://api.com")
# request with no content type
session.get("http://api.com", headers={"Content-Type": None}) |
stubs/requests/requests/sessions.pyi
Outdated
@@ -72,7 +72,7 @@ _Verify: TypeAlias = bool | str | |||
|
|||
class Session(SessionRedirectMixin): | |||
__attrs__: Any | |||
headers: CaseInsensitiveDict[str] | |||
headers: CaseInsensitiveDict[str | None] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned in https://docs.python-requests.org/en/latest/user/quickstart/#custom-headers , header values can also be bytestring.
headers: CaseInsensitiveDict[str | None] | |
headers: CaseInsensitiveDict[str | bytes | None] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. I think I added None to the wrong place. We want to allow str or bytes on actual headers, but None only on updates
This reverts commit d9ca9a7.
… well as str and bytes
stubs/requests/requests/sessions.pyi
Outdated
@@ -67,12 +67,14 @@ _Params: TypeAlias = Union[ | |||
str | bytes, | |||
] | |||
_TextMapping: TypeAlias = MutableMapping[str, str] | |||
_HeadersMapping = TypeAlias = MutableMapping[str, str | bytes] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconvenient because MutableMapping is invariant in its value type, so a dict[str, str]
would not be acceptable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about
MutableMapping[str, str] | MutableMapping[str, bytes]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…leMapping[str, bytes]` + simple assignment in alias definition
stubs/requests/requests/sessions.pyi
Outdated
@@ -67,12 +67,14 @@ _Params: TypeAlias = Union[ | |||
str | bytes, | |||
] | |||
_TextMapping: TypeAlias = MutableMapping[str, str] | |||
_HeadersMapping: TypeAlias = MutableMapping[str, str] | MutableMapping[str, bytes] | |||
_HeadersUpdateMapping: TypeAlias = MutableMapping[str, str] | MutableMapping[str, bytes] | MutableMapping[str, None] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that's correct, header values can be some str and some bytes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mmm I see - would we have to specify all combinations of mutable mappings for str, bytes and None?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment has been minimized.
This comment has been minimized.
stubs/requests/requests/models.pyi
Outdated
@@ -95,7 +95,7 @@ class Response: | |||
__attrs__: Any | |||
_content: bytes | None # undocumented | |||
status_code: int | |||
headers: CaseInsensitiveDict[str] | |||
headers: CaseInsensitiveDict[str | bytes] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is correct? These headers are from the HTTP response, and I'd expect requests to return the same type consistently.
This seems to be the cause of a false positive on this line found by mypy-primer: https://github.com/yurijmikhalevich/rclip/blob/98a2454b988986f6ed67ae6e9fe3342ea82e0f92/rclip/utils.py#L92
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+ these are casted to native strings here https://github.com/psf/requests/blob/40956723f27daf5e0d9759208ca69cef236ab339/requests/models.py#L484
This comment has been minimized.
This comment has been minimized.
I'm unsure what the next steps are |
You removed |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CaseInsensitiveDict[str | bytes]
has the same issues that MutableMapping[x, str | bytes]
has (invariance) — CaseInsensitiveDict[str] | CaseInsensitiveDict[bytes] | CaseInsensitiveDict[str | bytes]
would be better
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
Well, my suggested change to work around the invariance of |
This reverts commit f189735.
I find it quite challenging to have a local workflow for this. Not even testing other projects, but my own. I'd love some pointers if anyone has some |
Diff from mypy_primer, showing the effect of this PR on open source code: rotki (https://github.com/rotki/rotki)
+ rotkehlchen/premium/premium.py:219: error: Unused "type: ignore" comment
+ rotkehlchen/premium/premium.py:245: error: Unused "type: ignore" comment
+ rotkehlchen/premium/premium.py:270: error: Unused "type: ignore" comment
+ rotkehlchen/premium/premium.py:301: error: Unused "type: ignore" comment
+ rotkehlchen/premium/premium.py:328: error: Unused "type: ignore" comment
+ rotkehlchen/exchanges/kraken.py:546: error: Unused "type: ignore" comment
|
One quick-and-dirty way is to just edit the stub files used by your type checker (somewhere in site-packages) in place. You can also use |
To clarify, here's how you would use
This lets mypy import from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Primer is happy and the code makes sense to me (None
can be used to override whatever was configured in the session). Thanks for contributing! This one was trickier than expected.
After this change, my type checker is throwing an error:
Do headers have to be mutable? Can we also accept |
Due to recent typeshed change: python/typeshed#7773
python#7773 changed `requests.session.Session` methods to accept None for header values, but didn't do quite the same for the functions in `requests.api`. I think this was a mistake. The functions in `requests.api` just pass through the `headers` argument without doing anything in particular to it. Furthermore, it's useful to be able to pass None as a header value: because `requests.utils.default_headers` sets an `Accept-Encoding` header by default, the easiest way to send a request with no `Accept-Encoding` header is something like `requests.get(url, headers={"Accept-Encoding": None})`. It's annoying to have to construct a `Session` just to pass type-checking. It's a little confusing for the type alias to be called `_HeadersUpdateMapping` in `requests.sessions` but `_HeadersMapping` in `requests.api`; this is because the latter name was already used in other type stubs (`tensorflow.keras.callbacks`), so it seemed best to avoid breaking API.
python#7773 changed `requests.session.Session` methods to accept None for header values, but didn't do quite the same for the functions in `requests.api`. I think this was a mistake. The functions in `requests.api` just pass through the `headers` argument without doing anything in particular to it. Furthermore, it's useful to be able to pass None as a header value: because `requests.utils.default_headers` sets an `Accept-Encoding` header by default, the easiest way to send a request with no `Accept-Encoding` header is something like `requests.get(url, headers={"Accept-Encoding": None})`. It's annoying to have to construct a `Session` just to pass type-checking. It's a little confusing for the type alias to be called `_HeadersUpdateMapping` in `requests.sessions` but `_HeadersMapping` in `requests.api`; this is because the latter name was already used in other type stubs (`tensorflow.keras.callbacks`), so it seemed best to avoid breaking API.
#7773 changed `requests.session.Session` methods to accept None for header values, but didn't do quite the same for the functions in `requests.api`. I think this was a mistake. The functions in `requests.api` just pass through the `headers` argument without doing anything in particular to it. Furthermore, it's useful to be able to pass None as a header value: because `requests.utils.default_headers` sets an `Accept-Encoding` header by default, the easiest way to send a request with no `Accept-Encoding` header is something like `requests.get(url, headers={"Accept-Encoding": None})`. It's annoying to have to construct a `Session` just to pass type-checking. It's a little confusing for the type alias to be called `_HeadersUpdateMapping` in `requests.sessions` but `_HeadersMapping` in `requests.api`; this is because the latter name was already used in other type stubs (`tensorflow.keras.callbacks`), so it seemed best to avoid breaking API.
Session headers can be unset by setting them to none, see: https://github.com/psf/requests/blob/40956723f27daf5e0d9759208ca69cef236ab339/requests/sessions.py#L61