-
-
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
Accurate overloads for ZipFile.__init__
#12119
Conversation
ZipFile.__init__
ZipFile.__init__
This comment has been minimized.
This comment has been minimized.
Run-through of MyPy primer here: Pip: Removes false positive as the object they're passing in is readable, but doesn't implement werkzeug: Removes false positive in test where a writable |
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 would consider adding test cases for this overload. It is rather complex.
Sounds good, can handle that tomorrow! |
Added tests, found some minor issues which I fixed as a result: 4cf07ab |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@JelleZijlstra Just wanted to follow up on this one! |
I'll periodically look over open typeshed PRs when I have some time, but can't guarantee I'll come back to a specific one (and other maintainers may also pick up this PR if they're confident enough in the change to merge it). |
Sounds good, thanks for the initial look nonetheless. |
stdlib/zipfile/__init__.pyi
Outdated
@overload | ||
def __init__( | ||
self, | ||
file: StrPath | _ZipReadable | _ZipSeekTellable, |
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.
Is this right? I'm not sure _ZipSeekTellable
is enough, e.g. _RealGetContents
requires read
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.
You're right, we want a protocol that is seekable/readable if it's a valid zip file, otherwise it should implement tell
: 0b52c6a
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 think likely misread this, and assumed if an attribute error occurred it just needed to be tellable.
This comment has been minimized.
This comment has been minimized.
def __init__( | ||
self, | ||
file: StrPath | IO[bytes], | ||
mode: _ZipFileMode = "r", | ||
compression: int = 0, | ||
allowZip64: bool = True, | ||
compresslevel: int | None = None, | ||
*, | ||
strict_timestamps: bool = True, | ||
metadata_encoding: str | None = None, | ||
) -> 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.
Aren't all following overloads shadowed by this one?
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 - for example, IO[bytes]
is broader than _ZipReadable
, which will lead to the second overload getting chosen if you just an object that is readable.
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 for _ZipFileMode
, if file
doesn't match we'll end up skipping over the overload. The tests show that this is working properly.
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.
IO[bytes]
is broader than_ZipReadable
But that's exactly the problem. It's my understanding that overloads are processed in order (although the typing spec doesn't mention that), so IO[bytes]
always matches before _ZipReadable
can match.
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've opened python/typing#1803 for clarification.
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.
How is that a problem though? _ZipReadable
will get matched if IO[bytes]
isn't fully fulfilled, or am I misunderstanding something?
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.
Thanks, this looks good, but had one more question!
stdlib/zipfile/__init__.pyi
Outdated
) -> None: ... | ||
@overload | ||
def __init__( | ||
self, | ||
file: StrPath | IO[bytes], | ||
mode: _ZipFileMode = "r", | ||
file: StrPath | _ZipTellable | _ZipWritable, |
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.
While _ZipTellable
won't immediately error, I don't think the resulting object can be used for anything right? Unless I'm missing some use case, I think we should keep it StrPath | _ZipWritable
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 in fact it's definitely wrong, because __del__
will trigger close
will trigger a write attempt
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.
Let me fix this.
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.
@hauntsaninja Should be resolved now.
Diff from mypy_primer, showing the effect of this PR on open source code: pip (https://github.com/pypa/pip)
+ src/pip/_internal/network/lazy_wheel.py:162: error: Unused "type: ignore" comment [unused-ignore]
werkzeug (https://github.com/pallets/werkzeug)
- tests/test_wrappers.py:1216: error: No overload variant of "ZipFile" matches argument types "ResponseStream", "str" [call-overload]
- tests/test_wrappers.py:1216: note: Possible overload variants:
- tests/test_wrappers.py:1216: note: def __init__(self, file: str | PathLike[str] | IO[bytes], mode: Literal['r'] = ..., compression: int = ..., allowZip64: bool = ..., compresslevel: int | None = ..., *, strict_timestamps: bool = ..., metadata_encoding: str | None) -> ZipFile
- tests/test_wrappers.py:1216: note: def __init__(self, file: str | PathLike[str] | IO[bytes], mode: Literal['r', 'w', 'x', 'a'] = ..., compression: int = ..., allowZip64: bool = ..., compresslevel: int | None = ..., *, strict_timestamps: bool = ..., metadata_encoding: None = ...) -> ZipFile
|
Thank you! |
Co-authored-by: Shantanu <[email protected]>
Co-authored-by: Shantanu <[email protected]>
Add overload cases based on each mode to eliminate false positives for types that don't fully implement
IO[bytes]
, per #10880