The documentation on text handles is misleading, in particular for the seek method.
Steps to reproduce
handle = open('/tmp/lines.txt')
help(handle.seek)
This produces the following documentation:
Help on built-in function seek:
seek(cookie, whence=0, /) method of _io.TextIOWrapper instance
Change stream position.
Change the stream position to the given byte offset. The offset is
interpreted relative to the position indicated by whence. Values
for whence are:
* 0 -- start of stream (the default); offset should be zero or positive
* 1 -- current stream position; offset may be negative
* 2 -- end of stream; offset is usually negative
Return the new absolute position.
Issues
The documentation talks about a byte offset, but the interface mentions a cookie.
The constants defined in os module, like os.SEEK_END are not mentioned.
whence=2 with negative offset fails.
Generally, the behaviour is very inconsistent, seek relative to the end fail, seek relative to the start works, but might yield a situation when read fails.
@MatthiasWiesmann would you have time to write a PR with suggestied revisions of the help text?
To note, Python 3.12 will include the constants in os (see #104418), though there is quite a bit of inconsistency between the various seek() methods' docstrings:
I agree that it is confusing that the parameter names for the low-level API seek() aren't used consistently throughout the docs/docstrings. Luckily, these are all positional-only, so we can easily normalise them without backwards compatibility concerns.
Suggested improvements:
Consistently name the seek() params
Consistently use io.SEEK_* constants instead of os.SEEK_*
The confusion is caused by the fact that TextIOWrapper.seek() has no docstring, so pydoc shows a docstring from a parent class, which is inadequate due to significant difference in semantic.
The first argument of TextIOWrapper.seek() is not a byte offset, and not an offset at all. It is a "cookie", i.e. zero or an opaque number returned by tell(). Passing anything other than zero and the value returned by tell() when whence=SEEK_SET has undefined behavior.
SEEK_CUR and SEEK_END only support zero as the first argument.
Neither forward seeking nor backward seeking are supported. The only supported are rewinding to the start and restoring the previous position saved by tell(). Confusion could be avoided if TextIOWrapper.tell() returned a special type instead of integer, but for now it would be a large breaking change (because the cookie can be saved in a file as an integer and used in other process).
There are a lot of tasks here. Suggesting to proceed in this order:
Use whence instead of how as the name of the third position-only parameter of os.lseek. Rationale: the SEEK_* constants are also used for this function. If the SEEK_* constants are to talk about the whence parameter, we should use it for os.lseek as well.
Improve the documentation of os.SEEK_SET, os.SEEK_CUR and os.SEEK_END; explain that they are used for the whence parameter of os.lseek and of the seek() method of file objects; add a very short description to each constant.
Document os.SEEK_HOLE and os.SEEK_DATA (exposed in os though posix)
Consistently name _io.*.seek() params where it makes sense.
Improve the docs of the seek() methods (Doc/library/io.rst)
I'll close this issue as completed since #82969 was closed and #122299 is likely to be closed as well IMO. We can always add more docs if needed and use that issue as a tracker.
Activity
sunmy2019 commented on Aug 10, 2023
Note: If anything is changed here, the relevant doc should also be changed.
https://docs.python.org/3/library/io.html#io.IOBase.seek
AA-Turner commented on Aug 12, 2023
@MatthiasWiesmann would you have time to write a PR with suggestied revisions of the help text?
To note, Python 3.12 will include the constants in os (see #104418), though there is quite a bit of inconsistency between the various seek() methods' docstrings:
cpython/Modules/_io/iobase.c
Lines 82 to 99 in 2e27da1
cpython/Modules/_io/bufferedio.c
Lines 1285 to 1290 in 2e27da1
cpython/Modules/_io/bytesio.c
Lines 637 to 650 in 2e27da1
cpython/Modules/_io/fileio.c
Lines 954 to 969 in 2e27da1
cpython/Modules/_io/stringio.c
Lines 464 to 477 in 2e27da1
cpython/Modules/_io/textio.c
Lines 2428 to 2433 in 2e27da1
cc @erlend-aasland as the author of #104418 if you have any thoughts.
A
pythongh-107801: Improve io.*.seek docs and docstrings
erlend-aasland commented on Aug 13, 2023
I agree that it is confusing that the parameter names for the low-level API seek() aren't used consistently throughout the docs/docstrings. Luckily, these are all positional-only, so we can easily normalise them without backwards compatibility concerns.
Suggested improvements:
serhiy-storchaka commented on Aug 14, 2023
Neither forward seeking nor backward seeking are supported. The only supported are rewinding to the start and restoring the previous position saved by tell(). Confusion could be avoided if TextIOWrapper.tell() returned a special type instead of integer, but for now it would be a large breaking change (because the cookie can be saved in a file as an integer and used in other process).
erlend-aasland commented on Aug 14, 2023
As a data point: on macOS, Linux, and FreeBSD, the lseek and fseek manpages uses offset and whence as parameter names.
serhiy-storchaka commented on Aug 14, 2023
Because they only work with binary files. They do not work with TextIOWrapper which support multibyte stateful codecs.
erlend-aasland commented on Aug 14, 2023
There are a lot of tasks here. Suggesting to proceed in this order:
35 remaining items
[3.11] pythongh-107801: Document io.TextIOWrapper.tell (python#108265)
[3.11] gh-107801: Document io.TextIOWrapper.tell (#108265) (#108548)
[3.12] gh-107801: Document io.TextIOWrapper.tell (#108265) (#108547)
gh-107801: Improve the accuracy of io.IOBase.seek docs (#108268)
[3.12] pythongh-107801: Improve the accuracy of io.IOBase.seek docs (p…
[3.11] pythongh-107801: Improve the accuracy of io.IOBase.seek docs (p…
[3.11] gh-107801: Improve the accuracy of io.IOBase.seek docs (#108268)…
[3.12] gh-107801: Improve the accuracy of io.IOBase.seek docs (#108268)…
Merge branch 'main' into icompexc
hugovk commented on Nov 9, 2023
Lots of merged PRs here. 🚀
Anything still to do, or can the issue be closed?
vadmium commented on Jul 26, 2024
Issue #82969 is open about IOBase.seek/tell vs TextIOWrapper and the offset/cookie parameter
Issue #122299 is about the byte vs character seek offsets
picnixz commented on Dec 2, 2024
I'll close this issue as completed since #82969 was closed and #122299 is likely to be closed as well IMO. We can always add more docs if needed and use that issue as a tracker.