diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst index 98d8679fa3d..aa2a27084c3 100644 --- a/Doc/library/binascii.rst +++ b/Doc/library/binascii.rst @@ -92,6 +92,8 @@ The :mod:`binascii` module defines the following functions: The string should contain a complete number of binary bytes, or (in case of the last portion of the binhex4 data) have the remaining bits zero. + .. deprecated:: 3.9 + .. function:: rledecode_hqx(data) @@ -104,11 +106,15 @@ The :mod:`binascii` module defines the following functions: .. versionchanged:: 3.2 Accept only bytestring or bytearray objects as input. + .. deprecated:: 3.9 + .. function:: rlecode_hqx(data) Perform binhex4 style RLE-compression on *data* and return the result. + .. deprecated:: 3.9 + .. function:: b2a_hqx(data) @@ -116,6 +122,8 @@ The :mod:`binascii` module defines the following functions: argument should already be RLE-coded, and have a length divisible by 3 (except possibly the last fragment). + .. deprecated:: 3.9 + .. function:: crc_hqx(data, value) @@ -124,6 +132,8 @@ The :mod:`binascii` module defines the following functions: *x*:sup:`16` + *x*:sup:`12` + *x*:sup:`5` + 1, often represented as 0x1021. This CRC is used in the binhex4 format. + .. deprecated:: 3.9 + .. function:: crc32(data[, value]) diff --git a/Doc/library/binhex.rst b/Doc/library/binhex.rst index 2966e0dbfbc..7de6a663762 100644 --- a/Doc/library/binhex.rst +++ b/Doc/library/binhex.rst @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/binhex.py` +.. deprecated:: 3.9 + -------------- This module encodes and decodes files in binhex4 format, a format allowing diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 00341ef8019..0e82ff0695d 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -353,6 +353,16 @@ Deprecated deprecated and will be removed in version 3.11. (Contributed by Yury Selivanov and Kyle Stanley in :issue:`34790`.) +* binhex4 and hexbin4 standards are now deprecated. The :`binhex` module + and the following :mod:`binascii` functions are now deprecated: + + * :func:`~binascii.b2a_hqx`, :func:`~binascii.a2b_hqx` + * :func:`~binascii.rlecode_hqx`, :func:`~binascii.rledecode_hqx` + * :func:`~binascii.crc_hqx` + + (Contributed by Victor Stinner in :issue:`39353`.) + + Removed ======= diff --git a/Lib/binhex.py b/Lib/binhex.py index 56b5f852c00..6ff38dd8229 100644 --- a/Lib/binhex.py +++ b/Lib/binhex.py @@ -21,10 +21,16 @@ hexbin(inputfilename, outputfilename) # input. The resulting code (xx 90 90) would appear to be interpreted as an # escaped *value* of 0x90. All coders I've seen appear to ignore this nicety... # +import binascii +import contextlib import io import os import struct -import binascii +import warnings + +warnings.warn('the binhex module is deprecated', DeprecationWarning, + stacklevel=2) + __all__ = ["binhex","hexbin","Error"] @@ -76,6 +82,16 @@ class openrsrc: def close(self): pass + +# DeprecationWarning is already emitted on "import binhex". There is no need +# to repeat the warning at each call to deprecated binascii functions. +@contextlib.contextmanager +def _ignore_deprecation_warning(): + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '', DeprecationWarning) + yield + + class _Hqxcoderengine: """Write data to the coder in 3-byte chunks""" @@ -93,7 +109,8 @@ class _Hqxcoderengine: self.data = self.data[todo:] if not data: return - self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) + with _ignore_deprecation_warning(): + self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) self._flush(0) def _flush(self, force): @@ -109,7 +126,8 @@ class _Hqxcoderengine: def close(self): if self.data: - self.hqxdata = self.hqxdata + binascii.b2a_hqx(self.data) + with _ignore_deprecation_warning(): + self.hqxdata = self.hqxdata + binascii.b2a_hqx(self.data) self._flush(1) self.ofp.close() del self.ofp @@ -125,13 +143,15 @@ class _Rlecoderengine: self.data = self.data + data if len(self.data) < REASONABLY_LARGE: return - rledata = binascii.rlecode_hqx(self.data) + with _ignore_deprecation_warning(): + rledata = binascii.rlecode_hqx(self.data) self.ofp.write(rledata) self.data = b'' def close(self): if self.data: - rledata = binascii.rlecode_hqx(self.data) + with _ignore_deprecation_warning(): + rledata = binascii.rlecode_hqx(self.data) self.ofp.write(rledata) self.ofp.close() del self.ofp @@ -180,7 +200,8 @@ class BinHex: self._writecrc() def _write(self, data): - self.crc = binascii.crc_hqx(data, self.crc) + with _ignore_deprecation_warning(): + self.crc = binascii.crc_hqx(data, self.crc) self.ofp.write(data) def _writecrc(self): @@ -276,7 +297,8 @@ class _Hqxdecoderengine: # while True: try: - decdatacur, self.eof = binascii.a2b_hqx(data) + with _ignore_deprecation_warning(): + decdatacur, self.eof = binascii.a2b_hqx(data) break except binascii.Incomplete: pass @@ -312,8 +334,9 @@ class _Rledecoderengine: def _fill(self, wtd): self.pre_buffer = self.pre_buffer + self.ifp.read(wtd + 4) if self.ifp.eof: - self.post_buffer = self.post_buffer + \ - binascii.rledecode_hqx(self.pre_buffer) + with _ignore_deprecation_warning(): + self.post_buffer = self.post_buffer + \ + binascii.rledecode_hqx(self.pre_buffer) self.pre_buffer = b'' return @@ -340,8 +363,9 @@ class _Rledecoderengine: else: mark = mark - 1 - self.post_buffer = self.post_buffer + \ - binascii.rledecode_hqx(self.pre_buffer[:mark]) + with _ignore_deprecation_warning(): + self.post_buffer = self.post_buffer + \ + binascii.rledecode_hqx(self.pre_buffer[:mark]) self.pre_buffer = self.pre_buffer[mark:] def close(self): @@ -372,7 +396,8 @@ class HexBin: def _read(self, len): data = self.ifp.read(len) - self.crc = binascii.crc_hqx(data, self.crc) + with _ignore_deprecation_warning(): + self.crc = binascii.crc_hqx(data, self.crc) return data def _checkcrc(self): diff --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py index 08de5c9fc7c..649edbe2954 100644 --- a/Lib/test/test_binascii.py +++ b/Lib/test/test_binascii.py @@ -4,6 +4,7 @@ import unittest import binascii import array import re +from test import support # Note: "*_hex" functions are aliases for "(un)hexlify" b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu', @@ -36,6 +37,7 @@ class BinASCIITest(unittest.TestCase): self.assertTrue(hasattr(getattr(binascii, name), '__call__')) self.assertRaises(TypeError, getattr(binascii, name)) + @support.ignore_warnings(category=DeprecationWarning) def test_returned_value(self): # Limit to the minimum of all limits (b2a_uu) MAX_ALL = 45 @@ -179,6 +181,7 @@ class BinASCIITest(unittest.TestCase): with self.assertRaises(TypeError): binascii.b2a_uu(b"", True) + @support.ignore_warnings(category=DeprecationWarning) def test_crc_hqx(self): crc = binascii.crc_hqx(self.type2test(b"Test the CRC-32 of"), 0) crc = binascii.crc_hqx(self.type2test(b" this string."), crc) @@ -198,6 +201,7 @@ class BinASCIITest(unittest.TestCase): self.assertRaises(TypeError, binascii.crc32) + @support.ignore_warnings(category=DeprecationWarning) def test_hqx(self): # Perform binhex4 style RLE-compression # Then calculate the hexbin4 binary-to-ASCII translation @@ -208,6 +212,7 @@ class BinASCIITest(unittest.TestCase): res = binascii.rledecode_hqx(b) self.assertEqual(res, self.rawdata) + @support.ignore_warnings(category=DeprecationWarning) def test_rle(self): # test repetition with a repetition longer than the limit of 255 data = (b'a' * 100 + b'b' + b'c' * 300) @@ -354,6 +359,7 @@ class BinASCIITest(unittest.TestCase): self.assertEqual(b2a_qp(type2test(b'a.\n')), b'a.\n') self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E') + @support.ignore_warnings(category=DeprecationWarning) def test_empty_string(self): # A test for SF bug #1022953. Make sure SystemError is not raised. empty = self.type2test(b'') @@ -378,6 +384,7 @@ class BinASCIITest(unittest.TestCase): # crc_hqx needs 2 arguments self.assertRaises(TypeError, binascii.crc_hqx, "test", 0) + @support.ignore_warnings(category=DeprecationWarning) def test_unicode_a2b(self): # Unicode strings are accepted by a2b_* functions. MAX_ALL = 45 @@ -416,6 +423,21 @@ class BinASCIITest(unittest.TestCase): self.assertEqual(binascii.b2a_base64(b, newline=False), b'aGVsbG8=') + def test_deprecated_warnings(self): + with self.assertWarns(DeprecationWarning): + self.assertEqual(binascii.b2a_hqx(b'abc'), b'B@*M') + with self.assertWarns(DeprecationWarning): + self.assertEqual(binascii.a2b_hqx(b'B@*M'), (b'abc', 0)) + + with self.assertWarns(DeprecationWarning): + self.assertEqual(binascii.rlecode_hqx(b'a' * 10), b'a\x90\n') + + with self.assertWarns(DeprecationWarning): + self.assertEqual(binascii.rledecode_hqx(b'a\x90\n'), b'a' * 10) + + with self.assertWarns(DeprecationWarning): + self.assertEqual(binascii.crc_hqx(b'abc', 0), 40406) + class ArrayBinASCIITest(BinASCIITest): def type2test(self, s): diff --git a/Lib/test/test_binhex.py b/Lib/test/test_binhex.py index 2f3d53afbd1..86ca37ce1b9 100644 --- a/Lib/test/test_binhex.py +++ b/Lib/test/test_binhex.py @@ -3,10 +3,12 @@ Uses the mechanism of the python binhex module Based on an original test by Roger E. Masse. """ -import binhex import unittest from test import support +with support.check_warnings(('', DeprecationWarning)): + import binhex + class BinHexTestCase(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2020-01-16-10-21-48.bpo-39353.ntp7Ql.rst b/Misc/NEWS.d/next/Library/2020-01-16-10-21-48.bpo-39353.ntp7Ql.rst new file mode 100644 index 00000000000..c0d4583ca7f --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-01-16-10-21-48.bpo-39353.ntp7Ql.rst @@ -0,0 +1,4 @@ +Deprecate binhex4 and hexbin4 standards. Deprecate the :mod:`binhex` module and +the following :mod:`binascii` functions: :func:`~binascii.b2a_hqx`, +:func:`~binascii.a2b_hqx`, :func:`~binascii.rlecode_hqx`, +:func:`~binascii.rledecode_hqx`, :func:`~binascii.crc_hqx`. diff --git a/Modules/binascii.c b/Modules/binascii.c index 94b0732c12c..c6da3e0a635 100644 --- a/Modules/binascii.c +++ b/Modules/binascii.c @@ -613,6 +613,11 @@ static PyObject * binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=4d6d8c54d54ea1c1 input=0d914c680e0eed55]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "binascii.a2b_hqx() is deprecated", 1) < 0) { + return NULL; + } + const unsigned char *ascii_data; unsigned char *bin_data; int leftbits = 0; @@ -701,6 +706,11 @@ static PyObject * binascii_rlecode_hqx_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=393d79338f5f5629 input=e1f1712447a82b09]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "binascii.rlecode_hqx() is deprecated", 1) < 0) { + return NULL; + } + const unsigned char *in_data; unsigned char *out_data; unsigned char ch; @@ -763,6 +773,11 @@ static PyObject * binascii_b2a_hqx_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=d0aa5a704bc9f7de input=9596ebe019fe12ba]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "binascii.b2a_hqx() is deprecated", 1) < 0) { + return NULL; + } + unsigned char *ascii_data; const unsigned char *bin_data; int leftbits = 0; @@ -818,6 +833,11 @@ static PyObject * binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data) /*[clinic end generated code: output=9826619565de1c6c input=54cdd49fc014402c]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "binascii.rledecode_hqx() is deprecated", 1) < 0) { + return NULL; + } + const unsigned char *in_data; unsigned char *out_data; unsigned char in_byte, in_repeat; @@ -932,7 +952,7 @@ error: /*[clinic input] -binascii.crc_hqx -> unsigned_int +binascii.crc_hqx data: Py_buffer crc: unsigned_int(bitwise=True) @@ -941,10 +961,15 @@ binascii.crc_hqx -> unsigned_int Compute CRC-CCITT incrementally. [clinic start generated code]*/ -static unsigned int +static PyObject * binascii_crc_hqx_impl(PyObject *module, Py_buffer *data, unsigned int crc) -/*[clinic end generated code: output=8ec2a78590d19170 input=f18240ff8c705b79]*/ +/*[clinic end generated code: output=2fde213d0f547a98 input=56237755370a951c]*/ { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "binascii.crc_hqx() is deprecated", 1) < 0) { + return NULL; + } + const unsigned char *bin_data; Py_ssize_t len; @@ -956,7 +981,7 @@ binascii_crc_hqx_impl(PyObject *module, Py_buffer *data, unsigned int crc) crc = ((crc<<8)&0xff00) ^ crctab_hqx[(crc>>8)^*bin_data++]; } - return crc; + return PyLong_FromUnsignedLong(crc); } #ifndef USE_ZLIB_CRC32 diff --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h index 82942f08a68..4d02c72c472 100644 --- a/Modules/clinic/binascii.c.h +++ b/Modules/clinic/binascii.c.h @@ -328,7 +328,7 @@ PyDoc_STRVAR(binascii_crc_hqx__doc__, #define BINASCII_CRC_HQX_METHODDEF \ {"crc_hqx", (PyCFunction)(void(*)(void))binascii_crc_hqx, METH_FASTCALL, binascii_crc_hqx__doc__}, -static unsigned int +static PyObject * binascii_crc_hqx_impl(PyObject *module, Py_buffer *data, unsigned int crc); static PyObject * @@ -337,7 +337,6 @@ binascii_crc_hqx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; Py_buffer data = {NULL, NULL}; unsigned int crc; - unsigned int _return_value; if (!_PyArg_CheckPositional("crc_hqx", nargs, 2, 2)) { goto exit; @@ -358,11 +357,7 @@ binascii_crc_hqx(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (crc == (unsigned int)-1 && PyErr_Occurred()) { goto exit; } - _return_value = binascii_crc_hqx_impl(module, &data, crc); - if ((_return_value == (unsigned int)-1) && PyErr_Occurred()) { - goto exit; - } - return_value = PyLong_FromUnsignedLong((unsigned long)_return_value); + return_value = binascii_crc_hqx_impl(module, &data, crc); exit: /* Cleanup for data */ @@ -801,4 +796,4 @@ exit: return return_value; } -/*[clinic end generated code: output=ec26d03c2007eaac input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a1e878d3963b615e input=a9049054013a1b77]*/