bpo-39353: Deprecate the binhex module (GH-18025)

Deprecate binhex4 and hexbin4 standards. Deprecate the binhex module
and the following binascii functions:

* b2a_hqx(), a2b_hqx()
* rlecode_hqx(), rledecode_hqx()
* crc_hqx()
This commit is contained in:
Victor Stinner 2020-01-22 20:44:22 +01:00 committed by GitHub
parent 14d80d0b60
commit beea26b57e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 120 additions and 25 deletions

View file

@ -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 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. last portion of the binhex4 data) have the remaining bits zero.
.. deprecated:: 3.9
.. function:: rledecode_hqx(data) .. function:: rledecode_hqx(data)
@ -104,11 +106,15 @@ The :mod:`binascii` module defines the following functions:
.. versionchanged:: 3.2 .. versionchanged:: 3.2
Accept only bytestring or bytearray objects as input. Accept only bytestring or bytearray objects as input.
.. deprecated:: 3.9
.. function:: rlecode_hqx(data) .. function:: rlecode_hqx(data)
Perform binhex4 style RLE-compression on *data* and return the result. Perform binhex4 style RLE-compression on *data* and return the result.
.. deprecated:: 3.9
.. function:: b2a_hqx(data) .. 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 argument should already be RLE-coded, and have a length divisible by 3 (except
possibly the last fragment). possibly the last fragment).
.. deprecated:: 3.9
.. function:: crc_hqx(data, value) .. 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 *x*:sup:`16` + *x*:sup:`12` + *x*:sup:`5` + 1, often represented as
0x1021. This CRC is used in the binhex4 format. 0x1021. This CRC is used in the binhex4 format.
.. deprecated:: 3.9
.. function:: crc32(data[, value]) .. function:: crc32(data[, value])

View file

@ -6,6 +6,8 @@
**Source code:** :source:`Lib/binhex.py` **Source code:** :source:`Lib/binhex.py`
.. deprecated:: 3.9
-------------- --------------
This module encodes and decodes files in binhex4 format, a format allowing This module encodes and decodes files in binhex4 format, a format allowing

View file

