-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Update definition of constants in urllib3.util.retry #6892
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
Conversation
72c4d6c
to
dc5908e
Compare
stubs/urllib3/urllib3/util/retry.pyi
Outdated
@@ -12,8 +12,15 @@ ResponseError = exceptions.ResponseError | |||
log: Any | |||
|
|||
class Retry: | |||
DEFAULT_ALLOWED_METHODS: frozenset[str] | |||
RETRY_AFTER_STATUS_CODES: frozenset[int] | |||
DEFAULT_REMOVE_HEADERS_ON_REDIRECT: frozenset[list[str]] |
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.
DEFAULT_REMOVE_HEADERS_ON_REDIRECT: frozenset[list[str]] | |
DEFAULT_REMOVE_HEADERS_ON_REDIRECT: frozenset[str] |
Looks like a frozenset with a single element to me, the string "Authorization" 🙂 (It's actually impossible to have a frozenset of lists, since lists aren't hashable!) https://github.com/urllib3/urllib3/blob/33afb5c96c435ab7118b5f41e26f96c290fef55b/src/urllib3/util/retry.py#L192
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.
Yes good point @AlexWaygood! My bad. I will fix it now. Thank you
stubs/urllib3/urllib3/util/retry.pyi
Outdated
@@ -12,8 +12,15 @@ ResponseError = exceptions.ResponseError | |||
log: Any | |||
|
|||
class Retry: | |||
DEFAULT_ALLOWED_METHODS: frozenset[str] |
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.
DEFAULT_ALLOWED_METHODS: frozenset[str] | |
DEFAULT_ALLOWED_METHODS: ClassVar[frozenset[str]] |
Since these are class-level constants, it might be good to have them all as ClassVar
s (should apply similar changes to the other constants as well, if so)
Wait, do the deprecated constants in the stub even exist anymore? I can't see them in the source code anywhere... |
They don't exists anymore... I'm not sure how to deal with those to be honest. I mean, probably some people using older version can still have those as valid default constants. What do you suggest to do @AlexWaygood ? |
Typeshed generally only ships stubs for the most recent version of a package, so I think they should probably be deleted. Looks like they were removed from urllib3 in November 2020! urllib3/urllib3@c67c094#diff-53a96dd57c993a39101318e9df47f8aab6610e8c2c1064f8109f66943dcbbd78 |
Those constants have been renamed here urllib3/urllib3@382ab32 |
I removed deprecated constants and also used more precise types for the rest of the attributes (adding missing ones, and re-naming some of them). |
Looks great! Is there a reason why you've annotated some of the instance attributes differently to how they're annotated in the source code? E.g. |
My bad, I looked at an old version of the code, will fix it now. Thanks. |
While we're cleaning up this file, could you also possibly remove the |
Yes @AlexWaygood , I did update all the methods as well. I'm not sure how to update the stubtest bit. Any hint? |
Ah the CI is reporting those, I think. I'm fixing that. |
You'll need to remove the following entries from the stubtest allowlist as part of your PR (the test fails if there are unused entries):
There are some other stubtest failures as well, which I'll help you out with. |
I don't know why |
That's not necessarily true; there's a checkbox somewhere to allow edits by maintainers and it looks like @bugant didn't turn it on. |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
) -> None: ... | ||
def new(self, **kw): ... | ||
@classmethod | ||
def from_int(cls, retries, redirect=..., default=...): ... | ||
def get_backoff_time(self): ... | ||
def from_int(cls, retries, redirect=..., default=...) -> "Retry": ... |
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.
No need to have string-literal annotations in stubs; from __future__ import annotations
behaviour is enabled by default 🙂 same applies for the increment
method
def from_int(cls, retries, redirect=..., default=...) -> "Retry": ... | |
def from_int(cls, retries, redirect=..., default=...) -> Retry: ... |
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.
BUT, on second thought, the annotation in the source code is wrong. You should annotate the method like this: add from _typeshed import Self
at the top of the file, and then do:
def from_int(cls, retries, redirect=..., default=...) -> "Retry": ... | |
def from_int(cls: type[Self], retries, redirect=..., default=...) -> Self: ... |
Thought that was probably it, but wasn't sure. Thanks! |
Not sure which checkbox I have to tick |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
backoff_factor: float | ||
raise_on_redirect: bool | ||
raise_on_status: bool | ||
history: tuple[Any] | 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.
The attribute can never be None
at runtime; if the None
default in the __init__
method is used, then the attribute is set to an empty tuple.
You'll need to add back the RequestHistory
NamedTuple
you had in one of your previous commits (it's a collections.namedtuple
in the 1.26.x branch, but it can be a typing.NamedTuple
in the stub, like it is in the main
branch; type-checkers don't care about the different kinds of NamedTuples)
history: tuple[Any] | None | |
history: tuple[()] | tuple[RequestHistory, ...] |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
status: int | None | ||
other: int | None | ||
allowed_methods: Collection[str] | None | ||
status_forcelist: Collection[int] | 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 also can never be None
at runtime; it is set as an empty set
if no value is provided in __init__
.
status_forcelist: Collection[int] | None | |
status_forcelist: Collection[int] |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
raise_on_status: bool | ||
history: tuple[Any] | None | ||
respect_retry_after_header: bool | ||
remove_headers_on_redirect: Collection[str] |
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.
Any Collection
can be passed into __init__
, but it is changed to be a frozenset
when it is set as an attribute on the class.
remove_headers_on_redirect: Collection[str] | |
remove_headers_on_redirect: frozenset[str] |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
total: bool | int | None | ||
connect: int | None | ||
read: int | None | ||
redirect: bool | int | 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.
It appears that redirect can never be False
, only int
, None
or True
. You'll need to import Literal
from typing_extensions
.
redirect: bool | int | None | |
redirect: Literal[True] | int | None |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
@@ -44,7 +53,10 @@ class Retry: | |||
@classmethod | |||
def from_int(cls, retries, redirect=..., default=...): ... | |||
def get_backoff_time(self): ... | |||
def sleep(self, response: HTTPResponse | None = ...) -> None: ... | |||
def is_forced_retry(self, method, status_code): ... | |||
def parse_retry_after(self, retry_after: str): ... |
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.
def parse_retry_after(self, retry_after: str): ... | |
def parse_retry_after(self, retry_after: str) -> float: ... |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
def sleep(self, response: HTTPResponse | None = ...) -> None: ... | ||
def is_forced_retry(self, method, status_code): ... | ||
def parse_retry_after(self, retry_after: str): ... | ||
def get_retry_after(self, response: HTTPResponse): ... |
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.
def get_retry_after(self, response: HTTPResponse): ... | |
def get_retry_after(self, response: HTTPResponse) -> float | None: ... |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
def is_forced_retry(self, method, status_code): ... | ||
def parse_retry_after(self, retry_after: str): ... | ||
def get_retry_after(self, response: HTTPResponse): ... | ||
def sleep_for_retry(self, response: HTTPResponse | 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.
def sleep_for_retry(self, response: HTTPResponse | None = ...): ... | |
def sleep_for_retry(self, response: HTTPResponse | None = ...) -> bool: ... |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
def parse_retry_after(self, retry_after: str): ... | ||
def get_retry_after(self, response: HTTPResponse): ... | ||
def sleep_for_retry(self, response: HTTPResponse | None = ...): ... | ||
def sleep(self, response: HTTPResponse | 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.
def sleep(self, response: HTTPResponse | None = ...): ... | |
def sleep(self, response: HTTPResponse | None = ...) -> None: ... |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
def get_retry_after(self, response: HTTPResponse): ... | ||
def sleep_for_retry(self, response: HTTPResponse | None = ...): ... | ||
def sleep(self, response: HTTPResponse | None = ...): ... | ||
def is_retry(self, method: str, status_code: int, has_retry_after: bool = ...): ... |
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.
def is_retry(self, method: str, status_code: int, has_retry_after: bool = ...): ... | |
def is_retry(self, method: str, status_code: int, has_retry_after: bool = ...) -> bool: ... |
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's still more work to be done to finish annotating many of the methods in this file, but the changes you've made LGTM! (I don't have the power to merge, I'm just a contributor, not a maintainer.)
stubs/urllib3/urllib3/util/retry.pyi
Outdated
backoff_factor: float | ||
raise_on_redirect: bool | ||
raise_on_status: bool | ||
history: tuple[RequestHistory, ...] | tuple[()] |
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.
Why do we need the empty tuple called out here? The first union member is an arbitrary-length tuple, which includes the empty tuple.
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.
Oh that's my fault; I suggested that annotation, and didn't think that one through. My bad; you're quite right.
Thanks @AlexWaygood! What else is left there? I intentionally left out methods whose name starts with an _, thinking that those are kind of "private"/internal. |
The remaining changes can be made in other PRs! But this is what's still left to do -- feel free to add it in this PR if you like!
|
The |
Thanks @AlexWaygood , I added the missing annotatiions as you suggested. |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
) -> None: ... | ||
def new(self, **kw): ... | ||
def new(self, **kw: Any) -> Retry: ... |
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.
At runtime this will return an instance of a subclass if it's being called on a subclass of Retry
, so we should use a TypeVar
to annotate the return-type instead of hardcoding it. (This is different to how they've annotated their code on main
, but I think their annotation is wrong.) typeshed's established style is to use the _typeshed.Self
TypeVar
for these situations (you'll need to do from _typeshed import Self
at the top of the file).
def new(self, **kw: Any) -> Retry: ... | |
def new(self: Self, **kw: Any) -> Self: ... |
Thank you!! |
stubs/urllib3/urllib3/util/retry.pyi
Outdated
) -> None: ... | ||
def new(self, **kw): ... | ||
def new(self, **kw: Any) -> Self: ... |
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.
def new(self, **kw: Any) -> Self: ... | |
def new(self: Self, **kw: Any) -> Self: ... |
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.
Thanks!
@AlexWaygood do you know if it is possible to install |
@bugant: New versions of the stubs are released automatically every three hours, starting midnight UTC. So the next version of the package should be released in a bit over two hours. I unfortunately just missed the last release by about five minutes. |
Actually, I just manually forced urllib3 to update, types-urllib3 1.26.6 should have these changes. |
Fabulous! Thank you very much @srittau! |
This PR adds the latest naming for
urllib3.util.retry
default constants.