From 2f87ea0c8c898a434d110ff44e942f56ab244233 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 3 Nov 2022 20:01:46 -0700 Subject: [PATCH 01/13] typing: accept buffers in typing.IO.write Fixes #9082 --- stdlib/typing.pyi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index c9cfe304311e..7459fa6be9d7 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -2,7 +2,7 @@ import _typeshed import collections # Needed by aliases like DefaultDict, see mypy issue 2986 import sys from _collections_abc import dict_items, dict_keys, dict_values -from _typeshed import IdentityFunction, Incomplete, SupportsKeysAndGetItem +from _typeshed import IdentityFunction, Incomplete, ReadableBuffer, SupportsKeysAndGetItem from abc import ABCMeta, abstractmethod from contextlib import AbstractAsyncContextManager, AbstractContextManager from re import Match as Match, Pattern as Pattern @@ -671,7 +671,11 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): @abstractmethod def writable(self) -> bool: ... @abstractmethod - def write(self, __s: AnyStr) -> int: ... + @overload + def write(self: IO[str], __s: str) -> int: ... + @abstractmethod + @overload + def write(self: IO[bytes], __s: ReadableBuffer) -> int: ... @abstractmethod def writelines(self, __lines: Iterable[AnyStr]) -> None: ... @abstractmethod From e940cdfe96d02f1b0cf4486cb946553f987709e4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 3 Nov 2022 20:11:22 -0700 Subject: [PATCH 02/13] type ignore --- stdlib/typing.pyi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 7459fa6be9d7..585306ae3623 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -692,6 +692,12 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): class BinaryIO(IO[bytes]): @abstractmethod def __enter__(self) -> BinaryIO: ... + # False positive, see + # https://github.com/python/mypy/issues/14002 + # This method can be removed when the mypy bug is fixed, it's here just + # so we don't have to type ignore every subclass of BinaryIO. + @abstractmethod + def write(self, __s: ReadableBuffer) -> int: ... # type: ignore[override] class TextIO(IO[str]): # See comment regarding the @properties in the `IO` class From 8d82f82546766b9ef2ecb7a741656bb8c922ad85 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 3 Nov 2022 20:29:47 -0700 Subject: [PATCH 03/13] need this way --- stdlib/bz2.pyi | 4 ++-- stdlib/codecs.pyi | 4 ++-- stdlib/http/client.pyi | 2 +- stdlib/io.pyi | 18 ++++++++++-------- stdlib/lzma.pyi | 4 ++-- stdlib/tempfile.pyi | 22 +++++++++++++++++----- stdlib/typing.pyi | 12 +++++------- stdlib/urllib/response.pyi | 7 ++++--- 8 files changed, 43 insertions(+), 30 deletions(-) diff --git a/stdlib/bz2.pyi b/stdlib/bz2.pyi index 295271d4a80b..adcd89afd96c 100644 --- a/stdlib/bz2.pyi +++ b/stdlib/bz2.pyi @@ -126,8 +126,8 @@ class BZ2File(BaseStream, IO[bytes]): def readinto(self, b: WriteableBuffer) -> int: ... def readlines(self, size: SupportsIndex = ...) -> list[bytes]: ... def seek(self, offset: int, whence: int = ...) -> int: ... - def write(self, data: ReadableBuffer) -> int: ... - def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ... + def write(self, data: ReadableBuffer) -> int: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 + def writelines(self, seq: Iterable[ReadableBuffer]) -> None: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 @final class BZ2Compressor: diff --git a/stdlib/codecs.pyi b/stdlib/codecs.pyi index 26c4a5801678..446de1d55b68 100644 --- a/stdlib/codecs.pyi +++ b/stdlib/codecs.pyi @@ -231,7 +231,7 @@ class StreamReaderWriter(TextIO): def __next__(self) -> str: ... def __iter__(self: Self) -> Self: ... def write(self, data: str) -> None: ... # type: ignore[override] - def writelines(self, list: Iterable[str]) -> None: ... + def writelines(self, list: Iterable[str]) -> None: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 def reset(self) -> None: ... def seek(self, offset: int, whence: int = ...) -> None: ... # type: ignore[override] def __enter__(self: Self) -> Self: ... @@ -259,7 +259,7 @@ class StreamRecoder(BinaryIO): def __next__(self) -> bytes: ... def __iter__(self: Self) -> Self: ... def write(self, data: bytes) -> None: ... # type: ignore[override] - def writelines(self, list: Iterable[bytes]) -> None: ... + def writelines(self, list: Iterable[bytes]) -> None: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 def reset(self) -> None: ... def __getattr__(self, name: str) -> Any: ... def __enter__(self: Self) -> Self: ... diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index ad794ed9b073..6f6977e476a4 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -101,7 +101,7 @@ class HTTPMessage(email.message.Message): def parse_headers(fp: io.BufferedIOBase, _class: Callable[[], email.message.Message] = ...) -> HTTPMessage: ... -class HTTPResponse(io.BufferedIOBase, BinaryIO): +class HTTPResponse(io.BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 msg: HTTPMessage headers: HTTPMessage version: int diff --git a/stdlib/io.pyi b/stdlib/io.pyi index 9c4c769fe34b..77ade3118a1b 100644 --- a/stdlib/io.pyi +++ b/stdlib/io.pyi @@ -90,7 +90,7 @@ class BufferedIOBase(IOBase): def read(self, __size: int | None = ...) -> bytes: ... def read1(self, __size: int = ...) -> bytes: ... -class FileIO(RawIOBase, BinaryIO): +class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 mode: str name: StrOrBytesPath | int # type: ignore[assignment] def __init__( @@ -98,11 +98,12 @@ class FileIO(RawIOBase, BinaryIO): ) -> None: ... @property def closefd(self) -> bool: ... - def write(self, __b: ReadableBuffer) -> int: ... + # https://github.com/python/mypy/issues/14002 + def write(self, __b: ReadableBuffer) -> int: ... # type: ignore[override] def read(self, __size: int = ...) -> bytes: ... def __enter__(self: Self) -> Self: ... -class BytesIO(BufferedIOBase, BinaryIO): +class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ... # BytesIO does not contain a "name" field. This workaround is necessary # to allow BytesIO sub-classes to add this field, as it is defined @@ -113,17 +114,18 @@ class BytesIO(BufferedIOBase, BinaryIO): def getbuffer(self) -> memoryview: ... def read1(self, __size: int | None = ...) -> bytes: ... -class BufferedReader(BufferedIOBase, BinaryIO): +class BufferedReader(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __enter__(self: Self) -> Self: ... def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... def peek(self, __size: int = ...) -> bytes: ... -class BufferedWriter(BufferedIOBase, BinaryIO): +class BufferedWriter(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __enter__(self: Self) -> Self: ... def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... - def write(self, __buffer: ReadableBuffer) -> int: ... + # https://github.com/python/mypy/issues/14002 + def write(self, __buffer: ReadableBuffer) -> int: ... # type: ignore[override] -class BufferedRandom(BufferedReader, BufferedWriter): +class BufferedRandom(BufferedReader, BufferedWriter): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __enter__(self: Self) -> Self: ... def seek(self, __target: int, __whence: int = ...) -> int: ... # stubtest needs this @@ -144,7 +146,7 @@ class TextIOBase(IOBase): def readlines(self, __hint: int = ...) -> list[str]: ... # type: ignore[override] def read(self, __size: int | None = ...) -> str: ... -class TextIOWrapper(TextIOBase, TextIO): +class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __init__( self, buffer: IO[bytes], diff --git a/stdlib/lzma.pyi b/stdlib/lzma.pyi index 9d75c627f76d..22dcede4c65e 100644 --- a/stdlib/lzma.pyi +++ b/stdlib/lzma.pyi @@ -104,7 +104,7 @@ class LZMACompressor: class LZMAError(Exception): ... -class LZMAFile(io.BufferedIOBase, IO[bytes]): +class LZMAFile(io.BufferedIOBase, IO[bytes]): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 def __init__( self, filename: _PathOrFile | None = ..., @@ -120,7 +120,7 @@ class LZMAFile(io.BufferedIOBase, IO[bytes]): def read(self, size: int | None = ...) -> bytes: ... def read1(self, size: int = ...) -> bytes: ... def readline(self, size: int | None = ...) -> bytes: ... - def write(self, data: ReadableBuffer) -> int: ... + def write(self, data: ReadableBuffer) -> int: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 def seek(self, offset: int, whence: int = ...) -> int: ... @overload diff --git a/stdlib/tempfile.pyi b/stdlib/tempfile.pyi index 2c096f0fb4de..07eb4470e55e 100644 --- a/stdlib/tempfile.pyi +++ b/stdlib/tempfile.pyi @@ -1,6 +1,6 @@ import io import sys -from _typeshed import BytesPath, GenericPath, Self, StrPath, WriteableBuffer +from _typeshed import BytesPath, GenericPath, ReadableBuffer, Self, StrPath, WriteableBuffer from collections.abc import Iterable, Iterator from types import TracebackType from typing import IO, Any, AnyStr, Generic, overload @@ -215,8 +215,14 @@ class _TemporaryFileWrapper(Generic[AnyStr], IO[AnyStr]): def tell(self) -> int: ... def truncate(self, size: int | None = ...) -> int: ... def writable(self) -> bool: ... - def write(self, s: AnyStr) -> int: ... - def writelines(self, lines: Iterable[AnyStr]) -> None: ... + @overload + def write(self: _TemporaryFileWrapper[str], s: str) -> int: ... + @overload + def write(self: _TemporaryFileWrapper[bytes], s: ReadableBuffer) -> int: ... + @overload + def writelines(self: _TemporaryFileWrapper[str], lines: Iterable[str]) -> None: ... + @overload + def writelines(self: _TemporaryFileWrapper[bytes], lines: Iterable[ReadableBuffer]) -> None: ... if sys.version_info >= (3, 11): _SpooledTemporaryFileBase = io.IOBase @@ -338,8 +344,14 @@ class SpooledTemporaryFile(IO[AnyStr], _SpooledTemporaryFileBase): def seek(self, offset: int, whence: int = ...) -> int: ... def tell(self) -> int: ... def truncate(self, size: int | None = ...) -> None: ... # type: ignore[override] - def write(self, s: AnyStr) -> int: ... - def writelines(self, iterable: Iterable[AnyStr]) -> None: ... # type: ignore[override] + @overload + def write(self: SpooledTemporaryFile[str], s: str) -> int: ... + @overload + def write(self: SpooledTemporaryFile[bytes], s: ReadableBuffer) -> int: ... + @overload + def writelines(self: SpooledTemporaryFile[str], iterable: Iterable[str]) -> None: ... + @overload + def writelines(self: SpooledTemporaryFile[bytes], iterable: Iterable[ReadableBuffer]) -> None: ... def __iter__(self) -> Iterator[AnyStr]: ... # type: ignore[override] # These exist at runtime only on 3.11+. def readable(self) -> bool: ... diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 585306ae3623..a807de1fe4a9 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -677,7 +677,11 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): @overload def write(self: IO[bytes], __s: ReadableBuffer) -> int: ... @abstractmethod - def writelines(self, __lines: Iterable[AnyStr]) -> None: ... + @overload + def writelines(self: IO[str], __s: Iterable[str]) -> None: ... + @abstractmethod + @overload + def writelines(self: IO[bytes], __lines: Iterable[ReadableBuffer]) -> None: ... @abstractmethod def __next__(self) -> AnyStr: ... @abstractmethod @@ -692,12 +696,6 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): class BinaryIO(IO[bytes]): @abstractmethod def __enter__(self) -> BinaryIO: ... - # False positive, see - # https://github.com/python/mypy/issues/14002 - # This method can be removed when the mypy bug is fixed, it's here just - # so we don't have to type ignore every subclass of BinaryIO. - @abstractmethod - def write(self, __s: ReadableBuffer) -> int: ... # type: ignore[override] class TextIO(IO[str]): # See comment regarding the @properties in the `IO` class diff --git a/stdlib/urllib/response.pyi b/stdlib/urllib/response.pyi index 8c9a600f3c48..9e7e3d0925f7 100644 --- a/stdlib/urllib/response.pyi +++ b/stdlib/urllib/response.pyi @@ -1,5 +1,5 @@ import sys -from _typeshed import Self +from _typeshed import ReadableBuffer, Self from collections.abc import Callable, Iterable from email.message import Message from types import TracebackType @@ -33,8 +33,9 @@ class addbase(BinaryIO): def tell(self) -> int: ... def truncate(self, size: int | None = ...) -> int: ... def writable(self) -> bool: ... - def write(self, s: bytes) -> int: ... - def writelines(self, lines: Iterable[bytes]) -> None: ... + # https://github.com/python/mypy/issues/14002 + def write(self, s: ReadableBuffer) -> int: ... # type: ignore[override] + def writelines(self, lines: Iterable[bytes]) -> None: ... # type: ignore[override] class addclosehook(addbase): closehook: Callable[..., object] From 5aacf0a175de772ea74350a4df86e5e2071e3c96 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 3 Nov 2022 20:32:19 -0700 Subject: [PATCH 04/13] fix arg name --- stdlib/typing.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index a807de1fe4a9..f5b29fb6b4de 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -678,7 +678,7 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): def write(self: IO[bytes], __s: ReadableBuffer) -> int: ... @abstractmethod @overload - def writelines(self: IO[str], __s: Iterable[str]) -> None: ... + def writelines(self: IO[str], __lines: Iterable[str]) -> None: ... @abstractmethod @overload def writelines(self: IO[bytes], __lines: Iterable[ReadableBuffer]) -> None: ... From 2894148c61e9bc4dc1e8d011e0ac25f1dec8e909 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 8 Feb 2023 08:32:37 +0000 Subject: [PATCH 05/13] Update lzma.pyi --- stdlib/lzma.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/lzma.pyi b/stdlib/lzma.pyi index 2feb28a8e743..7d94943b0543 100644 --- a/stdlib/lzma.pyi +++ b/stdlib/lzma.pyi @@ -104,7 +104,7 @@ class LZMACompressor: class LZMAError(Exception): ... -class LZMAFile(io.BufferedIOBase, IO[bytes]): +class LZMAFile(io.BufferedIOBase, IO[bytes]): # type: ignore[misc] # incomptatible definitions of writelines in the 2 bases def __init__( self, filename: _PathOrFile | None = None, From 641511b28bd0dead347ed75bff54c29a5194c22e Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:19:42 -0800 Subject: [PATCH 06/13] Remove references to closed mypy issue --- stdlib/codecs.pyi | 5 +++-- stdlib/http/client.pyi | 3 ++- stdlib/io.pyi | 16 ++++++++-------- stdlib/urllib/response.pyi | 5 ++--- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/stdlib/codecs.pyi b/stdlib/codecs.pyi index f0226b9aa070..3f6d2d3d16b7 100644 --- a/stdlib/codecs.pyi +++ b/stdlib/codecs.pyi @@ -239,7 +239,7 @@ class StreamReaderWriter(TextIO): def __next__(self) -> str: ... def __iter__(self) -> Self: ... def write(self, data: str) -> None: ... # type: ignore[override] - def writelines(self, list: Iterable[str]) -> None: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 + def writelines(self, list: Iterable[str]) -> None: ... def reset(self) -> None: ... def seek(self, offset: int, whence: int = 0) -> None: ... # type: ignore[override] def __enter__(self) -> Self: ... @@ -272,8 +272,9 @@ class StreamRecoder(BinaryIO): def readlines(self, sizehint: int | None = None) -> list[bytes]: ... def __next__(self) -> bytes: ... def __iter__(self) -> Self: ... + # Base class accepts more types than just bytes def write(self, data: bytes) -> None: ... # type: ignore[override] - def writelines(self, list: Iterable[bytes]) -> None: ... # type: ignore[override] # https://github.com/python/mypy/issues/14002 + def writelines(self, list: Iterable[bytes]) -> None: ... # type: ignore[override] def reset(self) -> None: ... def __getattr__(self, name: str) -> Any: ... def __enter__(self) -> Self: ... diff --git a/stdlib/http/client.pyi b/stdlib/http/client.pyi index 972e417f290e..db96702f3454 100644 --- a/stdlib/http/client.pyi +++ b/stdlib/http/client.pyi @@ -101,7 +101,8 @@ class HTTPMessage(email.message.Message): def parse_headers(fp: io.BufferedIOBase, _class: Callable[[], email.message.Message] = ...) -> HTTPMessage: ... -class HTTPResponse(io.BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +# superclasses have incompatible write and writelines methods +class HTTPResponse(io.BufferedIOBase, BinaryIO): # type: ignore[misc] msg: HTTPMessage headers: HTTPMessage version: int diff --git a/stdlib/io.pyi b/stdlib/io.pyi index dd269ba9fda0..85f5a45168c3 100644 --- a/stdlib/io.pyi +++ b/stdlib/io.pyi @@ -90,7 +90,7 @@ class BufferedIOBase(IOBase): def read(self, __size: int | None = ...) -> bytes: ... def read1(self, __size: int = ...) -> bytes: ... -class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] mode: str name: FileDescriptorOrPath # type: ignore[assignment] def __init__( @@ -102,7 +102,7 @@ class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # https://github.com/p def read(self, __size: int = -1) -> bytes: ... def __enter__(self) -> Self: ... -class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ... # BytesIO does not contain a "name" field. This workaround is necessary # to allow BytesIO sub-classes to add this field, as it is defined @@ -113,18 +113,18 @@ class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github def getbuffer(self) -> memoryview: ... def read1(self, __size: int | None = -1) -> bytes: ... -class BufferedReader(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +# superclasses have incompatible write and writelines methods +class BufferedReader(BufferedIOBase, BinaryIO): # type: ignore[misc] def __enter__(self) -> Self: ... def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... def peek(self, __size: int = 0) -> bytes: ... -class BufferedWriter(BufferedIOBase, BinaryIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +class BufferedWriter(BufferedIOBase, BinaryIO): # type: ignore[misc] def __enter__(self) -> Self: ... def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... - # https://github.com/python/mypy/issues/14002 - def write(self, __buffer: ReadableBuffer) -> int: ... # type: ignore[override] + def write(self, __buffer: ReadableBuffer) -> int: ... -class BufferedRandom(BufferedReader, BufferedWriter): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +class BufferedRandom(BufferedReader, BufferedWriter): # type: ignore[misc] def __enter__(self) -> Self: ... def seek(self, __target: int, __whence: int = 0) -> int: ... # stubtest needs this @@ -145,7 +145,7 @@ class TextIOBase(IOBase): def readlines(self, __hint: int = -1) -> list[str]: ... # type: ignore[override] def read(self, __size: int | None = ...) -> str: ... -class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] # https://github.com/python/mypy/issues/14002 +class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] def __init__( self, buffer: IO[bytes], diff --git a/stdlib/urllib/response.pyi b/stdlib/urllib/response.pyi index 81fc00fbf34c..61ba687076b2 100644 --- a/stdlib/urllib/response.pyi +++ b/stdlib/urllib/response.pyi @@ -34,9 +34,8 @@ class addbase(BinaryIO): def tell(self) -> int: ... def truncate(self, size: int | None = ...) -> int: ... def writable(self) -> bool: ... - # https://github.com/python/mypy/issues/14002 - def write(self, s: ReadableBuffer) -> int: ... # type: ignore[override] - def writelines(self, lines: Iterable[bytes]) -> None: ... # type: ignore[override] + def write(self, s: ReadableBuffer) -> int: ... + def writelines(self, lines: Iterable[ReadableBuffer]) -> None: ... class addclosehook(addbase): closehook: Callable[..., object] From 590851b02b67c3ed7c74133cfdb719a824210fd3 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:35:40 -0800 Subject: [PATCH 07/13] Adjust overloads to work with pyright --- stdlib/tempfile.pyi | 8 ++++---- stdlib/typing.pyi | 4 ++-- test_cases/stdlib/typing/check_io.py | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 test_cases/stdlib/typing/check_io.py diff --git a/stdlib/tempfile.pyi b/stdlib/tempfile.pyi index 80a5af52a329..7019a7089f71 100644 --- a/stdlib/tempfile.pyi +++ b/stdlib/tempfile.pyi @@ -216,11 +216,11 @@ class _TemporaryFileWrapper(Generic[AnyStr], IO[AnyStr]): def truncate(self, size: int | None = ...) -> int: ... def writable(self) -> bool: ... @overload - def write(self: _TemporaryFileWrapper[str], s: str) -> int: ... + def write(self, s: AnyStr) -> int: ... @overload def write(self: _TemporaryFileWrapper[bytes], s: ReadableBuffer) -> int: ... @overload - def writelines(self: _TemporaryFileWrapper[str], lines: Iterable[str]) -> None: ... + def writelines(self, lines: Iterable[AnyStr]) -> None: ... @overload def writelines(self: _TemporaryFileWrapper[bytes], lines: Iterable[ReadableBuffer]) -> None: ... @@ -399,11 +399,11 @@ class SpooledTemporaryFile(IO[AnyStr], _SpooledTemporaryFileBase): def tell(self) -> int: ... def truncate(self, size: int | None = None) -> None: ... # type: ignore[override] @overload - def write(self: SpooledTemporaryFile[str], s: str) -> int: ... + def write(self, s: AnyStr) -> int: ... @overload def write(self: SpooledTemporaryFile[bytes], s: ReadableBuffer) -> int: ... @overload - def writelines(self: SpooledTemporaryFile[str], iterable: Iterable[str]) -> None: ... + def writelines(self, iterable: Iterable[AnyStr]) -> None: ... @overload def writelines(self: SpooledTemporaryFile[bytes], iterable: Iterable[ReadableBuffer]) -> None: ... def __iter__(self) -> Iterator[AnyStr]: ... # type: ignore[override] diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 38760485fb70..642a5048c995 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -688,13 +688,13 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): def writable(self) -> bool: ... @abstractmethod @overload - def write(self: IO[str], __s: str) -> int: ... + def write(self, __s: AnyStr) -> int: ... @abstractmethod @overload def write(self: IO[bytes], __s: ReadableBuffer) -> int: ... @abstractmethod @overload - def writelines(self: IO[str], __lines: Iterable[str]) -> None: ... + def writelines(self, __lines: Iterable[AnyStr]) -> None: ... @abstractmethod @overload def writelines(self: IO[bytes], __lines: Iterable[ReadableBuffer]) -> None: ... diff --git a/test_cases/stdlib/typing/check_io.py b/test_cases/stdlib/typing/check_io.py new file mode 100644 index 000000000000..03a7f1d1c50b --- /dev/null +++ b/test_cases/stdlib/typing/check_io.py @@ -0,0 +1,19 @@ +import pickle +from typing import AnyStr, IO + + +def check_write(io_bytes: IO[bytes], io_str: IO[str], io_anystr: IO[AnyStr], any_str: AnyStr, buf: pickle.PickleBuffer) -> None: + io_bytes.write(b"") + io_bytes.write(buf) + io_bytes.write("") # type: ignore + io_bytes.write(any_str) # type: ignore + + io_str.write(b"") # type: ignore + io_str.write(buf) # type: ignore + io_str.write("") + io_str.write(any_str) # type: ignore + + io_anystr.write(b"") # type: ignore + io_anystr.write(buf) # type: ignore + io_anystr.write("") # type: ignore + io_anystr.write(any_str) From b6174cb41b2eda5f37116c3717ba934ee6d61309 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 10 Mar 2023 03:36:54 +0000 Subject: [PATCH 08/13] [pre-commit.ci] auto fixes from pre-commit.com hooks --- test_cases/stdlib/typing/check_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_cases/stdlib/typing/check_io.py b/test_cases/stdlib/typing/check_io.py index 03a7f1d1c50b..f11d6d210a87 100644 --- a/test_cases/stdlib/typing/check_io.py +++ b/test_cases/stdlib/typing/check_io.py @@ -1,5 +1,5 @@ import pickle -from typing import AnyStr, IO +from typing import IO, AnyStr def check_write(io_bytes: IO[bytes], io_str: IO[str], io_anystr: IO[AnyStr], any_str: AnyStr, buf: pickle.PickleBuffer) -> None: From 92c2606236e8933dd0fbcacf235c56daf1de6349 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:41:54 -0800 Subject: [PATCH 09/13] ignore another --- stdlib/codecs.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/codecs.pyi b/stdlib/codecs.pyi index 3f6d2d3d16b7..fd33592593ce 100644 --- a/stdlib/codecs.pyi +++ b/stdlib/codecs.pyi @@ -239,7 +239,7 @@ class StreamReaderWriter(TextIO): def __next__(self) -> str: ... def __iter__(self) -> Self: ... def write(self, data: str) -> None: ... # type: ignore[override] - def writelines(self, list: Iterable[str]) -> None: ... + def writelines(self, list: Iterable[str]) -> None: ... # type: ignore[override] def reset(self) -> None: ... def seek(self, offset: int, whence: int = 0) -> None: ... # type: ignore[override] def __enter__(self) -> Self: ... From 7f10fc821abc40a7be0e0a19789b329235a2fcf4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:42:54 -0800 Subject: [PATCH 10/13] no picklebuffer in 3.7 --- test_cases/stdlib/typing/check_io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_cases/stdlib/typing/check_io.py b/test_cases/stdlib/typing/check_io.py index f11d6d210a87..517d4b2ba569 100644 --- a/test_cases/stdlib/typing/check_io.py +++ b/test_cases/stdlib/typing/check_io.py @@ -1,8 +1,8 @@ -import pickle +import mmap from typing import IO, AnyStr -def check_write(io_bytes: IO[bytes], io_str: IO[str], io_anystr: IO[AnyStr], any_str: AnyStr, buf: pickle.PickleBuffer) -> None: +def check_write(io_bytes: IO[bytes], io_str: IO[str], io_anystr: IO[AnyStr], any_str: AnyStr, buf: mmap.mmap) -> None: io_bytes.write(b"") io_bytes.write(buf) io_bytes.write("") # type: ignore From 684b4eed86e20bc4d42bb95274a39ff957d54767 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:45:54 -0800 Subject: [PATCH 11/13] into the uncertain future --- test_cases/stdlib/typing/check_io.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_cases/stdlib/typing/check_io.py b/test_cases/stdlib/typing/check_io.py index 517d4b2ba569..67f16dc91765 100644 --- a/test_cases/stdlib/typing/check_io.py +++ b/test_cases/stdlib/typing/check_io.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import mmap from typing import IO, AnyStr From bd78b5be90c967cf8b3eeadcc3b075f34785da4e Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 19:58:08 -0800 Subject: [PATCH 12/13] maybe help mypy primer --- stdlib/io.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/io.pyi b/stdlib/io.pyi index 85f5a45168c3..29efb1107b8c 100644 --- a/stdlib/io.pyi +++ b/stdlib/io.pyi @@ -177,6 +177,7 @@ class TextIOWrapper(TextIOBase, TextIO): # type: ignore[misc] def __iter__(self) -> Iterator[str]: ... # type: ignore[override] def __next__(self) -> str: ... # type: ignore[override] def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] + def write(self, __s: str) -> int: ... # 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 From 37bb27ef7a438ff4b9bf3fa813119a3d31f2a55c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 9 Mar 2023 20:18:00 -0800 Subject: [PATCH 13/13] try the other way --- stdlib/typing.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 642a5048c995..38760485fb70 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -688,13 +688,13 @@ class IO(Iterator[AnyStr], Generic[AnyStr]): def writable(self) -> bool: ... @abstractmethod @overload - def write(self, __s: AnyStr) -> int: ... + def write(self: IO[str], __s: str) -> int: ... @abstractmethod @overload def write(self: IO[bytes], __s: ReadableBuffer) -> int: ... @abstractmethod @overload - def writelines(self, __lines: Iterable[AnyStr]) -> None: ... + def writelines(self: IO[str], __lines: Iterable[str]) -> None: ... @abstractmethod @overload def writelines(self: IO[bytes], __lines: Iterable[ReadableBuffer]) -> None: ...