-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
gh-127647: Add typing.Reader and Writer protocols #127648
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
Changes from all commits
b45fec0
1525e05
7867ec1
6a22a02
5d632a3
4d50c2e
1e1ea41
56a38a0
f2c331b
6764b6a
022acaa
b86073d
65eb040
2b9159d
1f42b21
0325f5a
632511a
3b384f9
5bdb4cc
35dcaf4
5584a57
af81301
5a8b915
b1593fa
577b893
cedfa42
a0b9e47
53a2250
03aa3a2
ca72c19
3b5975e
96080fe
3723370
76003a8
43e23f0
c644770
bfab2fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -46,12 +46,14 @@ | |||||
"BufferedReader", "BufferedWriter", "BufferedRWPair", | ||||||
"BufferedRandom", "TextIOBase", "TextIOWrapper", | ||||||
"UnsupportedOperation", "SEEK_SET", "SEEK_CUR", "SEEK_END", | ||||||
"DEFAULT_BUFFER_SIZE", "text_encoding", "IncrementalNewlineDecoder"] | ||||||
"DEFAULT_BUFFER_SIZE", "text_encoding", "IncrementalNewlineDecoder", | ||||||
"Reader", "Writer"] | ||||||
|
||||||
|
||||||
import _io | ||||||
import abc | ||||||
|
||||||
from _collections_abc import _check_methods | ||||||
from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation, | ||||||
open, open_code, FileIO, BytesIO, StringIO, BufferedReader, | ||||||
BufferedWriter, BufferedRWPair, BufferedRandom, | ||||||
|
@@ -97,3 +99,55 @@ class TextIOBase(_io._TextIOBase, IOBase): | |||||
pass | ||||||
else: | ||||||
RawIOBase.register(_WindowsConsoleIO) | ||||||
|
||||||
# | ||||||
# Static Typing Support | ||||||
# | ||||||
|
||||||
GenericAlias = type(list[int]) | ||||||
|
||||||
|
||||||
class Reader(metaclass=abc.ABCMeta): | ||||||
"""Protocol for simple I/O reader instances. | ||||||
|
||||||
This protocol only supports blocking I/O. | ||||||
""" | ||||||
|
||||||
__slots__ = () | ||||||
|
||||||
@abc.abstractmethod | ||||||
def read(self, size=..., /): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry if this has been discussed before, but I'm unsure on the runtime use of Almost every other Would it be better to have
Suggested change
A There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mandating defaults is not really something you can do in a protocol. I also wouldn't want to mandate that implementors have to use a default of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, but this isn't a protocol -- it's an ABC, which do have defaults -- see e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's supposed to be a protocol, not an ABC. (Notwithstanding the fact that all protocols are ABCs.) It's just a protocol in the implementation for performance reasons. And using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
From the documentation of
I would expect the
This forbids There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I disagree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not sure I follow, though -- currently the ABC/protocol has the mandatory default of I ran the following with import abc
class Reader(metaclass=abc.ABCMeta):
__slots__ = ()
@abc.abstractmethod
def read(self, size: int = -1, /) -> bytes: pass
class CustomReader(Reader):
def read(self, size: int = -1, /) -> bytes:
return b''
class CustomReaderZero(Reader):
def read(self, size: int = 0, /) -> bytes:
return b''
assert issubclass(CustomReader, Reader)
assert issubclass(CustomReaderZero, Reader)
assert isinstance(CustomReader(), Reader)
assert isinstance(CustomReaderZero(), Reader)
def reader_func(r: Reader) -> None:
r.read()
reader_func(CustomReader())
reader_func(CustomReaderZero()) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with Sebastian here; we should use
The protocol should also match other file-like classes defined elsewhere in the stdlib or even in third-party libraries. When defining a protocol it's often useful to be permissive, so that all objects that are intended to match the protocol actually match it. |
||||||
"""Read data from the input stream and return it. | ||||||
|
||||||
If *size* is specified, at most *size* items (bytes/characters) will be | ||||||
read. | ||||||
""" | ||||||
|
||||||
@classmethod | ||||||
def __subclasshook__(cls, C): | ||||||
if cls is Reader: | ||||||
return _check_methods(C, "read") | ||||||
return NotImplemented | ||||||
|
||||||
__class_getitem__ = classmethod(GenericAlias) | ||||||
|
||||||
|
||||||
class Writer(metaclass=abc.ABCMeta): | ||||||
"""Protocol for simple I/O writer instances. | ||||||
|
||||||
This protocol only supports blocking I/O. | ||||||
""" | ||||||
|
||||||
__slots__ = () | ||||||
|
||||||
@abc.abstractmethod | ||||||
def write(self, data, /): | ||||||
"""Write *data* to the output stream and return the number of items written.""" | ||||||
|
||||||
@classmethod | ||||||
def __subclasshook__(cls, C): | ||||||
if cls is Writer: | ||||||
return _check_methods(C, "write") | ||||||
return NotImplemented | ||||||
|
||||||
__class_getitem__ = classmethod(GenericAlias) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Add protocols :class:`io.Reader` and :class:`io.Writer` as | ||
alternatives to :class:`typing.IO`, :class:`typing.TextIO`, and | ||
:class:`typing.BinaryIO`. |
Uh oh!
There was an error while loading. Please reload this page.