Title: readinto is not a method on io.TextIOBase
Type: behavior Stage: resolved
Components: Documentation Versions: Python 3.8
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: docs@python Nosy List: benjamin.peterson, cheryl.sabella, martin.panter, miss-islington, remi.lapeyre, steverpalmer, stutzbach, xtreak
Priority: normal Keywords: patch

Created on 2019-01-29 09:18 by steverpalmer, last changed 2019-04-09 04:57 by miss-islington. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 11893 merged python-dev, 2019-02-16 09:44
PR 12736 merged miss-islington, 2019-04-09 04:35
Messages (10)
msg334507 - (view) Author: Steve Palmer (steverpalmer) * Date: 2019-01-29 09:18
class io.IOBase states "Even though IOBase does not declare read(), readinto(), or write() because their signatures will vary, implementations and clients should consider those methods part of the interface. Also, implementations may raise a ValueError (or UnsupportedOperation) when operations they do not support are called."  However, even though class io.TextIOBase is described as inheriting from io.IOBase, a call to readinto method returns AttributeError exception indicating no readinto attribute, inconsistent with the documentation.
msg334524 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-01-29 14:37

> Base class for text streams. This class provides a character and line based interface to stream I/O. There is no readinto() method because Python’s character strings are immutable. It inherits IOBase. There is no public constructor.

io.TextIOBase docs say there is no readinto method in the documentation.
msg334526 - (view) Author: Rémi Lapeyre (remi.lapeyre) * Date: 2019-01-29 14:43
I checked and io.TextIOBase is the only io.IOBase subclass to lack one of read, readinto or write:

>>> import io, inspect
>>> for name, obj in inspect.getmembers(io, predicate=inspect.isclass):
... 	missing = {'read', 'readinto', 'write'} - {name for name, _ in inspect.getmembers(obj)}
...	if issubclass(obj, io.IOBase) and missing:
...	     print(obj, missing, issubclass(obj, io.TextIOBase))

<class 'io.IOBase'> {'write', 'read', 'readinto'} False
<class '_io.StringIO'> {'readinto'} True
<class 'io.TextIOBase'> {'readinto'} True
<class '_io.TextIOWrapper'> {'readinto'} True

I can open a PR to fix the conflicts between the two parts of the documentation. I think it's appropriate to change TextIOBase to raise UnsupportedOperation when calling readinto and to change the documentation accordingly.
msg334530 - (view) Author: Steve Palmer (steverpalmer) * Date: 2019-01-29 16:50
I agree with Karthikeyan that the method does not apply in the io.TextIOBase class context.  I'm sorry that I didn't spot the note in the description of io.TextIOBase - though I think that it is easy to miss.

I'd suggest that there are two ways to clear this up:

1. change only the documentation to read "Even though IOBase does not declare read() or write() because their signatures will vary, implementations and clients should consider those methods part of the interface."  (deleting reference to readinto())

2. change the standard library for io.TextIOBase to add a method readinto which will raise an UnsupportedOperation.

With option 1, the descriptions for io.RawIOBase and io.BufferedIOBase both include description of the readinto method, so nothing is lost by removing mention of it at the io.IOBase level of the hierarchy.  In any case, readinto() is not defined on the io.IOBase class.

>>> 'readinto' not in dir(io.IOBase)

With option 2, it feels like this is closer to the design intent of a common interface over similar but distinguished classes.  It also avoids removing things from the documentation in case someone already has some expectations of the behaviour.
msg334533 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python triager) Date: 2019-01-29 17:16
Thanks Steve for the details. I am adding io module maintainers to the issue who will have better context on whether to clarify the docs or to change the implementation to raise UnsupportedOperation.
msg334548 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2019-01-30 08:21
I think it would be more practical to fix the documentation (option 1). Do you have a use case for “TextIOBase.readinto” raising ValueError (something more concrete than someone having expectations)?
msg334549 - (view) Author: Steve Palmer (steverpalmer) * Date: 2019-01-30 08:37
I don't have a "real" use case.  I discovered the issue when I was developing a unittest suite for what it means to be "file-like".  I've been codifying the description in the standard library and exercising my tests against the built-in file-likes, such as the io.StringIO class, when it raised the Attribute Exception.

The more I think about it, the more like a documentation problem it feels.  For example, the statement "... because their signatures will vary ..." does not apply to readinto in the cases where it is defined.

For completeness, the note in io.TextIOBase stating "There is no readinto() method because Python’s character strings are immutable." would also need to be removed as part of a documentation fix.

(It's also nice when solutions result in less "stuff". :-)
msg335571 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2019-02-14 22:34

Would you be interested in creating a Github pull request with the documentation changes?
msg339697 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2019-04-09 04:35
New changeset 7b97ab35b28b761ab1253df427ee674b1a90f465 by Benjamin Peterson (Steve Palmer) in branch 'master':
closes bpo-35848: Move all documentation regarding the readinto out of IOBase. (GH-11893)
msg339698 - (view) Author: miss-islington (miss-islington) Date: 2019-04-09 04:57
New changeset 0a16bb15afec28f355bc28203b6b10610293f026 by Miss Islington (bot) in branch '3.7':
closes bpo-35848: Move all documentation regarding the readinto out of IOBase. (GH-11893)
Date User Action Args
2019-04-09 04:57:42miss-islingtonsetnosy: + miss-islington
messages: + msg339698
2019-04-09 04:35:39miss-islingtonsetpull_requests: + pull_request12659
2019-04-09 04:35:30benjamin.petersonsetstatus: open -> closed
resolution: fixed
messages: + msg339697

stage: patch review -> resolved
2019-02-16 09:44:34python-devsetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request11921
2019-02-14 22:34:33cheryl.sabellasetnosy: + cheryl.sabella
messages: + msg335571
components: + Documentation, - IO
2019-01-30 08:37:30steverpalmersetmessages: + msg334549
2019-01-30 08:21:28martin.pantersetnosy: + martin.panter
messages: + msg334548
2019-01-29 17:16:50xtreaksetnosy: + xtreak, stutzbach, benjamin.peterson
messages: + msg334533
2019-01-29 16:50:34steverpalmersetmessages: + msg334530
2019-01-29 14:43:57remi.lapeyresetversions: + Python 3.8, - Python 3.7
2019-01-29 14:43:42remi.lapeyresetversions: - Python 3.8
nosy: + remi.lapeyre, - docs@python, xtreak

messages: + msg334526

components: + IO, - Documentation
2019-01-29 14:37:51xtreaksetnosy: + xtreak
messages: + msg334524
2019-01-29 14:35:45SilentGhostsetversions: + Python 3.8
nosy: + docs@python

assignee: docs@python
components: + Documentation, - IO
stage: needs patch
2019-01-29 09:18:40steverpalmercreate