diff -r 65487938643d Doc/library/base64.rst --- a/Doc/library/base64.rst Sun Apr 28 15:56:32 2013 +0300 +++ b/Doc/library/base64.rst Sun Apr 28 18:02:52 2013 +0300 @@ -27,6 +27,10 @@ ASCII-only Unicode strings are now accepted by the decoding functions of the modern interface. +.. versionchanged:: 3.4 + Any :ref:`bytes-like objects ` are now accepted by the + encoding and decoding functions of the modern interface. + The modern interface provides: .. function:: b64encode(s, altchars=None) diff -r 65487938643d Lib/base64.py --- a/Lib/base64.py Sun Apr 28 15:56:32 2013 +0300 +++ b/Lib/base64.py Sun Apr 28 18:02:52 2013 +0300 @@ -35,11 +35,13 @@ return s.encode('ascii') except UnicodeEncodeError: raise ValueError('string argument should contain only ASCII characters') - elif isinstance(s, bytes_types): + if isinstance(s, bytes_types): return s - else: - raise TypeError("argument should be bytes or ASCII string, not %s" % s.__class__.__name__) - + try: + return memoryview(s).tobytes() + except TypeError: + raise TypeError("argument should be bytes-like object or ASCII string, " + "not %s" % s.__class__.__name__) from None # Base64 encoding/decoding uses binascii @@ -54,14 +56,9 @@ The encoded byte string is returned. """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) # Strip off the trailing newline encoded = binascii.b2a_base64(s)[:-1] if altchars is not None: - if not isinstance(altchars, bytes_types): - raise TypeError("expected bytes, not %s" - % altchars.__class__.__name__) assert len(altchars) == 2, repr(altchars) return encoded.translate(bytes.maketrans(b'+/', altchars)) return encoded @@ -160,7 +157,11 @@ s is the byte string to encode. The encoded byte string is returned. """ if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) + try: + s = memoryview(s).tobytes() + except TypeError: + raise TypeError("expected bytes-like object, not %s" % + s.__class__.__name__) from None quanta, leftover = divmod(len(s), 5) # Pad the last quantum with zero bits if necessary if leftover: @@ -279,8 +280,6 @@ s is the byte string to encode. The encoded byte string is returned. """ - if not isinstance(s, bytes_types): - raise TypeError("expected bytes, not %s" % s.__class__.__name__) return binascii.hexlify(s).upper() diff -r 65487938643d Lib/test/test_base64.py --- a/Lib/test/test_base64.py Sun Apr 28 15:56:32 2013 +0300 +++ b/Lib/test/test_base64.py Sun Apr 28 18:02:52 2013 +0300 @@ -5,6 +5,7 @@ import os import sys import subprocess +from array import array @@ -92,11 +93,18 @@ eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=b'*$'), b'01a*b$cd') # Non-bytes eq(base64.b64encode(bytearray(b'abcd')), b'YWJjZA==') + eq(base64.b64encode(memoryview(b'abcd')), b'YWJjZA==') + eq(base64.b64encode(array('B', b'abcd')), b'YWJjZA==') eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=bytearray(b'*$')), b'01a*b$cd') + eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=memoryview(b'*$')), + b'01a*b$cd') + eq(base64.b64encode(b'\xd3V\xbeo\xf7\x1d', altchars=array('B', b'*$')), + b'01a*b$cd') + self.assertRaises(TypeError, base64.b64encode, []) # Check if passing a str object raises an error self.assertRaises(TypeError, base64.b64encode, "") - self.assertRaises(TypeError, base64.b64encode, b"", altchars="") + self.assertRaises(TypeError, base64.b64encode, b"", altchars="*$") # Test standard alphabet eq(base64.standard_b64encode(b"www.python.org"), b"d3d3LnB5dGhvbi5vcmc=") eq(base64.standard_b64encode(b"a"), b"YQ==") @@ -111,12 +119,18 @@ b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==") # Non-bytes eq(base64.standard_b64encode(bytearray(b'abcd')), b'YWJjZA==') + eq(base64.standard_b64encode(memoryview(b'abcd')), b'YWJjZA==') + eq(base64.standard_b64encode(array('B', b'abcd')), b'YWJjZA==') + self.assertRaises(TypeError, base64.standard_b64encode, []) # Check if passing a str object raises an error self.assertRaises(TypeError, base64.standard_b64encode, "") # Test with 'URL safe' alternative characters eq(base64.urlsafe_b64encode(b'\xd3V\xbeo\xf7\x1d'), b'01a-b_cd') # Non-bytes eq(base64.urlsafe_b64encode(bytearray(b'\xd3V\xbeo\xf7\x1d')), b'01a-b_cd') + eq(base64.urlsafe_b64encode(memoryview(b'\xd3V\xbeo\xf7\x1d')), b'01a-b_cd') + eq(base64.urlsafe_b64encode(array('B', b'\xd3V\xbeo\xf7\x1d')), b'01a-b_cd') + self.assertRaises(TypeError, base64.urlsafe_b64encode, []) # Check if passing a str object raises an error self.assertRaises(TypeError, base64.urlsafe_b64encode, "") @@ -142,6 +156,9 @@ eq(base64.b64decode(data.decode('ascii')), res) # Non-bytes eq(base64.b64decode(bytearray(b"YWJj")), b"abc") + eq(base64.b64decode(memoryview(b"YWJj")), b"abc") + eq(base64.b64decode(array('B', b"YWJj")), b"abc") + self.assertRaises(TypeError, base64.b64decode, []) # Test with arbitrary alternative characters tests_altchars = {(b'01a*b$cd', b'*$'): b'\xd3V\xbeo\xf7\x1d', @@ -161,6 +178,9 @@ eq(base64.standard_b64decode(data.decode('ascii')), res) # Non-bytes eq(base64.standard_b64decode(bytearray(b"YWJj")), b"abc") + eq(base64.standard_b64decode(memoryview(b"YWJj")), b"abc") + eq(base64.standard_b64decode(array('B', b"YWJj")), b"abc") + self.assertRaises(TypeError, base64.standard_b64decode, []) # Test with 'URL safe' alternative characters tests_urlsafe = {b'01a-b_cd': b'\xd3V\xbeo\xf7\x1d', @@ -171,6 +191,9 @@ eq(base64.urlsafe_b64decode(data.decode('ascii')), res) # Non-bytes eq(base64.urlsafe_b64decode(bytearray(b'01a-b_cd')), b'\xd3V\xbeo\xf7\x1d') + eq(base64.urlsafe_b64decode(memoryview(b'01a-b_cd')), b'\xd3V\xbeo\xf7\x1d') + eq(base64.urlsafe_b64decode(array('B', b'01a-b_cd')), b'\xd3V\xbeo\xf7\x1d') + self.assertRaises(TypeError, base64.urlsafe_b64decode, []) def test_b64decode_padding_error(self): self.assertRaises(binascii.Error, base64.b64decode, b'abc') @@ -206,7 +229,10 @@ eq(base64.b32encode(b'abcde'), b'MFRGGZDF') # Non-bytes eq(base64.b32encode(bytearray(b'abcd')), b'MFRGGZA=') + eq(base64.b32encode(memoryview(b'abcd')), b'MFRGGZA=') + eq(base64.b32encode(array('B', b'abcd')), b'MFRGGZA=') self.assertRaises(TypeError, base64.b32encode, "") + self.assertRaises(TypeError, base64.b32encode, []) def test_b32decode(self): eq = self.assertEqual @@ -223,6 +249,9 @@ eq(base64.b32decode(data.decode('ascii')), res) # Non-bytes eq(base64.b32decode(bytearray(b'MFRGG===')), b'abc') + eq(base64.b32decode(memoryview(b'MFRGG===')), b'abc') + eq(base64.b32decode(array('B', b'MFRGG===')), b'abc') + self.assertRaises(TypeError, base64.b32decode, []) def test_b32decode_casefold(self): eq = self.assertEqual @@ -276,7 +305,10 @@ eq(base64.b16encode(b'\x00'), b'00') # Non-bytes eq(base64.b16encode(bytearray(b'\x01\x02\xab\xcd\xef')), b'0102ABCDEF') + eq(base64.b16encode(memoryview(b'\x01\x02\xab\xcd\xef')), b'0102ABCDEF') + eq(base64.b16encode(array('B', b'\x01\x02\xab\xcd\xef')), b'0102ABCDEF') self.assertRaises(TypeError, base64.b16encode, "") + self.assertRaises(TypeError, base64.b16encode, []) def test_b16decode(self): eq = self.assertEqual @@ -292,6 +324,7 @@ eq(base64.b16decode('0102abcdef', True), b'\x01\x02\xab\xcd\xef') # Non-bytes eq(base64.b16decode(bytearray(b"0102ABCDEF")), b'\x01\x02\xab\xcd\xef') + self.assertRaises(TypeError, base64.b16decode, []) def test_decode_nonascii_str(self): decode_funcs = (base64.b64decode,