Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-127647: Add typing.Reader and Writer protocols #127648

Merged
merged 37 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b45fec0
Add typing.Reader and Writer protocols
srittau Dec 5, 2024
1525e05
Add a note about Iterable
srittau Dec 5, 2024
7867ec1
Fix docs formatting
srittau Dec 5, 2024
6a22a02
Small wording improvements
srittau Dec 5, 2024
5d632a3
Simplify the docs/improve formatting
srittau Dec 5, 2024
4d50c2e
Explicitly document the methods
srittau Dec 5, 2024
1e1ea41
Mark protocol members as abstract
srittau Dec 6, 2024
56a38a0
Add .. versionadded
srittau Dec 6, 2024
f2c331b
Added slashes to documented signatures
srittau Dec 6, 2024
6764b6a
Fix overindentation
srittau Dec 6, 2024
022acaa
Fix documentation of Reader.__iter__()
srittau Dec 6, 2024
b86073d
Remove the @runtime_checkable flags
srittau Dec 6, 2024
65eb040
Merge branch 'main' into typing-readable-writable
srittau Jan 6, 2025
2b9159d
Merge branch 'main' into typing-readable-writable
srittau Feb 25, 2025
1f42b21
Remove Reader.__iter__() and readline()
srittau Feb 25, 2025
0325f5a
Move protocols to io
srittau Feb 25, 2025
632511a
Update whatsnew
srittau Feb 25, 2025
3b384f9
Update NEWS file
srittau Feb 25, 2025
5bdb4cc
Fix abstractmethod import
srittau Feb 25, 2025
35dcaf4
Fix runtime_checkable link in docs
srittau Feb 25, 2025
5584a57
Add Reader and Writer to proto allowlist
srittau Feb 25, 2025
af81301
Import Reader and Writer into _pyio
srittau Feb 25, 2025
5a8b915
Import _collections_abc dynamically
srittau Feb 25, 2025
b1593fa
Merge branch 'main' into typing-readable-writable
srittau Feb 25, 2025
577b893
Use metaclass instead of deriving from `ABC`
srittau Feb 25, 2025
cedfa42
Use __class_getitem__ instead of making the class generic
srittau Feb 25, 2025
a0b9e47
Remove type annotations
srittau Feb 25, 2025
53a2250
Move import back to top level
srittau Feb 25, 2025
03aa3a2
Merge branch 'main' into typing-readable-writable
srittau Feb 27, 2025
ca72c19
Fix doc reference to decorator
srittau Feb 27, 2025
3b5975e
Fix references in docs
srittau Feb 27, 2025
96080fe
Split signature
srittau Feb 27, 2025
3723370
Document that Reader and Writer are generic
srittau Feb 27, 2025
76003a8
Add tests
srittau Feb 27, 2025
43e23f0
Add missing import
srittau Feb 27, 2025
c644770
Doc fixes
srittau Feb 27, 2025
bfab2fd
Merge branch 'main' into typing-readable-writable
srittau Mar 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2803,8 +2803,8 @@ with :func:`@runtime_checkable <runtime_checkable>`.
An ABC with one abstract method ``__round__``
that is covariant in its return type.

ABCs for working with IO
------------------------
ABCs and Protocols for working with I/O
---------------------------------------

.. class:: IO
TextIO
Expand All @@ -2815,6 +2815,39 @@ ABCs for working with IO
represent the types of I/O streams such as returned by
:func:`open`.

The following protocols offer a simpler alternative for common use cases. They
are especially useful for annotating function and method arguments and are
decorated with :func:`@runtime_checkable <runtime_checkable>`.

.. class:: Reader[T]

Protocol for reading from a file or other input stream. Implementations
must support the ``read``, ``readline``, and ``__iter__`` methods.

For example::

def read_it(reader: Reader[str]):
assert reader.read(11) == "--marker--\n"
for line in reader:
print(line)

.. class:: Writer[T]

Protocol for writing to a file or other output stream. Implementations
must support the ``write`` method.

For example::

def write_binary(writer: Writer[bytes]):
writer.write(b"Hello world!\n")

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

def read_config(stream: Iterable[str]):
for line in stream:
...

Functions and decorators
------------------------

Expand Down
8 changes: 8 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,14 @@ tkinter
(Contributed by Zhikang Yan in :gh:`126899`.)


typing
------

* Add protocols :class:`typing.Reader` and :class:`typing.Writer` as a simpler
alternatives to the pseudo-protocols :class:`typing.IO`,
:class:`typing.TextIO`, and :class:`typing.BinaryIO`.


unicodedata
-----------

Expand Down
38 changes: 38 additions & 0 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
'AsyncContextManager',

# Structural checks, a.k.a. protocols.
'Reader',
'Reversible',
'SupportsAbs',
'SupportsBytes',
Expand All @@ -98,6 +99,7 @@
'SupportsIndex',
'SupportsInt',
'SupportsRound',
'Writer',

# Concrete collection types.
'ChainMap',
Expand Down Expand Up @@ -2925,6 +2927,42 @@ def __round__(self, ndigits: int = 0) -> T:
pass


@runtime_checkable
class Reader[T](Iterable[T], Protocol):
"""Protocol for simple I/O reader instances.

This protocol only supports blocking I/O.
"""

__slots__ = ()

def read(self, size: int = ..., /) -> T:
"""Read data from the I/O stream and return it.

If "size" is specified, at most "size" items (bytes/characters) will be
read.
"""
def readline(self, size: int = ..., /) -> T:
"""Read a line of data from the I/O stream and return it.

If "size" is specified, at most "size" items (bytes/characters) will be
read.
"""


@runtime_checkable
class Writer[T](Protocol):
"""Protocol for simple I/O writer instances.

This protocol only supports blocking I/O.
"""

__slots__ = ()

def write(self, o: T, /) -> int:
"""Write data to the I/O stream and return number of items written."""


def _make_nmtuple(name, fields, annotate_func, module, defaults = ()):
nm_tpl = collections.namedtuple(name, fields,
defaults=defaults, module=module)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Add protocols :class:`typing.Reader` and :class:`typing.Writer` as
alternatives to :class:`typing.IO`, :class:`typing.TextIO`, and
:class:`typing.BinaryIO`.
Loading