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

Skip to content

Commit e84c976

Browse files
committed
Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
base64.b64encode() uses it to avoid a memory copy.
1 parent 5df7fdd commit e84c976

6 files changed

Lines changed: 45 additions & 20 deletions

File tree

Doc/library/binascii.rst

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,16 @@ The :mod:`binascii` module defines the following functions:
5252
than one line may be passed at a time.
5353

5454

55-
.. function:: b2a_base64(data)
55+
.. function:: b2a_base64(data, \*, newline=True)
5656

5757
Convert binary data to a line of ASCII characters in base64 coding. The return
58-
value is the converted line, including a newline char. The length of *data*
59-
should be at most 57 to adhere to the base64 standard.
58+
value is the converted line, including a newline char if *newline* is
59+
true. The length of *data* should be at most 57 to adhere to the
60+
base64 standard.
61+
62+
63+
.. versionchanged:: 3.6
64+
Added the *newline* parameter.
6065

6166

6267
.. function:: a2b_qp(data, header=False)

Lib/base64.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,7 @@ def b64encode(s, altchars=None):
5858
5959
The encoded byte string is returned.
6060
"""
61-
# Strip off the trailing newline
62-
encoded = binascii.b2a_base64(s)[:-1]
61+
encoded = binascii.b2a_base64(s, newline=False)
6362
if altchars is not None:
6463
assert len(altchars) == 2, repr(altchars)
6564
return encoded.translate(bytes.maketrans(b'+/', altchars))

Lib/test/test_binascii.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,16 @@ def test_unicode_a2b(self):
262262
# non-ASCII string
263263
self.assertRaises(ValueError, a2b, "\x80")
264264

265+
def test_b2a_base64_newline(self):
266+
# Issue #25357: test newline parameter
267+
b = self.type2test(b'hello')
268+
self.assertEqual(binascii.b2a_base64(b),
269+
b'aGVsbG8=\n')
270+
self.assertEqual(binascii.b2a_base64(b, newline=True),
271+
b'aGVsbG8=\n')
272+
self.assertEqual(binascii.b2a_base64(b, newline=False),
273+
b'aGVsbG8=')
274+
265275

266276
class ArrayBinASCIITest(BinASCIITest):
267277
def type2test(self, s):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ Core and Builtins
5151
Library
5252
-------
5353

54+
- Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
55+
base64.b64encode() uses it to avoid a memory copy.
56+
5457
- Issue #24164: Objects that need calling ``__new__`` with keyword arguments,
5558
can now be pickled using pickle protocols older than protocol version 4.
5659

Modules/binascii.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -528,21 +528,22 @@ binascii_a2b_base64_impl(PyModuleDef *module, Py_buffer *data)
528528
binascii.b2a_base64
529529
530530
data: Py_buffer
531-
/
531+
*
532+
newline: int(c_default="1") = True
532533
533534
Base64-code line of data.
534535
[clinic start generated code]*/
535536

536537
static PyObject *
537-
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
538-
/*[clinic end generated code: output=3cd61fbee2913285 input=14ec4e47371174a9]*/
538+
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline)
539+
/*[clinic end generated code: output=19e1dd719a890b50 input=7b2ea6fa38d8924c]*/
539540
{
540541
unsigned char *ascii_data, *bin_data;
541542
int leftbits = 0;
542543
unsigned char this_ch;
543544
unsigned int leftchar = 0;
544545
PyObject *rv;
545-
Py_ssize_t bin_len;
546+
Py_ssize_t bin_len, out_len;
546547

547548
bin_data = data->buf;
548549
bin_len = data->len;
@@ -555,9 +556,12 @@ binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
555556
}
556557

557558
/* We're lazy and allocate too much (fixed up later).
558-
"+3" leaves room for up to two pad characters and a trailing
559-
newline. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
560-
if ( (rv=PyBytes_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL )
559+
"+2" leaves room for up to two pad characters.
560+
Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
561+
out_len = bin_len*2 + 2;
562+
if (newline)
563+
out_len++;
564+
if ( (rv=PyBytes_FromStringAndSize(NULL, out_len)) == NULL )
561565
return NULL;
562566
ascii_data = (unsigned char *)PyBytes_AS_STRING(rv);
563567

@@ -581,7 +585,8 @@ binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data)
581585
*ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2];
582586
*ascii_data++ = BASE64_PAD;
583587
}
584-
*ascii_data++ = '\n'; /* Append a courtesy newline */
588+
if (newline)
589+
*ascii_data++ = '\n'; /* Append a courtesy newline */
585590

586591
if (_PyBytes_Resize(&rv,
587592
(ascii_data -

Modules/clinic/binascii.c.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,26 +93,29 @@ binascii_a2b_base64(PyModuleDef *module, PyObject *arg)
9393
}
9494

9595
PyDoc_STRVAR(binascii_b2a_base64__doc__,
96-
"b2a_base64($module, data, /)\n"
96+
"b2a_base64($module, /, data, *, newline=True)\n"
9797
"--\n"
9898
"\n"
9999
"Base64-code line of data.");
100100

101101
#define BINASCII_B2A_BASE64_METHODDEF \
102-
{"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_O, binascii_b2a_base64__doc__},
102+
{"b2a_base64", (PyCFunction)binascii_b2a_base64, METH_VARARGS|METH_KEYWORDS, binascii_b2a_base64__doc__},
103103

104104
static PyObject *
105-
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data);
105+
binascii_b2a_base64_impl(PyModuleDef *module, Py_buffer *data, int newline);
106106

107107
static PyObject *
108-
binascii_b2a_base64(PyModuleDef *module, PyObject *arg)
108+
binascii_b2a_base64(PyModuleDef *module, PyObject *args, PyObject *kwargs)
109109
{
110110
PyObject *return_value = NULL;
111+
static char *_keywords[] = {"data", "newline", NULL};
111112
Py_buffer data = {NULL, NULL};
113+
int newline = 1;
112114

113-
if (!PyArg_Parse(arg, "y*:b2a_base64", &data))
115+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "y*|$i:b2a_base64", _keywords,
116+
&data, &newline))
114117
goto exit;
115-
return_value = binascii_b2a_base64_impl(module, &data);
118+
return_value = binascii_b2a_base64_impl(module, &data, newline);
116119

117120
exit:
118121
/* Cleanup for data */
@@ -516,4 +519,4 @@ binascii_b2a_qp(PyModuleDef *module, PyObject *args, PyObject *kwargs)
516519

517520
return return_value;
518521
}
519-
/*[clinic end generated code: output=b1a3cbf7660ebaa5 input=a9049054013a1b77]*/
522+
/*[clinic end generated code: output=b15a24350d105251 input=a9049054013a1b77]*/

0 commit comments

Comments
 (0)