From 027364153a751a8d3b907ccbea627a9be896c902 Mon Sep 17 00:00:00 2001 From: "Michiel W. Beijen" Date: Wed, 18 Feb 2026 21:29:07 +0100 Subject: [PATCH] gh-144975: Fix wave.Wave_write.setframerate() validation order Validate the frame rate after rounding to an integer, not before. This prevents values like 0.5 from passing validation (0.5 > 0) but then rounding to 0, which would cause a confusing delayed error "sampling rate not specified" when writing frames. With this fix, setframerate(0.5) immediately raises "bad frame rate", providing clear feedback at the point of the error. --- Lib/test/test_wave.py | 33 +++++++++++++++++++ Lib/wave.py | 3 +- ...-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst | 3 ++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 4c21f16553775c..d6b875a5287e45 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -207,6 +207,39 @@ def test_open_in_write_raises(self): support.gc_collect() self.assertIsNone(cm.unraisable) + def test_setframerate_rounds_then_validates(self): + """Test that setframerate rounds before validation""" + # Test that framerates that round to 0 or negative are rejected + with wave.open(io.BytesIO(), 'wb') as f: + f.setnchannels(1) + f.setsampwidth(2) + # 0.5 rounds to 0, should raise + with self.assertRaises(wave.Error): + f.setframerate(0.5) + # 0.4 rounds to 0, should raise + with self.assertRaises(wave.Error): + f.setframerate(0.4) + # Negative values should still raise + with self.assertRaises(wave.Error): + f.setframerate(-1) + with self.assertRaises(wave.Error): + f.setframerate(-0.5) + # 0 should raise + with self.assertRaises(wave.Error): + f.setframerate(0) + + # Valid values that round to positive integers should work + f.setframerate(1.4) # rounds to 1 + self.assertEqual(f.getframerate(), 1) + f.setframerate(1.5) # rounds to 2 + self.assertEqual(f.getframerate(), 2) + f.setframerate(1.6) # rounds to 2 + self.assertEqual(f.getframerate(), 2) + f.setframerate(44100.4) # rounds to 44100 + self.assertEqual(f.getframerate(), 44100) + f.setframerate(44100.5) # rounds to 44100 + self.assertEqual(f.getframerate(), 44100) + class WaveOpen(unittest.TestCase): def test_open_pathlike(self): diff --git a/Lib/wave.py b/Lib/wave.py index 25ca9ef168e8a5..841da8c49e9a2f 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -493,9 +493,10 @@ def getsampwidth(self): def setframerate(self, framerate): if self._datawritten: raise Error('cannot change parameters after starting to write') + framerate = int(round(framerate)) if framerate <= 0: raise Error('bad frame rate') - self._framerate = int(round(framerate)) + self._framerate = framerate def getframerate(self): if not self._framerate: diff --git a/Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst b/Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst new file mode 100644 index 00000000000000..37658064c2c351 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst @@ -0,0 +1,3 @@ +:meth:`wave.Wave_write.setframerate` now validates the frame rate after +rounding to an integer, preventing values like ``0.5`` from being accepted +and causing confusing errors later. Patch by Michiel Beijen.