diff -r 92025e9c6b54 Doc/library/binascii.rst --- a/Doc/library/binascii.rst Fri Oct 09 13:10:05 2015 +0200 +++ b/Doc/library/binascii.rst Fri Oct 09 19:05:11 2015 +0200 @@ -52,11 +52,12 @@ The :mod:`binascii` module defines the f than one line may be passed at a time. -.. function:: b2a_base64(data) +.. function:: b2a_base64(data, \*, newline=True) Convert binary data to a line of ASCII characters in base64 coding. The return - value is the converted line, including a newline char. The length of *data* - should be at most 57 to adhere to the base64 standard. + value is the converted line, including a newline char if *newline* is + true. The length of *data* should be at most 57 to adhere to the + base64 standard. .. function:: a2b_qp(data, header=False) diff -r 92025e9c6b54 Lib/base64.py --- a/Lib/base64.py Fri Oct 09 13:10:05 2015 +0200 +++ b/Lib/base64.py Fri Oct 09 19:05:11 2015 +0200 @@ -58,8 +58,7 @@ def b64encode(s, altchars=None): The encoded byte string is returned. """ - # Strip off the trailing newline - encoded = binascii.b2a_base64(s)[:-1] + encoded = binascii.b2a_base64(s, newline=False) if altchars is not None: assert len(altchars) == 2, repr(altchars) return encoded.translate(bytes.maketrans(b'+/', altchars)) diff -r 92025e9c6b54 Lib/test/test_binascii.py --- a/Lib/test/test_binascii.py Fri Oct 09 13:10:05 2015 +0200 +++ b/Lib/test/test_binascii.py Fri Oct 09 19:05:11 2015 +0200 @@ -262,6 +262,16 @@ class BinASCIITest(unittest.TestCase): # non-ASCII string self.assertRaises(ValueError, a2b, "\x80") + def test_b2a_base64_newline(self): + # Issue #25357: test newline parameter + b = self.type2test(b'hello') + self.assertEqual(binascii.b2a_base64(b), + b'aGVsbG8=\n') + self.assertEqual(binascii.b2a_base64(b, newline=True), + b'aGVsbG8=\n') + self.assertEqual(binascii.b2a_base64(b, newline=False), + b'aGVsbG8=') + class ArrayBinASCIITest(BinASCIITest): def type2test(self, s): diff -r 92025e9c6b54 Modules/binascii.c --- a/Modules/binascii.c Fri Oct 09 13:10:05 2015 +0200 +++ b/Modules/binascii.c Fri Oct 09 19:05:11 2015 +0200 @@ -528,21 +528,22 @@ binascii_a2b_base64_impl(PyModuleDef *mo binascii.b2a_base64 data: Py_buffer - / + * + newline: int(c_default="1") = True Base64-code line of data. [clinic start generated code]*/ static PyObject * -binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data) -/*[clinic end generated code: output=3cd61fbee2913285 input=14ec4e47371174a9]*/ +binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline) +/*[clinic end generated code: output=19e1dd719a890b50 input=7b2ea6fa38d8924c]*/ { unsigned char *ascii_data, *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; PyObject *rv; - Py_ssize_t bin_len; + Py_ssize_t bin_len, out_len; bin_data = data->buf; bin_len = data->len; @@ -557,7 +558,10 @@ binascii_b2a_base64_impl(PyModuleDef *mo /* We're lazy and allocate too much (fixed up later). "+3" leaves room for up to two pad characters and a trailing newline. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ - if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL ) + out_len = bin_len*2 + 2; + if (newline) + out_len++; + if ( (rv=PyBytes_FromStringAndSize(NULL, out_len)) == NULL ) return NULL; ascii_data = (unsigned char *)PyBytes_AS_STRING(rv); @@ -581,7 +585,8 @@ binascii_b2a_base64_impl(PyModuleDef *mo *ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2]; *ascii_data++ = BASE64_PAD; } - *ascii_data++ = '\n'; /* Append a courtesy newline */ + if (newline) + *ascii_data++ = '\n'; /* Append a courtesy newline */ if (_PyBytes_Resize(&rv, (ascii_data - diff -r 92025e9c6b54 Modules/clinic/binascii.c.h --- a/Modules/clinic/binascii.c.h Fri Oct 09 13:10:05 2015 +0200 +++ b/Modules/clinic/binascii.c.h Fri Oct 09 19:05:11 2015 +0200 @@ -93,26 +93,29 @@ exit: } PyDoc_STRVAR(binascii_b2a_base64__doc__, -"b2a_base64($module, data, /)\n" +"b2a_base64($module, /, data, *, newline=True)\n" "--\n" "\n" "Base64-code line of data."); #define BINASCII_B2A_BASE64_METHODDEF \ - {"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_O, binascii_b2a_base64__doc__}, + {"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_VARARGS|METH_KEYWORDS, binascii_b2a_base64__doc__}, static PyObject * -binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data); +binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline); static PyObject * -binascii_b2a_base64(PyModuleDef *module, PyObject *arg) +binascii_b2a_base64(PyModuleDef *module, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; + static char *_keywords[] = {"data", "newline", NULL}; Py_buffer data = {NULL, NULL}; + int newline = 1; - if (!PyArg_Parse(arg, "y*:b2a_base64", &data)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|$i:b2a_base64", _keywords, + &data, &newline)) goto exit; - return_value = binascii_b2a_base64_impl(module, &data); + return_value = binascii_b2a_base64_impl(module, &data, newline); exit: /* Cleanup for data */ @@ -516,4 +519,4 @@ exit: return return_value; } -/*[clinic end generated code: output=b1a3cbf7660ebaa5 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b15a24350d105251 input=a9049054013a1b77]*/