[pypy-commit] pypy refine-testrunner: merge from default

RonnyPfannschmidt noreply at buildbot.pypy.org
Sun Aug 31 18:50:33 CEST 2014


Author: Ronny Pfannschmidt <opensource at ronnypfannschmidt.de>
Branch: refine-testrunner
Changeset: r73240:a9df5830e867
Date: 2014-02-02 17:22 +0100
http://bitbucket.org/pypy/pypy/changeset/a9df5830e867/

Log:	merge from default

diff too long, truncating to 2000 out of 5591 lines

diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -426,25 +426,12 @@
 Could we use LLVM?
 ------------------
 
-In theory yes.  But we tried to use it 5 or 6 times already, as a
-translation backend or as a JIT backend --- and failed each time.
+There is a (static) translation backend using LLVM in the branch
+``llvm-translation-backend``.  It can translate PyPy with or without the JIT on
+Linux.
 
-In more details: using LLVM as a (static) translation backend is
-pointless nowadays because you can generate C code and compile it with
-clang.  (Note that compiling PyPy with clang gives a result that is not
-faster than compiling it with gcc.)  We might in theory get extra
-benefits from LLVM's GC integration, but this requires more work on the
-LLVM side before it would be remotely useful.  Anyway, it could be
-interfaced via a custom primitive in the C code.
-
-On the other hand, using LLVM as our JIT backend looks interesting as
-well --- but again we made an attempt, and it failed: LLVM has no way to
-patch the generated machine code.
-
-So the position of the core PyPy developers is that if anyone wants to
-make an N+1'th attempt with LLVM, they are welcome, and will be happy to
-provide help in the IRC channel, but they are left with the burden of proof
-that (a) it works and (b) it gives important benefits.
+Using LLVM as our JIT backend looks interesting as well -- we made an attempt,
+but it failed: LLVM has no way to patch the generated machine code.
 
 ----------------------
 How do I compile PyPy?
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -52,3 +52,8 @@
 .. branch: annotator
 Remove FlowObjSpace.
 Improve cohesion between rpython.flowspace and rpython.annotator.
+
+.. branch: detect-immutable-fields
+mapdicts keep track of whether or not an attribute is every assigned to
+multiple times. If it's only assigned once then an elidable lookup is used when
+possible.
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -232,9 +232,8 @@
         raise operationerrfmt(space.w_TypeError, msg, w_result)
 
     def ord(self, space):
-        typename = space.type(self).getname(space)
-        msg = "ord() expected string of length 1, but %s found"
-        raise operationerrfmt(space.w_TypeError, msg, typename)
+        msg = "ord() expected string of length 1, but %T found"
+        raise operationerrfmt(space.w_TypeError, msg, self)
 
     def __spacebind__(self, space):
         return self
diff --git a/pypy/interpreter/error.py b/pypy/interpreter/error.py
--- a/pypy/interpreter/error.py
+++ b/pypy/interpreter/error.py
@@ -6,7 +6,7 @@
 from errno import EINTR
 
 from rpython.rlib import jit
-from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.objectmodel import we_are_translated, specialize
 
 from pypy.interpreter import debug
 
@@ -40,12 +40,11 @@
             self.debug_excs = []
 
     def clear(self, space):
-        # for sys.exc_clear()
-        self.w_type = space.w_None
-        self._w_value = space.w_None
-        self._application_traceback = None
-        if not we_are_translated():
-            del self.debug_excs[:]
+        # XXX remove this method.  The point is that we cannot always
+        # hack at 'self' to clear w_type and _w_value, because in some
+        # corner cases the OperationError will be used again: see
+        # test_interpreter.py:test_with_statement_and_sys_clear.
+        pass
 
     def match(self, space, w_check_class):
         "Check if this application-level exception matches 'w_check_class'."
@@ -300,6 +299,10 @@
         """
         self._application_traceback = traceback
 
+ at specialize.memo()
+def get_cleared_operation_error(space):
+    return OperationError(space.w_None, space.w_None)
+
 # ____________________________________________________________
 # optimization only: avoid the slowest operation -- the string
 # formatting with '%' -- in the common case were we don't
@@ -371,8 +374,8 @@
 class OpErrFmtNoArgs(OperationError):
 
     def __init__(self, w_type, value):
+        self._value = value
         self.setup(w_type)
-        self._value = value
 
     def get_w_value(self, space):
         w_value = self._w_value
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -1,5 +1,5 @@
 import sys
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, get_cleared_operation_error
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib import jit
 
@@ -217,6 +217,17 @@
         if frame:     # else, the exception goes nowhere and is lost
             frame.last_exception = operror
 
+    def clear_sys_exc_info(self):
+        # Find the frame out of which sys_exc_info() would return its result,
+        # and hack this frame's last_exception to become the cleared
+        # OperationError (which is different from None!).
+        frame = self.gettopframe_nohidden()
+        while frame:
+            if frame.last_exception is not None:
+                frame.last_exception = get_cleared_operation_error(self.space)
+                break
+            frame = self.getnextframe_nohidden(frame)
+
     @jit.dont_look_inside
     def settrace(self, w_func):
         """Set the global trace function."""
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -744,6 +744,9 @@
             else:
                 raise OperationError(space.w_TypeError,
                     space.wrap("raise: no active exception to re-raise"))
+            if operror.w_type is space.w_None:
+                raise OperationError(space.w_TypeError,
+                    space.wrap("raise: the exception to re-raise was cleared"))
             # re-raise, no new traceback obj will be attached
             self.last_exception = operror
             raise RaiseWithExplicitTraceback(operror)
diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py
--- a/pypy/interpreter/test/test_interpreter.py
+++ b/pypy/interpreter/test/test_interpreter.py
@@ -311,3 +311,73 @@
             assert str(e) == "maximum recursion depth exceeded"
         else:
             assert 0, "should have raised!"
+
+    def test_with_statement_and_sys_clear(self):
+        import sys
+        class CM(object):
+            def __enter__(self):
+                return self
+            def __exit__(self, exc_type, exc_value, tb):
+                sys.exc_clear()
+        try:
+            with CM():
+                1 / 0
+            raise AssertionError("should not be reached")
+        except ZeroDivisionError:
+            pass
+
+    def test_sys_clear_while_handling_exception(self):
+        import sys
+        def f():
+            try:
+                some_missing_name
+            except NameError:
+                g()
+                assert sys.exc_info()[0] is NameError
+        def g():
+            assert sys.exc_info()[0] is NameError
+            try:
+                1 / 0
+            except ZeroDivisionError:
+                assert sys.exc_info()[0] is ZeroDivisionError
+                sys.exc_clear()
+                assert sys.exc_info()[0] is None
+                h()
+                assert sys.exc_info()[0] is None
+        def h():
+            assert sys.exc_info()[0] is None
+        f()
+
+    def test_sys_clear_while_handling_exception_nested(self):
+        import sys
+        def f():
+            try:
+                some_missing_name
+            except NameError:
+                g()
+                assert sys.exc_info()[0] is NameError
+        def g():
+            assert sys.exc_info()[0] is NameError
+            try:
+                1 / 0
+            except ZeroDivisionError:
+                assert sys.exc_info()[0] is ZeroDivisionError
+                h1()
+                assert sys.exc_info()[0] is None
+                h()
+                assert sys.exc_info()[0] is None
+        def h():
+            assert sys.exc_info()[0] is None
+        def h1():
+            sys.exc_clear()
+        f()
+
+    def test_sys_clear_reraise(self):
+        import sys
+        def f():
+            try:
+                1 / 0
+            except ZeroDivisionError:
+                sys.exc_clear()
+                raise
+        raises(TypeError, f)
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -3,7 +3,7 @@
 from rpython.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.objspace.std.typeobject import MethodCache
-from pypy.objspace.std.mapdict import IndexCache
+from pypy.objspace.std.mapdict import MapAttrCache
 from rpython.rlib import rposix, rgc
 
 
@@ -35,7 +35,7 @@
     cache.misses = {}
     cache.hits = {}
     if space.config.objspace.std.withmapdict:
-        cache = space.fromcache(IndexCache)
+        cache = space.fromcache(MapAttrCache)
         cache.misses = {}
         cache.hits = {}
 
@@ -45,7 +45,7 @@
     in the mapdict cache with the given attribute name."""
     assert space.config.objspace.std.withmethodcachecounter
     assert space.config.objspace.std.withmapdict
-    cache = space.fromcache(IndexCache)
+    cache = space.fromcache(MapAttrCache)
     return space.newtuple([space.newint(cache.hits.get(name, 0)),
                            space.newint(cache.misses.get(name, 0))])
 
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -400,16 +400,16 @@
     '_PyObject_CallFunction_SizeT', '_PyObject_CallMethod_SizeT',
 
     'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject',
-    'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_init_bufferobject',
+    'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_get_buffer_type',
 
     'PyCObject_FromVoidPtr', 'PyCObject_FromVoidPtrAndDesc', 'PyCObject_AsVoidPtr',
     'PyCObject_GetDesc', 'PyCObject_Import', 'PyCObject_SetVoidPtr',
