]> granicus.if.org Git - python/commitdiff
Add bytes/bytearray.maketrans() to mirror str.maketrans(), and deprecate
authorGeorg Brandl <georg@python.org>
Sun, 12 Apr 2009 15:51:51 +0000 (15:51 +0000)
committerGeorg Brandl <georg@python.org>
Sun, 12 Apr 2009 15:51:51 +0000 (15:51 +0000)
string.maketrans() which actually works on bytes.  (Also closes #5675.)

Doc/library/stdtypes.rst
Doc/library/string.rst
Include/bytes_methods.h
Lib/string.py
Lib/test/test_bigmem.py
Lib/test/test_bytes.py
Lib/test/test_string.py
Misc/NEWS
Objects/bytearrayobject.c
Objects/bytes_methods.c
Objects/bytesobject.c

index a8c3146f3cd20a227bc20a39a455a7cf5f46869d..72e2fb44b75beb5e25fe66a2e61b30c06aea101f 100644 (file)
@@ -479,7 +479,7 @@ debugging, and in numerical work.
    exponent.
 
 
-.. method:: float.fromhex(s)
+.. classmethod:: float.fromhex(s)
 
    Class method to return the float represented by a hexadecimal
    string *s*.  The string *s* may have leading and trailing
@@ -967,7 +967,7 @@ functions based on regular expressions.
       'example.com'
 
 
-.. method:: str.maketrans(x[, y[, z]])
+.. staticmethod:: str.maketrans(x[, y[, z]])
 
    This static method returns a translation table usable for :meth:`str.translate`.
 
@@ -1514,8 +1514,8 @@ Wherever one of these methods needs to interpret the bytes as characters
 
 The bytes and bytearray types have an additional class method:
 
-.. method:: bytes.fromhex(string)
-            bytearray.fromhex(string)
+.. classmethod:: bytes.fromhex(string)
+                 bytearray.fromhex(string)
 
    This :class:`bytes` class method returns a bytes or bytearray object,
    decoding the given string object.  The string must contain two hexadecimal
@@ -1524,7 +1524,9 @@ The bytes and bytearray types have an additional class method:
    >>> bytes.fromhex('f0 f1f2  ')
    b'\xf0\xf1\xf2'
 
-The translate method differs in semantics from the version available on strings:
+
+The maketrans and translate methods differ in semantics from the versions
+available on strings:
 
 .. method:: bytes.translate(table[, delete])
 
@@ -1533,8 +1535,7 @@ The translate method differs in semantics from the version available on strings:
    mapped through the given translation table, which must be a bytes object of
    length 256.
 
-   You can use the :func:`string.maketrans` helper function to create a
-   translation table.
+   You can use the :func:`bytes.maketrans` method to create a translation table.
 
    Set the *table* argument to ``None`` for translations that only delete
    characters::
@@ -1543,6 +1544,16 @@ The translate method differs in semantics from the version available on strings:
       b'rd ths shrt txt'
 
 
+.. staticmethod:: bytes.maketrans(from, to)
+
+   This static method returns a translation table usable for
+   :meth:`bytes.translate` that will map each character in *from* into the
+   character at the same position in *to*; *from* and *to* must be bytes objects
+   and have the same length.
+
+   .. versionadded:: 3.1
+
+
 .. _types-set:
 
 Set Types --- :class:`set`, :class:`frozenset`
@@ -1847,7 +1858,7 @@ pairs within braces, for example: ``{'jack': 4098, 'sjoerd': 4127}`` or ``{4098:
 
       Return a shallow copy of the dictionary.
 
-   .. method:: fromkeys(seq[, value])
+   .. classmethod:: fromkeys(seq[, value])
 
       Create a new dictionary with keys from *seq* and values set to *value*.
 
index 5867a5ae793a177fbc44897ee49928d055eccaa5..29bf160c5887223e5501c4cb2d779dd5fe05e672 100644 (file)
@@ -548,13 +548,9 @@ rule:
   delimiter), and it should appear last in the regular expression.
 
 
-String functions
+Helper functions
 ----------------
 
-The following functions are available to operate on string objects.
-They are not available as string methods.
-
-
 .. function:: capwords(s)
 
    Split the argument into words using :func:`split`, capitalize each word using
@@ -568,3 +564,6 @@ They are not available as string methods.
    Return a translation table suitable for passing to :meth:`bytes.translate`,
    that will map each character in *from* into the character at the same
    position in *to*; *from* and *to* must have the same length.
+
+   .. deprecated:: 3.1
+      Use the :meth:`bytes.maketrans` static method instead.
index 37518d20add43adbcf7e0ccda81e5cbda8580ba1..e973261efff50e2659fee1889018d121c0965c50 100644 (file)
@@ -20,6 +20,9 @@ extern void _Py_bytes_title(char *result, char *s, Py_ssize_t len);
 extern void _Py_bytes_capitalize(char *result, char *s, Py_ssize_t len);
 extern void _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len);
 
