diff -r 56f25569ba86 Doc/library/base64.rst --- a/Doc/library/base64.rst Tue May 21 12:47:57 2013 +0300 +++ b/Doc/library/base64.rst Wed May 22 09:53:19 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 :term:`bytes-like object`\ s are now accepted by the + encoding and decoding functions of the modern interface. + The modern interface provides: .. function:: b64encode(s, altchars=None) diff -r 56f25569ba86 Lib/base64.py --- a/Lib/base64.py Tue May 21 12:47:57 2013 +0300 +++ b/Lib/base64.py Wed May 22 09:53:19 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 a bytes-like object or ASCII " + "string, not %r" % 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 @@ -149,7 +146,7 @@ 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__) + s = memoryview(s).tobytes() leftover = len(s) % 5 # Pad the last quantum with zero bits if necessary if leftover: @@ -250,8 +247,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 56f25569ba86 Lib/test/test_base64.py --- a/Lib/test/test_base64.py Tue May 21 12:47:57 2013 +0300 +++ b/Lib/test/test_base64.py Wed May 22 09:53:19 2013 +0300 @@ -5,6 +5,7 @@ import os import sys import subprocess +from array import array @@ -25,6 +26,7 @@ # Non-bytes eq(base64.encodebytes(bytearray(b'abc')), b'YWJj\n') self.assertRaises(TypeError, base64.encodebytes, "") + self.assertRaises(TypeError, base64.encodebytes, []) def test_decodebytes(self): eq = self.assertEqual @@ -42,6 +44,7 @@ # Non-bytes eq(base64.decodebytes(bytearray(b'YWJj\n')), b'abc') self.assertRaises(TypeError, base64.decodebytes, "") + self.assertRaises(TypeError, base64.decodebytes, []) def test_encode(self): eq = self.assertEqual @@ -92,11 +95,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 +121,21 @@ 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(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 +161,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 +183,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', @@ -170,7 +195,13 @@ eq(base64.urlsafe_b64decode(data), res) 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(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 +237,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 +257,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 +313,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 +332,15 @@ 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') + eq(base64.b16decode(memoryview(b"0102ABCDEF")), b'\x01\x02\xab\xcd\xef') + eq(base64.b16decode(array('B', b"0102ABCDEF")), b'\x01\x02\xab\xcd\xef') + eq(base64.b16decode(bytearray(b"0102abcdef"), True), + b'\x01\x02\xab\xcd\xef') + eq(base64.b16decode(memoryview(b"0102abcdef"), True), + b'\x01\x02\xab\xcd\xef') + eq(base64.b16decode(array('B', b"0102abcdef"), True), + b'\x01\x02\xab\xcd\xef') + self.assertRaises(TypeError, base64.b16decode, []) def test_decode_nonascii_str(self): decode_funcs = (base64.b64decode,