-    'PyCObject_Type', '_Py_init_pycobject',
+    'PyCObject_Type', '_Py_get_cobject_type',
 
     'PyCapsule_New', 'PyCapsule_IsValid', 'PyCapsule_GetPointer',
     'PyCapsule_GetName', 'PyCapsule_GetDestructor', 'PyCapsule_GetContext',
     'PyCapsule_SetPointer', 'PyCapsule_SetName', 'PyCapsule_SetDestructor',
-    'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', '_Py_init_capsule',
+    'PyCapsule_SetContext', 'PyCapsule_Import', 'PyCapsule_Type', '_Py_get_capsule_type',
 
     'PyObject_AsReadBuffer', 'PyObject_AsWriteBuffer', 'PyObject_CheckReadBuffer',
 
@@ -691,17 +691,25 @@
         prefix = 'PyPy'
     else:
         prefix = 'cpyexttest'
-    init_buffer = rffi.llexternal('_%s_init_bufferobject' % prefix, [], lltype.Void,
-                                  compilation_info=eci, releasegil=False)
-    init_pycobject = rffi.llexternal('_%s_init_pycobject' % prefix, [], lltype.Void,
-                                     compilation_info=eci, releasegil=False)
-    init_capsule = rffi.llexternal('_%s_init_capsule' % prefix, [], lltype.Void,
-                                   compilation_info=eci, releasegil=False)
-    INIT_FUNCTIONS.extend([
-        lambda space: init_buffer(),
-        lambda space: init_pycobject(),
-        lambda space: init_capsule(),
-    ])
+    # jump through hoops to avoid releasing the GIL during initialization
+    # of the cpyext module.  The C functions are called with no wrapper,
+    # but must not do anything like calling back PyType_Ready().  We
+    # use them just to get a pointer to the PyTypeObjects defined in C.
+    get_buffer_type = rffi.llexternal('_%s_get_buffer_type' % prefix,
+                                      [], PyTypeObjectPtr,
+                                      compilation_info=eci, _nowrapper=True)
+    get_cobject_type = rffi.llexternal('_%s_get_cobject_type' % prefix,
+                                       [], PyTypeObjectPtr,
+                                       compilation_info=eci, _nowrapper=True)
+    get_capsule_type = rffi.llexternal('_%s_get_capsule_type' % prefix,
+                                       [], PyTypeObjectPtr,
+                                       compilation_info=eci, _nowrapper=True)
+    def init_types(space):
+        from pypy.module.cpyext.typeobject import py_type_ready
+        py_type_ready(space, get_buffer_type())
+        py_type_ready(space, get_cobject_type())
+        py_type_ready(space, get_capsule_type())
+    INIT_FUNCTIONS.append(init_types)
     from pypy.module.posix.interp_posix import add_fork_hook
     reinit_tls = rffi.llexternal('%sThread_ReInitTLS' % prefix, [], lltype.Void,
                                  compilation_info=eci)
diff --git a/pypy/module/cpyext/include/pyconfig.h b/pypy/module/cpyext/include/pyconfig.h
--- a/pypy/module/cpyext/include/pyconfig.h
+++ b/pypy/module/cpyext/include/pyconfig.h
@@ -15,6 +15,8 @@
 #define HAVE_UNICODE
 #define WITHOUT_COMPLEX
 #define HAVE_WCHAR_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
 
 /* PyPy supposes Py_UNICODE == wchar_t */
 #define HAVE_USABLE_WCHAR_T 1
diff --git a/pypy/module/cpyext/include/pyport.h b/pypy/module/cpyext/include/pyport.h
--- a/pypy/module/cpyext/include/pyport.h
+++ b/pypy/module/cpyext/include/pyport.h
@@ -64,4 +64,45 @@
 #   error "Python needs a typedef for Py_uintptr_t in pyport.h."
 #endif /* HAVE_UINTPTR_T */
 
+/*******************************
+ * stat() and fstat() fiddling *
+ *******************************/
+
+/* We expect that stat and fstat exist on most systems.
+ *  It's confirmed on Unix, Mac and Windows.
+ *  If you don't have them, add
+ *      #define DONT_HAVE_STAT
+ * and/or
+ *      #define DONT_HAVE_FSTAT
+ * to your pyconfig.h. Python code beyond this should check HAVE_STAT and
+ * HAVE_FSTAT instead.
+ * Also
+ *      #define HAVE_SYS_STAT_H
+ * if <sys/stat.h> exists on your platform, and
+ *      #define HAVE_STAT_H
+ * if <stat.h> does.
+ */
+#ifndef DONT_HAVE_STAT
+#define HAVE_STAT
+#endif
+
+#ifndef DONT_HAVE_FSTAT
+#define HAVE_FSTAT
+#endif
+
+#ifdef RISCOS
+#include <sys/types.h>
+#include "unixstuff.h"
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#if defined(PYOS_OS2) && defined(PYCC_GCC)
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+#elif defined(HAVE_STAT_H)
+#include <stat.h>
+#else
+#endif
+
 #endif /* Py_PYPORT_H */
diff --git a/pypy/module/cpyext/src/bufferobject.c b/pypy/module/cpyext/src/bufferobject.c
--- a/pypy/module/cpyext/src/bufferobject.c
+++ b/pypy/module/cpyext/src/bufferobject.c
@@ -783,9 +783,9 @@
     return size;
 }
 
-void _Py_init_bufferobject(void)
+PyTypeObject *_Py_get_buffer_type(void)
 {
-    PyType_Ready(&PyBuffer_Type);
+    return &PyBuffer_Type;
 }
 
 static PySequenceMethods buffer_as_sequence = {
diff --git a/pypy/module/cpyext/src/capsule.c b/pypy/module/cpyext/src/capsule.c
--- a/pypy/module/cpyext/src/capsule.c
+++ b/pypy/module/cpyext/src/capsule.c
@@ -321,8 +321,7 @@
     PyCapsule_Type__doc__	/*tp_doc*/
 };
 
-void _Py_init_capsule()
+PyTypeObject *_Py_get_capsule_type(void)
 {
-    PyType_Ready(&PyCapsule_Type);
+    return &PyCapsule_Type;
 }
-
diff --git a/pypy/module/cpyext/src/cobject.c b/pypy/module/cpyext/src/cobject.c
--- a/pypy/module/cpyext/src/cobject.c
+++ b/pypy/module/cpyext/src/cobject.c
@@ -156,7 +156,7 @@
     PyCObject_Type__doc__	/*tp_doc*/
 };
 
-void _Py_init_pycobject()
+PyTypeObject *_Py_get_cobject_type(void)
 {
-    PyType_Ready(&PyCObject_Type);
+    return &PyCObject_Type;
 }
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -549,11 +549,14 @@
     pto.c_tp_flags |= Py_TPFLAGS_READY
     return pto
 
+def py_type_ready(space, pto):
+    if pto.c_tp_flags & Py_TPFLAGS_READY:
+        return
+    type_realize(space, rffi.cast(PyObject, pto))
+
 @cpython_api([PyTypeObjectPtr], rffi.INT_real, error=-1)
 def PyType_Ready(space, pto):
-    if pto.c_tp_flags & Py_TPFLAGS_READY:
-        return 0
-    type_realize(space, rffi.cast(PyObject, pto))
+    py_type_ready(space, pto)
     return 0
 
 def type_realize(space, py_obj):
diff --git a/pypy/module/gc/interp_gc.py b/pypy/module/gc/interp_gc.py
--- a/pypy/module/gc/interp_gc.py
+++ b/pypy/module/gc/interp_gc.py
@@ -12,8 +12,8 @@
         cache = space.fromcache(MethodCache)
         cache.clear()
         if space.config.objspace.std.withmapdict:
-            from pypy.objspace.std.mapdict import IndexCache
-            cache = space.fromcache(IndexCache)
+            from pypy.objspace.std.mapdict import MapAttrCache
+            cache = space.fromcache(MapAttrCache)
             cache.clear()
     rgc.collect()
     return space.wrap(0)
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -394,6 +394,9 @@
 class W_Float64Box(W_FloatingBox, PrimitiveBox):
     descr__new__, _get_dtype, descr_reduce = new_dtype_getter("float64")
 
+    def descr_as_integer_ratio(self, space):
+        return space.call_method(self.item(space), 'as_integer_ratio')
+
 class W_ComplexFloatingBox(W_InexactBox):
     def descr_get_real(self, space):
         dtype = self._COMPONENTS_BOX._get_dtype(space)
@@ -719,6 +722,7 @@
     __module__ = "numpy",
     __new__ = interp2app(W_Float64Box.descr__new__.im_func),
     __reduce__ = interp2app(W_Float64Box.descr_reduce),