+/* This one gets the raw argument list. */
+extern PyObject* _Py_bytes_maketrans(PyObject *args);
+
 /* Shared __doc__ strings. */
 extern const char _Py_isspace__doc__[];
 extern const char _Py_isalpha__doc__[];
@@ -33,6 +36,7 @@ extern const char _Py_upper__doc__[];
 extern const char _Py_title__doc__[];
 extern const char _Py_capitalize__doc__[];
 extern const char _Py_swapcase__doc__[];
+extern const char _Py_maketrans__doc__[];
 
 #define FLAG_LOWER  0x01
 #define FLAG_UPPER  0x02
index ea0d359002fbcab33d7262e156ba578c852a9393..8667c0ee69eeed671ab1f763e2955bcd6dc45f6b 100644 (file)
@@ -49,6 +49,9 @@ def maketrans(frm: bytes, to: bytes) -> bytes:
     mapped to the byte at the same position in to.
     The strings frm and to must be of the same length.
     """
+    import warnings
+    warnings.warn("string.maketrans is deprecated, use bytes.maketrans instead",
+                  DeprecationWarning)
     if len(frm) != len(to):
         raise ValueError("maketrans arguments must have same length")
     if not (isinstance(frm, bytes) and isinstance(to, bytes)):
index 7896748fe8659de8f252483dd6cb4386e9123aaa..091893e7fe466b3f16bcdb6dab759a3b59f0e25d 100644 (file)
@@ -418,18 +418,15 @@ class BaseStrTest:
     @bigmemtest(minsize=_2G, memuse=2)
     def test_translate(self, size):
         _ = self.from_latin1
-        trans = {
-            ord(_('.')): _('-'),
-            ord(_('a')): _('!'),
-            ord(_('Z')): _('$'),
-        }
         SUBSTR = _('aZz.z.Aaz.')
-        if not isinstance(SUBSTR, str):
-            # Workaround the inexistence of bytes.maketrans()
-            chars = bytearray(range(256))
-            for k, v in trans.items():
-                chars[k] = ord(v)
-            trans = chars
+        if isinstance(SUBSTR, str):
+            trans = {
+                ord(_('.')): _('-'),
+                ord(_('a')): _('!'),
+                ord(_('Z')): _('$'),
+            }
+        else:
+            trans = bytes.maketrans(b'.aZ', b'-!$')
         sublen = len(SUBSTR)
         repeats = size // sublen + 2
         s = SUBSTR * repeats
index cb7fb460002e72ce887b5a77764133100f1d9dc4..a3ea40aa50f0d5aecde6c5d08823ca5c6f84e0d4 100644 (file)
@@ -450,6 +450,13 @@ class BaseBytesTest(unittest.TestCase):
         self.assertEqual([ord(b[i:i+1]) for i in range(len(b))],
                          [0, 65, 127, 128, 255])
 
+    def test_maketrans(self):
+        transtable = b'\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
+
+        self.assertEqual(self.type2test.maketrans(b'abc', b'xyz'), transtable)
+        self.assertRaises(ValueError, self.type2test.maketrans, b'abc', b'xyzq')
+        self.assertRaises(TypeError, self.type2test.maketrans, 'abc', 'def')
+
 
 class BytesTest(BaseBytesTest):
     type2test = bytes
index 66f2204de4a89e6f3ab05c4ee1132794c5bb33c7..16d1edb0e388cc362a1338f2bde6a75d67364910 100644 (file)
@@ -101,14 +101,6 @@ class ModuleTest(unittest.TestCase):
         self.assertRaises(ValueError, fmt.format, "{0}", 10, 20, i=100)
         self.assertRaises(ValueError, fmt.format, "{i}", 10, 20, i=100)
 
-
-    def test_maketrans(self):
-        transtable = b'\000\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037 !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`xyzdefghijklmnopqrstuvwxyz{|}~\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377'
-
-        self.assertEqual(string.maketrans(b'abc', b'xyz'), transtable)
-        self.assertRaises(ValueError, string.maketrans, b'abc', b'xyzq')
-        self.assertRaises(TypeError, string.maketrans, 'abc', 'def')
-
 def test_main():
     support.run_unittest(ModuleTest)
 
index a08f320cad063f40c50b84e58e0cd5bd1cd88c99..b89516c8d3a16b30d5cebb257cbdb9c1e286480d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,11 @@ What's New in Python 3.1 beta 1?
 Core and Builtins
 -----------------
 
+- The string.maketrans() function is deprecated; there is a new static method
+  maketrans() on the bytes and bytearray classes.  This removes confusion about
+  the types string.maketrans() is supposed to work with, and mirrors the
+  methods available on the str class.
+
 - Issue #2170: refactored xml.dom.minidom.normalize, increasing both
   its clarity and its speed.
 
index bc8f39e803c8ac60262307e707662fc71a4c1641..ca597a2e3fd6555e2739ab8f212793a251d69c5b 100644 (file)
@@ -1451,6 +1451,13 @@ done:
 }
 
 
+static PyObject *
+bytes_maketrans(PyObject *null, PyObject *args)
+{
+       return _Py_bytes_maketrans(args);
+}
+
+
 #define FORWARD 1
 #define REVERSE -1
 
@@ -3131,6 +3138,8 @@ bytes_methods[] = {
     {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, ljust__doc__},
     {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__},
     {"lstrip", (PyCFunction)bytes_lstrip, METH_VARARGS, lstrip__doc__},
+    {"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC,
+     _Py_maketrans__doc__},
     {"partition", (PyCFunction)bytes_partition, METH_O, partition__doc__},
     {"pop", (PyCFunction)bytes_pop, METH_VARARGS, pop__doc__},
     {"remove", (PyCFunction)bytes_remove, METH_O, remove__doc__},
index 2d55601d39a92e0849cd5aa174e7db13bc7659df..403b131b95c6c5cee32d8057cf316b6c2da2cad7 100644 (file)
@@ -608,3 +608,70 @@ _Py_bytes_swapcase(char *result, char *s, Py_ssize_t len)
        }
 }
 
+
+PyDoc_STRVAR_shared(_Py_maketrans__doc__,
+"B.maketrans(frm, to) -> translation table\n\
+\n\
+Return a translation table (a bytes object of length 256)\n\
+suitable for use in bytes.translate where each byte in frm is\n\
+mapped to the byte at the same position in to.\n\
+The strings frm and to must be of the same length.");
+
+static Py_ssize_t
+_getbuffer(PyObject *obj, Py_buffer *view)
+{
+    PyBufferProcs *buffer = Py_TYPE(obj)->tp_as_buffer;
+
+    if (buffer == NULL || buffer->bf_getbuffer == NULL)
+    {
+        PyErr_Format(PyExc_TypeError,
+                     "Type %.100s doesn't support the buffer API",
+                     Py_TYPE(obj)->tp_name);
+        return -1;
+    }
+
+    if (buffer->bf_getbuffer(obj, view, PyBUF_SIMPLE) < 0)
+            return -1;
+    return view->len;
+}
+
+PyObject *
+_Py_bytes_maketrans(PyObject *args)
+{
+       PyObject *frm, *to, *res = NULL;
+       Py_buffer bfrm, bto;
+       int i;
+       char *p;
+
+       bfrm.len = -1;
+       bto.len = -1;
+       
+       if (!PyArg_ParseTuple(args, "OO:maketrans", &frm, &to))
+               return NULL;
+       if (_getbuffer(frm, &bfrm) < 0)
+               return NULL;
+       if (_getbuffer(to, &bto) < 0)
+               goto done;
+       if (bfrm.len != bto.len) {
+               PyErr_Format(PyExc_ValueError,
+                            "maketrans arguments must have same length");
+               goto done;
+       }
+       res = PyBytes_FromStringAndSize(NULL, 256);
+       if (!res) {
+               goto done;
+       }
+       p = PyBytes_AS_STRING(res);
+       for (i = 0; i < 256; i++)
+               p[i] = i;
+       for (i = 0; i < bfrm.len; i++) {
+               p[(int)((char *)bfrm.buf)[i]] = ((char *)bto.buf)[i];
+       }
+
+  done:
+       if (bfrm.len != -1)
+               PyBuffer_Release(&bfrm);
+       if (bto.len != -1)
+               PyBuffer_Release(&bto);
+       return res;
+}
index d5c2bea35e5f9d931f750baf41d749047fd7bc5e..1239680b4723f4a3796e31029c5e0597963a424f 100644 (file)
@@ -1950,6 +1950,12 @@ string_translate(PyBytesObject *self, PyObject *args)
 }
 
 
+static PyObject *
+string_maketrans(PyObject *null, PyObject *args)
+{
+       return _Py_bytes_maketrans(args);
+}
+
 #define FORWARD 1
 #define REVERSE -1
 
@@ -2851,6 +2857,8 @@ string_methods[] = {
        {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, ljust__doc__},
        {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__},
        {"lstrip", (PyCFunction)string_lstrip, METH_VARARGS, lstrip__doc__},
+       {"maketrans", (PyCFunction)string_maketrans, METH_VARARGS|METH_STATIC,
+        _Py_maketrans__doc__},
        {"partition", (PyCFunction)string_partition, METH_O, partition__doc__},
        {"replace", (PyCFunction)string_replace, METH_VARARGS, replace__doc__},
        {"rfind", (PyCFunction)string_rfind, METH_VARARGS, rfind__doc__},