[pypy-commit] pypy py3.5: Speed up 'bytes(unicode, encoding)' and systematically check that

arigo pypy.commits at gmail.com
Fri Nov 18 11:39:26 EST 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r88474:e6763b1bfc48
Date: 2016-11-18 17:38 +0100
http://bitbucket.org/pypy/pypy/changeset/e6763b1bfc48/

Log:	Speed up 'bytes(unicode, encoding)' and systematically check that no
	encoding is given if the argument is not a unicode

diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -530,7 +530,8 @@
     def descr_new(space, w_stringtype, w_source=None, encoding=None,
                   errors=None):
         if (w_source and space.is_w(space.type(w_source), space.w_bytes) and
-            space.is_w(w_stringtype, space.w_bytes)):
+            space.is_w(w_stringtype, space.w_bytes) and encoding is None
+            and errors is None):
             return w_source
         value = newbytesdata_w(space, w_source, encoding, errors)
         w_obj = space.allocate_instance(W_BytesObject, w_stringtype)
@@ -687,13 +688,28 @@
     return chr(value)
 
 def newbytesdata_w(space, w_source, encoding, errors):
+    # Unicode with encoding
+    if w_source is not None and space.isinstance_w(w_source, space.w_unicode):
+        if encoding is None:
+            raise oefmt(space.w_TypeError,
+                        "string argument without an encoding")
+        from pypy.objspace.std.unicodeobject import encode_object
+        w_source = encode_object(space, w_source, encoding, errors)
+        # and continue with the encoded string
+    elif encoding is not None or errors is not None:
+        if w_source is None:
+            raise oefmt(space.w_TypeError,
+                        "encoding or errors without string argument")
+        raise oefmt(space.w_TypeError,
+               "encoding or errors without string argument (got '%T' instead)",
+               w_source)
     # None value
     if w_source is None:
-        if encoding is not None or errors is not None:
-            raise oefmt(space.w_TypeError,
-                        "encoding or errors without string argument")
         return b""
-    # Some object with __bytes__ special method
+    # Fast-path for bytes
+    if space.isinstance_w(w_source, space.w_str):
+        return space.bytes_w(w_source)
+    # Some other object with a __bytes__ special method
     w_bytes_method = space.lookup(w_source, "__bytes__")
     if w_bytes_method is not None:
         w_bytes = space.get_and_call_function(w_bytes_method, w_source)
@@ -711,19 +727,7 @@
     else:
         if count < 0:
             raise oefmt(space.w_ValueError, "negative count")
-        if encoding is not None or errors is not None:
-            raise oefmt(space.w_TypeError,
-                        "encoding or errors without string argument")
         return '\0' * count
-    # Unicode with encoding
-    if space.isinstance_w(w_source, space.w_unicode):
-        if encoding is None:
-            raise RuntimeError
-            raise oefmt(space.w_TypeError,
-                        "string argument without an encoding")
-        from pypy.objspace.std.unicodeobject import encode_object
-        w_source = encode_object(space, w_source, encoding, errors)
-        # and continue with the encoded string
 
     return _convert_from_buffer_or_iterable(space, w_source)
 
diff --git a/pypy/objspace/std/test/test_bytearrayobject.py b/pypy/objspace/std/test/test_bytearrayobject.py
--- a/pypy/objspace/std/test/test_bytearrayobject.py
+++ b/pypy/objspace/std/test/test_bytearrayobject.py
@@ -580,3 +580,7 @@
             assert not b.endswith(bb)
             assert not b.endswith((bb, bb))
             assert bytearray.maketrans(bb, bb)
+
+    def test_constructor_typeerror(self):
+        raises(TypeError, bytearray, b'', 'ascii')
+        raises(TypeError, bytearray, '')
diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -934,3 +934,7 @@
         e = raises(TypeError, b'abc'.__getitem__, b'd')
         assert str(e.value).startswith(
             'byte indices must be integers or slices')
+
+    def test_constructor_typeerror(self):
+        raises(TypeError, bytes, b'', 'ascii')
+        raises(TypeError, bytes, '')


More information about the pypy-commit mailing list