[Python-checkins] cpython: Issue #25357: Add an optional newline paramer to binascii.b2a_base64().

victor.stinner python-checkins at python.org
Sun Oct 11 05:01:32 EDT 2015


https://hg.python.org/cpython/rev/463a09a3bfff
changeset:   98683:463a09a3bfff
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Sun Oct 11 11:01:02 2015 +0200
summary:
  Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
base64.b64encode() uses it to avoid a memory copy.

files:
  Doc/library/binascii.rst    |  11 ++++++++---
  Lib/base64.py               |   3 +--
  Lib/test/test_binascii.py   |  10 ++++++++++
  Misc/NEWS                   |   3 +++
  Modules/binascii.c          |  21 +++++++++++++--------
  Modules/clinic/binascii.c.h |  17 ++++++++++-------
  6 files changed, 45 insertions(+), 20 deletions(-)


diff --git a/Doc/library/binascii.rst b/Doc/library/binascii.rst
--- a/Doc/library/binascii.rst
+++ b/Doc/library/binascii.rst
@@ -52,11 +52,16 @@
    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.
+
+
+   .. versionchanged:: 3.6
+      Added the *newline* parameter.
 
 
 .. function:: a2b_qp(data, header=False)
diff --git a/Lib/base64.py b/Lib/base64.py
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -58,8 +58,7 @@
 
     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 --git a/Lib/test/test_binascii.py b/Lib/test/test_binascii.py
--- a/Lib/test/test_binascii.py
+++ b/Lib/test/test_binascii.py
@@ -262,6 +262,16 @@
             # 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 --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -51,6 +51,9 @@
 Library
 -------
 
+- Issue #25357: Add an optional newline paramer to binascii.b2a_base64().
+  base64.b64encode() uses it to avoid a memory copy.
+
 - Issue #24164: Objects that need calling ``__new__`` with keyword arguments,
   can now be pickled using pickle protocols older than protocol version 4.
 
diff --git a/Modules/binascii.c b/Modules/binascii.c
--- a/Modules/binascii.c
+++ b/Modules/binascii.c
@@ -528,21 +528,22 @@
 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;
@@ -555,9 +556,12 @@
     }
 
     /* 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 )
+       "+2" leaves room for up to two pad characters.
+       Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */
+    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 @@
         *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 --git a/Modules/clinic/binascii.c.h b/Modules/clinic/binascii.c.h
--- a/Modules/clinic/binascii.c.h
+++ b/Modules/clinic/binascii.c.h
@@ -93,26 +93,29 @@
 }
 
 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 @@
 
     return return_value;
 }
-/*[clinic end generated code: output=b1a3cbf7660ebaa5 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=b15a24350d105251 input=a9049054013a1b77]*/

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list