diff --git a/pyproject.toml b/pyproject.toml index 9efc93d93cab..e3c8e51df969 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,6 +66,7 @@ extra-standard-library = [ "_dummy_threading", "_heapq", "_imp", + "_io", "_json", "_locale", "_markupbase", diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index f4c134c25da1..b7c176166ff9 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -34,6 +34,7 @@ _dummy_thread: 3.0-3.8 _dummy_threading: 2.7-3.8 _heapq: 2.7- _imp: 3.0- +_io: 3.0- _json: 2.7- _locale: 2.7- _markupbase: 2.7- diff --git a/stdlib/_io.pyi b/stdlib/_io.pyi new file mode 100644 index 000000000000..47244154c1d2 --- /dev/null +++ b/stdlib/_io.pyi @@ -0,0 +1,188 @@ +import builtins +import codecs +import sys +from _typeshed import FileDescriptorOrPath, ReadableBuffer, WriteableBuffer +from collections.abc import Callable, Iterable, Iterator +from io import BufferedIOBase, RawIOBase, TextIOBase, UnsupportedOperation as UnsupportedOperation +from os import _Opener +from types import TracebackType +from typing import IO, Any, BinaryIO, TextIO, TypeVar, overload +from typing_extensions import Literal, Self + +_T = TypeVar("_T") + +DEFAULT_BUFFER_SIZE: Literal[8192] + +open = builtins.open +BlockingIOError = builtins.BlockingIOError + +if sys.version_info >= (3, 8): + def open_code(path: str) -> IO[bytes]: ... + +if sys.version_info >= (3, 10): + @overload + def text_encoding(__encoding: None, __stacklevel: int = 2) -> Literal["locale", "utf-8"]: ... + @overload + def text_encoding(__encoding: _T, __stacklevel: int = 2) -> _T: ... + +class _IOBase: + def __del__(self) -> None: ... + def __enter__(self) -> Self: ... + def __exit__( + self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None + ) -> None: ... + def __iter__(self) -> Iterator[bytes]: ... + def __next__(self) -> bytes: ... + def close(self) -> None: ... + @property + def closed(self) -> bool: ... + def fileno(self) -> int: ... + def flush(self) -> None: ... + def isatty(self) -> bool: ... + read: Callable[..., Any] + def readable(self) -> bool: ... + def readline(self, __size: int | None = -1) -> bytes: ... + def readlines(self, __hint: int = -1) -> list[bytes]: ... + def seek(self, __offset: int, __whence: int = ...) -> int: ... + def seekable(self) -> bool: ... + def tell(self) -> int: ... + def truncate(self, __size: int | None = ...) -> int: ... + def writable(self) -> bool: ... + write: Callable[..., Any] + def writelines(self, __lines: Iterable[ReadableBuffer]) -> None: ... + def _checkClosed(self, msg: str | None = ...) -> None: ... # undocumented + +class _RawIOBase(_IOBase): + def read(self, __size: int = -1) -> bytes | None: ... + def readall(self) -> bytes: ... + def readinto(self, __buffer: WriteableBuffer) -> int | None: ... + def write(self, __b: ReadableBuffer) -> int | None: ... + +class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes + mode: str + name: FileDescriptorOrPath + def __init__( + self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ... + ) -> None: ... + @property + def closefd(self) -> bool: ... + def read(self, __size: int = -1) -> bytes: ... + def write(self, __b: ReadableBuffer) -> int: ... + + # these are only here so stubtest is happy with the argument names + def seek(self, __pos: int, __whence: int = ...) -> int: ... + +class _BufferedIOBase(_IOBase): + def detach(self) -> RawIOBase: ... + def read(self, __size: int | None = ...) -> bytes: ... + def read1(self, __size: int = ...) -> bytes: ... + def readinto(self, __buffer: WriteableBuffer) -> int: ... + def readinto1(self, __buffer: WriteableBuffer) -> int: ... + def write(self, __buffer: ReadableBuffer) -> int: ... + +class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + # BytesIO does not contain a "name" field. This workaround is necessary + # to allow BytesIO sub-classes to add this field, as it is defined + # as a read-only property on IO[]. + name: Any + def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ... + def getbuffer(self) -> memoryview: ... + def getvalue(self) -> bytes: ... + def read1(self, __size: int | None = -1) -> bytes: ... + def readlines(self, __size: int | None = None) -> list[bytes]: ... + + # these are only here so stubtest is happy with the argument names + def seek(self, __pos: int, __whence: int = ...) -> int: ... + +class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + # technically has mode and name attributes, but they're just pass-throughs to + # self.raw.* + raw: RawIOBase + def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... + def peek(self, __size: int = 0) -> bytes: ... + + # these are only here so stubtest is happy with the argument names + def truncate(self, __pos: int | None = ...) -> int: ... + def seek(self, __target: int, __whence: int = ...) -> int: ... + +class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes + # technically has mode and name attributes, but they're just pass-throughs to + # self.raw.* + raw: RawIOBase + def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... + def write(self, __buffer: ReadableBuffer) -> int: ... + + # these are only here so stubtest is happy with the argument names + def truncate(self, __pos: int | None = ...) -> int: ... + def seek(self, __target: int, __whence: int = ...) -> int: ... + +class BufferedRWPair(BufferedIOBase, _BufferedIOBase): + def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ... + def peek(self, __size: int = ...) -> bytes: ... + +class BufferedRandom(BufferedReader, BufferedWriter, _BufferedIOBase): ... # type: ignore[misc] # incompatible definitions of methods in the base classes + +class _TextIOBase(_IOBase): + encoding: str + errors: str | None + newlines: str | tuple[str, ...] | None + def __iter__(self) -> Iterator[str]: ... # type: ignore[override] + def __next__(self) -> str: ... # type: ignore[override] + def detach(self) -> BinaryIO: ... + def read(self, __size: int | None = ...) -> str: ... + def readline(self, __size: int = ...) -> str: ... # type: ignore[override] + def readlines(self, __hint: int = -1) -> list[str]: ... # type: ignore[override] + def write(self, __s: str) -> int: ... + def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] + +class TextIOWrapper(TextIOBase, _TextIOBase, TextIO): # type: ignore[misc] # incompatible definitions of methods in the base classes + def __init__( + self, + buffer: IO[bytes], + encoding: str | None = ..., + errors: str | None = ..., + newline: str | None = ..., + line_buffering: bool = ..., + write_through: bool = ..., + ) -> None: ... + @property + def buffer(self) -> BinaryIO: ... + @property + def line_buffering(self) -> bool: ... + @property + def name(self) -> str: ... + @property + def write_through(self) -> bool: ... + def reconfigure( + self, + *, + encoding: str | None = None, + errors: str | None = None, + newline: str | None = None, + line_buffering: bool | None = None, + write_through: bool | None = None, + ) -> None: ... + + # these are only here so stubtest is happy with the argument names + def truncate(self, __pos: int | None = ...) -> int: ... + def seek(self, __cookie: int, __whence: int = ...) -> int: ... + +class StringIO(TextIOWrapper, _TextIOBase): # type: ignore[misc] # incompatible definitions of methods in the base classes + # StringIO does not contain a "name" field. This workaround is necessary + # to allow StringIO sub-classes to add this field, as it is defined + # as a read-only property on IO[]. + name: Any + def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ... + @property + def line_buffering(self) -> bool: ... + def getvalue(self) -> str: ... + + # these are only here so stubtest is happy with the argument names + def seek(self, __pos: int, __whence: int = ...) -> int: ... + +class IncrementalNewlineDecoder(codecs.IncrementalDecoder): + def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ... + @property + def newlines(self) -> str | tuple[str, ...] | None: ... + def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ... + def setstate(self, __state: tuple[bytes, int]) -> None: ... diff --git a/stdlib/io.pyi b/stdlib/io.pyi index ee4eda1b4eb0..11118f4f7305 100644 --- a/stdlib/io.pyi +++ b/stdlib/io.pyi @@ -1,13 +1,24 @@ import abc -import builtins -import codecs import sys -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, TextIO, TypeVar, overload -from typing_extensions import Literal, Self +from _io import ( + DEFAULT_BUFFER_SIZE as DEFAULT_BUFFER_SIZE, + BlockingIOError as BlockingIOError, + BufferedRandom as BufferedRandom, + BufferedReader as BufferedReader, + BufferedRWPair as BufferedRWPair, + BufferedWriter as BufferedWriter, + BytesIO as BytesIO, + FileIO as FileIO, + IncrementalNewlineDecoder as IncrementalNewlineDecoder, + StringIO as StringIO, + TextIOWrapper as TextIOWrapper, + _BufferedIOBase, + _IOBase, + _RawIOBase, + _TextIOBase, + open as open, +) +from typing_extensions import Literal __all__ = [ "BlockingIOError", @@ -30,178 +41,23 @@ __all__ = [ "SEEK_END", ] +if sys.version_info >= (3, 10): + from _io import text_encoding as text_encoding + if sys.version_info >= (3, 8): + from _io import open_code as open_code + __all__ += ["open_code"] if sys.version_info >= (3, 11): __all__ += ["DEFAULT_BUFFER_SIZE", "IncrementalNewlineDecoder", "text_encoding"] -_T = TypeVar("_T") - -DEFAULT_BUFFER_SIZE: Literal[8192] - SEEK_SET: Literal[0] SEEK_CUR: Literal[1] SEEK_END: Literal[2] -open = builtins.open - -if sys.version_info >= (3, 8): - def open_code(path: str) -> IO[bytes]: ... - -BlockingIOError = builtins.BlockingIOError - class UnsupportedOperation(OSError, ValueError): ... - -class IOBase(metaclass=abc.ABCMeta): - def __iter__(self) -> Iterator[bytes]: ... - def __next__(self) -> bytes: ... - def __enter__(self) -> Self: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> None: ... - def close(self) -> None: ... - def fileno(self) -> int: ... - def flush(self) -> None: ... - def isatty(self) -> bool: ... - def readable(self) -> bool: ... - read: Callable[..., Any] - def readlines(self, __hint: int = -1) -> list[bytes]: ... - def seek(self, __offset: int, __whence: int = ...) -> int: ... - def seekable(self) -> bool: ... - def tell(self) -> int: ... - def truncate(self, __size: int | None = ...) -> int: ... - def writable(self) -> bool: ... - write: Callable[..., Any] - def writelines(self, __lines: Iterable[ReadableBuffer]) -> None: ... - def readline(self, __size: int | None = -1) -> bytes: ... - def __del__(self) -> None: ... - @property - def closed(self) -> bool: ... - def _checkClosed(self, msg: str | None = ...) -> None: ... # undocumented - -class RawIOBase(IOBase): - def readall(self) -> bytes: ... - def readinto(self, __buffer: WriteableBuffer) -> int | None: ... - def write(self, __b: ReadableBuffer) -> int | None: ... - def read(self, __size: int = -1) -> bytes | None: ... - -class BufferedIOBase(IOBase): - raw: RawIOBase # This is not part of the BufferedIOBase API and may not exist on some implementations. - def detach(self) -> RawIOBase: ... - def readinto(self, __buffer: WriteableBuffer) -> int: ... - def write(self, __buffer: ReadableBuffer) -> int: ... - def readinto1(self, __buffer: WriteableBuffer) -> int: ... - def read(self, __size: int | None = ...) -> bytes: ... - def read1(self, __size: int = ...) -> bytes: ... - -class FileIO(RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes - mode: str - name: FileDescriptorOrPath - def __init__( - self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ... - ) -> None: ... - @property - def closefd(self) -> bool: ... - def write(self, __b: ReadableBuffer) -> int: ... - def read(self, __size: int = -1) -> bytes: ... - def __enter__(self) -> Self: ... - -class BytesIO(BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes - 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 - # as a read-only property on IO[]. - name: Any - def __enter__(self) -> Self: ... - def getvalue(self) -> bytes: ... - def getbuffer(self) -> memoryview: ... - def read1(self, __size: int | None = -1) -> bytes: ... - -class BufferedReader(BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes - 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] # incompatible definitions of writelines in the base classes - def __enter__(self) -> Self: ... - def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ... - def write(self, __buffer: ReadableBuffer) -> int: ... - -class BufferedRandom(BufferedReader, BufferedWriter): # type: ignore[misc] # incompatible definitions of methods in the base classes - def __enter__(self) -> Self: ... - def seek(self, __target: int, __whence: int = 0) -> int: ... # stubtest needs this - -class BufferedRWPair(BufferedIOBase): - def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ... - def peek(self, __size: int = ...) -> bytes: ... - -class TextIOBase(IOBase): - encoding: str - errors: str | None - newlines: str | tuple[str, ...] | None - def __iter__(self) -> Iterator[str]: ... # type: ignore[override] - def __next__(self) -> str: ... # type: ignore[override] - def detach(self) -> BinaryIO: ... - def write(self, __s: str) -> int: ... - def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override] - def readline(self, __size: int = ...) -> str: ... # type: ignore[override] - 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] # incompatible definitions of write in the base classes - def __init__( - self, - buffer: IO[bytes], - encoding: str | None = ..., - errors: str | None = ..., - newline: str | None = ..., - line_buffering: bool = ..., - write_through: bool = ..., - ) -> None: ... - @property - def buffer(self) -> BinaryIO: ... - @property - def closed(self) -> bool: ... - @property - def line_buffering(self) -> bool: ... - @property - def write_through(self) -> bool: ... - def reconfigure( - self, - *, - encoding: str | None = None, - errors: str | None = None, - newline: str | None = None, - line_buffering: bool | None = None, - write_through: bool | None = None, - ) -> None: ... - # These are inherited from TextIOBase, but must exist in the stub to satisfy mypy. - def __enter__(self) -> Self: ... - 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 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 - -class StringIO(TextIOWrapper): - def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ... - # StringIO does not contain a "name" field. This workaround is necessary - # to allow StringIO sub-classes to add this field, as it is defined - # as a read-only property on IO[]. - name: Any - def getvalue(self) -> str: ... - -class IncrementalNewlineDecoder(codecs.IncrementalDecoder): - def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ... - def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ... - @property - def newlines(self) -> str | tuple[str, ...] | None: ... - def setstate(self, __state: tuple[bytes, int]) -> None: ... - -if sys.version_info >= (3, 10): - @overload - def text_encoding(__encoding: None, __stacklevel: int = 2) -> Literal["locale", "utf-8"]: ... - @overload - def text_encoding(__encoding: _T, __stacklevel: int = 2) -> _T: ... +class IOBase(_IOBase, metaclass=abc.ABCMeta): ... +class RawIOBase(_RawIOBase, IOBase): ... +class BufferedIOBase(_BufferedIOBase, IOBase): ... +class TextIOBase(_TextIOBase, IOBase): ... diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index c79bcacd6565..9f3a33373212 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -52,17 +52,6 @@ importlib.abc.Loader.exec_module # See Lib/importlib/_abc.py. Might be defined importlib.abc.MetaPathFinder.find_spec # Not defined on the actual class, but expected to exist. importlib.abc.PathEntryFinder.find_spec # Not defined on the actual class, but expected to exist. importlib.machinery.ExtensionFileLoader.get_filename # Wrapped with _check_name decorator which changes runtime signature -io.BufferedRandom.truncate -io.BufferedReader.seek -io.BufferedReader.truncate -io.BufferedWriter.seek -io.BufferedWriter.truncate -io.BytesIO.readlines -io.BytesIO.seek # Parameter name for a positional-only param differs from its name in the inherited method -io.FileIO.seek -io.StringIO.seek -io.StringIO.truncate -io.TextIOWrapper.truncate ipaddress.IPv4Interface.hostmask ipaddress.IPv6Interface.hostmask ipaddress._BaseNetwork.broadcast_address