+    as_integer_ratio = interp2app(W_Float64Box.descr_as_integer_ratio),
 )
 
 W_ComplexFloatingBox.typedef = TypeDef("complexfloating", W_InexactBox.typedef,
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -903,8 +903,8 @@
             w_res = self.descr_mul(space, other)
             assert isinstance(w_res, W_NDimArray)
             return w_res.descr_sum(space, space.wrap(-1), out)
-        dtype = interp_ufuncs.find_binop_result_dtype(space,
-                                     self.get_dtype(), other.get_dtype())
+        dtype = interp_ufuncs.find_binop_result_dtype(space, self.get_dtype(),
+                                                             other.get_dtype())
         if self.get_size() < 1 and other.get_size() < 1:
             # numpy compatability
             return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
@@ -912,25 +912,27 @@
         out_shape, other_critical_dim = _match_dot_shapes(space, self, other)
         if out:
             matches = True
-            if len(out.get_shape()) != len(out_shape):
+            if dtype != out.get_dtype():
+                matches = False
+            elif not out.implementation.order == "C":
+                matches = False
+            elif len(out.get_shape()) != len(out_shape):
                 matches = False
             else:
                 for i in range(len(out_shape)):
                     if out.get_shape()[i] != out_shape[i]:
                         matches = False
                         break
-            if dtype != out.get_dtype():
-                matches = False
-            if not out.implementation.order == "C":
-                matches = False
             if not matches:
                 raise OperationError(space.w_ValueError, space.wrap(
-                    'output array is not acceptable (must have the right type, nr dimensions, and be a C-Array)'))
+                    'output array is not acceptable (must have the right type, '
+                    'nr dimensions, and be a C-Array)'))
             w_res = out
+            w_res.fill(space, self.get_dtype().coerce(space, None))
         else:
             w_res = W_NDimArray.from_shape(space, out_shape, dtype, w_instance=self)
         # This is the place to add fpypy and blas
-        return loop.multidim_dot(space, self, other,  w_res, dtype,
+        return loop.multidim_dot(space, self, other, w_res, dtype,
                                  other_critical_dim)
 
     def descr_mean(self, space, __args__):
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -254,6 +254,13 @@
             return out
         return res
 
+    def descr_outer(self, space, __args__):
+        return self._outer(space, __args__)
+
+    def _outer(self, space, __args__):
+        raise OperationError(space.w_ValueError,
+                             space.wrap("outer product only supported for binary functions"))
+
 class W_Ufunc1(W_Ufunc):
     _immutable_fields_ = ["func", "bool_result"]
     argcount = 1
@@ -432,6 +439,7 @@
     nin = interp_attrproperty("argcount", cls=W_Ufunc),
 
     reduce = interp2app(W_Ufunc.descr_reduce),
+    outer = interp2app(W_Ufunc.descr_outer),
 )
 
 
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -146,8 +146,7 @@
     while not obj_iter.done():
         reduce_driver.jit_merge_point(shapelen=shapelen, func=func,
                                       done_func=done_func,
-                                      calc_dtype=calc_dtype,
-                                      )
+                                      calc_dtype=calc_dtype)
         rval = obj_iter.getitem().convert_to(space, calc_dtype)
         if done_func is not None and done_func(calc_dtype, rval):
             return rval
@@ -172,8 +171,7 @@
     shapelen = len(obj.get_shape())
     while not obj_iter.done():
         reduce_cum_driver.jit_merge_point(shapelen=shapelen, func=func,
-                                          dtype=calc_dtype,
-                                         )
+                                          dtype=calc_dtype)
         rval = obj_iter.getitem().convert_to(space, calc_dtype)
         cur_value = func(calc_dtype, cur_value, rval)
         out_iter.setitem(cur_value)
@@ -271,8 +269,7 @@
         iter.next()
         shapelen = len(arr.get_shape())
         while not iter.done():
-            arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype,
-                                      )
+            arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
             w_val = iter.getitem()
             new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
             if dtype.itemtype.ne(new_best, cur_best):
@@ -311,6 +308,7 @@
                                          if i != right_critical_dim]
     right_skip = range(len(left_shape) - 1)
     result_skip = [len(result.get_shape()) - (len(right_shape) > 1)]
+    assert result.get_dtype() == dtype
     outi = result.create_dot_iter(broadcast_shape, result_skip)
     lefti = left.create_dot_iter(broadcast_shape, left_skip)
     righti = right.create_dot_iter(broadcast_shape, right_skip)
@@ -318,10 +316,10 @@
         dot_driver.jit_merge_point(dtype=dtype)
         lval = lefti.getitem().convert_to(space, dtype)
         rval = righti.getitem().convert_to(space, dtype)
-        outval = outi.getitem().convert_to(space, dtype)
+        outval = outi.getitem()
         v = dtype.itemtype.mul(lval, rval)
-        value = dtype.itemtype.add(v, outval).convert_to(space, dtype)
-        outi.setitem(value)
+        v = dtype.itemtype.add(v, outval)
+        outi.setitem(v)
         outi.next()
         righti.next()
         lefti.next()
@@ -652,8 +650,8 @@
     out_iter = out.create_iter(shape)
     while not arr_iter.done():
         round_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
-        w_v = dtype.itemtype.round(arr_iter.getitem().convert_to(space, dtype),
-                     decimals)
+        w_v = arr_iter.getitem().convert_to(space, dtype)
+        w_v = dtype.itemtype.round(w_v, decimals)
         out_iter.setitem(w_v)
         arr_iter.next()
         out_iter.next()
diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py
--- a/pypy/module/micronumpy/test/test_arrayops.py
+++ b/pypy/module/micronumpy/test/test_arrayops.py
@@ -56,6 +56,10 @@
         b = arange(12).reshape(4, 3)
         c = a.dot(b)
         assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
+        c = a.dot(b.astype(float))
+        assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
+        c = a.astype(float).dot(b)
+        assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
 
         a = arange(24).reshape(2, 3, 4)
         raises(ValueError, "a.dot(a)")
@@ -91,9 +95,11 @@
         out = arange(9).reshape(3, 3)
         c = dot(a, b, out=out)
         assert (c == out).all()
