python / python/cpython

'_Stream' object has no attribute 'seekable'

オープン
#124,293 コメント 7 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

3.12 3.13 3.14 stdlib type-bug
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

Bug report

Bug description:

From a recent application, I have found tarfile._Stream doesn't have a seekable() method. A quick reproduction of the problem is as follows:

import tarfile
import io

data = b"Test data."
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode="w") as tf:
    ti = tarfile.TarInfo(name="test.txt")
    ti.size = len(data)
    tf.addfile(tarinfo=ti, fileobj=io.BytesIO(data))

buf.seek(0)
tf = tarfile.open(fileobj=buf, mode="r|")
for entry in tf:
    f = tf.extractfile(entry)  # `f` is in type of `class ExFileObject(io.BufferedReader)`
    f.seekable()  # AttributeError
    f.seek(0)  # AttributeError

Output:

Traceback (most recent call last):
  File "a.py", line 17, in <module>
    print(f.seekable())
  File "AppData\Local\Programs\Python\Python310\lib\tarfile.py", line 641, in seekable
    return self.fileobj.seekable()
AttributeError: '_Stream' object has no attribute 'seekable'

When opening tarfile with r| mode, ExFileObject.fileobj would be a _Stream object. So when calling ExFileObject.seekable(), as _Stream object dun have seekable() method, it will raise AttributeError.

Also, as BufferedReader.seek() will also check its raw.seekable() (i.e. in Modules/_io/bufferedio.c, func _io__Buffered_seek_impl(), there is a call to _PyIOBase_check_seekable(state, self->raw, Py_True)), f.seek() in the above example will also raise AttributeError.

I have thought of if we can simply define seekable() in _Stream object, but as it is only "forward-seekable", I am not sure if directly returning a true/false in _Stream.seekable() is appropriate or not. However, this issue does break the IOBase interface and there should be a solution.

Thanks for everyone's time and effort for looking into this.

CPython versions tested on:

3.10, 3.11, 3.12, 3.13, CPython main branch

Operating systems tested on:

Linux, Windows

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、提供された tarfile の再現を r| mode で実行し、次に tarfile.py の tarfile._Stream と ExFileObject、および Modules/_io/bufferedio.c の _io__Buffered_seek_impl() を調べます。前方向のみのストリームに対する適切な seek の動作を判断し、報告されている seekable() と seek() の AttributeErrors がストリーミングのセマンティクスを壊すことなく解消されることを確認します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
backend
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
38/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。