diff --git a/stdlib/@tests/test_cases/check_io.py b/stdlib/@tests/test_cases/check_io.py index abf84dd5a103..d0713a26ae86 100644 --- a/stdlib/@tests/test_cases/check_io.py +++ b/stdlib/@tests/test_cases/check_io.py @@ -1,6 +1,7 @@ from gzip import GzipFile from io import FileIO, TextIOWrapper +from typing_extensions import assert_type -TextIOWrapper(FileIO("")) -TextIOWrapper(FileIO(13)) -TextIOWrapper(GzipFile("")) +assert_type(TextIOWrapper(FileIO("")).buffer, FileIO) +assert_type(TextIOWrapper(FileIO(13)).detach(), FileIO) +assert_type(TextIOWrapper(GzipFile("")).buffer, GzipFile) diff --git a/stdlib/io.pyi b/stdlib/io.pyi index 01f3bfc06a27..66b9a0f5642a 100644 --- a/stdlib/io.pyi +++ b/stdlib/io.pyi @@ -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, Protocol, TextIO, TypeVar, overload, type_check_only +from typing import IO, Any, BinaryIO, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only from typing_extensions import Self __all__ = [ @@ -173,12 +173,12 @@ class _WrappedBuffer(Protocol): # 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 +_BufferT_co = TypeVar("_BufferT_co", bound=_WrappedBuffer, default=_WrappedBuffer, covariant=True) + +class TextIOWrapper(TextIOBase, TextIO, Generic[_BufferT_co]): # type: ignore[misc] # incompatible definitions of write in the base classes def __init__( self, - buffer: _WrappedBuffer, + buffer: _BufferT_co, encoding: str | None = None, errors: str | None = None, newline: str | None = None, @@ -187,7 +187,7 @@ class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # incompatible d ) -> None: ... # Equals the "buffer" argument passed in to the constructor. @property - def buffer(self) -> BinaryIO: ... + def buffer(self) -> _BufferT_co: ... # type: ignore[override] @property def closed(self) -> bool: ... @property @@ -211,7 +211,7 @@ class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # incompatible d def readline(self, size: int = -1, /) -> str: ... # type: ignore[override] def readlines(self, hint: int = -1, /) -> list[str]: ... # type: ignore[override] # Equals the "buffer" argument passed in to the constructor. - def detach(self) -> BinaryIO: ... + def detach(self) -> _BufferT_co: ... # type: ignore[override] # TextIOWrapper's version of seek only supports a limited subset of # operations. def seek(self, cookie: int, whence: int = 0, /) -> int: ...