Skip to content

make io classes inherit from typing IO classes #4145

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

Merged
merged 1 commit into from
May 30, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 24 additions & 49 deletions stdlib/3/io.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from typing import (
List, BinaryIO, TextIO, Iterator, Union, Optional, Callable, Tuple, Type, Any, IO, Iterable
List, BinaryIO, TextIO, Iterator, Union, Optional, Callable, Tuple, Type, Any, IO, Iterable, TypeVar
)
import builtins
import codecs
import sys
from mmap import mmap
from types import TracebackType
from typing import TypeVar

if sys.version_info >= (3, 8):
from typing import Literal
Expand Down Expand Up @@ -85,16 +84,20 @@ class BufferedIOBase(IOBase):
def read(self, __size: Optional[int] = ...) -> bytes: ...
def read1(self, __size: int = ...) -> bytes: ...

class FileIO(RawIOBase):
class FileIO(RawIOBase, BinaryIO):
mode: str
name: Union[int, str]
# Technically this is whatever is passed in as file, either a str, a bytes, or an int.
name: Union[int, str] # type: ignore
Comment on lines +89 to +90
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not type it as Union[str, bytes, int] then?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to broaden the type because nobody has complained about it, it's not directly related to the goal of this PR, and there's some chance broadening the type could cause new errors for people using the attribute.

Technically the right solution is to make various IO classes (not just this one but also at least TextIOWrapper) generic over (str, bytes, int) and give .name that generic type. But making these classes generic has the cost that now all users with --disallow-any-generics on have to specify the type parameter. That doesn't seem worth it for a rarely used attribute that nobody has even opened an issue about.

def __init__(
self,
file: Union[str, bytes, int],
mode: str = ...,
closefd: bool = ...,
opener: Optional[Callable[[Union[int, str], str], int]] = ...
) -> None: ...
def write(self, __b: bytes) -> int: ...
def read(self, __size: int = ...) -> bytes: ...
def __enter__(self: _T) -> _T: ...

class BytesIO(BufferedIOBase, BinaryIO):
def __init__(self, initial_bytes: bytes = ...) -> None: ...
Expand All @@ -110,23 +113,24 @@ class BytesIO(BufferedIOBase, BinaryIO):
else:
def read1(self, __size: Optional[int]) -> bytes: ... # type: ignore

class BufferedReader(BufferedIOBase):
class BufferedReader(BufferedIOBase, BinaryIO):
def __enter__(self: _T) -> _T: ...
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
def peek(self, __size: int = ...) -> bytes: ...
if sys.version_info >= (3, 7):
def read1(self, __size: int = ...) -> bytes: ...
else:
def read1(self, __size: int) -> bytes: ... # type: ignore

class BufferedWriter(BufferedIOBase):
class BufferedWriter(BufferedIOBase, BinaryIO):
def __enter__(self: _T) -> _T: ...
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
def flush(self) -> None: ...
def write(self, __buffer: Union[bytes, bytearray]) -> int: ...

class BufferedRandom(BufferedReader, BufferedWriter):
def __enter__(self: _T) -> _T: ...
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
def seek(self, __target: int, __whence: int = ...) -> int: ...
def tell(self) -> int: ...
if sys.version_info >= (3, 7):
def read1(self, __size: int = ...) -> bytes: ...
else:
Expand All @@ -144,25 +148,18 @@ class TextIOBase(IOBase):
def __iter__(self) -> Iterator[str]: ... # type: ignore
def __next__(self) -> str: ... # type: ignore
def detach(self) -> BinaryIO: ...
def write(self, s: str) -> int: ...
def write(self, __s: str) -> int: ...
def writelines(self, __lines: List[str]) -> None: ... # type: ignore
def readline(self, size: int = ...) -> str: ... # type: ignore
def readline(self, __size: int = ...) -> str: ... # type: ignore
def readlines(self, __hint: int = ...) -> List[str]: ... # type: ignore
def read(self, size: Optional[int] = ...) -> str: ...
def seek(self, offset: int, whence: int = ...) -> int: ...
def read(self, __size: Optional[int] = ...) -> str: ...
def tell(self) -> int: ...

# TODO should extend from TextIOBase
class TextIOWrapper(TextIO):
class TextIOWrapper(TextIOBase, TextIO):
line_buffering: bool
# TODO uncomment after fixing mypy about using write_through
# def __init__(self, buffer: IO[bytes], encoding: str = ...,
# errors: Optional[str] = ..., newline: Optional[str] = ...,
# line_buffering: bool = ..., write_through: bool = ...) \
# -> None: ...
def __init__(
self,
buffer: BinaryIO,
buffer: IO[bytes],
encoding: Optional[str] = ...,
errors: Optional[str] = ...,
newline: Optional[str] = ...,
Expand All @@ -181,36 +178,15 @@ class TextIOWrapper(TextIO):
line_buffering: Optional[bool] = ...,
write_through: Optional[bool] = ...
) -> None: ...
# copied from IOBase
def __exit__(self, t: Optional[Type[BaseException]] = ..., value: Optional[BaseException] = ...,
traceback: Optional[TracebackType] = ...) -> Optional[bool]: ...
def close(self) -> None: ...
def fileno(self) -> int: ...
def flush(self) -> None: ...
def isatty(self) -> bool: ...
def readable(self) -> bool: ...
def readlines(self, __hint: int = ...) -> List[str]: ...
def seekable(self) -> bool: ...
def truncate(self, __size: Optional[int] = ...) -> int: ...
def writable(self) -> bool: ...
# TODO should be the next line instead
# def writelines(self, lines: List[str]) -> None: ...
def writelines(self, __lines: Any) -> None: ...
def __del__(self) -> None: ...
closed: bool
# copied from TextIOBase
encoding: str
errors: Optional[str]
newlines: Union[str, Tuple[str, ...], None]
def __iter__(self) -> Iterator[str]: ...
def __next__(self) -> str: ...
def __enter__(self) -> TextIO: ...
def detach(self) -> BinaryIO: ...
def write(self, __text: str) -> int: ...
def readline(self, __size: int = ...) -> str: ...
def read(self, __size: Optional[int] = ...) -> str: ...
# These are inherited from TextIOBase, but must exist in the stub to satisfy mypy.
def __enter__(self: _T) -> _T: ...
def __iter__(self) -> Iterator[str]: ... # type: ignore
def __next__(self) -> str: ... # type: ignore
def writelines(self, __lines: List[str]) -> None: ... # type: ignore
def readline(self, __size: int = ...) -> str: ... # type: ignore
def readlines(self, __hint: int = ...) -> List[str]: ... # type: ignore
def seek(self, __cookie: int, __whence: int = ...) -> int: ...
def tell(self) -> int: ...

class StringIO(TextIOWrapper):
def __init__(self, initial_value: Optional[str] = ...,
Expand All @@ -220,7 +196,6 @@ class StringIO(TextIOWrapper):
# as a read-only property on IO[].
name: Any
def getvalue(self) -> str: ...
def __enter__(self) -> StringIO: ...

class IncrementalNewlineDecoder(codecs.IncrementalDecoder):
def __init__(self, decoder: Optional[codecs.IncrementalDecoder],
Expand Down