Skip to content

Commit

Permalink
bpo-39353: Deprecate the binhex module (GH-18025)
Browse files Browse the repository at this point in the history
Deprecate binhex4 and hexbin4 standards. Deprecate the binhex module
and the following binascii functions:

* b2a_hqx(), a2b_hqx()
* rlecode_hqx(), rledecode_hqx()
* crc_hqx()
  • Loading branch information
vstinner authored Jan 22, 2020
1 parent 14d80d0 commit beea26b
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 25 deletions.
10 changes: 10 additions & 0 deletions Doc/library/binascii.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -104,18 +106,24 @@ 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)

Perform hexbin4 binary-to-ASCII translation and return the resulting string. The
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)

Expand All @@ -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])

Expand Down
2 changes: 2 additions & 0 deletions Doc/library/binhex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
=======

Expand Down
49 changes: 37 additions & 12 deletions Lib/binhex.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@
# 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"]

Expand Down Expand Up @@ -76,6 +82,16 @@ def write(self, *args):
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"""

Expand All @@ -93,7 +109,8 @@ def write(self, data):
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):
Expand All @@ -109,7 +126,8 @@ def _flush(self, force):

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
Expand All @@ -125,13 +143,15 @@ def write(self, data):
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
Expand Down Expand Up @@ -180,7 +200,8 @@ def _writeinfo(self, name, finfo):
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):
Expand Down Expand Up @@ -276,7 +297,8 @@ def read(self, totalwtd):
#
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
Expand Down Expand Up @@ -312,8 +334,9 @@ def read(self, wtd):
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

Expand All @@ -340,8 +363,9 @@ def _fill(self, wtd):
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):
Expand Down Expand Up @@ -372,7 +396,8 @@ def __init__(self, ifp):

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):
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_binascii.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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',
Expand Down Expand Up @@ -36,6 +37,7 @@ def test_functions(self):
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
Expand Down Expand Up @@ -179,6 +181,7 @@ def test_uu(self):
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)
Expand All @@ -198,6 +201,7 @@ def test_crc32(self):

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
Expand All @@ -208,6 +212,7 @@ def test_hqx(self):
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)
Expand Down Expand Up @@ -354,6 +359,7 @@ def test_qp(self):
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'')
Expand All @@ -378,6 +384,7 @@ def test_unicode_b2a(self):
# 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
Expand Down Expand Up @@ -416,6 +423,21 @@ def test_b2a_base64_newline(self):
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):
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_binhex.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
33 changes: 29 additions & 4 deletions Modules/binascii.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -932,7 +952,7 @@ binascii_rledecode_hqx_impl(PyObject *module, Py_buffer *data)


/*[clinic input]
binascii.crc_hqx -> unsigned_int
binascii.crc_hqx
data: Py_buffer
crc: unsigned_int(bitwise=True)
Expand All @@ -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;

Expand All @@ -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
Expand Down
Loading

0 comments on commit beea26b

Please sign in to comment.