diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2013-11-16 11:04:00 (GMT) |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2013-11-16 11:04:00 (GMT) |
commit | 7714ebbe0e7556bbfa6b768e434042b55474939c (patch) | |
tree | edfc3e4daeaca4f88a3efb384c1a34bdf7f808b1 | |
parent | a7a34a83f3f2b9b319cb6f379f6e189066233c76 (diff) | |
download | cpython-7714ebbe0e7556bbfa6b768e434042b55474939c.zip cpython-7714ebbe0e7556bbfa6b768e434042b55474939c.tar.gz cpython-7714ebbe0e7556bbfa6b768e434042b55474939c.tar.bz2 |
Issue #5202: Added support for unseekable files in the wave module.
-rw-r--r-- | Doc/library/wave.rst | 10 | ||||
-rw-r--r-- | Lib/test/audiotests.py | 60 | ||||
-rw-r--r-- | Lib/test/test_aifc.py | 44 | ||||
-rw-r--r-- | Lib/wave.py | 8 | ||||
-rw-r--r-- | Misc/NEWS | 2 |
5 files changed, 90 insertions, 34 deletions
diff --git a/Doc/library/wave.rst b/Doc/library/wave.rst index 9d12455..189f21a 100644 --- a/Doc/library/wave.rst +++ b/Doc/library/wave.rst @@ -19,7 +19,7 @@ The :mod:`wave` module defines the following function and exception: .. function:: open(file, mode=None) If *file* is a string, open the file by that name, otherwise treat it as a - seekable file-like object. *mode* can be: + file-like object. *mode* can be: ``'rb'`` Read only mode. @@ -43,6 +43,8 @@ The :mod:`wave` module defines the following function and exception: <wave.Wave_read.close>` or :meth:`Wave_write.close() <wave.Wave_write.close()>` method is called. + .. versionchanged:: 3.4 + Added support for unseekable files. .. function:: openfp(file, mode) @@ -154,7 +156,8 @@ Wave_write objects, as returned by :func:`.open`, have the following methods: .. method:: Wave_write.close() Make sure *nframes* is correct, and close the file if it was opened by - :mod:`wave`. This method is called upon object collection. + :mod:`wave`. This method is called upon object collection. Can raise an + exception if *nframes* is not correct and a file is not seekable. .. method:: Wave_write.setnchannels(n) @@ -208,7 +211,8 @@ Wave_write objects, as returned by :func:`.open`, have the following methods: .. method:: Wave_write.writeframes(data) - Write audio frames and make sure *nframes* is correct. + Write audio frames and make sure *nframes* is correct. Can raise an + exception if a file is not seekable. Note that it is invalid to set any parameters after calling :meth:`writeframes` diff --git a/Lib/test/audiotests.py b/Lib/test/audiotests.py index 7b39269..c22f0a1 100644 --- a/Lib/test/audiotests.py +++ b/Lib/test/audiotests.py @@ -21,6 +21,13 @@ def byteswap4(data): a.byteswap() return a.tobytes() +class UnseekableIO(io.FileIO): + def tell(self): + raise io.UnsupportedOperation + + def seek(self, *args, **kwargs): + raise io.UnsupportedOperation + class AudioTests: close_fd = False @@ -177,6 +184,59 @@ class AudioWriteTests(AudioTests): self.assertEqual(testfile.read(13), b'ababagalamaga') self.check_file(testfile, self.nframes, self.frames) + def test_unseekable_read(self): + with self.create_file(TESTFN) as f: + f.setnframes(self.nframes) + f.writeframes(self.frames) + + with UnseekableIO(TESTFN, 'rb') as testfile: + self.check_file(testfile, self.nframes, self.frames) + + def test_unseekable_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + with self.create_file(testfile) as f: + f.setnframes(self.nframes) + f.writeframes(self.frames) + + self.check_file(TESTFN, self.nframes, self.frames) + + def test_unseekable_incompleted_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + testfile.write(b'ababagalamaga') + f = self.create_file(testfile) + f.setnframes(self.nframes + 1) + try: + f.writeframes(self.frames) + except OSError: + pass + try: + f.close() + except OSError: + pass + + with open(TESTFN, 'rb') as testfile: + self.assertEqual(testfile.read(13), b'ababagalamaga') + self.check_file(testfile, self.nframes + 1, self.frames) + + def test_unseekable_overflowed_write(self): + with UnseekableIO(TESTFN, 'wb') as testfile: + testfile.write(b'ababagalamaga') + f = self.create_file(testfile) + f.setnframes(self.nframes - 1) + try: + f.writeframes(self.frames) + except OSError: + pass + try: + f.close() + except OSError: + pass + + with open(TESTFN, 'rb') as testfile: + self.assertEqual(testfile.read(13), b'ababagalamaga') + framesize = self.nchannels * self.sampwidth + self.check_file(testfile, self.nframes - 1, self.frames[:-framesize]) + class AudioTestsWithSourceFile(AudioTests): diff --git a/Lib/test/test_aifc.py b/Lib/test/test_aifc.py index 3e9a1d1..b4270bc 100644 --- a/Lib/test/test_aifc.py +++ b/Lib/test/test_aifc.py @@ -8,10 +8,17 @@ import struct import aifc -class AifcPCM8Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): +class AifcTest(audiotests.AudioWriteTests, + audiotests.AudioTestsWithSourceFile): module = aifc + close_fd = True + test_unseekable_read = None + test_unseekable_write = None + test_unseekable_incompleted_write = None + test_unseekable_overflowed_write = None + + +class AifcPCM8Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm8.aiff' sndfilenframes = 3307 nchannels = 2 @@ -26,13 +33,9 @@ class AifcPCM8Test(audiotests.AudioWriteTests, 11FA 3EFB BCFC 66FF CF04 4309 C10E 5112 EE17 8216 7F14 8012 \ 490E 520D EF0F CE0F E40C 630A 080A 2B0B 510E 8B11 B60E 440A \ """) - close_fd = True -class AifcPCM16Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM16Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm16.aiff' sndfilenframes = 3307 nchannels = 2 @@ -49,13 +52,9 @@ class AifcPCM16Test(audiotests.AudioWriteTests, EEE21753 82071665 7FFF1443 8004128F 49A20EAF 52BB0DBA EFB40F60 CE3C0FBF \ E4B30CEC 63430A5C 08C80A20 2BBB0B08 514A0E43 8BCF1139 B6F60EEB 44120A5E \ """) - close_fd = True -class AifcPCM24Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM24Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm24.aiff' sndfilenframes = 3307 nchannels = 2 @@ -78,13 +77,9 @@ class AifcPCM24Test(audiotests.AudioWriteTests, E4B49C0CEA2D 6344A80A5A7C 08C8FE0A1FFE 2BB9860B0A0E \ 51486F0E44E1 8BCC64113B05 B6F4EC0EEB36 4413170A5B48 \ """) - close_fd = True -class AifcPCM32Test(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcPCM32Test(AifcTest, unittest.TestCase): sndfilename = 'pluck-pcm32.aiff' sndfilenframes = 3307 nchannels = 2 @@ -107,13 +102,9 @@ class AifcPCM32Test(audiotests.AudioWriteTests, E4B49CC00CEA2D90 6344A8800A5A7CA0 08C8FE800A1FFEE0 2BB986C00B0A0E00 \ 51486F800E44E190 8BCC6480113B0580 B6F4EC000EEB3630 441317800A5B48A0 \ """) - close_fd = True -class AifcULAWTest(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcULAWTest(AifcTest, unittest.TestCase): sndfilename = 'pluck-ulaw.aifc' sndfilenframes = 3307 nchannels = 2 @@ -132,13 +123,9 @@ class AifcULAWTest(audiotests.AudioWriteTests, """) if sys.byteorder != 'big': frames = audiotests.byteswap2(frames) - close_fd = True -class AifcALAWTest(audiotests.AudioWriteTests, - audiotests.AudioTestsWithSourceFile, - unittest.TestCase): - module = aifc +class AifcALAWTest(AifcTest, unittest.TestCase): sndfilename = 'pluck-alaw.aifc' sndfilenframes = 3307 nchannels = 2 @@ -157,7 +144,6 @@ class AifcALAWTest(audiotests.AudioWriteTests, """) if sys.byteorder != 'big': frames = audiotests.byteswap2(frames) - close_fd = True class AifcMiscTest(audiotests.AudioTests, unittest.TestCase): diff --git a/Lib/wave.py b/Lib/wave.py index e723423..3d01817 100644 --- a/Lib/wave.py +++ b/Lib/wave.py @@ -491,14 +491,18 @@ class Wave_write: if not self._nframes: self._nframes = initlength // (self._nchannels * self._sampwidth) self._datalength = self._nframes * self._nchannels * self._sampwidth - self._form_length_pos = self._file.tell() + try: + self._form_length_pos = self._file.tell() + except (AttributeError, OSError): + self._form_length_pos = None self._file.write(struct.pack('<L4s4sLHHLLHH4s', 36 + self._datalength, b'WAVE', b'fmt ', 16, WAVE_FORMAT_PCM, self._nchannels, self._framerate, self._nchannels * self._framerate * self._sampwidth, self._nchannels * self._sampwidth, self._sampwidth * 8, b'data')) - self._data_length_pos = self._file.tell() + if self._form_length_pos is not None: + self._data_length_pos = self._file.tell() self._file.write(struct.pack('<L', self._datalength)) self._headerwritten = True @@ -47,6 +47,8 @@ Core and Builtins Library ------- +- Issue #5202: Added support for unseekable files in the wave module. + - Issue #19544 and Issue #1180: Restore global option to ignore ~/.pydistutils.cfg in Distutils, accidentally removed in backout of distutils2 changes. |