Skip to content

Commit 7dd820f

Browse files
committed
add _io module
In addition to shuffling defintions between files, these things got tweaked: - I moved BufferedIOBase.raw to the child classes which *do* define that attribute on themselves - Removed several redundant definitions of __enter__. These seem to be an artifact of using TypeVar instead of Self originally - seek and truncate have inconsistent variable names. They're also positional only, so they were in the stubtest allowlist before, but I went ahead and made them explicit in the stubs - BytesIO.readlines shouldn't have been on the allowlist in the first place. It differs not only in variable name, but also default value. - A big block of functions in TextIOWrapper were commented that mypy needed them, but I don't think it does anymore, unless there's a problem with subclassing TextIOWrapper that doesn't show up in typeshed itself. No indication in the history about that. - In the implementation, the concrete classes inherit from the private implementation _*IOBase classes, not the classes in io which are actually metaclasses, but they are registered to those metaclasses at runtime. It wasn't technically required for any reason, but I split the difference on this by keeping the _*IOBase classes in their base classes directly. I think it's a bit of a reminder of the actual implementation, and means that a stubtest check for inheritance will show that typeshed is adding to the base classes, rather than replacing the base class, and I think that's a little cleaner. Partially related to #3968
1 parent ba7bd9f commit 7dd820f

File tree

5 files changed

+217
-183
lines changed

5 files changed