-        out = arange(9,dtype=float).reshape(3, 3)
+        assert (c == [[42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
+        out = arange(9, dtype=float).reshape(3, 3)
         exc = raises(ValueError, dot, a, b, out)
-        assert exc.value[0].find('not acceptable') > 0
+        assert exc.value[0] == ('output array is not acceptable (must have the '
+                                'right type, nr dimensions, and be a C-Array)')
 
     def test_choose_basic(self):
         from numpypy import array
diff --git a/pypy/module/micronumpy/test/test_scalar.py b/pypy/module/micronumpy/test/test_scalar.py
--- a/pypy/module/micronumpy/test/test_scalar.py
+++ b/pypy/module/micronumpy/test/test_scalar.py
@@ -181,6 +181,11 @@
             s = np.dtype([('a', 'int64'), ('b', 'int64')]).type('a' * 16)
             assert s.view('S16') == 'a' * 16
 
+    def test_as_integer_ratio(self):
+        import numpy as np
+        raises(AttributeError, 'np.float32(1.5).as_integer_ratio()')
+        assert np.float64(1.5).as_integer_ratio() == (3, 2)
+
     def test_complex_scalar_complex_cast(self):
         import numpy as np
         for tp in [np.csingle, np.cdouble, np.clongdouble]:
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -1052,3 +1052,9 @@
                 np.array([0, -1, -3, -6, -10])).all()
         assert (np.divide.accumulate(todivide) ==
                 np.array([2., 4., 16.])).all()
+
+    def test_outer(self):
+        import numpy as np
+        from numpypy import absolute
+        exc = raises(ValueError, np.absolute.outer, [-1, -2])
+        assert exc.value[0] == 'outer product only supported for binary functions'
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -7,9 +7,9 @@
         from rpython.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
-                from _ffi import CDLL, types
+                from _rawffi.alt import CDLL, types
             except ImportError:
-                sys.stderr.write('SKIP: cannot import _ffi\n')
+                sys.stderr.write('SKIP: cannot import _rawffi.alt\n')
                 return 0
 
             libm = CDLL(libm_name)
@@ -45,9 +45,9 @@
         from rpython.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
-                from _ffi import CDLL, types
+                from _rawffi.alt import CDLL, types
             except ImportError:
-                sys.stderr.write('SKIP: cannot import _ffi\n')
+                sys.stderr.write('SKIP: cannot import _rawffi.alt\n')
                 return 0
 
             libm = CDLL(libm_name)
@@ -82,12 +82,12 @@
             from threading import Thread
             #
             if os.name == 'nt':
-                from _ffi import WinDLL, types
+                from _rawffi.alt import WinDLL, types
                 libc = WinDLL('Kernel32.dll')
                 sleep = libc.getfunc('Sleep', [types.uint], types.uint)
                 delays = [0]*n + [1000]
             else:
-                from _ffi import CDLL, types
+                from _rawffi.alt import CDLL, types
                 libc = CDLL(libc_name)
                 sleep = libc.getfunc('sleep', [types.uint], types.uint)
                 delays = [0]*n + [1]
@@ -144,7 +144,7 @@
 
     def test__ffi_struct(self):
         def main():
-            from _ffi import _StructDescr, Field, types
+            from _rawffi.alt import _StructDescr, Field, types
             fields = [
                 Field('x', types.slong),
                 ]
diff --git a/pypy/module/pypyjit/test_pypy_c/test_instance.py b/pypy/module/pypyjit/test_pypy_c/test_instance.py
--- a/pypy/module/pypyjit/test_pypy_c/test_instance.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_instance.py
@@ -35,7 +35,7 @@
             class A(object):
                 pass
             a = A()
-            a.x = 2
+            a.x = 1
             def main(n):
                 i = 0
                 while i < n:
@@ -49,8 +49,7 @@
             i9 = int_lt(i5, i6)
             guard_true(i9, descr=...)
             guard_not_invalidated(descr=...)
-            i10 = int_add_ovf(i5, i7)
-            guard_no_overflow(descr=...)
+            i10 = int_add(i5, 1)
             --TICK--
             jump(..., descr=...)
         """)
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -155,9 +155,7 @@
 to exc_info() will return (None,None,None) until another exception is
 raised and caught in the current thread or the execution stack returns to a
 frame where another exception is being handled."""
-    operror = space.getexecutioncontext().sys_exc_info()
-    if operror is not None:
-        operror.clear(space)
+    space.getexecutioncontext().clear_sys_exc_info()
 
 def settrace(space, w_func):
     """Set the global debug tracing function.  It will be called on each
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -1,20 +1,21 @@
 """The builtin bytearray implementation"""
 
+from rpython.rlib.objectmodel import (
+    import_from_mixin, newlist_hint, resizelist_hint)
+from rpython.rlib.rstring import StringBuilder
+
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.buffer import RWBuffer
 from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
+from pypy.interpreter.gateway import WrappedDefault, interp2app, unwrap_spec
 from pypy.interpreter.signature import Signature
 from pypy.objspace.std.sliceobject import W_SliceObject
 from pypy.objspace.std.stdtypedef import StdTypeDef
 from pypy.objspace.std.stringmethods import StringMethods
 from pypy.objspace.std.util import get_positive_index
-from rpython.rlib.objectmodel import newlist_hint, resizelist_hint, import_from_mixin
-from rpython.rlib.rstring import StringBuilder
 
+NON_HEX_MSG = "non-hexadecimal number found in fromhex() arg at position %d"
 
-def _make_data(s):
-    return [s[i] for i in range(len(s))]
 
 class W_BytearrayObject(W_Root):
     import_from_mixin(StringMethods)
@@ -23,7 +24,7 @@
         w_self.data = data
 
     def __repr__(w_self):
-        """ representation for debugging purposes """
+        """representation for debugging purposes"""
         return "%s(%s)" % (w_self.__class__.__name__, ''.join(w_self.data))
 
     def _new(self, value):
@@ -127,11 +128,6 @@
 
     @staticmethod
     def descr_fromhex(space, w_bytearraytype, w_hexstring):
-        "bytearray.fromhex(string) -> bytearray\n"
-        "\n"
-        "Create a bytearray object from a string of hexadecimal numbers.\n"
-        "Spaces between two numbers are accepted.\n"
-        "Example: bytearray.fromhex('B9 01EF') -> bytearray(b'\\xb9\\x01\\xef')."
         hexstring = space.str_w(w_hexstring)
         hexstring = hexstring.lower()
         data = []
@@ -143,18 +139,15 @@
                 i += 1
             if i >= length:
                 break
-            if i+1 == length:
-                raise OperationError(space.w_ValueError, space.wrap(
-                    "non-hexadecimal number found in fromhex() arg at position %d" % i))
+            if i + 1 == length:
+                raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i)
 
             top = _hex_digit_to_int(hexstring[i])
             if top == -1:
-                raise OperationError(space.w_ValueError, space.wrap(
-                    "non-hexadecimal number found in fromhex() arg at position %d" % i))
+                raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i)
             bot = _hex_digit_to_int(hexstring[i+1])
             if bot == -1:
-                raise OperationError(space.w_ValueError, space.wrap(
-                    "non-hexadecimal number found in fromhex() arg at position %d" % (i+1,)))
+                raise operationerrfmt(space.w_ValueError, NON_HEX_MSG, i + 1)
             data.append(chr(top*16 + bot))
 
         # in CPython bytearray.fromhex is a staticmethod, so
@@ -178,23 +171,25 @@
             from pypy.objspace.std.unicodeobject import (
                 _get_encoding_and_errors, encode_object
             )
-            encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
+            encoding, errors = _get_encoding_and_errors(space, w_encoding,
+                                                        w_errors)
 
-            # if w_source is an integer this correctly raises a TypeError
-            # the CPython error message is: "encoding or errors without a string argument"
-            # ours is: "expected unicode, got int object"
+            # if w_source is an integer this correctly raises a
+            # TypeError the CPython error message is: "encoding or
+            # errors without a string argument" ours is: "expected
+            # unicode, got int object"
             w_source = encode_object(space, w_source, encoding, errors)
 
         # Is it an int?
         try:
             count = space.int_w(w_source)
-        except OperationError, e:
+        except OperationError as e:
             if not e.match(space, space.w_TypeError):
                 raise
         else:
             if count < 0:
-                raise OperationError(space.w_ValueError,
-                                     space.wrap("bytearray negative count"))
+                raise operationerrfmt(space.w_ValueError,
+                                      "bytearray negative count")
             self.data = ['\0'] * count
             return
 
@@ -224,8 +219,8 @@
             elif not '\x20' <= c < '\x7f':
                 n = ord(c)
                 buf.append('\\x')
-                buf.append("0123456789abcdef"[n>>4])
-                buf.append("0123456789abcdef"[n&0xF])
+                buf.append("0123456789abcdef"[n >> 4])
+                buf.append("0123456789abcdef"[n & 0xF])
             else:
                 buf.append(c)
 
@@ -238,51 +233,60 @@
 
     def descr_eq(self, space, w_other):
         try:
-            return space.newbool(self._val(space) == self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) == self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
 
     def descr_ne(self, space, w_other):
         try:
-            return space.newbool(self._val(space) != self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) != self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
 
     def descr_lt(self, space, w_other):
         try:
-            return space.newbool(self._val(space) < self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) < self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
 
     def descr_le(self, space, w_other):
         try:
-            return space.newbool(self._val(space) <= self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) <= self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
 
     def descr_gt(self, space, w_other):
         try:
-            return space.newbool(self._val(space) > self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) > self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
 
     def descr_ge(self, space, w_other):
         try:
-            return space.newbool(self._val(space) >= self._op_val(space, w_other))
-        except OperationError, e:
+            res = self._val(space) >= self._op_val(space, w_other)
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
+        return space.newbool(res)
+
+    def descr_iter(self, space):
+        return space.newseqiter(self)
 
     def descr_buffer(self, space):
         return BytearrayBuffer(self.data)
@@ -297,7 +301,7 @@
     def descr_inplace_mul(self, space, w_times):
         try:
             times = space.getindex_w(w_times, space.w_OverflowError)
-        except OperationError, e:
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
@@ -312,12 +316,13 @@
             _setitem_slice_helper(space, self.data, start, step,
                                   slicelength, sequence2, empty_elem='\x00')
         else:
-            idx = space.getindex_w(w_index, space.w_IndexError, "bytearray index")
+            idx = space.getindex_w(w_index, space.w_IndexError,
+                                   "bytearray index")
             try:
                 self.data[idx] = getbytevalue(space, w_other)
             except IndexError:
-                raise OperationError(space.w_IndexError,
-                                     space.wrap("bytearray index out of range"))
+                raise operationerrfmt(space.w_IndexError,
+                                      "bytearray index out of range")
 
     def descr_delitem(self, space, w_idx):
         if isinstance(w_idx, W_SliceObject):
@@ -325,12 +330,13 @@
                                                             len(self.data))
             _delitem_slice_helper(space, self.data, start, step, slicelength)
         else:
-            idx = space.getindex_w(w_idx, space.w_IndexError, "bytearray index")
+            idx = space.getindex_w(w_idx, space.w_IndexError,
+                                   "bytearray index")
             try:
                 del self.data[idx]
             except IndexError:
-                raise OperationError(space.w_IndexError,
-                                     space.wrap("bytearray deletion index out of range"))
+                raise operationerrfmt(space.w_IndexError,
+                                      "bytearray deletion index out of range")
 
     def descr_append(self, space, w_item):
         self.data.append(getbytevalue(space, w_item))
@@ -357,10 +363,9 @@
             result = self.data.pop(index)
         except IndexError:
             if not self.data:
-                raise OperationError(space.w_IndexError, space.wrap(
-                    "pop from empty bytearray"))
-            raise OperationError(space.w_IndexError, space.wrap(
-                "pop index out of range"))
+                raise operationerrfmt(space.w_IndexError,
+                                      "pop from empty bytearray")
+            raise operationerrfmt(space.w_IndexError, "pop index out of range")
         return space.wrap(ord(result))
 
     def descr_remove(self, space, w_char):
@@ -368,27 +373,55 @@
         try:
             self.data.remove(chr(char))
         except ValueError:
-            raise OperationError(space.w_ValueError, space.wrap(
-                "value not found in bytearray"))
+            raise operationerrfmt(space.w_ValueError,
+                                  "value not found in bytearray")
+
+    _StringMethods_descr_contains = descr_contains
+    def descr_contains(self, space, w_sub):
+        if space.isinstance_w(w_sub, space.w_int):
+            char = space.int_w(w_sub)
+            return _descr_contains_bytearray(self.data, space, char)
+        return self._StringMethods_descr_contains(space, w_sub)
 
     def descr_reverse(self, space):
         self.data.reverse()
 
+
+# ____________________________________________________________
+# helpers for slow paths, moved out because they contain loops
+
+def _make_data(s):
+    return [s[i] for i in range(len(s))]
+
+
+def _descr_contains_bytearray(data, space, char):
+    if not 0 <= char < 256:
+        raise operationerrfmt(space.w_ValueError,
+                              "byte must be in range(0, 256)")
+    for c in data:
+        if ord(c) == char:
+            return space.w_True
+    return space.w_False
+
+# ____________________________________________________________
+
+
 def getbytevalue(space, w_value):
     if space.isinstance_w(w_value, space.w_str):
         string = space.str_w(w_value)
         if len(string) != 1:
-            raise OperationError(space.w_ValueError, space.wrap(
-                "string must be of size 1"))
+            raise operationerrfmt(space.w_ValueError,
+                                  "string must be of size 1")
         return string[0]
 
     value = space.getindex_w(w_value, None)
     if not 0 <= value < 256:
         # this includes the OverflowError in case the long is too large
-        raise OperationError(space.w_ValueError, space.wrap(
-            "byte must be in range(0, 256)"))
+        raise operationerrfmt(space.w_ValueError,
+                              "byte must be in range(0, 256)")
     return chr(value)
 
+
 def new_bytearray(space, w_bytearraytype, data):
     w_obj = space.allocate_instance(W_BytearrayObject, w_bytearraytype)
     W_BytearrayObject.__init__(w_obj, data)
@@ -399,7 +432,7 @@
     # String-like argument
     try:
         string = space.bufferstr_new_w(w_source)
-    except OperationError, e:
+    except OperationError as e:
         if not e.match(space, space.w_TypeError):
             raise
     else:
@@ -413,7 +446,7 @@
     while True:
         try:
             w_item = space.next(w_iter)
-        except OperationError, e:
+        except OperationError as e:
             if not e.match(space, space.w_StopIteration):
                 raise
             break
@@ -424,6 +457,7 @@
         resizelist_hint(data, extended)
     return data
 
+
 def _hex_digit_to_int(d):
     val = ord(d)
     if 47 < val < 58:
@@ -560,12 +594,12 @@
     def decode():
         """B.decode(encoding=None, errors='strict') -> unicode
 
-        Decode B using the codec registered for encoding. encoding defaults
-        to the default encoding. errors may be given to set a different error
-        handling scheme.  Default is 'strict' meaning that encoding errors raise
-        a UnicodeDecodeError.  Other possible values are 'ignore' and 'replace'
-        as well as any other name registered with codecs.register_error that is
-        able to handle UnicodeDecodeErrors.
+        Decode B using the codec registered for encoding. encoding defaults to
+        the default encoding. errors may be given to set a different error
+        handling scheme.  Default is 'strict' meaning that encoding errors
+        raise a UnicodeDecodeError.  Other possible values are 'ignore' and
+        'replace' as well as any other name registered with
+        codecs.register_error that is able to handle UnicodeDecodeErrors.
         """
 
     def endswith():
@@ -602,7 +636,7 @@
         """
 
     def fromhex():
-        """bytearray.fromhex(string) -> bytearray (static method)
+        r"""bytearray.fromhex(string) -> bytearray (static method)
 
         Create a bytearray object from a string of hexadecimal numbers.
         Spaces between two numbers are accepted.
@@ -884,6 +918,8 @@
     __ge__ = interp2app(W_BytearrayObject.descr_ge,
                         doc=BytearrayDocstrings.__ge__.__doc__),
 
+    __iter__ = interp2app(W_BytearrayObject.descr_iter,
+                         doc=BytearrayDocstrings.__iter__.__doc__),
     __len__ = interp2app(W_BytearrayObject.descr_len,
                          doc=BytearrayDocstrings.__len__.__doc__),
     __contains__ = interp2app(W_BytearrayObject.descr_contains,
@@ -1024,9 +1060,10 @@
 
 _space_chars = ''.join([chr(c) for c in [9, 10, 11, 12, 13, 32]])
 
-#XXX share the code again with the stuff in listobject.py
+
+# XXX share the code again with the stuff in listobject.py
 def _delitem_slice_helper(space, items, start, step, slicelength):
-    if slicelength==0:
+    if slicelength == 0:
         return
 
     if step < 0:
@@ -1056,6 +1093,7 @@
         assert start >= 0 # annotator hint
         del items[start:]
 
+
 def _setitem_slice_helper(space, items, start, step, slicelength, sequence2,
                           empty_elem):
     assert slicelength >= 0
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
@@ -1,19 +1,23 @@
 """The builtin str implementation"""
 
+from rpython.rlib.jit import we_are_jitted
+from rpython.rlib.objectmodel import (
+    compute_hash, compute_unique_id, import_from_mixin)
+from rpython.rlib.rstring import StringBuilder, replace
+
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.buffer import StringBuffer
 from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault, interpindirect2app
+from pypy.interpreter.gateway import (
+    WrappedDefault, interp2app, interpindirect2app, unwrap_spec)
 from pypy.objspace.std import newformat
 from pypy.objspace.std.basestringtype import basestring_typedef
 from pypy.objspace.std.formatting import mod_format
 from pypy.objspace.std.stdtypedef import StdTypeDef
 from pypy.objspace.std.stringmethods import StringMethods
-from pypy.objspace.std.unicodeobject import (unicode_from_string,
-    decode_object, unicode_from_encoded_object, _get_encoding_and_errors)
-from rpython.rlib.jit import we_are_jitted
-from rpython.rlib.objectmodel import compute_hash, compute_unique_id, import_from_mixin
-from rpython.rlib.rstring import StringBuilder, replace
+from pypy.objspace.std.unicodeobject import (
+    _get_encoding_and_errors, decode_object, unicode_from_encoded_object,
+    unicode_from_string)
 
 
 class W_AbstractBytesObject(W_Root):
@@ -184,8 +188,8 @@
     def descr_format(self, space, __args__):
         """S.format(*args, **kwargs) -> string
 
-        Return a formatted version of S, using substitutions from args and kwargs.
-        The substitutions are identified by braces ('{' and '}').
+        Return a formatted version of S, using substitutions from args and
+        kwargs.  The substitutions are identified by braces ('{' and '}').
         """
 
     def descr_index(self, space, w_sub, w_start=None, w_end=None):
@@ -319,8 +323,8 @@
         """S.rpartition(sep) -> (head, sep, tail)
 
         Search for the separator sep in S, starting at the end of S, and return
-        the part before it, the separator itself, and the part after it.  If the
-        separator is not found, return two empty strings and S.
+        the part before it, the separator itself, and the part after it.  If
+        the separator is not found, return two empty strings and S.
         """
 
     @unwrap_spec(maxsplit=int)
@@ -432,7 +436,7 @@
         self._value = str
 
     def __repr__(self):
-        """ representation for debugging purposes """
+        """representation for debugging purposes"""
         return "%s(%r)" % (self.__class__.__name__, self._value)
 
     def unwrap(self, space):
@@ -521,7 +525,7 @@
         return space.newlist_bytes(lst)
 
     @staticmethod
-    @unwrap_spec(w_object = WrappedDefault(""))
+    @unwrap_spec(w_object=WrappedDefault(""))
     def descr_new(space, w_stringtype, w_object):
         # NB. the default value of w_object is really a *wrapped* empty string:
         #     there is gateway magic at work
@@ -624,7 +628,8 @@
     _StringMethods_descr_add = descr_add
     def descr_add(self, space, w_other):
         if space.isinstance_w(w_other, space.w_unicode):
-            self_as_unicode = unicode_from_encoded_object(space, self, None, None)
+            self_as_unicode = unicode_from_encoded_object(space, self, None,
+                                                          None)
             return space.add(self_as_unicode, w_other)
         elif space.isinstance_w(w_other, space.w_bytearray):
             # XXX: eliminate double-copy
@@ -635,7 +640,7 @@
             from pypy.objspace.std.strbufobject import W_StringBufferObject
             try:
                 other = self._op_val(space, w_other)
-            except OperationError, e:
+            except OperationError as e:
                 if e.match(space, space.w_TypeError):
                     return space.w_NotImplemented
                 raise
@@ -648,24 +653,32 @@
     _StringMethods__startswith = _startswith
     def _startswith(self, space, value, w_prefix, start, end):
         if space.isinstance_w(w_prefix, space.w_unicode):
-            self_as_unicode = unicode_from_encoded_object(space, self, None, None)
-            return self_as_unicode._startswith(space, self_as_unicode._value, w_prefix, start, end)
-        return self._StringMethods__startswith(space, value, w_prefix, start, end)
+            self_as_unicode = unicode_from_encoded_object(space, self, None,
+                                                          None)
+            return self_as_unicode._startswith(space, self_as_unicode._value,
+                                               w_prefix, start, end)
+        return self._StringMethods__startswith(space, value, w_prefix, start,
+                                               end)
 
     _StringMethods__endswith = _endswith
     def _endswith(self, space, value, w_suffix, start, end):
         if space.isinstance_w(w_suffix, space.w_unicode):
-            self_as_unicode = unicode_from_encoded_object(space, self, None, None)
-            return self_as_unicode._endswith(space, self_as_unicode._value, w_suffix, start, end)
-        return self._StringMethods__endswith(space, value, w_suffix, start, end)
+            self_as_unicode = unicode_from_encoded_object(space, self, None,
+                                                          None)
+            return self_as_unicode._endswith(space, self_as_unicode._value,
+                                             w_suffix, start, end)
+        return self._StringMethods__endswith(space, value, w_suffix, start,
+                                             end)
 
     _StringMethods_descr_contains = descr_contains
     def descr_contains(self, space, w_sub):
         if space.isinstance_w(w_sub, space.w_unicode):
             from pypy.objspace.std.unicodeobject import W_UnicodeObject
             assert isinstance(w_sub, W_UnicodeObject)
-            self_as_unicode = unicode_from_encoded_object(space, self, None, None)
-            return space.newbool(self_as_unicode._value.find(w_sub._value) >= 0)
+            self_as_unicode = unicode_from_encoded_object(space, self, None,
+                                                          None)
+            return space.newbool(
+                self_as_unicode._value.find(w_sub._value) >= 0)
         return self._StringMethods_descr_contains(space, w_sub)
 
     _StringMethods_descr_replace = descr_replace
@@ -685,16 +698,19 @@
             try:
                 res = replace(input, sub, by, count)
             except OverflowError:
-                raise OperationError(space.w_OverflowError,
-                                     space.wrap("replace string is too long"))
+                raise operationerrfmt(space.w_OverflowError,
+                                      "replace string is too long")
             return self_as_uni._new(res)
         return self._StringMethods_descr_replace(space, w_old, w_new, count)
 
-    def descr_lower(self, space):
-        return W_BytesObject(self._value.lower())
-
-    def descr_upper(self, space):
-        return W_BytesObject(self._value.upper())
+    _StringMethods_descr_join = descr_join
+    def descr_join(self, space, w_list):
+        l = space.listview_bytes(w_list)
+        if l is not None:
+            if len(l) == 1:
+                return space.wrap(l[0])
+            return space.wrap(self._val(space).join(l))
+        return self._StringMethods_descr_join(space, w_list)
 
     def _join_return_one(self, space, w_obj):
         return (space.is_w(space.type(w_obj), space.w_str) or
@@ -714,6 +730,12 @@
         w_u = space.call_function(space.w_unicode, self)
         return space.call_method(w_u, "join", w_list)
 
+    def descr_lower(self, space):
+        return W_BytesObject(self._value.lower())
+
+    def descr_upper(self, space):
+        return W_BytesObject(self._value.upper())
+
     def descr_formatter_parser(self, space):
         from pypy.objspace.std.newformat import str_template_formatter
         tformat = str_template_formatter(space, space.str_w(self))
@@ -751,6 +773,7 @@
                 return W_BytesObject.EMPTY
     return W_BytesObject(s)
 
+
 def wrapchar(space, c):
     if space.config.objspace.std.withprebuiltchar and not we_are_jitted():
         return W_BytesObject.PREBUILT[ord(c)]
@@ -830,7 +853,8 @@
     __format__ = interpindirect2app(W_BytesObject.descr__format__),
     __mod__ = interpindirect2app(W_BytesObject.descr_mod),
     __buffer__ = interpindirect2app(W_AbstractBytesObject.descr_buffer),
-    __getnewargs__ = interpindirect2app(W_AbstractBytesObject.descr_getnewargs),
+    __getnewargs__ = interpindirect2app(
+        W_AbstractBytesObject.descr_getnewargs),
     _formatter_parser = interp2app(W_BytesObject.descr_formatter_parser),
     _formatter_field_name_split =
         interp2app(W_BytesObject.descr_formatter_field_name_split),
@@ -865,8 +889,8 @@
                 buf.append_slice(s, startslice, i)
             startslice = i + 1
             buf.append('\\x')
-            buf.append("0123456789abcdef"[n>>4])
-            buf.append("0123456789abcdef"[n&0xF])
+            buf.append("0123456789abcdef"[n >> 4])
+            buf.append("0123456789abcdef"[n & 0xF])
 
         if use_bs_char:
             if i != startslice:
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -162,9 +162,9 @@
         return self
 
     @staticmethod
-    def newlist_bytes(space, list_s):
+    def newlist_bytes(space, list_b):
         strategy = space.fromcache(BytesListStrategy)
-        storage = strategy.erase(list_s)
+        storage = strategy.erase(list_b)
         return W_ListObject.from_storage_and_strategy(space, storage, strategy)
 
     @staticmethod
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -1,15 +1,16 @@
 import weakref
-from rpython.rlib import jit, objectmodel, debug
+
+from rpython.rlib import jit, objectmodel, debug, rerased
 from rpython.rlib.rarithmetic import intmask, r_uint
-from rpython.rlib import rerased
 
 from pypy.interpreter.baseobjspace import W_Root
-from pypy.objspace.std.dictmultiobject import W_DictMultiObject, DictStrategy, ObjectDictStrategy
-from pypy.objspace.std.dictmultiobject import BaseKeyIterator, BaseValueIterator, BaseItemIterator
-from pypy.objspace.std.dictmultiobject import _never_equal_to_string
-from pypy.objspace.std.objectobject import W_ObjectObject
+from pypy.objspace.std.dictmultiobject import (
+    W_DictMultiObject, DictStrategy, ObjectDictStrategy, BaseKeyIterator,
+    BaseValueIterator, BaseItemIterator, _never_equal_to_string
+)
 from pypy.objspace.std.typeobject import TypeCell
 
+
 # ____________________________________________________________
 # attribute shapes
 
@@ -19,7 +20,7 @@
 # we want to propagate knowledge that the result cannot be negative
 
 class AbstractAttribute(object):
-    _immutable_fields_ = ['terminator']
+    _immutable_fields_ = ['terminator', 'ever_mutated?']
     cache_attrs = None
     _size_estimate = 0
 
@@ -27,46 +28,60 @@
         self.space = space
         assert isinstance(terminator, Terminator)
         self.terminator = terminator
+        self.ever_mutated = False
 
     def read(self, obj, selector):
-        index = self.index(selector)
-        if index < 0:
+        attr = self.find_map_attr(selector)
+        if attr is None:
             return self.terminator._read_terminator(obj, selector)
-        return obj._mapdict_read_storage(index)
+        if (
+            jit.isconstant(attr.storageindex) and
+            jit.isconstant(obj) and
+            not attr.ever_mutated
+        ):
+            return self._pure_mapdict_read_storage(obj, attr.storageindex)
+        else:
+            return obj._mapdict_read_storage(attr.storageindex)
+
+    @jit.elidable
+    def _pure_mapdict_read_storage(self, obj, storageindex):
+        return obj._mapdict_read_storage(storageindex)
 
     def write(self, obj, selector, w_value):
-        index = self.index(selector)
-        if index < 0:
+        attr = self.find_map_attr(selector)
+        if attr is None:
             return self.terminator._write_terminator(obj, selector, w_value)
-        obj._mapdict_write_storage(index, w_value)
+        if not attr.ever_mutated:
+            attr.ever_mutated = True
+        obj._mapdict_write_storage(attr.storageindex, w_value)
         return True
 
     def delete(self, obj, selector):
         return None
 
-    def index(self, selector):
+    def find_map_attr(self, selector):
         if jit.we_are_jitted():
             # hack for the jit:
-            # the _index method is pure too, but its argument is never
+            # the _find_map_attr method is pure too, but its argument is never
             # constant, because it is always a new tuple
-            return self._index_jit_pure(selector[0], selector[1])
+            return self._find_map_attr_jit_pure(selector[0], selector[1])
         else:
-            return self._index_indirection(selector)
+            return self._find_map_attr_indirection(selector)
 
     @jit.elidable
-    def _index_jit_pure(self, name, index):
-        return self._index_indirection((name, index))
+    def _find_map_attr_jit_pure(self, name, index):
+        return self._find_map_attr_indirection((name, index))
 
     @jit.dont_look_inside
-    def _index_indirection(self, selector):
+    def _find_map_attr_indirection(self, selector):
         if (self.space.config.objspace.std.withmethodcache):
-            return self._index_cache(selector)
-        return self._index(selector)
+            return self._find_map_attr_cache(selector)
+        return self._find_map_attr(selector)
 
     @jit.dont_look_inside
-    def _index_cache(self, selector):
+    def _find_map_attr_cache(self, selector):
         space = self.space
-        cache = space.fromcache(IndexCache)
+        cache = space.fromcache(MapAttrCache)
         SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
         SHIFT1 = SHIFT2 - 5
         attrs_as_int = objectmodel.current_object_addr_as_int(self)
@@ -74,32 +89,32 @@
         # _pure_lookup_where_with_method_cache()
         hash_selector = objectmodel.compute_hash(selector)
         product = intmask(attrs_as_int * hash_selector)
-        index_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
+        attr_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
         # ^^^Note2: same comment too
-        cached_attr = cache.attrs[index_hash]
+        cached_attr = cache.attrs[attr_hash]
         if cached_attr is self:
-            cached_selector = cache.selectors[index_hash]
+            cached_selector = cache.selectors[attr_hash]
             if cached_selector == selector:
-                index = cache.indices[index_hash]
+                attr = cache.cached_attrs[attr_hash]
                 if space.config.objspace.std.withmethodcachecounter:
                     name = selector[0]
                     cache.hits[name] = cache.hits.get(name, 0) + 1
-                return index
-        index = self._index(selector)
-        cache.attrs[index_hash] = self
-        cache.selectors[index_hash] = selector
-        cache.indices[index_hash] = index
+                return attr
+        attr = self._find_map_attr(selector)
+        cache.attrs[attr_hash] = self
+        cache.selectors[attr_hash] = selector
+        cache.cached_attrs[attr_hash] = attr
         if space.config.objspace.std.withmethodcachecounter:
             name = selector[0]
             cache.misses[name] = cache.misses.get(name, 0) + 1
-        return index
+        return attr
 
-    def _index(self, selector):
+    def _find_map_attr(self, selector):
         while isinstance(self, PlainAttribute):
             if selector == self.selector:
-                return self.position
+                return self
             self = self.back
-        return -1
+        return None
 
     def copy(self, obj):
         raise NotImplementedError("abstract base class")
@@ -155,7 +170,7 @@
         # the order is important here: first change the map, then the storage,
         # for the benefit of the special subclasses
         obj._set_mapdict_map(attr)
-        obj._mapdict_write_storage(attr.position, w_value)
+        obj._mapdict_write_storage(attr.storageindex, w_value)
 
     def materialize_r_dict(self, space, obj, dict_w):
         raise NotImplementedError("abstract base class")
@@ -261,11 +276,11 @@
         return Terminator.set_terminator(self, obj, terminator)
 
 class PlainAttribute(AbstractAttribute):
-    _immutable_fields_ = ['selector', 'position', 'back']
+    _immutable_fields_ = ['selector', 'storageindex', 'back']
     def __init__(self, selector, back):
         AbstractAttribute.__init__(self, back.space, back.terminator)
         self.selector = selector
-        self.position = back.length()
+        self.storageindex = back.length()
         self.back = back
         self._size_estimate = self.length() * NUM_DIGITS_POW2
 
@@ -288,7 +303,7 @@
         return new_obj
 
     def length(self):
-        return self.position + 1
+        return self.storageindex + 1
 
     def set_terminator(self, obj, terminator):
         new_obj = self.back.set_terminator(obj, terminator)
@@ -304,7 +319,7 @@
         new_obj = self.back.materialize_r_dict(space, obj, dict_w)
         if self.selector[1] == DICT:
             w_attr = space.wrap(self.selector[0])
-            dict_w[w_attr] = obj._mapdict_read_storage(self.position)
+            dict_w[w_attr] = obj._mapdict_read_storage(self.storageindex)
         else:
             self._copy_attr(obj, new_obj)
         return new_obj
@@ -316,21 +331,21 @@
         return new_obj
 
     def __repr__(self):
-        return "<PlainAttribute %s %s %r>" % (self.selector, self.position, self.back)
+        return "<PlainAttribute %s %s %r>" % (self.selector, self.storageindex, self.back)
 
 def _become(w_obj, new_obj):
     # this is like the _become method, really, but we cannot use that due to
     # RPython reasons
     w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
 
-class IndexCache(object):
+class MapAttrCache(object):
     def __init__(self, space):
         assert space.config.objspace.std.withmethodcache
         SIZE = 1 << space.config.objspace.std.methodcachesizeexp
         self.attrs = [None] * SIZE
         self._empty_selector = (None, INVALID)
         self.selectors = [self._empty_selector] * SIZE
-        self.indices = [0] * SIZE
+        self.cached_attrs = [None] * SIZE
         if space.config.objspace.std.withmethodcachecounter:
             self.hits = {}
             self.misses = {}
@@ -340,6 +355,8 @@
             self.attrs[i] = None
         for i in range(len(self.selectors)):
             self.selectors[i] = self._empty_selector
+        for i in range(len(self.cached_attrs)):
+            self.cached_attrs[i] = None
 
 # ____________________________________________________________
 # object implementation
@@ -416,16 +433,16 @@
                 self.typedef is W_InstanceObject.typedef)
         self._init_empty(w_subtype.terminator)
 
-    def getslotvalue(self, index):
-        key = ("slot", SLOTS_STARTING_FROM + index)
+    def getslotvalue(self, slotindex):
+        key = ("slot", SLOTS_STARTING_FROM + slotindex)
         return self._get_mapdict_map().read(self, key)
 
-    def setslotvalue(self, index, w_value):
-        key = ("slot", SLOTS_STARTING_FROM + index)
+    def setslotvalue(self, slotindex, w_value):
+        key = ("slot", SLOTS_STARTING_FROM + slotindex)
         self._get_mapdict_map().write(self, key, w_value)
 
-    def delslotvalue(self, index):
-        key = ("slot", SLOTS_STARTING_FROM + index)
+    def delslotvalue(self, slotindex):
+        key = ("slot", SLOTS_STARTING_FROM + slotindex)
         new_obj = self._get_mapdict_map().delete(self, key)
         if new_obj is None:
             return False
@@ -460,11 +477,13 @@
         self.map = map
         self.storage = make_sure_not_resized([None] * map.size_estimate())
 
-    def _mapdict_read_storage(self, index):
-        assert index >= 0
-        return self.storage[index]
-    def _mapdict_write_storage(self, index, value):
-        self.storage[index] = value
+    def _mapdict_read_storage(self, storageindex):
+        assert storageindex >= 0
+        return self.storage[storageindex]
+
+    def _mapdict_write_storage(self, storageindex, value):
+        self.storage[storageindex] = value
+
     def _mapdict_storage_length(self):
         return len(self.storage)
     def _set_mapdict_storage_and_map(self, storage, map):
@@ -519,7 +538,6 @@
     rangenmin1 = unroll.unrolling_iterable(range(nmin1))
     class subcls(BaseMapdictObject, supercls):
         def _init_empty(self, map):
-            from rpython.rlib.debug import make_sure_not_resized
             for i in rangen:
                 setattr(self, "_value%s" % i, erase_item(None))
             self.map = map
@@ -531,26 +549,26 @@
             erased = getattr(self, "_value%s" % nmin1)
             return unerase_list(erased)
 
-        def _mapdict_read_storage(self, index):
-            assert index >= 0
-            if index < nmin1:
+        def _mapdict_read_storage(self, storageindex):
+            assert storageindex >= 0
+            if storageindex < nmin1:
                 for i in rangenmin1:
-                    if index == i:
+                    if storageindex == i:
                         erased = getattr(self, "_value%s" % i)
                         return unerase_item(erased)
             if self._has_storage_list():
-                return self._mapdict_get_storage_list()[index - nmin1]
+                return self._mapdict_get_storage_list()[storageindex - nmin1]
             erased = getattr(self, "_value%s" % nmin1)
             return unerase_item(erased)
 
-        def _mapdict_write_storage(self, index, value):
+        def _mapdict_write_storage(self, storageindex, value):
             erased = erase_item(value)
             for i in rangenmin1:
-                if index == i:
+                if storageindex == i:
                     setattr(self, "_value%s" % i, erased)
                     return
             if self._has_storage_list():
-                self._mapdict_get_storage_list()[index - nmin1] = value
+                self._mapdict_get_storage_list()[storageindex - nmin1] = value
                 return
             setattr(self, "_value%s" % nmin1, erased)
 
@@ -785,7 +803,7 @@
 
 class CacheEntry(object):
     version_tag = None
-    index = 0
+    storageindex = 0
     w_method = None # for callmethod
     success_counter = 0
     failure_counter = 0
@@ -818,14 +836,14 @@
     pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries
 
 @jit.dont_look_inside
-def _fill_cache(pycode, nameindex, map, version_tag, index, w_method=None):
+def _fill_cache(pycode, nameindex, map, version_tag, storageindex, w_method=None):
     entry = pycode._mapdict_caches[nameindex]
     if entry is INVALID_CACHE_ENTRY:
         entry = CacheEntry()
         pycode._mapdict_caches[nameindex] = entry
     entry.map_wref = weakref.ref(map)
     entry.version_tag = version_tag
-    entry.index = index
+    entry.storageindex = storageindex
     entry.w_method = w_method
     if pycode.space.config.objspace.std.withmethodcachecounter:
         entry.failure_counter += 1
@@ -837,7 +855,7 @@
     map = w_obj._get_mapdict_map()
     if entry.is_valid_for_map(map) and entry.w_method is None:
         # everything matches, it's incredibly fast
-        return w_obj._mapdict_read_storage(entry.index)
+        return w_obj._mapdict_read_storage(entry.storageindex)
     return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, map)
 LOAD_ATTR_caching._always_inline_ = True
 
@@ -871,19 +889,19 @@
                     selector = ("slot", SLOTS_STARTING_FROM + w_descr.index)
             else:
                 # There is a non-data descriptor in the class.  If there is
-                # also a dict attribute, use the latter, caching its position.
+                # also a dict attribute, use the latter, caching its storageindex.
                 # If not, we loose.  We could do better in this case too,
                 # but we don't care too much; the common case of a method
                 # invocation is handled by LOOKUP_METHOD_xxx below.
                 selector = (name, DICT)
             #
             if selector[1] != INVALID:
-                index = map.index(selector)
-                if index >= 0:
+                attr = map.find_map_attr(selector)
+                if attr is not None:
                     # Note that if map.terminator is a DevolvedDictTerminator,
-                    # map.index() will always return -1 if selector[1]==DICT.
-                    _fill_cache(pycode, nameindex, map, version_tag, index)
-                    return w_obj._mapdict_read_storage(index)
+                    # map.find_map_attr will always return None if selector[1]==DICT.
+                    _fill_cache(pycode, nameindex, map, version_tag, attr.storageindex)
+                    return w_obj._mapdict_read_storage(attr.storageindex)
     if space.config.objspace.std.withmethodcachecounter:
         INVALID_CACHE_ENTRY.failure_counter += 1
     return space.getattr(w_obj, w_name)
diff --git a/pypy/objspace/std/stringmethods.py b/pypy/objspace/std/stringmethods.py
--- a/pypy/objspace/std/stringmethods.py
+++ b/pypy/objspace/std/stringmethods.py
@@ -1,18 +1,22 @@
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
-from pypy.objspace.std import slicetype
-from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+"""Functionality shared between bytes/bytearray/unicode"""
+
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import ovfcheck
-from rpython.rlib.rstring import split, rsplit, replace, startswith, endswith
+from rpython.rlib.rstring import endswith, replace, rsplit, split, startswith
+
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import WrappedDefault, unwrap_spec
+from pypy.objspace.std import slicetype
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
 
 
 class StringMethods(object):
     def _sliced(self, space, s, start, stop, orig_obj):
         assert start >= 0
         assert stop >= 0
-        #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj), space.w_str):
+        #if start == 0 and stop == len(s) and space.is_w(space.type(orig_obj),
+        #                                                space.w_str):
         #    return orig_obj
         return self._new(s[start:stop])
 
@@ -21,7 +25,7 @@
         value = self._val(space)
         lenself = len(value)
         start, end = slicetype.unwrap_start_stop(
-                space, lenself, w_start, w_end, upper_bound=upper_bound)
+            space, lenself, w_start, w_end, upper_bound=upper_bound)
         return (value, start, end)
 
     def descr_len(self, space):
@@ -31,17 +35,14 @@
     #    pass
 
     def descr_contains(self, space, w_sub):
-        from pypy.objspace.std.bytearrayobject import W_BytearrayObject
-        if (isinstance(self, W_BytearrayObject) and
-            space.isinstance_w(w_sub, space.w_int)):
-            char = space.int_w(w_sub)
-            return _descr_contains_bytearray(self.data, space, char)
-        return space.newbool(self._val(space).find(self._op_val(space, w_sub)) >= 0)
+        value = self._val(space)
+        other = self._op_val(space, w_sub)
+        return space.newbool(value.find(other) >= 0)
 
     def descr_add(self, space, w_other):
         try:
             other = self._op_val(space, w_other)
-        except OperationError, e:
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
@@ -50,7 +51,7 @@
     def descr_mul(self, space, w_times):
         try:
             times = space.getindex_w(w_times, space.w_OverflowError)
-        except OperationError, e:
+        except OperationError as e:
             if e.match(space, space.w_TypeError):
                 return space.w_NotImplemented
             raise
@@ -82,12 +83,11 @@
         if index < 0:
             index += selflen
         if index < 0 or index >= selflen:
-            raise OperationError(space.w_IndexError,
-                                 space.wrap("string index out of range"))
+            raise operationerrfmt(space.w_IndexError,
+                                  "string index out of range")
         from pypy.objspace.std.bytearrayobject import W_BytearrayObject
         if isinstance(self, W_BytearrayObject):
             return space.wrap(ord(selfvalue[index]))
-        #return wrapchar(space, selfvalue[index])
         return self._new(selfvalue[index])
 
     def descr_getslice(self, space, w_start, w_stop):
@@ -115,35 +115,39 @@
         value = self._val(space)
         fillchar = self._op_val(space, w_fillchar)
         if len(fillchar) != 1:
-            raise OperationError(space.w_TypeError,
-                space.wrap("center() argument 2 must be a single character"))
+            raise operationerrfmt(space.w_TypeError,
+                                  "center() argument 2 must be a single "
+                                  "character")
 
         d = width - len(value)
-        if d>0:
+        if d > 0:
             offset = d//2 + (d & width & 1)
             fillchar = fillchar[0]    # annotator hint: it's a single character
-            u_centered = offset * fillchar + value + (d - offset) * fillchar
+            centered = offset * fillchar + value + (d - offset) * fillchar
         else:
-            u_centered = value
+            centered = value
 
-        return self._new(u_centered)
+        return self._new(centered)
 
     def descr_count(self, space, w_sub, w_start=None, w_end=None):
         value, start, end = self._convert_idx_params(space, w_start, w_end)
-        return space.newint(value.count(self._op_val(space, w_sub), start, end))
+        return space.newint(value.count(self._op_val(space, w_sub), start,
+                                        end))
 
     def descr_decode(self, space, w_encoding=None, w_errors=None):
-        from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \
-            unicode_from_string, decode_object
-        encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
+        from pypy.objspace.std.unicodeobject import (
+            _get_encoding_and_errors, decode_object, unicode_from_string)
+        encoding, errors = _get_encoding_and_errors(space, w_encoding,
+                                                    w_errors)
         if encoding is None and errors is None:
             return unicode_from_string(space, self)
         return decode_object(space, self, encoding, errors)
 
     def descr_encode(self, space, w_encoding=None, w_errors=None):
-        from pypy.objspace.std.unicodeobject import _get_encoding_and_errors, \
-            encode_object
-        encoding, errors = _get_encoding_and_errors(space, w_encoding, w_errors)
+        from pypy.objspace.std.unicodeobject import (
+            _get_encoding_and_errors, encode_object)
+        encoding, errors = _get_encoding_and_errors(space, w_encoding,
+                                                    w_errors)
         return encode_object(space, self, encoding, errors)
 
     @unwrap_spec(tabsize=int)
@@ -156,18 +160,19 @@
         try:
             ovfcheck(len(splitted) * tabsize)
         except OverflowError:
-            raise OperationError(space.w_OverflowError,
-                                 space.wrap("new string is too long"))
+            raise operationerrfmt(space.w_OverflowError,
+                                  "new string is too long")
         expanded = oldtoken = splitted.pop(0)
 
         for token in splitted:
-            expanded += self._chr(' ') * self._tabindent(oldtoken, tabsize) + token
+            expanded += self._chr(' ') * self._tabindent(oldtoken,
+                                                         tabsize) + token
             oldtoken = token
 
         return self._new(expanded)
 
     def _tabindent(self, token, tabsize):
-        "calculates distance behind the token to the next tabstop"
+        """calculates distance behind the token to the next tabstop"""
 
         distance = tabsize
         if token:
@@ -203,8 +208,8 @@
         (value, start, end) = self._convert_idx_params(space, w_start, w_end)
         res = value.find(self._op_val(space, w_sub), start, end)
         if res < 0:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("substring not found in string.index"))
