Skip to content

wave.open fails on non-seekable input streams that implement tell() #158772

Description

@augusto-rehfeldt

Bug report

Bug description:

Documented behaviour: The wave module's opening documentation states: "When the setpos() and rewind() methods are not used, the seek() method is not necessary."

Expected: Opening succeeds; sequential reads return (b'', b'\xce', b'$', b'', b'').

Actual: AttributeError: 'Stream' object has no attribute 'seek'

import struct
import wave

wav = b'RIFF&\x00\x00\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00@\x1f\x00\x00@\x1f\x00\x00\x01\x00\x08\x00data\x02\x00\x00\x00\xce$'
requests = (0, 1, 2, 3, 1)

class Stream:
    def __init__(self):
        self.pos = 0
    def read(self, n=-1):
        end = len(wav) if n < 0 else min(len(wav), self.pos + n)
        data = wav[self.pos:end]
        self.pos = end
        return data
    def tell(self):
        return self.pos
    def close(self):
        pass

def main():
    try:
        fields = struct.unpack('<4sI4s4sIHHIIHH4sI2s', wav)
        valid = fields == (
            b'RIFF', len(wav) - 8, b'WAVE', b'fmt ', 16,
            1, 1, 8000, 8000, 1, 8, b'data', 2, b'\xce$'
        )
    except struct.error:
        valid = False
    if not valid:
        print('REFUTATION REJECTED:', 'input is not the complete PCM WAV claimed')
        return

    audio = fields[-1]
    pos = 0
    chunks = []
    for n in requests:
        chunks.append(audio[pos:pos + n])
        pos = min(len(audio), pos + n)
    expected = ('ok', (1, 1, 8000, len(audio), 'NONE', 'not compressed'),
                tuple(chunks))
    try:
        with wave.open(Stream(), 'rb') as reader:
            actual = ('ok', tuple(reader.getparams()),
                      tuple(reader.readframes(n) for n in requests))
    except Exception as exc:
        actual = ('exception', type(exc).__name__, str(exc))

    if actual != expected:
        print('REFUTATION CONFIRMED:',
              {'wav': wav, 'read_requests': requests},
              'actual:', actual, 'expected:', expected)
    else:
        print('REFUTATION REJECTED:', 'sequential reading matches the documented expectation')

main()

Output on Python 3.14.6 (Windows-11-10.0.26220-SP0), standard library wave:

REFUTATION CONFIRMED: {'wav': b'RIFF&\x00\x00\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x01\x00@\x1f\x00\x00@\x1f\x00\x00\x01\x00\x08\x00data\x02\x00\x00\x00\xce$', 'read_requests': (0, 1, 2, 3, 1)} actual: ('exception', 'AttributeError', "'Stream' object has no attribute 'seek'") expected: ('ok', (1, 1, 8000, 2, 'NONE', 'not compressed'), (b'', b'\xce', b'$', b'', b''))

This report was found and written by an automated property-testing tool I run (bugforge). The reproducer above was executed and its output is pasted unedited; no person reviewed the report before it was filed. The search script is in https://github.com/augusto-rehfeldt/bugforge-results/tree/main/wave-20261003-182548-c1

CPython versions tested on:

3.14

Operating systems tested on:

Windows

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions