Index: Modules/binascii.c =================================================================== --- Modules/binascii.c (revision 76839) +++ Modules/binascii.c (working copy) @@ -739,7 +739,7 @@ PyObject *rv; Py_ssize_t in_len, out_len, out_len_left; - if ( !PyArg_ParseTuple(args, "s*:rledecode_hqx", &pin) ) + if ( !PyArg_ParseTuple(args, "y*:rledecode_hqx", &pin) ) return NULL; in_data = pin.buf; in_len = pin.len; @@ -1110,7 +1110,7 @@ char* retbuf; Py_ssize_t i, j; - if (!PyArg_ParseTuple(args, "s*:a2b_hex", &parg)) + if (!PyArg_ParseTuple(args, "y*:a2b_hex", &parg)) return NULL; argbuf = parg.buf; arglen = parg.len; @@ -1188,7 +1188,7 @@ static char *kwlist[] = {"data", "header", NULL}; int header = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s*|i", kwlist, &pdata, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|i", kwlist, &pdata, &header)) return NULL; data = pdata.buf; Index: Doc/library/binascii.rst =================================================================== --- Doc/library/binascii.rst (revision 76839) +++ Doc/library/binascii.rst (working copy) @@ -18,6 +18,11 @@ low-level functions written in C for greater speed that are used by the higher-level modules. +.. note:: + + Encoding and decoding functions do not accept Unicode strings. Only bytestring + and bytearray objects can be processed. + The :mod:`binascii` module defines the following functions: @@ -54,6 +59,9 @@ data. More than one line may be passed at a time. If the optional argument *header* is present and true, underscores will be decoded as spaces. + .. versionchanged:: 3.1 + accept only bytestring or bytearray object as input. + .. function:: b2a_qp(data, quotetabs=False, istext=True, header=False) @@ -83,6 +91,9 @@ decompressed data, unless data input data ends in an orphaned repeat indicator, in which case the :exc:`Incomplete` exception is raised. + .. versionchanged:: 3.1 + accept only bytestring or bytearray object as input. + .. function:: rlecode_hqx(data) @@ -109,11 +120,11 @@ use as a checksum algorithm, it is not suitable for use as a general hash algorithm. Use as follows:: - print(binascii.crc32("hello world")) + print(binascii.crc32(b"hello world")) # Or, in two pieces: - crc = binascii.crc32("hello") - crc = binascii.crc32(" world", crc) & 0xffffffff - print('crc32 = 0x%08x' % crc) + crc = binascii.crc32(b"hello") + crc = binascii.crc32(b" world", crc) & 0xffffffff + print('crc32 = {:#010x}'.format(crc)) .. note:: To generate the same numeric value across all Python versions and @@ -139,6 +150,9 @@ of hexadecimal digits (which can be upper or lower case), otherwise a :exc:`TypeError` is raised. + .. versionchanged:: 3.1 + accept only bytestring or bytearray object as input. + .. exception:: Error @@ -164,4 +178,3 @@ Module :mod:`quopri` Support for quoted-printable encoding used in MIME email messages. - Index: Lib/email/base64mime.py =================================================================== --- Lib/email/base64mime.py (revision 76839) +++ Lib/email/base64mime.py (working copy) @@ -74,12 +74,12 @@ def body_encode(s, maxlinelen=76, eol=NL): - """Encode a string with base64. + r"""Encode a string with base64. Each line will be wrapped at, at most, maxlinelen characters (defaults to 76 characters). - Each line of encoded text will end with eol, which defaults to "\\n". Set + Each line of encoded text will end with eol, which defaults to "\n". Set this to "\r\n" if you will be using the result of this function directly in an email. """ Index: Lib/email/message.py =================================================================== --- Lib/email/message.py (revision 76839) +++ Lib/email/message.py (working copy) @@ -198,18 +198,20 @@ return None cte = self.get('content-transfer-encoding', '').lower() if cte == 'quoted-printable': + if isinstance(payload, str): + payload = payload.encode('ascii') return utils._qdecode(payload) elif cte == 'base64': try: if isinstance(payload, str): - payload = payload.encode('raw-unicode-escape') + payload = payload.encode('ascii') return base64.b64decode(payload) #return utils._bdecode(payload) except binascii.Error: # Incorrect padding pass elif cte in ('x-uuencode', 'uuencode', 'uue', 'x-uue'): - in_file = BytesIO(payload.encode('raw-unicode-escape')) + in_file = BytesIO(payload.encode('ascii')) out_file = BytesIO() try: uu.decode(in_file, out_file, quiet=True) Index: Lib/pickle.py =================================================================== --- Lib/pickle.py (revision 76839) +++ Lib/pickle.py (working copy) @@ -1311,7 +1311,7 @@ else: ashex = ashex[2:] assert len(ashex) & 1 == 0, (x, ashex) - binary = _binascii.unhexlify(ashex) + binary = _binascii.unhexlify(ashex.encode('ascii')) return bytes(binary[::-1]) def decode_long(data): Index: Lib/test/test_binascii.py =================================================================== --- Lib/test/test_binascii.py (revision 76839) +++ Lib/test/test_binascii.py (working copy) @@ -4,6 +4,18 @@ import unittest import binascii +all_functions = [ + 'a2b_base64', 'b2a_base64', + 'a2b_hex', 'b2a_hex', # aliases for (un)hexlify + 'a2b_hqx', 'b2a_hqx', + 'a2b_qp', 'b2a_qp', + 'a2b_uu', 'b2a_uu', + 'crc32', 'crc_hqx', + 'hexlify', 'unhexlify', + 'rlecode_hqx', 'rledecode_hqx', +] + + class BinASCIITest(unittest.TestCase): # Create binary test data @@ -19,18 +31,9 @@ def test_functions(self): # Check presence of all functions - funcs = [] - for suffix in "base64", "hqx", "uu", "hex": - prefixes = ["a2b_", "b2a_"] - if suffix == "hqx": - prefixes.extend(["crc_", "rlecode_", "rledecode_"]) - for prefix in prefixes: - name = prefix + suffix - self.assertTrue(hasattr(getattr(binascii, name), '__call__')) - self.assertRaises(TypeError, getattr(binascii, name)) - for name in ("hexlify", "unhexlify"): - self.assertTrue(hasattr(getattr(binascii, name), '__call__')) - self.assertRaises(TypeError, getattr(binascii, name)) + for func in all_functions: + self.assertTrue(hasattr(getattr(binascii, func), '__call__')) + self.assertRaises(TypeError, getattr(binascii, func)) def test_base64valid(self): # Test base64 with valid data @@ -126,11 +129,11 @@ def test_qp(self): # A test for SF bug 534347 (segfaults without the proper fix) try: - binascii.a2b_qp("", **{1:1}) + binascii.a2b_qp(b"", **{1: 1}) except TypeError: pass else: - self.fail("binascii.a2b_qp(**{1:1}) didn't raise TypeError") + self.fail("binascii.a2b_qp(**{1: 1}) didn't raise TypeError") self.assertEqual(binascii.a2b_qp(b"= "), b"= ") self.assertEqual(binascii.a2b_qp(b"=="), b"=") self.assertEqual(binascii.a2b_qp(b"=AX"), b"=AX") @@ -138,12 +141,10 @@ self.assertEqual(binascii.a2b_qp(b"=00\r\n=00"), b"\x00\r\n\x00") self.assertEqual( binascii.b2a_qp(b"\xff\r\n\xff\n\xff"), - b"=FF\r\n=FF\r\n=FF" - ) + b"=FF\r\n=FF\r\n=FF") self.assertEqual( binascii.b2a_qp(b"0"*75+b"\xff\r\n\xff\r\n\xff"), - b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF" - ) + b"0"*75+b"=\r\n=FF\r\n=FF\r\n=FF") self.assertEqual(binascii.b2a_qp(b'\0\n'), b'=00\n') self.assertEqual(binascii.b2a_qp(b'\0\n', quotetabs=True), b'=00\n') @@ -157,24 +158,24 @@ def test_empty_string(self): # A test for SF bug #1022953. Make sure SystemError is not raised. - for n in ['b2a_qp', 'a2b_hex', 'b2a_base64', 'a2b_uu', 'a2b_qp', - 'b2a_hex', 'unhexlify', 'hexlify', 'crc32', 'b2a_hqx', - 'a2b_hqx', 'a2b_base64', 'rlecode_hqx', 'b2a_uu', - 'rledecode_hqx']: - f = getattr(binascii, n) + for func in all_functions: + if func == 'crc_hqx': + # crc_hqx needs 2 arguments + binascii.crc_hqx(b'', 0) + continue + f = getattr(binascii, func) try: f(b'') except SystemError as err: self.fail("%s(b'') raises SystemError: %s" % (n, err)) - binascii.crc_hqx(b'', 0) - def test_no_binary_strings(self): - # b2a_ must not accept strings - for f in (binascii.b2a_uu, binascii.b2a_base64, - binascii.b2a_hqx, binascii.b2a_qp, - binascii.hexlify, binascii.rlecode_hqx, - binascii.crc_hqx, binascii.crc32): - self.assertRaises(TypeError, f, "test") + def test_unicode_strings(self): + # Unicode strings are not accepted. + for func in all_functions: + self.assertRaises(TypeError, getattr(binascii, func), "test") + # crc_hqx needs 2 arguments + self.assertRaises(TypeError, binascii.crc_hqx, "test", 0) + def test_main(): support.run_unittest(BinASCIITest) Index: Lib/test/test_struct.py =================================================================== --- Lib/test/test_struct.py (revision 76839) +++ Lib/test/test_struct.py (working copy) @@ -196,6 +196,7 @@ expected = hex(expected)[2:] # chop "0x" if len(expected) & 1: expected = "0" + expected + expected = expected.encode('ascii') expected = unhexlify(expected) expected = b"\x00" * (self.bytesize - len(expected)) + expected @@ -242,6 +243,7 @@ expected = hex(expected)[2:] # chop "0x" if len(expected) & 1: expected = "0" + expected + expected = expected.encode('ascii') expected = unhexlify(expected) expected = b"\x00" * (self.bytesize - len(expected)) + expected