+217
-183
lines changed

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ extra-standard-library = [
6666
"_dummy_threading",
6767
"_heapq",
6868
"_imp",
69+
"_io",
6970
"_json",
7071
"_locale",
7172
"_markupbase",

stdlib/VERSIONS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ _dummy_thread: 3.0-3.8
3434
_dummy_threading: 2.7-3.8
3535
_heapq: 2.7-
3636
_imp: 3.0-
37+
_io: 3.0-
3738
_json: 2.7-
3839
_locale: 2.7-
3940
_markupbase: 2.7-

stdlib/_io.pyi

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
import builtins
2+
import codecs
3+
import sys
4+
from _typeshed import FileDescriptorOrPath, ReadableBuffer, WriteableBuffer
5+
from collections.abc import Callable, Iterable, Iterator
6+
from io import BufferedIOBase, RawIOBase, TextIOBase, UnsupportedOperation as UnsupportedOperation
7+
from os import _Opener
8+
from types import TracebackType
9+
from typing import IO, Any, BinaryIO, TextIO, TypeVar, overload
10+
from typing_extensions import Literal, Self
11+
12+
_T = TypeVar("_T")
13+
14+
DEFAULT_BUFFER_SIZE: Literal[8192]
15+
16+
open = builtins.open
17+
BlockingIOError = builtins.BlockingIOError
18+
19+
if sys.version_info >= (3, 8):
20+
def open_code(path: str) -> IO[bytes]: ...
21+
22+
if sys.version_info >= (3, 10):
23+
@overload
24+
def text_encoding(__encoding: None, __stacklevel: int = 2) -> Literal["locale", "utf-8"]: ...
25+
@overload
26+
def text_encoding(__encoding: _T, __stacklevel: int = 2) -> _T: ...
27+
28+
class _IOBase:
29+
def __del__(self) -> None: ...
30+
def __enter__(self) -> Self: ...
31+
def __exit__(
32+
self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None
33+
) -> None: ...
34+
def __iter__(self) -> Iterator[bytes]: ...
35+
def __next__(self) -> bytes: ...
36+
def close(self) -> None: ...
37+
@property
38+
def closed(self) -> bool: ...
39+
def fileno(self) -> int: ...
40+
def flush(self) -> None: ...
41+
def isatty(self) -> bool: ...
42+
read: Callable[..., Any]
43+
def readable(self) -> bool: ...
44+
def readline(self, __size: int | None = -1) -> bytes: ...
45+
def readlines(self, __hint: int = -1) -> list[bytes]: ...
46+
def seek(self, __offset: int, __whence: int = ...) -> int: ...
47+
def seekable(self) -> bool: ...
48+
def tell(self) -> int: ...
49+
def truncate(self, __size: int | None = ...) -> int: ...
50+
def writable(self) -> bool: ...
51+
write: Callable[..., Any]
52+
def writelines(self, __lines: Iterable[ReadableBuffer]) -> None: ...
53+
def _checkClosed(self, msg: str | None = ...) -> None: ... # undocumented
54+
55+
class _RawIOBase(_IOBase):
56+
def read(self, __size: int = -1) -> bytes | None: ...
57+
def readall(self) -> bytes: ...
58+
def readinto(self, __buffer: WriteableBuffer) -> int | None: ...
59+
def write(self, __b: ReadableBuffer) -> int | None: ...
60+
61+
class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes
62+
mode: str
63+
name: FileDescriptorOrPath
64+
def __init__(
65+
self, file: FileDescriptorOrPath, mode: str = ..., closefd: bool = ..., opener: _Opener | None = ...
66+
) -> None: ...
67+
@property
68+
def closefd(self) -> bool: ...
69+
def read(self, __size: int = -1) -> bytes: ...
70+
def write(self, __b: ReadableBuffer) -> int: ...
71+
72+
# these are only here so stubtest is happy with the argument names
73+
def seek(self, __pos: int, __whence: int = ...) -> int: ...
74+
75+
class _BufferedIOBase(_IOBase):
76+
def detach(self) -> RawIOBase: ...
77+
def read(self, __size: int | None = ...) -> bytes: ...
78+
def read1(self, __size: int = ...) -> bytes: ...
79+
def readinto(self, __buffer: WriteableBuffer) -> int: ...
80+
def readinto1(self, __buffer: WriteableBuffer) -> int: ...
81+
def write(self, __buffer: ReadableBuffer) -> int: ...
82+
83+
class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes
84+
# BytesIO does not contain a "name" field. This workaround is necessary
85+
# to allow BytesIO sub-classes to add this field, as it is defined
86+
# as a read-only property on IO[].
87+
name: Any
88+
def __init__(self, initial_bytes: ReadableBuffer = ...) -> None: ...
89+
def getbuffer(self) -> memoryview: ...
90+
def getvalue(self) -> bytes: ...
91+
def read1(self, __size: int | None = -1) -> bytes: ...
92+
def readlines(self, __size: int | None = None) -> list[bytes]: ...
93+
94+
# these are only here so stubtest is happy with the argument names
95+
def seek(self, __pos: int, __whence: int = ...) -> int: ...
96+
97+
class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes
98+
# technically has mode and name attributes, but they're just pass-throughs to
99+
# self.raw.*
100+
raw: RawIOBase
101+
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
102+
def peek(self, __size: int = 0) -> bytes: ...
103+
104+
# these are only here so stubtest is happy with the argument names
105+
def truncate(self, __pos: int | None = ...) -> int: ...
106+
def seek(self, __target: int, __whence: int = ...) -> int: ...
107+
108+
class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes
109+
# technically has mode and name attributes, but they're just pass-throughs to
110+
# self.raw.*
111+
raw: RawIOBase
112+
def __init__(self, raw: RawIOBase, buffer_size: int = ...) -> None: ...
113+
def write(self, __buffer: ReadableBuffer) -> int: ...
114+
115+
# these are only here so stubtest is happy with the argument names
116+
def truncate(self, __pos: int | None = ...) -> int: ...
117+
def seek(self, __target: int, __whence: int = ...) -> int: ...
118+
119+
class BufferedRWPair(BufferedIOBase, _BufferedIOBase):
120+
def __init__(self, reader: RawIOBase, writer: RawIOBase, buffer_size: int = ...) -> None: ...
121+
def peek(self, __size: int = ...) -> bytes: ...
122+
123+
class BufferedRandom(BufferedReader, BufferedWriter, _BufferedIOBase): ... # type: ignore[misc] # incompatible definitions of methods in the base classes
124+
125+
class _TextIOBase(_IOBase):
126+
encoding: str
127+
errors: str | None
128+
newlines: str | tuple[str, ...] | None
129+
def __iter__(self) -> Iterator[str]: ... # type: ignore[override]
130+
def __next__(self) -> str: ... # type: ignore[override]
131+
def detach(self) -> BinaryIO: ...
132+
def read(self, __size: int | None = ...) -> str: ...
133+
def readline(self, __size: int = ...) -> str: ... # type: ignore[override]
134+
def readlines(self, __hint: int = -1) -> list[str]: ... # type: ignore[override]
135+
def write(self, __s: str) -> int: ...
136+
def writelines(self, __lines: Iterable[str]) -> None: ... # type: ignore[override]
137+
138+
class TextIOWrapper(TextIOBase, _TextIOBase, TextIO): # type: ignore[misc] # incompatible definitions of methods in the base classes
139+
name: str
140+
def __init__(
141+
self,
142+
buffer: IO[bytes],
143+
encoding: str | None = ...,
144+
errors: str | None = ...,
145+
newline: str | None = ...,
146+
line_buffering: bool = ...,
147+
write_through: bool = ...,
148+
) -> None: ...
149+
@property
150+
def buffer(self) -> BinaryIO: ...
151+
@property
152+
def line_buffering(self) -> bool: ...
153+
@property
154+
def write_through(self) -> bool: ...
155+
def reconfigure(
156+
self,
157+
*,
158+
encoding: str | None = None,
159+
errors: str | None = None,
160+
newline: str | None = None,
161+
line_buffering: bool | None = None,
162+
write_through: bool | None = None,
163+
) -> None: ...
164+
165+
# these are only here so stubtest is happy with the argument names
166+
def truncate(self, __pos: int | None = ...) -> int: ...
167+
def seek(self, __cookie: int, __whence: int = ...) -> int: ...
168+
169+
class StringIO(TextIOWrapper, _TextIOBase): # type: ignore[misc] # incompatible definitions of methods in the base classes
170+
# StringIO does not contain a "name" field. This workaround is necessary
171+
# to allow StringIO sub-classes to add this field, as it is defined
172+
# as a read-only property on IO[].
173+
name: Any
174+
def __init__(self, initial_value: str | None = ..., newline: str | None = ...) -> None: ...
175+
@property
176+
def line_buffering(self) -> bool: ...
177+
def getvalue(self) -> str: ...
178+
179+
# these are only here so stubtest is happy with the argument names
180+
def seek(self, __pos: int, __whence: int = ...) -> int: ...
181+
182+
class IncrementalNewlineDecoder(codecs.IncrementalDecoder):
183+
def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = ...) -> None: ...
184+
@property
185+
def newlines(self) -> str | tuple[str, ...] | None: ...
186+
def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ...
187+
def setstate(self, __state: tuple[bytes, int]) -> None: ...

0 commit comments

Comments
 (0)