@ -353,6 +353,16 @@ Deprecated
deprecated and will be removed in version 3.11. deprecated and will be removed in version 3.11.
(Contributed by Yury Selivanov and Kyle Stanley in :issue:`34790`.) (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 Removed
======= =======

View file

@ -21,10 +21,16 @@ hexbin(inputfilename, outputfilename)
# input. The resulting code (xx 90 90) would appear to be interpreted as an # 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... # escaped *value* of 0x90. All coders I've seen appear to ignore this nicety...
# #
import binascii
import contextlib
import io import io
import os import os
import struct import struct
import binascii import warnings
warnings.warn('the binhex module is deprecated', DeprecationWarning,
stacklevel=2)
__all__ = ["binhex","hexbin","Error"] __all__ = ["binhex","hexbin","Error"]
@ -76,6 +82,16 @@ class openrsrc:
def close(self): def close(self):
pass 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: class _Hqxcoderengine:
"""Write data to the coder in 3-byte chunks""" """Write data to the coder in 3-byte chunks"""
@ -93,7 +109,8 @@ class _Hqxcoderengine:
self.data = self.data[todo:] self.data = self.data[todo:]
if not data: if not data:
return return
self.hqxdata = self.hqxdata + binascii.b2a_hqx(data) with _ignore_deprecation_warning():
self.hqxdata = self.hqxdata + binascii.b2a_hqx(data)
self._flush(0) self._flush(0)
def _flush(self, force): def _flush(self, force):
@ -109,7 +126,8 @@ class _Hqxcoderengine:
def close(self): def close(self):
if self.data: 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._flush(1)
self.ofp.close() self.ofp.close()
del self.ofp del self.ofp
@ -125,13 +143,15 @@ class _Rlecoderengine:
self.data = self.data + data self.data = self.data + data
if len(self.data) < REASONABLY_LARGE: if len(self.data) < REASONABLY_LARGE:
return return
rledata = binascii.rlecode_hqx(self.data) with _ignore_deprecation_warning():
rledata = binascii.rlecode_hqx(self.data)
self.ofp.write(rledata) self.ofp.write(rledata)
self.data = b'' self.data = b''
def close(self): def close(self):
if self.data: 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.write(rledata)
self.ofp.close() self.ofp.close()
del self.ofp del self.ofp
@ -180,7 +200,8 @@ class BinHex:
self._writecrc() self._writecrc()
def _write(self, data): 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) self.ofp.write(data)
def _writecrc(self): def _writecrc(self):
@ -276,7 +297,8 @@ class _Hqxdecoderengine:
# #
while True: while True:
try: try:
decdatacur, self.eof = binascii.a2b_hqx(data) with _ignore_deprecation_warning():
decdatacur, self.eof = binascii.a2b_hqx(data)
break break
except binascii.Incomplete: except binascii.Incomplete:
pass pass
@ -312,8 +334,9 @@ class _Rledecoderengine:
def _fill(self, wtd): def _fill(self, wtd):
self.pre_buffer = self.pre_buffer + self.ifp.read(wtd + 4) self.pre_buffer = self.pre_buffer + self.ifp.read(wtd + 4)
if self.ifp.eof: if self.ifp.eof:
self.post_buffer = self.post_buffer + \ with _ignore_deprecation_warning():
binascii.rledecode_hqx(self.pre_buffer) self.post_buffer = self.post_buffer + \
binascii.rledecode_hqx(self.pre_buffer)
self.pre_buffer = b'' self.pre_buffer = b''
return return
@ -340,8 +363,9 @@ class _Rledecoderengine:
else: else:
mark = mark - 1 mark = mark - 1
self.post_buffer = self.post_buffer + \ with _ignore_deprecation_warning():
binascii.rledecode_hqx(self.pre_buffer[:mark]) self.post_buffer = self.post_buffer + \
binascii.rledecode_hqx(self.pre_buffer[:mark])
self.pre_buffer = self.pre_buffer[mark:] self.pre_buffer = self.pre_buffer[mark:]
def close(self): def close(self):
@ -372,7 +396,8 @@ class HexBin:
def _read(self, len): def _read(self, len):
data = self.ifp.read(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 return data
def _checkcrc(self): def _checkcrc(self):

View file

@ -4,6 +4,7 @@ import unittest
import binascii import binascii
import array import array
import re import re
from test import support
# Note: "*_hex" functions are aliases for "(un)hexlify" # Note: "*_hex" functions are aliases for "(un)hexlify"
b2a_functions = ['b2a_base64', 'b2a_hex', 'b2a_hqx', 'b2a_qp', 'b2a_uu', 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.assertTrue(hasattr(getattr(binascii, name), '__call__'))
self.assertRaises(TypeError, getattr(binascii, name)) self.assertRaises(TypeError, getattr(binascii, name))
@support.ignore_warnings(category=DeprecationWarning)
def test_returned_value(self): def test_returned_value(self):
# Limit to the minimum of all limits (b2a_uu) # Limit to the minimum of all limits (b2a_uu)
MAX_ALL = 45 MAX_ALL = 45
@ -179,6 +181,7 @@ class BinASCIITest(unittest.TestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
binascii.b2a_uu(b"", True) binascii.b2a_uu(b"", True)
@support.ignore_warnings(category=DeprecationWarning)
def test_crc_hqx(self): 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"Test the CRC-32 of"), 0)
crc = binascii.crc_hqx(self.type2test(b" this string."), crc) crc = binascii.crc_hqx(self.type2test(b" this string."), crc)
@ -198,6 +201,7 @@ class BinASCIITest(unittest.TestCase):
self.assertRaises(TypeError, binascii.crc32) self.assertRaises(TypeError, binascii.crc32)
@support.ignore_warnings(category=DeprecationWarning)
def test_hqx(self): def test_hqx(self):
# Perform binhex4 style RLE-compression # Perform binhex4 style RLE-compression
# Then calculate the hexbin4 binary-to-ASCII translation # Then calculate the hexbin4 binary-to-ASCII translation
@ -208,6 +212,7 @@ class BinASCIITest(unittest.TestCase):
res = binascii.rledecode_hqx(b) res = binascii.rledecode_hqx(b)
self.assertEqual(res, self.rawdata) self.assertEqual(res, self.rawdata)
@support.ignore_warnings(category=DeprecationWarning)
def test_rle(self): def test_rle(self):
# test repetition with a repetition longer than the limit of 255 # test repetition with a repetition longer than the limit of 255
data = (b'a' * 100 + b'b' + b'c' * 300) 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.\n')), b'a.\n')
self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E') self.assertEqual(b2a_qp(type2test(b'.a')[:-1]), b'=2E')
@support.ignore_warnings(category=DeprecationWarning)
def test_empty_string(self): def test_empty_string(self):
# A test for SF bug #1022953. Make sure SystemError is not raised. # A test for SF bug #1022953. Make sure SystemError is not raised.
empty = self.type2test(b'') empty = self.type2test(b'')
@ -378,6 +384,7 @@ class BinASCIITest(unittest.TestCase):
# crc_hqx needs 2 arguments # crc_hqx needs 2 arguments
self.assertRaises(TypeError, binascii.crc_hqx, "test", 0) self.assertRaises(TypeError, binascii.crc_hqx, "test", 0)
@support.ignore_warnings(category=DeprecationWarning)
def test_unicode_a2b(self): def test_unicode_a2b(self):
# Unicode strings are accepted by a2b_* functions. # Unicode strings are accepted by a2b_* functions.
MAX_ALL = 45 MAX_ALL = 45
@ -416,6 +423,21 @@ class BinASCIITest(unittest.TestCase):
self.assertEqual(binascii.b2a_base64(b, newline=False), self.assertEqual(binascii.b2a_base64(b, newline=False),
b'aGVsbG8=') 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): class ArrayBinASCIITest(BinASCIITest):
def type2test(self, s): def type2test(self, s):

View file

@ -3,10 +3,12 @@
Uses the mechanism of the python binhex module Uses the mechanism of the python binhex module
Based on an original test by Roger E. Masse. Based on an original test by Roger E. Masse.
""" """
import binhex
import unittest import unittest
from test import support from test import support
with support.check_warnings(('', DeprecationWarning)):
import binhex
class BinHexTestCase(unittest.TestCase): class BinHexTestCase(unittest.TestCase):

View file

@ -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`.

View file

@ -613,6 +613,11 @@ static PyObject *
binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data) binascii_a2b_hqx_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=4d6d8c54d54ea1c1 input=0d914c680e0eed55]*/ /*[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; const unsigned char *ascii_data;
unsigned char *bin_data; unsigned char *bin_data;
int leftbits = 0; int leftbits = 0;
@ -701,6 +706,11 @@ static PyObject *
binascii_rlecode_hqx_impl(PyObject *module, Py_buffer *data) binascii_rlecode_hqx_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=393d79338f5f5629 input=e1f1712447a82b09]*/ /*[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; const unsigned char *in_data;
unsigned char *out_data; unsigned char *out_data;
unsigned char ch; unsigned char ch;
@ -763,6 +773,11 @@ static PyObject *
binascii_b2a_hqx_impl(PyObject *module, Py_buffer *data) binascii_b2a_hqx_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=d0aa5a704bc9f7de input=9596ebe019fe12ba]*/ /*[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; unsigned char *ascii_data;
const unsigned char *bin_data; const unsigned char *bin_data;
int leftbits = 0; int leftbits = 0;
@ -818,6 +833,11 @@ static PyObject *
binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data) binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data)
/*[clinic end generated code: output=9826619565de1c6c input=54cdd49fc014402c]*/ /*[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; const unsigned char *in_data;
unsigned char *out_data; unsigned char *out_data;
unsigned char in_byte, in_repeat; unsigned char in_byte, in_repeat;
@ -932,7 +952,7 @@ error:
/*[clinic input] /*[clinic input]
binascii.crc_hqx -> unsigned_int binascii.crc_hqx
data: Py_buffer data: Py_buffer
crc: unsigned_int(bitwise=True) crc: unsigned_int(bitwise=True)
@ -941,10 +961,15 @@ binascii.crc_hqx -> unsigned_int
Compute CRC-CCITT incrementally. Compute CRC-CCITT incrementally.
[clinic start generated code]*/ [clinic start generated code]*/
static unsigned int static PyObject *
binascii_crc_hqx_impl(PyObject *module, Py_buffer *data, unsigned int crc) 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; const unsigned char *bin_data;
Py_ssize_t len; 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++]; crc = ((crc<<8)&0xff00) ^ crctab_hqx[(crc>>8)^*bin_data++];
} }
return crc; return PyLong_FromUnsignedLong(crc);
} }
#ifndef USE_ZLIB_CRC32 #ifndef USE_ZLIB_CRC32

View file

@ -328,7 +328,7 @@ PyDoc_STRVAR(binascii_crc_hqx__doc__,
#define BINASCII_CRC_HQX_METHODDEF \ #define BINASCII_CRC_HQX_METHODDEF \
{"crc_hqx", (PyCFunction)(void(*)(void))binascii_crc_hqx, METH_FASTCALL, binascii_crc_hqx__doc__}, {"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); binascii_crc_hqx_impl(PyObject *module, Py_buffer *data, unsigned int crc);
static PyObject * static PyObject *
@ -337,7 +337,6 @@ binascii_crc_hqx(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
PyObject *return_value = NULL; PyObject *return_value = NULL;
Py_buffer data = {NULL, NULL}; Py_buffer data = {NULL, NULL};
unsigned int crc; unsigned int crc;
unsigned int _return_value;
if (!_PyArg_CheckPositional("crc_hqx", nargs, 2, 2)) { if (!_PyArg_CheckPositional("crc_hqx", nargs, 2, 2)) {
goto exit; 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()) { if (crc == (unsigned int)-1 && PyErr_Occurred()) {
goto exit; goto exit;
} }
_return_value = binascii_crc_hqx_impl(module, &data, crc); 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);
exit: exit:
/* Cleanup for data */ /* Cleanup for data */
@ -801,4 +796,4 @@ exit:
return return_value; return return_value;
} }
/*[clinic end generated code: output=ec26d03c2007eaac input=a9049054013a1b77]*/ /*[clinic end generated code: output=a1e878d3963b615e input=a9049054013a1b77]*/