https://github.com/python/cpython/commit/ff287a72de43e7fc6517aba9049cb23470e000b2
commit: ff287a72de43e7fc6517aba9049cb23470e000b2
branch: main
author: Michiel W. Beijen <[email protected]>
committer: encukou <[email protected]>
date: 2026-03-17T18:01:18+01:00
summary:

gh-144975: Fix wave.Wave_write.setframerate() validation order (GH-144976)

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.

files:
A Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst
M Lib/test/test_wave.py
M Lib/wave.py

diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py
index 4c21f16553775c..05e7d377517798 100644
--- a/Lib/test/test_wave.py
+++ b/Lib/test/test_wave.py
@@ -207,6 +207,43 @@ def test_open_in_write_raises(self):
             support.gc_collect()
             self.assertIsNone(cm.unraisable)
 
+    @support.subTests('arg', (
+        # rounds to 0, should raise:
+        0.5,
+        0.4,
+        # Negative values should still raise:
+        -1,
+        -0.5,
+        -0.4,
+        # 0 should raise:
+        0,
+    ))
+    def test_setframerate_validates_rounded_values(self, arg):
+        """Test that setframerate that round to 0 or negative are rejected"""
+        with wave.open(io.BytesIO(), 'wb') as f:
+            f.setnchannels(1)
+            f.setsampwidth(2)
+            with self.assertRaises(wave.Error):
+                f.setframerate(arg)
+            with self.assertRaises(wave.Error):
+                f.close()
+
+    @support.subTests(('arg', 'expected'), (
+        (1.4, 1),
+        (1.5, 2),
+        (1.6, 2),
+        (44100.4, 44100),
+        (44100.5, 44100),
+        (44100.6, 44101),
+    ))
+    def test_setframerate_rounds(self, arg, expected):
+        """Test that setframerate is rounded"""
+        with wave.open(io.BytesIO(), 'wb') as f:
+            f.setnchannels(1)
+            f.setsampwidth(2)
+            f.setframerate(arg)
+            self.assertEqual(f.getframerate(), expected)
+
 
 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.

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to