-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add missing attribute hints for click.types #4813
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
Add missing attribute hints for click.types #4813
Conversation
third_party/2and3/click/types.pyi
Outdated
| readable: bool | ||
| resolve_path: bool | ||
| allow_dash: bool | ||
| type: Optional[Type[_PathType]] |
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.
Not sure on the typing for this causes the tests to fail.
I already tried fixing it according to the hints produced by the failing test, but had not luck.
Please advise
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 typevar doesn't make sense in this context, since there's nothing to bind it. Perhaps you want Optional[Union[Type[str], Type[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.
I see it seems I slightly misunderstood TypeVars and binding until now. I've added the type as per your suggestion since I also believe this to be the correct hint for this. For this I added it as an alias _PathTypeBound just below the _PathType TypeVar. As to prevent possible future type changes only being done to the _PathType init argument and not the attribute, especially since they argument and attribute do not share the exact same name.
Also rebased to the latest master containing the proposed fix for #4815 .
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 typevar is actually already broken in the current version: It's used in two different functions without the class being generic. I see two possible solutions:
- Make the class generic over the path type and use the typevar in all three positions.
- Use the union in all three positions.
I have a slight preference for the first option, although with the usual caveat that this requires every user of Path to annotate it. (At least as long as we don't have support for generic defaults.) Cc @JelleZijlstra.
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.
Making the class generic seems to make sense; in that case we should add an overload to the __init__ function to specify the value of the typevar when the path argument isn't passed.
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.
@max-frank Do you want to change it? Otherwise I would merge the PR as is and send a separate PR myself.
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.
@srittau Ah yes sorry I was doing a deep dive into the click code base and got a bit side tracked.
Yes please, if you wan't you can do a separate PR I was just in the process of figuring out what the default would actually be when path_type=None.
From what I can see it should boil down to the following two cases depending on the system
unicode: forPY2 and WIN(read as boolean expression)str: for all other cases
One question on the __init__ overload would that look like the following:
_PathTypeDefault = unicode if PY2 and WIN else str
...
def __init__(self: Path[_PathTypeDefault], ..., path_type: Literal[None] = None):
...The above conclusion is derived from the following click code:
Special argv parsing for PY2 and WIN, other cases use normal sys.argv which gives us List[str]
if PY2 and WIN and _initial_argv_hash == _hash_py_argv():
return _get_windows_argv()
return sys.argv[1:]with the windows function using windows libs and some custom code to get List[unicode].
https://github.com/pallets/click/blob/1784558ed7c75c65764d2a434bd9cbb206ca939d/src/click/_winconsole.py#L307
For Path options/args eventually one list element will make it to the Path.convert function which in turn calls
coerce_path_result(self, rv) with the value as rv
if self.type is not None and not isinstance(rv, self.type):
if self.type is text_type:
rv = rv.decode(get_filesystem_encoding())
else:
rv = rv.encode(get_filesystem_encoding())
return rvNow the above is for the 7.1.2 code base 8.0 drops support for python2.7 so the custom code will be removed (i.e., for the pre-release it is already).
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.
@srittau Another side node related the above in the click code review process I noticed that the type hints on the Path functions are not entirely correct.
def coerce_path_result(self, rv: Union[str, bytes]) -> _PathType: ...
def __call__(self, value: Optional[str], param: Optional[Parameter] = ..., ctx: Optional[Context] = ...) -> _PathType: ...
def convert(self, value: str, param: Optional[Parameter], ctx: Optional[Context]) -> _PathType: ...I believe the value arg on __call__ and convert should match rv from coerce_path_result.
bc14484 to
4094aab
Compare
|
The tests still seem to be failing with #4815, but I suspect this might be a CI runner cache issue or something since locally the failing test goes through without a problem. |
|
@max-frank If you merge |
4094aab to
7339cf3
Compare
srittau
left a comment
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.
One more thing I noticed.
srittau
left a comment
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 am sorry for the delay. This looks mostly good, but one more thing I noticed below.
third_party/2and3/click/types.pyi
Outdated
| formats: Iterable[str] | ||
| def __init__(self, formats: Optional[List[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 len() is called on .formats, this needs to be a Sequence. The List in __init__ could also be changed. Another alternative is to just use List for the attribute to give additional guarantees to users.
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 see looking at the doc string for DateTime.__init__ it seems format should be either a Tuple or a List so the current type hint doesnt match this anyway.
So we either replace Iterable[str] and List[str] with Union[List[str], Tuple[str]] or as you suggested use Sequence which would be less strict I guess. Which do you prefer?
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.
Sequence is better I think.
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.
Ok I've updated the PR accordingly
| mode: str | ||
| encoding: Optional[str] | ||
| errors: str | ||
| lazy: Optional[str] | ||
| atomic: 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.
Side note (not part of your PR): I just noticed that errors and lazy are marked as Optional[] in the __init__() argument, which seems to be wrong.
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 did a more thorough check now and it seems my change is wrong for errors while it defaults to the string strict the function calls it is used it actually allows for None to be passed in explicitly.
e.g.,
Looking at lazy again it seems that the __init__ hint is correct and I made a mistake when reading the code the first time. From the click doc and its usage in the code the attribute should be Optional[bool].
Sorry I should have caught this in my first code review these click functions.
I will be changing the PR to
errors: Optional[str]
lazy: Optional[bool]
max-frank
left a comment
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 am sorry for the delay. This looks mostly good, but one more thing I noticed below.
No worries it being so close to Christmas I wasn't expecting this PR to get done this year.
So thanks for your quick reviews.
third_party/2and3/click/types.pyi
Outdated
| formats: Iterable[str] | ||
| def __init__(self, formats: Optional[List[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 see looking at the doc string for DateTime.__init__ it seems format should be either a Tuple or a List so the current type hint doesnt match this anyway.
So we either replace Iterable[str] and List[str] with Union[List[str], Tuple[str]] or as you suggested use Sequence which would be less strict I guess. Which do you prefer?
| mode: str | ||
| encoding: Optional[str] | ||
| errors: str | ||
| lazy: Optional[str] | ||
| atomic: 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.
I did a more thorough check now and it seems my change is wrong for errors while it defaults to the string strict the function calls it is used it actually allows for None to be passed in explicitly.
e.g.,
Looking at lazy again it seems that the __init__ hint is correct and I made a mistake when reading the code the first time. From the click doc and its usage in the code the attribute should be Optional[bool].
Sorry I should have caught this in my first code review these click functions.
I will be changing the PR to
errors: Optional[str]
lazy: Optional[bool]3a9e8bd to
f1d35f7
Compare
f1d35f7 to
1323c31
Compare
|
Note I did a finally rebase to be on par with #4825 |
This PR adds attribute type hints for known attributes of
click.types.Current release click 7.1.2 was used as reference.
PR in response to mypy errors experienced in mkdocs/mkdocs-click#25