[pypy-commit] pypy py3k: Add str.maketrans()

amauryfa noreply at buildbot.pypy.org
Sun Dec 18 19:34:21 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r50664:540ce4e08539
Date: 2011-12-18 15:52 +0100
http://bitbucket.org/pypy/pypy/changeset/540ce4e08539/

Log:	Add str.maketrans()

diff --git a/pypy/objspace/std/test/test_unicodeobject.py b/pypy/objspace/std/test/test_unicodeobject.py
--- a/pypy/objspace/std/test/test_unicodeobject.py
+++ b/pypy/objspace/std/test/test_unicodeobject.py
@@ -404,6 +404,24 @@
 
         raises(TypeError, 'hello'.translate)
 
+    def test_maketrans(self):
+        assert 'abababc' == 'abababc'.translate({'b': '<i>'})
+        tbl = str.maketrans({'a': None, 'b': '<i>'})
+        assert '<i><i><i>c' == 'abababc'.translate(tbl)
+        tbl = str.maketrans('abc', 'xyz', 'd')
+        assert 'xyzzy' == 'abdcdcbdddd'.translate(tbl)
+
+        raises(TypeError, str.maketrans)
+        raises(ValueError, str.maketrans, 'abc', 'defg')
+        raises(TypeError, str.maketrans, 2, 'def')
+        raises(TypeError, str.maketrans, 'abc', 2)
+        raises(TypeError, str.maketrans, 'abc', 'def', 2)
+        raises(ValueError, str.maketrans, {'xy': 2})
+        raises(TypeError, str.maketrans, {(1,): 2})
+
+        raises(TypeError, 'hello'.translate)
+        raises(TypeError, 'abababc'.translate, 'abc', 'xyz')
+
     def test_unicode_form_encoded_object(self):
         assert str(b'x', 'utf-8') == 'x'
         assert str(b'x', 'utf-8', 'strict') == 'x'
diff --git a/pypy/objspace/std/unicodetype.py b/pypy/objspace/std/unicodetype.py
--- a/pypy/objspace/std/unicodetype.py
+++ b/pypy/objspace/std/unicodetype.py
@@ -329,6 +329,90 @@
     W_UnicodeObject.__init__(w_newobj, w_value._value)
     return w_newobj
 
+def descr_maketrans(space, w_type, w_x, w_y=None, w_z=None):
+    """str.maketrans(x[, y[, z]]) -> dict (static method)
+
+    Return a translation table usable for str.translate().
+    If there is only one argument, it must be a dictionary mapping Unicode
+    ordinals (integers) or characters to Unicode ordinals, strings or None.
+    Character keys will be then converted to ordinals.
+    If there are two arguments, they must be strings of equal length, and
+    in the resulting dictionary, each character in x will be mapped to the
+    character at the same position in y. If there is a third argument, it
+    must be a string, whose characters will be mapped to None in the result."""
+
+    if space.is_w(w_y, space.w_None):
+        y = None
+    else:
+        y = space.unicode_w(w_y)
+    if space.is_w(w_z, space.w_None):
+        z = None
+    else:
+        z = space.unicode_w(w_z)
+
+    w_new = space.newdict()
+    if y is not None:
+        # x must be a string too, of equal length
+        ylen = len(y)
+        try:
+            x = space.unicode_w(w_x)
+        except OperationError, e:
+            if not e.match(space, space.w_TypeError):
+                raise
+            raise OperationError(space.w_TypeError, space.wrap(
+                    "first maketrans argument must "
+                    "be a string if there is a second argument"))
+        if len(x) != ylen:
+            raise OperationError(space.w_ValueError, space.wrap(
+                    "the first two maketrans "
+                    "arguments must have equal length"))
+        # create entries for translating chars in x to those in y
+        for i in range(len(x)):
+            w_key = space.newint(ord(x[i]))
+            w_value = space.newint(ord(y[i]))
+            space.setitem(w_new, w_key, w_value)
+        # create entries for deleting chars in z
+        if z is not None:
+            for i in range(len(z)):
+                w_key = space.newint(ord(z[i]))
+                space.setitem(w_new, w_key, space.w_None)
+    else:
+        # x must be a dict
+        if not space.is_w(space.type(w_x), space.w_dict):
+            raise OperationError(space.w_TypeError, space.wrap(
+                    "if you give only one argument "
+                    "to maketrans it must be a dict"))
+        # copy entries into the new dict, converting string keys to int keys
+        w_iter = space.call_method(w_x, "iteritems")
+        while True:
+            try:
+                w_item = space.next(w_iter)
+            except OperationError, e:
+                if not e.match(space, space.w_StopIteration):
+                    raise
+                break
+            w_key, w_value = space.unpackiterable(w_item, 2)
+            if space.isinstance_w(w_key, space.w_unicode):
+                # convert string keys to integer keys
+                key = space.unicode_w(w_key)
+                if len(key) != 1:
+                    raise OperationError(space.w_ValueError, space.wrap(
+                            "string keys in translate "
+                            "table must be of length 1"))
+                w_key = space.newint(ord(key[0]))
+            else:
+                # just keep integer keys
+                try:
+                    space.int_w(w_key)
+                except OperationError, e:
+                    if not e.match(space, space.w_TypeError):
+                        raise
+                    raise OperationError(space.w_TypeError, space.wrap(
+                            "keys in translate table must "
+                            "be strings or integers"))
+            space.setitem(w_new, w_key, w_value)
+    return w_new
+
 # ____________________________________________________________
 
 unicode_typedef = StdTypeDef("str",
@@ -337,7 +421,8 @@
 
 Create a new Unicode object from the given encoded string.
 encoding defaults to the current default string encoding.
-errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.'''
+errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'.''',
+    maketrans = gateway.interp2app(descr_maketrans, as_classmethod=True),
     )
 
 unicode_typedef.registermethods(globals())


More information about the pypy-commit mailing list