]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-144975: Fix wave.Wave_write.setframerate() validation order (GH-144976)
authorMichiel W. Beijen <mb@x14.nl>
Tue, 17 Mar 2026 17:01:18 +0000 (18:01 +0100)
committerGitHub <noreply@github.com>
Tue, 17 Mar 2026 17:01:18 +0000 (18:01 +0100)
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
Lib/wave.py
Misc/NEWS.d/next/Library/2026-02-18-21-45-00.gh-issue-144975.Ab3XyZ.rst [new file with mode: 0644]

index 4c21f16553775cc0b1e77d9f128acbd609433f0d..05e7d377517798f70c8532ccdd6f17442dad4d29 100644 (file)
@@ -207,6 +207,43 @@ class WaveLowLevelTest(unittest.TestCase):
             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):
index 25ca9ef168e8a539256ec4326bb7b0425690a565..841da8c49e9a2fe6a1e478e870297e9aea76cba3 100644 (file)
@@ -493,9 +493,10 @@ class Wave_write:
     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 (file)
index 0000000..3765806
--- /dev/null
@@ -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.