+            raise operationerrfmt(space.w_ValueError,
+                                  "substring not found in string.index")
 
         return space.wrap(res)
 
@@ -212,8 +217,8 @@
         (value, start, end) = self._convert_idx_params(space, w_start, w_end)
         res = value.rfind(self._op_val(space, w_sub), start, end)
         if res < 0:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("substring not found in string.rindex"))
+            raise operationerrfmt(space.w_ValueError,
+                                  "substring not found in string.rindex")
 
         return space.wrap(res)
 
@@ -307,22 +312,6 @@
         return space.newbool(cased)
 
     def descr_join(self, space, w_list):
-        from pypy.objspace.std.bytesobject import W_BytesObject
-        from pypy.objspace.std.unicodeobject import W_UnicodeObject
-
-        if isinstance(self, W_BytesObject):
-            l = space.listview_bytes(w_list)
-            if l is not None:
-                if len(l) == 1:
-                    return space.wrap(l[0])
-                return space.wrap(self._val(space).join(l))
-        elif isinstance(self, W_UnicodeObject):
-            l = space.listview_unicode(w_list)
-            if l is not None:
-                if len(l) == 1:
-                    return space.wrap(l[0])
-                return space.wrap(self._val(space).join(l))
-
         list_w = space.listview(w_list)
         size = len(list_w)
 
