Skip to content

Commit cc28830

Browse files
committed
gh-149306: Improve error messages in wave module to include the offending value
Include the offending value in wave.Error messages raised by Wave_read._read_fmt_chunk and Wave_write setters (setnchannels, setsampwidth, setframerate). For setframerate, the original value is shown rather than the rounded one to aid debugging.
1 parent c1940bc commit cc28830

3 files changed

Lines changed: 46 additions & 12 deletions

File tree

Lib/test/test_wave.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from test.support.os_helper import FakePath, unlink
55
import io
66
import os
7+
import re
78
import struct
89
import tempfile
910
import sys
@@ -323,14 +324,14 @@ def test_read_wrong_number_of_channels(self):
323324
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
324325
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 0, 11025, 11025, 1, 8)
325326
b += b'data' + struct.pack('<L', 0)
326-
with self.assertRaisesRegex(wave.Error, 'bad # of channels'):
327+
with self.assertRaisesRegex(wave.Error, 'bad # of channels: 0'):
327328
wave.open(io.BytesIO(b))
328329

329330
def test_read_wrong_sample_width(self):
330331
b = b'RIFF' + struct.pack('<L', 36) + b'WAVE'
331332
b += b'fmt ' + struct.pack('<LHHLLHH', 16, 1, 1, 11025, 11025, 1, 0)
332333
b += b'data' + struct.pack('<L', 0)
333-
with self.assertRaisesRegex(wave.Error, 'bad sample width'):
334+
with self.assertRaisesRegex(wave.Error, 'bad sample width: 0'):
334335
wave.open(io.BytesIO(b))
335336

336337
def test_open_in_write_raises(self):
@@ -430,6 +431,36 @@ def test_setframerate_rounds(self, arg, expected):
430431
f.setframerate(arg)
431432
self.assertEqual(f.getframerate(), expected)
432433

434+
@support.subTests('nchannels', (0, -1))
435+
def test_setnchannels_error_includes_value(self, nchannels):
436+
with wave.open(io.BytesIO(), 'wb') as f:
437+
with self.assertRaisesRegex(wave.Error,
438+
re.escape(f'bad # of channels: {nchannels!r}')):
439+
f.setnchannels(nchannels)
440+
with self.assertRaises(wave.Error):
441+
f.close()
442+
443+
@support.subTests('sampwidth', (0, 5))
444+
def test_setsampwidth_error_includes_value(self, sampwidth):
445+
with wave.open(io.BytesIO(), 'wb') as f:
446+
f.setnchannels(1)
447+
with self.assertRaisesRegex(wave.Error,
448+
re.escape(f'bad sample width: {sampwidth!r}')):
449+
f.setsampwidth(sampwidth)
450+
with self.assertRaises(wave.Error):
451+
f.close()
452+
453+
@support.subTests('arg', (-1, 0, 0.4))
454+
def test_setframerate_error_includes_value(self, arg):
455+
with wave.open(io.BytesIO(), 'wb') as f:
456+
f.setnchannels(1)
457+
f.setsampwidth(2)
458+
with self.assertRaisesRegex(wave.Error,
459+
re.escape(f'bad frame rate: {arg!r}')):
460+
f.setframerate(arg)
461+
with self.assertRaises(wave.Error):
462+
f.close()
463+
433464
def test_write_odd_data_chunk_pads_and_updates_riff_size(self):
434465
# gh-117716: odd-sized data chunks must be padded with one zero byte.
435466
with io.BytesIO() as output:

Lib/wave.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ def readframes(self, nframes):
388388

389389
def _read_fmt_chunk(self, chunk):
390390
try:
391-
self._format, self._nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
391+
self._format, nchannels, self._framerate, dwAvgBytesPerSec, wBlockAlign = struct.unpack_from('<HHLLH', chunk.read(14))
392392
except struct.error:
393393
raise EOFError from None
394394
if self._format not in (WAVE_FORMAT_PCM, WAVE_FORMAT_IEEE_FLOAT, WAVE_FORMAT_EXTENSIBLE):
@@ -415,9 +415,10 @@ def _read_fmt_chunk(self, chunk):
415415
raise Error(subformat_msg)
416416
self._sampwidth = (sampwidth + 7) // 8
417417
if not self._sampwidth:
418-
raise Error('bad sample width')
419-
if not self._nchannels:
420-
raise Error('bad # of channels')
418+
raise Error(f'bad sample width: {sampwidth!r}')
419+
if not nchannels:
420+
raise Error(f'bad # of channels: {nchannels!r}')
421+
self._nchannels = nchannels
421422
self._framesize = self._nchannels * self._sampwidth
422423
self._comptype = 'NONE'
423424
self._compname = 'not compressed'
@@ -495,7 +496,7 @@ def setnchannels(self, nchannels):
495496
if self._datawritten:
496497
raise Error('cannot change parameters after starting to write')
497498
if nchannels < 1:
498-
raise Error('bad # of channels')
499+
raise Error(f'bad # of channels: {nchannels!r}')
499500
self._nchannels = nchannels
500501

501502
def getnchannels(self):
@@ -510,7 +511,7 @@ def setsampwidth(self, sampwidth):
510511
if sampwidth not in (4, 8):
511512
raise Error('unsupported sample width for IEEE float format')
512513
elif sampwidth < 1 or sampwidth > 4:
513-
raise Error('bad sample width')
514+
raise Error(f'bad sample width: {sampwidth!r}')
514515
self._sampwidth = sampwidth
515516

516517
def getsampwidth(self):
@@ -521,10 +522,10 @@ def getsampwidth(self):
521522
def setframerate(self, framerate):
522523
if self._datawritten:
523524
raise Error('cannot change parameters after starting to write')
524-
framerate = int(round(framerate))
525-
if framerate <= 0:
526-
raise Error('bad frame rate')
527-
self._framerate = framerate
525+
rounded = int(round(framerate))
526+
if rounded <= 0:
527+
raise Error(f'bad frame rate: {framerate!r}')
528+
self._framerate = rounded
528529

529530
def getframerate(self):
530531
if not self._framerate:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Error messages in :mod:`wave` for invalid channel count, sample width, and
2+
frame rate now include the offending value.

0 commit comments

Comments
 (0)