Skip to content

Commit 0325f5a

Browse files
committed
Move protocols to io
1 parent 1f42b21 commit 0325f5a

File tree

4 files changed

+106
-73
lines changed

4 files changed

+106
-73
lines changed

Doc/library/io.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,49 @@ Text I/O
11471147
It inherits from :class:`codecs.IncrementalDecoder`.
11481148

11491149

1150+
Static Typing
1151+
-------------
1152+
1153+
The following protocols can be used for annotating function and method
1154+
arguments for simple stream reading or writing operations. They are decorated
1155+
with :func:`@runtime_checkable <runtime_checkable>`.
1156+
1157+
.. class:: Reader[T]
1158+
1159+
Protocol for reading from a file or other input stream.
1160+
1161+
.. versionadded:: next
1162+
1163+
.. method:: read(size=..., /)
1164+
1165+
Read data from the input stream and return it. If ``size`` is
1166+
specified, at most ``size`` items (bytes/characters) will be read.
1167+
1168+
For example::
1169+
1170+
def read_it(reader: Reader[str]):
1171+
data = reader.read(11)
1172+
assert isinstance(data, str)
1173+
1174+
.. class:: Writer[T]
1175+
1176+
Protocol for writing to a file or other output stream.
1177+
1178+
.. versionadded:: next
1179+
1180+
.. method:: write(data, /)
1181+
1182+
Write data to the output stream and return number of items
1183+
(bytes/characters) written.
1184+
1185+
For example::
1186+
1187+
def write_binary(writer: Writer[bytes]):
1188+
writer.write(b"Hello world!\n")
1189+
1190+
See :ref:`typing-io` for other I/O related protocols and classes used for
1191+
static type checking.
1192+
11501193
Performance
11511194
-----------
11521195

Doc/library/typing.rst

Lines changed: 14 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,54 +2803,28 @@ with :func:`@runtime_checkable <runtime_checkable>`.
28032803
An ABC with one abstract method ``__round__``
28042804
that is covariant in its return type.
28052805

2806+
.. _typing-io:
2807+
28062808
ABCs and Protocols for working with I/O
28072809
---------------------------------------
28082810

2809-
.. class:: IO
2810-
TextIO
2811-
BinaryIO
2811+
.. class:: IO[AnyStr]
2812+
TextIO[AnyStr]
2813+
BinaryIO[AnyStr]
28122814

2813-
Generic type ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])``
2815+
Generic class ``IO[AnyStr]`` and its subclasses ``TextIO(IO[str])``
28142816
and ``BinaryIO(IO[bytes])``
28152817
represent the types of I/O streams such as returned by
2816-
:func:`open`.
2817-
2818-
The following protocols offer a simpler alternative for common use cases. They
2819-
are especially useful for annotating function and method arguments and are
2820-
decorated with :func:`@runtime_checkable <runtime_checkable>`.
2821-
2822-
.. class:: Reader[T]
2823-
2824-
Protocol for reading from a file or other input stream.
2825-
2826-
.. versionadded:: next
2827-
2828-
.. method:: read(size=..., /)
2829-
2830-
Read data from the input stream and return it. If ``size`` is
2831-
specified, at most ``size`` items (bytes/characters) will be read.
2832-
2833-
For example::
2834-
2835-
def read_it(reader: Reader[str]):
2836-
data = reader.read(11)
2837-
assert isinstance(data, str)
2838-
2839-
.. class:: Writer[T]
2840-
2841-
Protocol for writing to a file or other output stream.
2818+
:func:`open`. Please note that these classes are not protocols, and
2819+
their interface is fairly broad.
28422820

2843-
.. versionadded:: next
2844-
2845-
.. method:: write(data, /)
2846-
2847-
Write data to the output stream and return number of items
2848-
(bytes/characters) written.
2849-
2850-
For example::
2821+
The protocols :class:`.io.Reader` and :class:`.io.Writer` offer a simpler
2822+
alternative for argument types, when only the ``read()`` or ``write()``
2823+
methods are accessed, respectively::
28512824

