Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5743691

Browse files
committed
Merged upstream changes.
2 parents aa8a62d + c229e6e commit 5743691

10 files changed

Lines changed: 147 additions & 83 deletions

File tree

Doc/library/base64.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,14 @@ POST request. The encoding algorithm is not the same as the
1818

1919
There are two interfaces provided by this module. The modern interface
2020
supports encoding and decoding ASCII byte string objects using all three
21-
alphabets. The legacy interface provides for encoding and decoding to and from
22-
file-like objects as well as byte strings, but only using the Base64 standard
23-
alphabet.
21+
alphabets. Additionally, the decoding functions of the modern interface also
22+
accept Unicode strings containing only ASCII characters. The legacy interface
23+
provides for encoding and decoding to and from file-like objects as well as
24+
byte strings, but only using the Base64 standard alphabet.
25+
26+
.. versionchanged:: 3.3
27+
ASCII-only Unicode strings are now accepted by the decoding functions of
28+
the modern interface.
2429

2530
The modern interface provides:
2631

Doc/whatsnew/3.3.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,20 @@ Porting C code
939939
:c:func:`PyUnicode_FromFormat()`, your code will automatically take
940940
advantage of the new unicode representations.
941941

942+
Building C extensions
943+
---------------------
944+
945+
* The range of possible file names for C extensions has been narrowed.
946+
Very rarely used spellings have been suppressed: under POSIX, files
947+
named ``xxxmodule.so``, ``xxxmodule.abi3.so`` and
948+
``xxxmodule.cpython-*.so`` are no longer recognized as implementing
949+
the ``xxx`` module. If you had been generating such files, you have
950+
to switch to the other spellings (i.e., remove the ``module`` string
951+
from the file names).
952+
953+
(implemented in :issue:`14040`.)
954+
955+
942956
Other issues
943957
------------
944958

Lib/base64.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@
2929

3030
bytes_types = (bytes, bytearray) # Types acceptable as binary data
3131

32+
def _bytes_from_decode_data(s):
33+
if isinstance(s, str):
34+
try:
35+
return s.encode('ascii')
36+
except UnicodeEncodeError:
37+
raise ValueError('string argument should contain only ASCII characters')
38+
elif isinstance(s, bytes_types):
39+
return s
40+
else:
41+
raise TypeError("argument should be bytes or ASCII string, not %s" % s.__class__.__name__)
3242

