-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Turn TextIOWrapper(buffer) into a protocol #11420
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
Changes from all commits
9ea524b
b2b7077
789b965
fdb4aa7
7650976
6768aa3
fb3ab4e
4325219
45478e2
ffbcde3
ad8461f
2580cb7
36226c9
de9c18d
4c12b2d
7c9d035
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -6,7 +6,7 @@ from _typeshed import FileDescriptorOrPath, ReadableBuffer, WriteableBuffer | |||||
from collections.abc import Callable, Iterable, Iterator | ||||||
from os import _Opener | ||||||
from types import TracebackType | ||||||
from typing import IO, Any, BinaryIO, Literal, TextIO, TypeVar, overload | ||||||
from typing import IO, Any, BinaryIO, Literal, Protocol, TextIO, TypeVar, overload, type_check_only | ||||||
from typing_extensions import Self | ||||||
|
||||||
__all__ = [ | ||||||
|
@@ -94,7 +94,10 @@ class BufferedIOBase(IOBase): | |||||
|
||||||
class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes | ||||||
mode: str | ||||||
name: FileDescriptorOrPath | ||||||
# The type of "name" equals the argument passed in to the constructor, | ||||||
# but that can make FileIO incompatible with other I/O types that assume | ||||||
# "name" is a str. In the future, making FileIO generic might help. | ||||||
name: Any | ||||||
def __init__( | ||||||
self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ... | ||||||
) -> None: ... | ||||||
|
@@ -146,16 +149,43 @@ class TextIOBase(IOBase): | |||||
def readlines(self, __hint: int = -1) -> list[str]: ... # type: ignore[override] | ||||||
def read(self, __size: int | None = ...) -> str: ... | ||||||
|
||||||
@type_check_only | ||||||
class _WrappedBuffer(Protocol): | ||||||
# "name" is wrapped by TextIOWrapper. Its type is inconsistent between | ||||||
# the various I/O types, see the comments on TextIOWrapper.name and | ||||||
# TextIO.name. | ||||||
@property | ||||||
def name(self) -> Any: ... | ||||||
@property | ||||||
def closed(self) -> bool: ... | ||||||
def read(self, size: int = ..., /) -> ReadableBuffer: ... | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
It always calls read with an argument. Note this change makes the protocol more permissive. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately that's not true: https://github.com/python/cpython/blob/81e140d10b77f0a41a5581412e3f3471cc77981f/Modules/_io/textio.c#L1977. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe add a comment linking to that line in the source code? |
||||||
# Optional: def read1(self, size: int, /) -> ReadableBuffer: ... | ||||||
def write(self, b: bytes, /) -> object: ... | ||||||
def flush(self) -> object: ... | ||||||
def close(self) -> object: ... | ||||||
def seekable(self) -> bool: ... | ||||||
def readable(self) -> bool: ... | ||||||
def writable(self) -> bool: ... | ||||||
def truncate(self, size: int, /) -> int: ... | ||||||
def fileno(self) -> int: ... | ||||||
def isatty(self) -> int: ... | ||||||
# Optional: Only needs to be present if seekable() returns True. | ||||||
# def seek(self, offset: Literal[0], whence: Literal[2]) -> int: ... | ||||||
# def tell(self) -> int: ... | ||||||
|
||||||
# TODO: Should be generic over the buffer type, but needs to wait for | ||||||
# TypeVar defaults. | ||||||
class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # incompatible definitions of write in the base classes | ||||||
def __init__( | ||||||
self, | ||||||
buffer: IO[bytes], | ||||||
buffer: _WrappedBuffer, | ||||||
encoding: str | None = ..., | ||||||
errors: str | None = ..., | ||||||
newline: str | None = ..., | ||||||
line_buffering: bool = ..., | ||||||
write_through: bool = ..., | ||||||
) -> None: ... | ||||||
# Equals the "buffer" argument passed in to the constructor. | ||||||
@property | ||||||
def buffer(self) -> BinaryIO: ... | ||||||
@property | ||||||
|
@@ -180,7 +210,11 @@ class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # incompatible d | |||||
def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] | ||||||
def readline(self, __size: int = -1) -> str: ... # type: ignore[override] | ||||||
def readlines(self, __hint: int = -1) -> list[str]: ... # type: ignore[override] | ||||||
def seek(self, __cookie: int, __whence: int = 0) -> int: ... # stubtest needs this | ||||||
# Equals the "buffer" argument passed in to the constructor. | ||||||
def detach(self) -> BinaryIO: ... | ||||||
# TextIOWrapper's version of seek only supports a limited subset of | ||||||
# operations. | ||||||
def seek(self, __cookie: int, __whence: int = 0) -> int: ... | ||||||
|
||||||
class StringIO(TextIOWrapper): | ||||||
def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ... | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from gzip import GzipFile | ||
from io import FileIO, TextIOWrapper | ||
|
||
TextIOWrapper(FileIO("")) | ||
TextIOWrapper(FileIO(13)) | ||
TextIOWrapper(GzipFile("")) |
Uh oh!
There was an error while loading. Please reload this page.