@@ -349,8 +338,7 @@
             if check_item == 1:
                 raise operationerrfmt(
                     space.w_TypeError,
-                    "sequence item %d: expected string, %s "
-                    "found", i, space.type(w_s).getname(space))
+                    "sequence item %d: expected string, %T found", i, w_s)
             elif check_item == 2:
                 return self._join_autoconvert(space, list_w)
             prealloc_size += len(self._op_val(space, w_s))
@@ -370,9 +358,9 @@
         value = self._val(space)
         fillchar = self._op_val(space, w_fillchar)
         if len(fillchar) != 1:
-            raise OperationError(space.w_TypeError,
-                space.wrap("ljust() argument 2 must be a single character"))
-
+            raise operationerrfmt(space.w_TypeError,
+                                  "ljust() argument 2 must be a single "
+                                  "character")
         d = width - len(value)
         if d > 0:
             fillchar = fillchar[0]    # annotator hint: it's a single character
@@ -385,9 +373,9 @@
         value = self._val(space)
         fillchar = self._op_val(space, w_fillchar)
         if len(fillchar) != 1:
-            raise OperationError(space.w_TypeError,
-                space.wrap("rjust() argument 2 must be a single character"))
-
+            raise operationerrfmt(space.w_TypeError,
+                                  "rjust() argument 2 must be a single "
+                                  "character")
         d = width - len(value)
         if d > 0:
             fillchar = fillchar[0]    # annotator hint: it's a single character
@@ -406,8 +394,7 @@
         value = self._val(space)


More information about the pypy-commit mailing list