3343
def _translate(s, altchars):
3444
if not isinstance(s, bytes_types):
@@ -79,12 +89,9 @@ def b64decode(s, altchars=None, validate=False):
7989
discarded prior to the padding check. If validate is True,
8090
non-base64-alphabet characters in the input result in a binascii.Error.
8191
"""
82-
if not isinstance(s, bytes_types):
83-
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
92+
s = _bytes_from_decode_data(s)
8493
if altchars is not None:
85-
if not isinstance(altchars, bytes_types):
86-
raise TypeError("expected bytes, not %s"
87-
% altchars.__class__.__name__)
94+
altchars = _bytes_from_decode_data(altchars)
8895
assert len(altchars) == 2, repr(altchars)
8996
s = _translate(s, {chr(altchars[0]): b'+', chr(altchars[1]): b'/'})
9097
if validate and not re.match(b'^[A-Za-z0-9+/]*={0,2}$', s):
@@ -211,17 +218,15 @@ def b32decode(s, casefold=False, map01=None):
211218
the input is incorrectly padded or if there are non-alphabet
212219
characters present in the input.
213220
"""
214-
if not isinstance(s, bytes_types):
215-
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
221+
s = _bytes_from_decode_data(s)
216222
quanta, leftover = divmod(len(s), 8)
217223
if leftover:
218224
raise binascii.Error('Incorrect padding')
219225
# Handle section 2.4 zero and one mapping. The flag map01 will be either
220226
# False, or the character to map the digit 1 (one) to. It should be
221227
# either L (el) or I (eye).
222228
if map01 is not None:
223-
if not isinstance(map01, bytes_types):
224-
raise TypeError("expected bytes, not %s" % map01.__class__.__name__)
229+
map01 = _bytes_from_decode_data(map01)
225230
assert len(map01) == 1, repr(map01)
226231
s = _translate(s, {b'0': b'O', b'1': map01})
227232
if casefold:
@@ -292,8 +297,7 @@ def b16decode(s, casefold=False):
292297
s were incorrectly padded or if there are non-alphabet characters
293298
present in the string.
294299
"""
295-
if not isinstance(s, bytes_types):
296-
raise TypeError("expected bytes, not %s" % s.__class__.__name__)
300+
s = _bytes_from_decode_data(s)
297301
if casefold:
298302
s = s.upper()
299303
if re.search(b'[^0-9A-F]', s):

Lib/test/test_base64.py

Lines changed: 104 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -102,44 +102,53 @@ def test_b64encode(self):
102102

103103
def test_b64decode(self):
104104
eq = self.assertEqual
105-
eq(base64.b64decode(b"d3d3LnB5dGhvbi5vcmc="), b"www.python.org")
106-
eq(base64.b64decode(b'AA=='), b'\x00')
107-
eq(base64.b64decode(b"YQ=="), b"a")
108-
eq(base64.b64decode(b"YWI="), b"ab")
109-
eq(base64.b64decode(b"YWJj"), b"abc")
110-
eq(base64.b64decode(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
111-
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
112-
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="),
113-
b"abcdefghijklmnopqrstuvwxyz"
114-
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
115-
b"0123456789!@#0^&*();:<>,. []{}")
116-
eq(base64.b64decode(b''), b'')
105+
106+
tests = {b"d3d3LnB5dGhvbi5vcmc=": b"www.python.org",
107+
b'AA==': b'\x00',
108+
b"YQ==": b"a",
109+
b"YWI=": b"ab",
110+
b"YWJj": b"abc",
111+
b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
112+
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0\nNT"
113+
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ==":
114+
115+
b"abcdefghijklmnopqrstuvwxyz"
116+
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
117+
b"0123456789!@#0^&*();:<>,. []{}",
118+
b'': b'',
119+
}
120+
for data, res in tests.items():
121+
eq(base64.b64decode(data), res)
122+
eq(base64.b64decode(data.decode('ascii')), res)
123+
117124
# Test with arbitrary alternative characters
118-
eq(base64.b64decode(b'01a*b$cd', altchars=b'*$'), b'\xd3V\xbeo\xf7\x1d')
119-
# Check if passing a str object raises an error
120-
self.assertRaises(TypeError, base64.b64decode, "")
121-
self.assertRaises(TypeError, base64.b64decode, b"", altchars="")
125+
tests_altchars = {(b'01a*b$cd', b'*$'): b'\xd3V\xbeo\xf7\x1d',
126+
}
127+
for (data, altchars), res in tests_altchars.items():
128+
data_str = data.decode('ascii')
129+
altchars_str = altchars.decode('ascii')
130+
131+
eq(base64.b64decode(data, altchars=altchars), res)
132+
eq(base64.b64decode(data_str, altchars=altchars), res)
133+
eq(base64.b64decode(data, altchars=altchars_str), res)
134+
eq(base64.b64decode(data_str, altchars=altchars_str), res)
135+
122136
# Test standard alphabet
123-
eq(base64.standard_b64decode(b"d3d3LnB5dGhvbi5vcmc="), b"www.python.org")
124-
eq(base64.standard_b64decode(b"YQ=="), b"a")
125-
eq(base64.standard_b64decode(b"YWI="), b"ab")
126-
eq(base64.standard_b64decode(b"YWJj"), b"abc")
127-
eq(base64.standard_b64decode(b""), b"")
128-
eq(base64.standard_b64decode(b"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNE"
129-
b"RUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM0NT"
130-
b"Y3ODkhQCMwXiYqKCk7Ojw+LC4gW117fQ=="),
131-
b"abcdefghijklmnopqrstuvwxyz"
132-
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
133-
b"0123456789!@#0^&*();:<>,. []{}")
134-
# Check if passing a str object raises an error
135-
self.assertRaises(TypeError, base64.standard_b64decode, "")
136-
self.assertRaises(TypeError, base64.standard_b64decode, b"", altchars="")
137+
for data, res in tests.items():
138+
eq(base64.standard_b64decode(data), res)
139+
eq(base64.standard_b64decode(data.decode('ascii')), res)
140+
137141
# Test with 'URL safe' alternative characters
138-
eq(base64.urlsafe_b64decode(b'01a-b_cd'), b'\xd3V\xbeo\xf7\x1d')
139-
self.assertRaises(TypeError, base64.urlsafe_b64decode, "")
142+
tests_urlsafe = {b'01a-b_cd': b'\xd3V\xbeo\xf7\x1d',
143+
b'': b'',
144+
}
145+
for data, res in tests_urlsafe.items():
146+
eq(base64.urlsafe_b64decode(data), res)
147+
eq(base64.urlsafe_b64decode(data.decode('ascii')), res)
140148

141149
def test_b64decode_padding_error(self):
142150
self.assertRaises(binascii.Error, base64.b64decode, b'abc')
151+
self.assertRaises(binascii.Error, base64.b64decode, 'abc')
143152

144153
def test_b64decode_invalid_chars(self):
145154
# issue 1466065: Test some invalid characters.
@@ -154,8 +163,10 @@ def test_b64decode_invalid_chars(self):
154163
(b'YWJj\nYWI=', b'abcab'))
155164
for bstr, res in tests:
156165
self.assertEqual(base64.b64decode(bstr), res)
166+
self.assertEqual(base64.b64decode(bstr.decode('ascii')), res)
157167
with self.assertRaises(binascii.Error):
158168
base64.b64decode(bstr, validate=True)
169+
base64.b64decode(bstr.decode('ascii'), validate=True)
159170

160171
def test_b32encode(self):
161172
eq = self.assertEqual
@@ -170,40 +181,62 @@ def test_b32encode(self):
170181

171182
def test_b32decode(self):
172183
eq = self.assertEqual
173-
eq(base64.b32decode(b''), b'')
174-
eq(base64.b32decode(b'AA======'), b'\x00')
175-
eq(base64.b32decode(b'ME======'), b'a')
176-
eq(base64.b32decode(b'MFRA===='), b'ab')
177-
eq(base64.b32decode(b'MFRGG==='), b'abc')
178-
eq(base64.b32decode(b'MFRGGZA='), b'abcd')
179-
eq(base64.b32decode(b'MFRGGZDF'), b'abcde')
180-
self.assertRaises(TypeError, base64.b32decode, "")
184+
tests = {b'': b'',
185+
b'AA======': b'\x00',
186+
b'ME======': b'a',
187+
b'MFRA====': b'ab',
188+
b'MFRGG===': b'abc',
189+
b'MFRGGZA=': b'abcd',
190+
b'MFRGGZDF': b'abcde',
191+
}
192+
for data, res in tests.items():
193+
eq(base64.b32decode(data), res)
194+
eq(base64.b32decode(data.decode('ascii')), res)
181195

182196
def test_b32decode_casefold(self):
183197
eq = self.assertEqual
184-
eq(base64.b32decode(b'', True), b'')
185-
eq(base64.b32decode(b'ME======', True), b'a')
186-
eq(base64.b32decode(b'MFRA====', True), b'ab')
187-
eq(base64.b32decode(b'MFRGG===', True), b'abc')
188-
eq(base64.b32decode(b'MFRGGZA=', True), b'abcd')
189-
eq(base64.b32decode(b'MFRGGZDF', True), b'abcde')
190-
# Lower cases
191-
eq(base64.b32decode(b'me======', True), b'a')
192-
eq(base64.b32decode(b'mfra====', True), b'ab')
193-
eq(base64.b32decode(b'mfrgg===', True), b'abc')
194-
eq(base64.b32decode(b'mfrggza=', True), b'abcd')
195-
eq(base64.b32decode(b'mfrggzdf', True), b'abcde')
196-
# Expected exceptions
198+
tests = {b'': b'',
199+
b'ME======': b'a',
200+
b'MFRA====': b'ab',
201+
b'MFRGG===': b'abc',
202+
b'MFRGGZA=': b'abcd',
203+
b'MFRGGZDF': b'abcde',
204+
# Lower cases
205+
b'me======': b'a',
206+
b'mfra====': b'ab',
207+
b'mfrgg===': b'abc',
208+
b'mfrggza=': b'abcd',
209+
b'mfrggzdf': b'abcde',
210+
}
211+
212+
for data, res in tests.items():
213+
eq(base64.b32decode(data, True), res)
214+
eq(base64.b32decode(data.decode('ascii'), True), res)
215+
197216
self.assertRaises(TypeError, base64.b32decode, b'me======')
217+
self.assertRaises(TypeError, base64.b32decode, 'me======')
218+
198219
# Mapping zero and one
199220
eq(base64.b32decode(b'MLO23456'), b'b\xdd\xad\xf3\xbe')
200-
eq(base64.b32decode(b'M1023456', map01=b'L'), b'b\xdd\xad\xf3\xbe')
201-
eq(base64.b32decode(b'M1023456', map01=b'I'), b'b\x1d\xad\xf3\xbe')
202-
self.assertRaises(TypeError, base64.b32decode, b"", map01="")
221+
eq(base64.b32decode('MLO23456'), b'b\xdd\xad\xf3\xbe')
222+
223+
map_tests = {(b'M1023456', b'L'): b'b\xdd\xad\xf3\xbe',
224+
(b'M1023456', b'I'): b'b\x1d\xad\xf3\xbe',
225+
}
226+
for (data, map01), res in map_tests.items():
227+
data_str = data.decode('ascii')
228+
map01_str = map01.decode('ascii')
229+
230+
eq(base64.b32decode(data, map01=map01), res)
231+
eq(base64.b32decode(data_str, map01=map01), res)
232+
eq(base64.b32decode(data, map01=map01_str), res)
233+
eq(base64.b32decode(data_str, map01=map01_str), res)
203234

204235
def test_b32decode_error(self):
205-
self.assertRaises(binascii.Error, base64.b32decode, b'abc')
206-
self.assertRaises(binascii.Error, base64.b32decode, b'ABCDEF==')
236+
for data in [b'abc', b'ABCDEF==']:
237+
with self.assertRaises(binascii.Error):
238+
base64.b32decode(data)
239+
base64.b32decode(data.decode('ascii'))
207240

208241
def test_b16encode(self):
209242
eq = self.assertEqual
@@ -214,12 +247,24 @@ def test_b16encode(self):
214247
def test_b16decode(self):
215248
eq = self.assertEqual
216249
eq(base64.b16decode(b'0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
250+
eq(base64.b16decode('0102ABCDEF'), b'\x01\x02\xab\xcd\xef')
217251
eq(base64.b16decode(b'00'), b'\x00')
252+
eq(base64.b16decode('00'), b'\x00')
218253
# Lower case is not allowed without a flag
219254
self.assertRaises(binascii.Error, base64.b16decode, b'0102abcdef')
255+
self.assertRaises(binascii.Error, base64.b16decode, '0102abcdef')
220256
# Case fold
221257
eq(base64.b16decode(b'0102abcdef', True), b'\x01\x02\xab\xcd\xef')
222-
self.assertRaises(TypeError, base64.b16decode, "")
258+
eq(base64.b16decode('0102abcdef', True), b'\x01\x02\xab\xcd\xef')
259+
260+
def test_decode_nonascii_str(self):
261+
decode_funcs = (base64.b64decode,
262+
base64.standard_b64decode,
263+
base64.urlsafe_b64decode,
264+
base64.b32decode,
265+
base64.b16decode)
266+
for f in decode_funcs:
267+
self.assertRaises(ValueError, f, 'with non-ascii \xcb')
223268

224269
def test_ErrorHeritage(self):
225270
self.assertTrue(issubclass(binascii.Error, ValueError))

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #14040: Remove rarely used file name suffixes for C extensions
14+
(under POSIX mainly).
15+
1316
- Issue #14051: Allow arbitrary attributes to be set of classmethod and
1417
staticmethod.
1518

@@ -469,6 +472,9 @@ Core and Builtins
469472
Library
470473
-------
471474

475+
- Issue #13641: Decoding functions in the base64 module now accept ASCII-only
476+
unicode strings. Patch by Catalin Iacob.
477+
472478
- Issue #14043: Speed up importlib's _FileFinder by at least 8x, and add a
473479
new importlib.invalidate_caches() function.
474480

Python/dynload_aix.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ typedef struct Module {
2828

2929
const struct filedescr _PyImport_DynLoadFiletab[] = {
3030
{".so", "rb", C_EXTENSION},
31-
{"module.so", "rb", C_EXTENSION},
3231
{0, 0}
3332
};
3433

Python/dynload_dl.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ extern char *Py_GetProgramName(void);
1111

1212
const struct filedescr _PyImport_DynLoadFiletab[] = {
1313
{".o", "rb", C_EXTENSION},
14-
{"module.o", "rb", C_EXTENSION},
1514
{0, 0}
1615
};
1716

Python/dynload_hpux.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
const struct filedescr _PyImport_DynLoadFiletab[] = {
1717
{SHLIB_EXT, "rb", C_EXTENSION},
18-
{"module"SHLIB_EXT, "rb", C_EXTENSION},
1918
{0, 0}
2019
};
2120

Python/dynload_next.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
const struct filedescr _PyImport_DynLoadFiletab[] = {
1212
{".so", "rb", C_EXTENSION},
13-
{"module.so", "rb", C_EXTENSION},
1413
{0, 0}
1514
};
1615

Python/dynload_shlib.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
const struct filedescr _PyImport_DynLoadFiletab[] = {
4040
#ifdef __CYGWIN__
4141
{".dll", "rb", C_EXTENSION},
42-
{"module.dll", "rb", C_EXTENSION},
4342
#else /* !__CYGWIN__ */
4443
#if defined(PYOS_OS2) && defined(PYCC_GCC)
4544
{".pyd", "rb", C_EXTENSION},
@@ -48,15 +47,10 @@ const struct filedescr _PyImport_DynLoadFiletab[] = {
4847
#ifdef __VMS
4948
{".exe", "rb", C_EXTENSION},
5049
{".EXE", "rb", C_EXTENSION},
51-
{"module.exe", "rb", C_EXTENSION},
52-
{"MODULE.EXE", "rb", C_EXTENSION},
5350
#else /* !__VMS */
5451
{"." SOABI ".so", "rb", C_EXTENSION},
55-
{"module." SOABI ".so", "rb", C_EXTENSION},
5652
{".abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION},
57-
{"module.abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION},
5853
{".so", "rb", C_EXTENSION},
59-
{"module.so", "rb", C_EXTENSION},
6054
#endif /* __VMS */
6155
#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */
6256
#endif /* __CYGWIN__ */

0 commit comments

Comments
 (0)