diff --git a/.gitattributes b/.gitattributes index 4ed95069442f3d..bab1ef0d010460 100644 --- a/.gitattributes +++ b/.gitattributes @@ -18,7 +18,6 @@ *.zip binary # Specific binary files -Lib/test/sndhdrdata/sndhdr.* binary PC/classicAppCompat.* binary # Text files that should not be subject to eol conversion diff --git a/Doc/library/sndhdr.rst b/Doc/library/sndhdr.rst deleted file mode 100644 index fa9323e18dc348..00000000000000 --- a/Doc/library/sndhdr.rst +++ /dev/null @@ -1,104 +0,0 @@ -:mod:`sndhdr` --- Determine type of sound file -============================================== - -.. module:: sndhdr - :synopsis: Determine type of a sound file. - :deprecated: - -.. sectionauthor:: Fred L. Drake, Jr. -.. Based on comments in the module source file. - -**Source code:** :source:`Lib/sndhdr.py` - -.. index:: - single: A-LAW - single: u-LAW - -.. deprecated-removed:: 3.11 3.13 - The :mod:`sndhdr` module is deprecated - (see :pep:`PEP 594 <594#sndhdr>` for details and alternatives). - --------------- - -The :mod:`sndhdr` provides utility functions which attempt to determine the type -of sound data which is in a file. When these functions are able to determine -what type of sound data is stored in a file, they return a -:func:`~collections.namedtuple`, containing five attributes: (``filetype``, -``framerate``, ``nchannels``, ``nframes``, ``sampwidth``). The value for *type* -indicates the data type and will be one of the strings ``'aifc'``, ``'aiff'``, -``'au'``, ``'hcom'``, ``'sndr'``, ``'sndt'``, ``'voc'``, ``'wav'``, ``'8svx'``, -``'sb'``, ``'ub'``, or ``'ul'``. The *sampling_rate* will be either the actual -value or ``0`` if unknown or difficult to decode. Similarly, *channels* will be -either the number of channels or ``0`` if it cannot be determined or if the -value is difficult to decode. The value for *frames* will be either the number -of frames or ``-1``. The last item in the tuple, *bits_per_sample*, will either -be the sample size in bits or ``'A'`` for A-LAW or ``'U'`` for u-LAW. - - -.. function:: what(filename) - - Determines the type of sound data stored in the file *filename* using - :func:`whathdr`. If it succeeds, returns a namedtuple as described above, otherwise - ``None`` is returned. - - .. versionchanged:: 3.5 - Result changed from a tuple to a namedtuple. - - -.. function:: whathdr(filename) - - Determines the type of sound data stored in a file based on the file header. - The name of the file is given by *filename*. This function returns a namedtuple as - described above on success, or ``None``. - - .. versionchanged:: 3.5 - Result changed from a tuple to a namedtuple. - -The following sound header types are recognized, as listed below with the return value -from :func:`whathdr`: and :func:`what`: - -+------------+------------------------------------+ -| Value | Sound header format | -+============+====================================+ -| ``'aifc'`` | Compressed Audio Interchange Files | -+------------+------------------------------------+ -| ``'aiff'`` | Audio Interchange Files | -+------------+------------------------------------+ -| ``'au'`` | Au Files | -+------------+------------------------------------+ -| ``'hcom'`` | HCOM Files | -+------------+------------------------------------+ -| ``'sndt'`` | Sndtool Sound Files | -+------------+------------------------------------+ -| ``'voc'`` | Creative Labs Audio Files | -+------------+------------------------------------+ -| ``'wav'`` | Waveform Audio File Format Files | -+------------+------------------------------------+ -| ``'8svx'`` | 8-Bit Sampled Voice Files | -+------------+------------------------------------+ -| ``'sb'`` | Signed Byte Audio Data Files | -+------------+------------------------------------+ -| ``'ub'`` | UB Files | -+------------+------------------------------------+ -| ``'ul'`` | uLAW Audio Files | -+------------+------------------------------------+ - -.. data:: tests - - A list of functions performing the individual tests. Each function takes two - arguments: the byte-stream and an open file-like object. When :func:`what` is - called with a byte-stream, the file-like object will be ``None``. - - The test function should return a string describing the image type if the test - succeeded, or ``None`` if it failed. - -Example: - -.. code-block:: pycon - - >>> import sndhdr - >>> imghdr.what('bass.wav') - 'wav' - >>> imghdr.whathdr('bass.wav') - 'wav' - diff --git a/Doc/library/superseded.rst b/Doc/library/superseded.rst index aaf66ea121d39c..dcfa183a92c514 100644 --- a/Doc/library/superseded.rst +++ b/Doc/library/superseded.rst @@ -24,7 +24,6 @@ backwards compatibility. They have been superseded by other modules. optparse.rst ossaudiodev.rst pipes.rst - sndhdr.rst spwd.rst sunau.rst telnetlib.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index af331c46f1c0e4..0f027ad0940d41 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -102,6 +102,11 @@ Deprecated Removed ======= +* Remove the ``sndhdr`` module, deprecated in Python 3.11: use the projects + `filetype `_, + `puremagic `_, + or `python-magic `_ instead. + (Contributed by Victor Stinner in :gh:`104773`.) Porting to Python 3.13 diff --git a/Lib/sndhdr.py b/Lib/sndhdr.py deleted file mode 100644 index 45def9ad16d32c..00000000000000 --- a/Lib/sndhdr.py +++ /dev/null @@ -1,271 +0,0 @@ -"""Routines to help recognizing sound files. - -Function whathdr() recognizes various types of sound file headers. -It understands almost all headers that SOX can decode. - -The return tuple contains the following items, in this order: -- file type (as SOX understands it) -- sampling rate (0 if unknown or hard to decode) -- number of channels (0 if unknown or hard to decode) -- number of frames in the file (-1 if unknown or hard to decode) -- number of bits/sample, or 'U' for U-LAW, or 'A' for A-LAW - -If the file doesn't have a recognizable type, it returns None. -If the file can't be opened, OSError is raised. - -To compute the total time, divide the number of frames by the -sampling rate (a frame contains a sample for each channel). - -Function what() calls whathdr(). (It used to also use some -heuristics for raw data, but this doesn't work very well.) - -Finally, the function test() is a simple main program that calls -what() for all files mentioned on the argument list. For directory -arguments it calls what() for all files in that directory. Default -argument is "." (testing all files in the current directory). The -option -r tells it to recurse down directories found inside -explicitly given directories. -""" - -import warnings - -warnings._deprecated(__name__, remove=(3, 13)) - -# The file structure is top-down except that the test program and its -# subroutine come last. - -__all__ = ['what', 'whathdr'] - -from collections import namedtuple - -SndHeaders = namedtuple('SndHeaders', - 'filetype framerate nchannels nframes sampwidth') - -SndHeaders.filetype.__doc__ = ("""The value for type indicates the data type -and will be one of the strings 'aifc', 'aiff', 'au','hcom', -'sndr', 'sndt', 'voc', 'wav', '8svx', 'sb', 'ub', or 'ul'.""") -SndHeaders.framerate.__doc__ = ("""The sampling_rate will be either the actual -value or 0 if unknown or difficult to decode.""") -SndHeaders.nchannels.__doc__ = ("""The number of channels or 0 if it cannot be -determined or if the value is difficult to decode.""") -SndHeaders.nframes.__doc__ = ("""The value for frames will be either the number -of frames or -1.""") -SndHeaders.sampwidth.__doc__ = ("""Either the sample size in bits or -'A' for A-LAW or 'U' for u-LAW.""") - -def what(filename): - """Guess the type of a sound file.""" - res = whathdr(filename) - return res - - -def whathdr(filename): - """Recognize sound headers.""" - with open(filename, 'rb') as f: - h = f.read(512) - for tf in tests: - res = tf(h, f) - if res: - return SndHeaders(*res) - return None - - -#-----------------------------------# -# Subroutines per sound header type # -#-----------------------------------# - -tests = [] - -def test_aifc(h, f): - """AIFC and AIFF files""" - with warnings.catch_warnings(): - warnings.simplefilter('ignore', category=DeprecationWarning) - import aifc - if not h.startswith(b'FORM'): - return None - if h[8:12] == b'AIFC': - fmt = 'aifc' - elif h[8:12] == b'AIFF': - fmt = 'aiff' - else: - return None - f.seek(0) - try: - a = aifc.open(f, 'r') - except (EOFError, aifc.Error): - return None - return (fmt, a.getframerate(), a.getnchannels(), - a.getnframes(), 8 * a.getsampwidth()) - -tests.append(test_aifc) - - -def test_au(h, f): - """AU and SND files""" - if h.startswith(b'.snd'): - func = get_long_be - elif h[:4] in (b'\0ds.', b'dns.'): - func = get_long_le - else: - return None - filetype = 'au' - hdr_size = func(h[4:8]) - data_size = func(h[8:12]) - encoding = func(h[12:16]) - rate = func(h[16:20]) - nchannels = func(h[20:24]) - sample_size = 1 # default - if encoding == 1: - sample_bits = 'U' - elif encoding == 2: - sample_bits = 8 - elif encoding == 3: - sample_bits = 16 - sample_size = 2 - else: - sample_bits = '?' - frame_size = sample_size * nchannels - if frame_size: - nframe = data_size / frame_size - else: - nframe = -1 - return filetype, rate, nchannels, nframe, sample_bits - -tests.append(test_au) - - -def test_hcom(h, f): - """HCOM file""" - if h[65:69] != b'FSSD' or h[128:132] != b'HCOM': - return None - divisor = get_long_be(h[144:148]) - if divisor: - rate = 22050 / divisor - else: - rate = 0 - return 'hcom', rate, 1, -1, 8 - -tests.append(test_hcom) - - -def test_voc(h, f): - """VOC file""" - if not h.startswith(b'Creative Voice File\032'): - return None - sbseek = get_short_le(h[20:22]) - rate = 0 - if 0 <= sbseek < 500 and h[sbseek] == 1: - ratecode = 256 - h[sbseek+4] - if ratecode: - rate = int(1000000.0 / ratecode) - return 'voc', rate, 1, -1, 8 - -tests.append(test_voc) - - -def test_wav(h, f): - """WAV file""" - import wave - # 'RIFF' 'WAVE' 'fmt ' - if not h.startswith(b'RIFF') or h[8:12] != b'WAVE' or h[12:16] != b'fmt ': - return None - f.seek(0) - try: - w = wave.open(f, 'r') - except (EOFError, wave.Error): - return None - return ('wav', w.getframerate(), w.getnchannels(), - w.getnframes(), 8*w.getsampwidth()) - -tests.append(test_wav) - - -def test_8svx(h, f): - """8SVX file""" - if not h.startswith(b'FORM') or h[8:12] != b'8SVX': - return None - # Should decode it to get #channels -- assume always 1 - return '8svx', 0, 1, 0, 8 - -tests.append(test_8svx) - - -def test_sndt(h, f): - """SNDT file""" - if h.startswith(b'SOUND'): - nsamples = get_long_le(h[8:12]) - rate = get_short_le(h[20:22]) - return 'sndt', rate, 1, nsamples, 8 - -tests.append(test_sndt) - - -def test_sndr(h, f): - """SNDR file""" - if h.startswith(b'\0\0'): - rate = get_short_le(h[2:4]) - if 4000 <= rate <= 25000: - return 'sndr', rate, 1, -1, 8 - -tests.append(test_sndr) - - -#-------------------------------------------# -# Subroutines to extract numbers from bytes # -#-------------------------------------------# - -def get_long_be(b): - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3] - -def get_long_le(b): - return (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0] - -def get_short_be(b): - return (b[0] << 8) | b[1] - -def get_short_le(b): - return (b[1] << 8) | b[0] - - -#--------------------# -# Small test program # -#--------------------# - -def test(): - import sys - recursive = 0 - if sys.argv[1:] and sys.argv[1] == '-r': - del sys.argv[1:2] - recursive = 1 - try: - if sys.argv[1:]: - testall(sys.argv[1:], recursive, 1) - else: - testall(['.'], recursive, 1) - except KeyboardInterrupt: - sys.stderr.write('\n[Interrupted]\n') - sys.exit(1) - -def testall(list, recursive, toplevel): - import sys - import os - for filename in list: - if os.path.isdir(filename): - print(filename + '/:', end=' ') - if recursive or toplevel: - print('recursing down:') - import glob - names = glob.glob(os.path.join(glob.escape(filename), '*')) - testall(names, recursive, 0) - else: - print('*** directory (use -r) ***') - else: - print(filename + ':', end=' ') - sys.stdout.flush() - try: - print(what(filename)) - except OSError: - print('*** not found ***') - -if __name__ == '__main__': - test() diff --git a/Lib/test/sndhdrdata/README b/Lib/test/sndhdrdata/README deleted file mode 100644 index b2cb664615b9c7..00000000000000 --- a/Lib/test/sndhdrdata/README +++ /dev/null @@ -1,5 +0,0 @@ -Sound file samples used by Lib/test/test_sndhdr.py and generated using the -following commands: - - dd if=/dev/zero of=sndhdr.raw bs=20 count=1 - sox -s -2 -c 2 -r 44100 sndhdr.raw sndhdr. diff --git a/Lib/test/sndhdrdata/sndhdr.8svx b/Lib/test/sndhdrdata/sndhdr.8svx deleted file mode 100644 index 8cd6cde5e09f35..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.8svx and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.aifc b/Lib/test/sndhdrdata/sndhdr.aifc deleted file mode 100644 index 8aae4e730bdafe..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.aifc and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.aiff b/Lib/test/sndhdrdata/sndhdr.aiff deleted file mode 100644 index 8c279a762f1c70..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.aiff and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.au b/Lib/test/sndhdrdata/sndhdr.au deleted file mode 100644 index 67c9e8fdd995ef..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.au and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.hcom b/Lib/test/sndhdrdata/sndhdr.hcom deleted file mode 100644 index debb02d9dd935f..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.hcom and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.sndt b/Lib/test/sndhdrdata/sndhdr.sndt deleted file mode 100644 index e1ca9cb185d157..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.sndt and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.voc b/Lib/test/sndhdrdata/sndhdr.voc deleted file mode 100644 index 53a91fd1eae30b..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.voc and /dev/null differ diff --git a/Lib/test/sndhdrdata/sndhdr.wav b/Lib/test/sndhdrdata/sndhdr.wav deleted file mode 100644 index 0dca36739cde30..00000000000000 Binary files a/Lib/test/sndhdrdata/sndhdr.wav and /dev/null differ diff --git a/Lib/test/test_sndhdr.py b/Lib/test/test_sndhdr.py deleted file mode 100644 index 4d97437f9072c2..00000000000000 --- a/Lib/test/test_sndhdr.py +++ /dev/null @@ -1,40 +0,0 @@ -import pickle -import unittest -from test.support import findfile -from test.support import warnings_helper - -sndhdr = warnings_helper.import_deprecated("sndhdr") - - -class TestFormats(unittest.TestCase): - def test_data(self): - for filename, expected in ( - ('sndhdr.8svx', ('8svx', 0, 1, 0, 8)), - ('sndhdr.aifc', ('aifc', 44100, 2, 5, 16)), - ('sndhdr.aiff', ('aiff', 44100, 2, 5, 16)), - ('sndhdr.au', ('au', 44100, 2, 5.0, 16)), - ('sndhdr.hcom', ('hcom', 22050.0, 1, -1, 8)), - ('sndhdr.sndt', ('sndt', 44100, 1, 5, 8)), - ('sndhdr.voc', ('voc', 0, 1, -1, 8)), - ('sndhdr.wav', ('wav', 44100, 2, 5, 16)), - ): - filename = findfile(filename, subdir="sndhdrdata") - what = sndhdr.what(filename) - self.assertNotEqual(what, None, filename) - self.assertSequenceEqual(what, expected) - self.assertEqual(what.filetype, expected[0]) - self.assertEqual(what.framerate, expected[1]) - self.assertEqual(what.nchannels, expected[2]) - self.assertEqual(what.nframes, expected[3]) - self.assertEqual(what.sampwidth, expected[4]) - - def test_pickleable(self): - filename = findfile('sndhdr.aifc', subdir="sndhdrdata") - what = sndhdr.what(filename) - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - dump = pickle.dumps(what, proto) - self.assertEqual(pickle.loads(dump), what) - - -if __name__ == '__main__': - unittest.main() diff --git a/Makefile.pre.in b/Makefile.pre.in index eb79c9c4ca1801..30ae9beff25194 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2122,7 +2122,6 @@ TESTSUBDIRS= idlelib/idle_test \ test/imghdrdata \ test/leakers \ test/libregrtest \ - test/sndhdrdata \ test/subprocessdata \ test/support \ test/support/_hypothesis_stubs \ diff --git a/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst b/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst new file mode 100644 index 00000000000000..81ef1c8736e10f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-23-01-37-40.gh-issue-104773.8c-GsG.rst @@ -0,0 +1,4 @@ +Remove the ``sndhdr`` module, deprecated in Python 3.11: use the projects +`filetype `_, `puremagic +`_, or `python-magic +`_ instead. Patch by Victor Stinner. diff --git a/Python/stdlib_module_names.h b/Python/stdlib_module_names.h index ed4a0ac2dd32de..7a34fc33b74b40 100644 --- a/Python/stdlib_module_names.h +++ b/Python/stdlib_module_names.h @@ -239,7 +239,6 @@ static const char* _Py_stdlib_module_names[] = { "signal", "site", "smtplib", -"sndhdr", "socket", "socketserver", "spwd",