2852-
def write_binary(writer: Writer[bytes]):
2853-
writer.write(b"Hello world!\n")
2825+
def read_and_write(reader: Reader[str], writer: Writer[bytes]):
2826+
data = reader.read()
2827+
writer.write(data.encode())
28542828

28552829
Also consider using :class:`collections.abc.Iterable` for iterating over
28562830
the lines of an input stream::

Lib/io.py

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,14 @@
4646
"BufferedReader", "BufferedWriter", "BufferedRWPair",
4747
"BufferedRandom", "TextIOBase", "TextIOWrapper",
4848
"UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END",
49-
"DEFAULT_BUFFER_SIZE", "text_encoding", "IncrementalNewlineDecoder"]
49+
"DEFAULT_BUFFER_SIZE", "text_encoding", "IncrementalNewlineDecoder",
50+
"Reader", "Writer"]
5051

5152

5253
import _io
5354
import abc
5455

56+
from _collections_abc import _check_methods
5557
from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation,
5658
open, open_code, FileIO, BytesIO, StringIO, BufferedReader,
5759
BufferedWriter, BufferedRWPair, BufferedRandom,
@@ -97,3 +99,49 @@ class TextIOBase(_io._TextIOBase, IOBase):
9799
pass
98100
else:
99101
RawIOBase.register(_WindowsConsoleIO)
102+
103+
#
104+
# Static Typing Support
105+
#
106+
107+
108+
class Reader[T](abc.ABC):
109+
"""Protocol for simple I/O reader instances.
110+
111+
This protocol only supports blocking I/O.
112+
"""
113+
114+
__slots__ = ()
115+
116+
@abstractmethod
117+
def read(self, size: int = ..., /) -> T:
118+
"""Read data from the input stream and return it.
119+
120+
If "size" is specified, at most "size" items (bytes/characters) will be
121+
read.
122+
"""
123+
124+
@classmethod
125+
def __subclasshook__(cls, C):
126+
if cls is Reader:
127+
return _check_methods(C, "read")
128+
return NotImplemented
129+
130+
131+
class Writer[T](abc.ABC):
132+
"""Protocol for simple I/O writer instances.
133+
134+
This protocol only supports blocking I/O.
135+
"""
136+
137+
__slots__ = ()
138+
139+
@abstractmethod
140+
def write(self, data: T, /) -> int:
141+
"""Write data to the output stream and return number of items written."""
142+
143+
@classmethod
144+
def __subclasshook__(cls, C):
145+
if cls is Writer:
146+
return _check_methods(C, "write")
147+
return NotImplemented

Lib/typing.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
'AsyncContextManager',
9191

9292
# Structural checks, a.k.a. protocols.
93-
'Reader',
9493
'Reversible',
9594
'SupportsAbs',
9695
'SupportsBytes',
@@ -99,7 +98,6 @@
9998
'SupportsIndex',
10099
'SupportsInt',
101100
'SupportsRound',
102-
'Writer',
103101

104102
# Concrete collection types.
105103
'ChainMap',
@@ -2931,36 +2929,6 @@ def __round__(self, ndigits: int = 0) -> T:
29312929
pass
29322930

29332931

2934-
class Reader[T](Protocol):
2935-
"""Protocol for simple I/O reader instances.
2936-
2937-
This protocol only supports blocking I/O.
2938-
"""
2939-
2940-
__slots__ = ()
2941-
2942-
@abstractmethod
2943-
def read(self, size: int = ..., /) -> T:
2944-
"""Read data from the input stream and return it.
2945-
2946-
If "size" is specified, at most "size" items (bytes/characters) will be
2947-
read.
2948-
"""
2949-
2950-
2951-
class Writer[T](Protocol):
2952-
"""Protocol for simple I/O writer instances.
2953-
2954-
This protocol only supports blocking I/O.
2955-
"""
2956-
2957-
__slots__ = ()
2958-
2959-
@abstractmethod
2960-
def write(self, data: T, /) -> int:
2961-
"""Write data to the output stream and return number of items written."""
2962-
2963-
29642932
def _make_nmtuple(name, fields, annotate_func, module, defaults = ()):
29652933
nm_tpl = collections.namedtuple(name, fields,
29662934
defaults=defaults, module=module)

0 commit comments

Comments
 (0)