make io.pyi import everything from _io.py(i), like io.py does#1395
make io.pyi import everything from _io.py(i), like io.py does#1395JelleZijlstra merged 10 commits intomasterfrom
Conversation
Also, as far as possible, try to simplify, by moving methods into base classes.
|
This PR got larger than expected. The basic motivation is to allow code like to pass type-checking. (Which it didn't before, since |
|
Do you have code that directly imports Anyway, I tested this without our internal code and it found one issue, io.BufferedIOBase is supposed to define I am also still worried about some classes not inheriting from BinaryIO where they should. BinaryIO is abstract, we must ensure the abstractness or concreteness of various classes matches those in the stdlib. |
We do, unfortunately. Some in internal code, but I'm also seeing occurrences in third party packages like pymock and astroid.
Right. Made |
|
Seeing all the |
|
I don't see why not. Let me look into it. |
JelleZijlstra
left a comment
There was a problem hiding this comment.
Thanks for all the cleanup! I left some comments from comparing this with the C code and (mostly) the docs.
stdlib/2/_io.pyi
Outdated
| def writable(self) -> bool: ... | ||
| def write(self, s: bytes) -> int: ... | ||
| def __exit__(self, type, value, traceback) -> bool: ... | ||
| # This just returns self: |
There was a problem hiding this comment.
Then why not use a self type?
stdlib/2/_io.pyi
Outdated
| def truncate(self, size: Optional[int] = ...) -> int: ... | ||
| def writable(self) -> bool: ... | ||
| def write(self, s: bytes) -> int: ... | ||
| def __exit__(self, type, value, traceback) -> bool: ... |
There was a problem hiding this comment.
Why did you remove the argument types here?
There was a problem hiding this comment.
My bad. The types got under the wheel when I shifted __exit__ back and fro.
That said, I'm not sure what we get out of having types on __exit__. This function is invoked by the type-checker, not user code (nobody ever does a manual x.__exit__(a, b,c)), and the parameters are not originating from user code, either.
Either way, I added types.
stdlib/2/_io.pyi
Outdated
| def write(self, s: str) -> int: ... | ||
| def write(self, s: bytes) -> int: ... | ||
| def detach(self) -> "_BufferedIOBase": ... | ||
| def __enter__(self) -> '_BufferedIOBase': ... |
There was a problem hiding this comment.
Looks odd to have double quotes on one line and single on the next. Since this is a stub, we can just remove all quotes anyway.
| def __enter__(self) -> '_RawIOBase': ... | ||
|
|
||
| class FileIO(_RawIOBase): | ||
| class FileIO(_RawIOBase, BytesIO): # type: ignore # for __enter__ |
There was a problem hiding this comment.
Would this not be necessary if you used self types for these __enter__ methods?
stdlib/2/io.pyi
Outdated
| import _io | ||
|
|
||
| DEFAULT_BUFFER_SIZE = 0 | ||
| from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation, |
There was a problem hiding this comment.
These need x as x imports to make clear that they're re-exported.
stdlib/2/_io.pyi
Outdated
|
|
||
| class BufferedRWPair(_BufferedIOBase): | ||
| def peek(self, n: int = ...) -> str: ... | ||
| def __init__(self, reader: _RawIOBase, writer: _RawIOBase) -> None: ... |
There was a problem hiding this comment.
This also takes buffer_size and max_buffer_size arguments.
stdlib/2/_io.pyi
Outdated
| # Note: In the actual _io.py, _TextIOBase inherits from _IOBase. | ||
| class _TextIOBase(TextIO): | ||
| errors = ... # type: Optional[str] | ||
| newlines = ... # type: Union[str, unicode] |
There was a problem hiding this comment.
According to the docs it can also be None or a tuple of strings.
There was a problem hiding this comment.
Actually, on _TextIOBase, this always returns None:
https://github.com/python/cpython/blob/2.7/Modules/_io/textio.c#L104
overloaded below.
stdlib/2/_io.pyi
Outdated
| def _checkSeekable(self) -> None: ... | ||
| def _checkWritable(self) -> None: ... | ||
| def close(self) -> None: ... | ||
| def detach(self) -> None: ... |
There was a problem hiding this comment.
This returns the underlying BufferedIOBase, not None.
There was a problem hiding this comment.
Had to make this IO, since _TextIOBase doesn't inherit from BufferedIOBase, and the underlying stream might be either.
buffer is IO below, too.
stdlib/2/_io.pyi
Outdated
| _CHUNK_SIZE = ... # type: int | ||
|
|
||
| def open(file: Union[int, str], mode: str = ...) -> _IOBase: ... | ||
| def __init__(self, buffer: IO, encoding: unicode = ..., |
There was a problem hiding this comment.
I think this should be IO[bytes].
There was a problem hiding this comment.
No, this works:
_io.TextIOWrapper(_io.StringIO(u"hello world")).read()
stdlib/2/_io.pyi
Outdated
|
|
||
| def open(file: Union[int, str], mode: str = ...) -> _IOBase: ... | ||
| def __init__(self, buffer: IO, encoding: unicode = ..., | ||
| errors: unicode = ..., newline: unicode = ..., |
There was a problem hiding this comment.
Further up you had encoding and errors attributes as str on _TextIOBase.
There was a problem hiding this comment.
Done. These parameters are actually more permissive. They allow None, as well.
|
Thanks for the thorough review! |
|
Is there a way to tell github that (you think) you addressed all the requested changes on a PR? It seems we occasionally have dangling PRs because it's not clear whether the author is still working on it or not. |
|
I don't think so, the convention we follow is for the contributor to send a
comment to the PR saying they're done addressing the feedback.
|
|
That's also something I've missed in GitHub's workflow (similar to "request review" in Phabricator). I'll take another look at this PR in a few days. |
|
Well, "request review" exists -- it's just that "request re-review" doesn't. :-) |
gvanrossum
left a comment
There was a problem hiding this comment.
I personally think this is good to go, but I'll leave it up to @JelleZijlstra to approve and merge.
|
I guess I was stretching the definition of "a few days" :) Thanks! |
No description provided.