From 8b77c5ab985508dcbf78d5a77ae1d8796c692847 Mon Sep 17 00:00:00 2001 From: Yannis Gerlach <100762533+ygerlach@users.noreply.github.com> Date: Wed, 23 Apr 2025 23:32:35 +0200 Subject: [PATCH] GH-132445: Allowing to reset parameters of Wave_write --- Doc/library/wave.rst | 30 +++++++++++++++-- Lib/test/test_wave.py | 33 +++++++++++++++++++ Lib/wave.py | 19 ++++++----- ...-04-30-18-12-53.gh-issue-132445.zPEifv.rst | 1 + 4 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-04-30-18-12-53.gh-issue-132445.zPEifv.rst diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index 36c2bde87fb8fb..a86e2451bb2b31 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -198,11 +198,20 @@ Wave_write Objects Set the number of channels. + Raises an :exc:`wave.Error`, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. .. method:: setsampwidth(n) Set the sample width to *n* bytes. + Raises an :exc:`wave.Error`, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. + .. method:: setframerate(n) @@ -212,6 +221,11 @@ Wave_write Objects A non-integral input to this method is rounded to the nearest integer. + Raises an :exc:`wave.Error`, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. + .. method:: setnframes(n) @@ -219,12 +233,20 @@ Wave_write Objects of frames actually written is different (this update attempt will raise an error if the output stream is not seekable). + Raises an :exc:`wave.Error`, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. .. method:: setcomptype(type, name) Set the compression type and description. At the moment, only compression type ``NONE`` is supported, meaning no compression. + Raises an Error, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. .. method:: setparams(tuple) @@ -232,6 +254,10 @@ Wave_write Objects compname)``, with values valid for the ``set*()`` methods. Sets all parameters. + Raises an :exc:`wave.Error`, if the value is set after data was written. + + .. versionchanged:: 3.14 + :exc:`wave.Error` is not raised, if the value is the same. .. method:: tell() @@ -257,6 +283,6 @@ Wave_write Objects .. versionchanged:: 3.4 Any :term:`bytes-like object` is now accepted. - Note that it is invalid to set any parameters after calling :meth:`writeframes` + Note that it is invalid to change any parameters after calling :meth:`writeframes` or :meth:`writeframesraw`, and any attempt to do so will raise - :exc:`wave.Error`. + :exc:`wave.Error`, if the value is different from the current value. diff --git a/Lib/test/test_wave.py b/Lib/test/test_wave.py index 5e771c8de969ec..522ee23d5fce04 100644 --- a/Lib/test/test_wave.py +++ b/Lib/test/test_wave.py @@ -162,6 +162,39 @@ def test_write_deprecations(self): with self.assertWarns(DeprecationWarning): self.assertIsNone(writer.getmarkers()) + def test_setters(self): + with io.BytesIO(b'') as tmpfile: + with wave.open(tmpfile, 'wb') as writer: + writer.setnchannels(1) + writer.setsampwidth(1) + writer.setframerate(1) + writer.setcomptype('NONE', 'not compressed') + + # no errors, when chaning and nothing was written + writer.setnchannels(2) + writer.setsampwidth(2) + writer.setframerate(2) + writer.setcomptype('NONE', 'uncompressed') + + # write some frames + writer.writeframes(b'\0' * 16) + + # changeing now should result in an error + with self.assertRaises(wave.Error): + writer.setnchannels(1) + with self.assertRaises(wave.Error): + writer.setsampwidth(1) + with self.assertRaises(wave.Error): + writer.setframerate(1) + with self.assertRaises(wave.Error): + writer.setcomptype('NONE', 'other') + + # same value, so it should not raise Error + writer.setnchannels(2) + writer.setsampwidth(2) + writer.setframerate(2) + writer.setcomptype('NONE', 'uncompressed') + class WaveLowLevelTest(unittest.TestCase): diff --git a/Lib/wave.py b/Lib/wave.py index a34af244c3e224..282f2d3a03ecf5 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -478,7 +478,7 @@ def __exit__(self, *args): # User visible methods. # def setnchannels(self, nchannels): - if self._datawritten: + if self._datawritten and self._nchannels != nchannels: raise Error('cannot change parameters after starting to write') if nchannels < 1: raise Error('bad # of channels') @@ -490,7 +490,7 @@ def getnchannels(self): return self._nchannels def setsampwidth(self, sampwidth): - if self._datawritten: + if self._datawritten and self._sampwidth != sampwidth: raise Error('cannot change parameters after starting to write') if sampwidth < 1 or sampwidth > 4: raise Error('bad sample width') @@ -502,11 +502,12 @@ def getsampwidth(self): return self._sampwidth def setframerate(self, framerate): - if self._datawritten: + rounded_framerate = int(round(framerate)) + if self._datawritten and self._framerate != rounded_framerate: raise Error('cannot change parameters after starting to write') - if framerate <= 0: + if rounded_framerate <= 0: raise Error('bad frame rate') - self._framerate = int(round(framerate)) + self._framerate = rounded_framerate def getframerate(self): if not self._framerate: @@ -514,7 +515,7 @@ def getframerate(self): return self._framerate def setnframes(self, nframes): - if self._datawritten: + if self._datawritten and self._nframes != nframes: raise Error('cannot change parameters after starting to write') self._nframes = nframes @@ -522,7 +523,7 @@ def getnframes(self): return self._nframeswritten def setcomptype(self, comptype, compname): - if self._datawritten: + if self._datawritten and (self._comptype != comptype or self._compname != compname): raise Error('cannot change parameters after starting to write') if comptype not in ('NONE',): raise Error('unsupported compression type') @@ -537,8 +538,8 @@ def getcompname(self): def setparams(self, params): nchannels, sampwidth, framerate, nframes, comptype, compname = params - if self._datawritten: - raise Error('cannot change parameters after starting to write') + # no check for value change required: either the properties have the same + # value or they throw the exception them selfs self.setnchannels(nchannels) self.setsampwidth(sampwidth) self.setframerate(framerate) diff --git a/Misc/NEWS.d/next/Library/2025-04-30-18-12-53.gh-issue-132445.zPEifv.rst b/Misc/NEWS.d/next/Library/2025-04-30-18-12-53.gh-issue-132445.zPEifv.rst new file mode 100644 index 00000000000000..977504dc1e71ca --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-30-18-12-53.gh-issue-132445.zPEifv.rst @@ -0,0 +1 @@ +:class:`Wave_write` setters don't raise an error anymore, if the value did not change after frames were written.