indygreg / python-zstandard

Python bindings to the Zstandard (zstd) compression library
BSD 3-Clause "New" or "Revised" License
499 stars 86 forks source link

`fileno` not available on `ZstdDecompressionReader` #212

Open jap opened 9 months ago

jap commented 9 months ago

According to the shipped typing stubs, ZstdDecompressionReader implements the typing.BinaryIO interface.

Unfortunately, it lacks the fileno() method that is promised by BinaryIO so this is a bit of a lie. This breaks when trying to do something like:

>>> f = open('foo.zstd', 'rb')
>>> d = zstandard.ZstdDecompressor()
>>> g = d.stream_reader(f)
>>> subprocess.run(['cat'], stdin = g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/spaans/.pyenv/versions/3.12.1/lib/python3.12/subprocess.py", line 548, in run
    with Popen(*popenargs, **kwargs) as process:
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/spaans/.pyenv/versions/3.12.1/lib/python3.12/subprocess.py", line 992, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/spaans/.pyenv/versions/3.12.1/lib/python3.12/subprocess.py", line 1708, in _get_handles
    p2cread = stdin.fileno()
              ^^^^^^^^^^^^
AttributeError: 'zstd.ZstdDecompressionReader' object has no attribute 'fileno'

Note that StringIO in the standard library also doesn't support fileno, but has instead chosen to raise an Exception when it is used like this, so a possible solution could be to just mimic that behaviour.

enkore commented 6 months ago

The "specification" for this is in the io module and says

Return the underlying file descriptor (an integer) of the stream if it exists. An OSError is raised if the IO object does not use a file descriptor.