Author: Spenser Andrew Bauman <saba...@gmail.com>
Branch: clean-exported-state
Changeset: r87948:52de89fb0bdb
Date: 2016-10-24 21:00 -0400
http://bitbucket.org/pypy/pypy/changeset/52de89fb0bdb/

Log:    Merge with default

diff too long, truncating to 2000 out of 2085 lines

diff --git a/pypy/doc/faq.rst b/pypy/doc/faq.rst
--- a/pypy/doc/faq.rst
+++ b/pypy/doc/faq.rst
@@ -397,3 +397,13 @@
 in auto-generated C code, and at least some knowledge about the
 various components involved, from PyPy's own RPython source code to
 the GC and possibly the JIT.
+
+
+Why doesn't PyPy move to GitHub, Gitlab, ...?
+----------------------------------------------
+
+We've been quite happy with bitbucket.org. Moving version control systems and
+hosting is a lot of hard work: On the one hand, PyPy's mercurial history is
+long and gnarly. On the other hand, all our infrastructure (buildbots,
+benchmarking, etc) would have to be adapted. So unless somebody steps up and
+volunteers to do all that work, it will likely not happen.
diff --git a/pypy/doc/install.rst b/pypy/doc/install.rst
--- a/pypy/doc/install.rst
+++ b/pypy/doc/install.rst
@@ -1,8 +1,17 @@
 Downloading and Installing PyPy
 ===============================
 
+Using a packaged PyPy
+~~~~~~~~~~~~~~~~~~~~~
+
+Some Linux distributions provide a pypy package. Note that in order to
+install additional modules that require compilation, you may need to install
+additional packages such as pypy-dev. This will manifest as an error about
+"missing Python.h". Distributions do not as of yet supply many pypy-ready
+packages, if you require additional modules we recommend creating a virtualenv
+and using pip. 
+
 .. _prebuilt-pypy:
-
 Download a pre-built PyPy
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -38,6 +47,9 @@
 and not move the binary there, else PyPy would not be able to find its
 library.
 
+Installing more modules
+~~~~~~~~~~~~~~~~~~~~~~~
+
 If you want to install 3rd party libraries, the most convenient way is
 to install pip_ using ensurepip_ (unless you want to install virtualenv as 
 explained below; then you can directly use pip inside virtualenvs):
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
@@ -67,11 +67,16 @@
 Make optimiseopt iterative instead of recursive so it can be reasoned about
 more easily and debugging is faster.
 
-.. branch: stdlib-2.7.11
+.. branch: Tiberiumk/fix-2412-1476011166874
+.. branch: redirect-assembler-jitlog
 
-Update stdlib to version 2.7.11
 
-.. branch: vendor/stdlib
+
 .. branch: stdlib-2.7.12
 
 Update stdlib to version 2.7.12
+
+.. branch: buffer-interface2
+
+Improve support for new buffer interface in cpyext, bf_getbuffer on built-in
+types still missing
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -207,6 +207,9 @@
 
     def buffer_w(self, space, flags):
         w_impl = space.lookup(self, '__buffer__')
+        if w_impl is None:
+            # cpyext types that may have only old buffer interface
+            w_impl = space.lookup(self, '__wbuffer__')
         if w_impl is not None:
             w_result = space.get_and_call_function(w_impl, self, 
                                         space.newint(flags))
@@ -215,7 +218,10 @@
         raise BufferInterfaceNotFound
 
     def readbuf_w(self, space):
-        w_impl = space.lookup(self, '__buffer__')
+        # cpyext types that may have old buffer protocol
+        w_impl = space.lookup(self, '__rbuffer__')
+        if w_impl is None:
+            w_impl = space.lookup(self, '__buffer__')
         if w_impl is not None:
             w_result = space.get_and_call_function(w_impl, self,
                                         space.newint(space.BUF_FULL_RO))
@@ -224,7 +230,10 @@
         raise BufferInterfaceNotFound
 
     def writebuf_w(self, space):
-        w_impl = space.lookup(self, '__buffer__')
+        # cpyext types that may have old buffer protocol
+        w_impl = space.lookup(self, '__wbuffer__')
+        if w_impl is None:
+            w_impl = space.lookup(self, '__buffer__')
         if w_impl is not None:
             w_result = space.get_and_call_function(w_impl, self,
                                         space.newint(space.BUF_FULL))
diff --git a/pypy/module/array/test/test_array.py 
b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -2,7 +2,18 @@
 import pytest
 
 
-class BaseArrayTests:
+class AppTestArray(object):
+    spaceconfig = {'usemodules': ['array', 'struct', '_rawffi', 'binascii']}
+
+    def setup_class(cls):
+        cls.w_array = cls.space.appexec([], """():
+            import array
+            return array.array
+        """)
+        cls.w_tempfile = cls.space.wrap(
+            str(pytest.ensuretemp('array').join('tmpfile')))
+        cls.w_maxint = cls.space.wrap(sys.maxint)
+
     def test_ctor(self):
         assert len(self.array('c')) == 0
         assert len(self.array('i')) == 0
@@ -22,8 +33,8 @@
         a = self.array('u')
         raises(TypeError, a.append, 7)
         raises(TypeError, a.append, u'hi')
-        a.append(unicode('h'))
-        assert a[0] == unicode('h')
+        a.append(u'h')
+        assert a[0] == u'h'
         assert type(a[0]) is unicode
         assert len(a) == 1
 
@@ -67,7 +78,7 @@
                            ('H', (     0, 56783, 65535),  int),
                            ('i', (-32768, 30535, 32767),  int),
                            ('I', (     0, 56783, 65535), long),
-                           ('l', (-2 ** 32 / 2, 34, 2 ** 32 / 2 - 1),  int),
+                           ('l', (-2 ** 32 // 2, 34, 2 ** 32 // 2 - 1),  int),
                            ('L', (0, 3523532, 2 ** 32 - 1), long),
                            ):
             a = self.array(tc, ok)
@@ -105,7 +116,7 @@
             assert a.tolist() == vals
 
             a = self.array(tc.lower())
-            vals = [-1 * (2 ** itembits) / 2,  (2 ** itembits) / 2 - 1]
+            vals = [-1 * (2 ** itembits) // 2,  (2 ** itembits) // 2 - 1]
             a.fromlist(vals)
             assert a.tolist() == vals
 
@@ -137,11 +148,11 @@
         for t in inttypes:
             a = self.array(t, [1, 2, 3])
             b = a.itemsize
-            for v in (-2 ** (8 * b) / 2, 2 ** (8 * b) / 2 - 1):
+            for v in (-2 ** (8 * b) // 2, 2 ** (8 * b) // 2 - 1):
                 a[1] = v
                 assert a[0] == 1 and a[1] == v and a[2] == 3
-            raises(OverflowError, a.append, -2 ** (8 * b) / 2 - 1)
-            raises(OverflowError, a.append, 2 ** (8 * b) / 2)
+            raises(OverflowError, a.append, -2 ** (8 * b) // 2 - 1)
+            raises(OverflowError, a.append, 2 ** (8 * b) // 2)
 
             a = self.array(t.upper(), [1, 2, 3])
             b = a.itemsize
@@ -175,42 +186,35 @@
                 raises(ValueError, a.fromstring, '\x00' * (a.itemsize + 1))
                 raises(ValueError, a.fromstring, '\x00' * (2 * a.itemsize - 1))
                 raises(ValueError, a.fromstring, '\x00' * (2 * a.itemsize + 1))
-            b = self.array(t, '\x00' * a.itemsize * 2)
+            b = self.array(t, b'\x00' * a.itemsize * 2)
             assert len(b) == 2 and b[0] == 0 and b[1] == 0
             if sys.version_info >= (2, 7, 11):
                 raises(ValueError, a.fromstring, a)
 
     def test_fromfile(self):
-
-        ## class myfile(object):
-        ##     def __init__(self, c, s):
-        ##         self.c = c
-        ##         self.s = s
-        ##     def read(self,n):
-        ##         return self.c*min(n,self.s)
         def myfile(c, s):
-            f = open(self.tempfile, 'w')
+            f = open(self.tempfile, 'wb')
             f.write(c * s)
             f.close()
-            return open(self.tempfile, 'r')
+            return open(self.tempfile, 'rb')
 
-        f = myfile('\x00', 100)
+        f = myfile(b'\x00', 100)
         for t in 'bBhHiIlLfd':
             a = self.array(t)
             a.fromfile(f, 2)
             assert len(a) == 2 and a[0] == 0 and a[1] == 0
 
         a = self.array('b')
-        a.fromfile(myfile('\x01', 20), 2)
+        a.fromfile(myfile(b'\x01', 20), 2)
         assert len(a) == 2 and a[0] == 1 and a[1] == 1
 
         a = self.array('h')
-        a.fromfile(myfile('\x01', 20), 2)
+        a.fromfile(myfile(b'\x01', 20), 2)
         assert len(a) == 2 and a[0] == 257 and a[1] == 257
 
         for i in (0, 1):
             a = self.array('h')
-            raises(EOFError, a.fromfile, myfile('\x01', 2 + i), 2)
+            raises(EOFError, a.fromfile, myfile(b'\x01', 2 + i), 2)
             assert len(a) == 1 and a[0] == 257
 
     def test_fromlist(self):
@@ -250,12 +254,12 @@
         assert repr(a) == "array('b', [1, 2, 1, 2])"
 
     def test_fromunicode(self):
-        raises(ValueError, self.array('i').fromunicode, unicode('hi'))
+        raises(ValueError, self.array('i').fromunicode, u'hi')
         a = self.array('u')
-        a.fromunicode(unicode('hi'))
+        a.fromunicode(u'hi')
         assert len(a) == 2 and a[0] == 'h' and a[1] == 'i'
 
-        b = self.array('u', unicode('hi'))
+        b = self.array('u', u'hi')
         assert len(b) == 2 and b[0] == 'h' and b[1] == 'i'
 
     def test_sequence(self):
@@ -357,23 +361,6 @@
                         except ValueError:
                             assert not ok
 
-    def test_reversingslice_pre26(self):
-        import sys
-        if sys.version_info >= (2, 6):
-            skip('arrays can handle more slice ops than lists in 2.6')
-
-        for a in range(-4, 5):
-            for b in range(-4, 5):
-                for c in [-4, -3, -2, -1, 1, 2, 3, 4]:
-                    lst = [1, 2, 3]
-                    arr = self.array('i', lst)
-                    for vals in ([4, 5], [6], []):
-                        try:
-                            lst[a:b:c] = vals
-                        except ValueError:
-                            raises(ValueError,
-                                   "arr[a:b:c]=self.array('i', vals)")
-
     def test_toxxx(self):
         a = self.array('i', [1, 2, 3])
         l = a.tolist()
@@ -405,7 +392,7 @@
                                ('BHILfd', (127, 0, 1, 7, 255, 169)),
                                ('hilHILfd', (32760, 30123, 3422, 23244))):
             for tc in tcodes:
-                values += ((2 ** self.array(tc).itemsize) / 2 - 1, )
+                values += ((2 ** self.array(tc).itemsize) // 2 - 1, )
                 s = self.array(tc, values).tostring()
                 a = unpack(tc * len(values), s)
                 assert a == values
@@ -420,8 +407,7 @@
         assert repr(a) == "array('c', 'hi')"
 
         raises(ValueError, self.array('i').tounicode)
-        assert self.array('u', unicode('hello')).tounicode() == \
-               unicode('hello')
+        assert self.array('u', u'hello').tounicode() == u'hello'
 
     def test_empty_tostring(self):
         a = self.array('l')
@@ -493,14 +479,14 @@
 
     def test_compare(self):
         class comparable(object):
-            def __cmp__(self, other):
-                return 0
+            def __eq__(self, other):
+                return True
         class incomparable(object):
             pass
 
         for v1, v2, tt in (([1, 2, 3], [1, 3, 2], 'bhilBHIL'),
                          ('abc', 'acb', 'c'),
-                         (unicode('abc'), unicode('acb'), 'u')):
+                         (u'abc', u'acb', 'u')):
             for t in tt:
                 a = self.array(t, v1)
                 b = self.array(t, v1)
@@ -767,16 +753,16 @@
                 self.height = height
                 return self
 
-            def _index(self, (x,y)):
+            def _index(self, x, y):
                 x = min(max(x, 0), self.width-1)
                 y = min(max(y, 0), self.height-1)
                 return y * self.width + x
 
             def __getitem__(self, i):
-                return array.__getitem__(self, self._index(i))
+                return array.__getitem__(self, self._index(*i))
 
             def __setitem__(self, i, val):
-                return array.__setitem__(self, self._index(i), val)
+                return array.__setitem__(self, self._index(*i), val)
 
         img = Image(5, 10, 'B')
         for y in range(10):
@@ -844,8 +830,8 @@
         assert repr(mya('i', (1, 2, 3))) == "array('i', [1, 2, 3])"
 
     def test_unicode_outofrange(self):
-        a = self.array('u', unicode(r'\x01\u263a\x00\ufeff', 'unicode-escape'))
-        b = self.array('u', unicode(r'\x01\u263a\x00\ufeff', 'unicode-escape'))
+        a = self.array('u', u'\x01\u263a\x00\ufeff')
+        b = self.array('u', u'\x01\u263a\x00\ufeff')
         b.byteswap()
         assert a != b
 
@@ -853,7 +839,7 @@
         import sys
         if sys.maxunicode == 0xffff:
             skip("test for 32-bit unicodes")
-        a = self.array('u', '\xff\xff\xff\xff')
+        a = self.array('u', b'\xff\xff\xff\xff')
         assert len(a) == 1
         assert repr(a[0]) == "u'\Uffffffff'"
         if sys.maxint == 2147483647:
@@ -954,28 +940,6 @@
         assert a[0] == u'b'
 
 
-class TestCPythonsOwnArray(BaseArrayTests):
-    def setup_class(cls):
-        import array
-        cls.array = array.array
-        import struct
-        cls.struct = struct
-        cls.tempfile = str(pytest.ensuretemp('array').join('tmpfile'))
-        cls.maxint = sys.maxint
-
-
-class AppTestArray(BaseArrayTests):
-    spaceconfig = {'usemodules': ['array', 'struct', '_rawffi', 'binascii']}
-
-    def setup_class(cls):
-        cls.w_array = cls.space.appexec([], """():
-            import array
-            return array.array
-        """)
-        cls.w_tempfile = cls.space.wrap(
-            str(pytest.ensuretemp('array').join('tmpfile')))
-        cls.w_maxint = cls.space.wrap(sys.maxint)
-
     def test_buffer_info(self):
         a = self.array('c', 'Hi!')
         bi = a.buffer_info()
diff --git a/pypy/module/array/test/test_array_old.py 
b/pypy/module/array/test/test_array_old.py
deleted file mode 100644
--- a/pypy/module/array/test/test_array_old.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# minimal tests.  See also lib-python/modified-2.4.1/test/test_array.
-
-import py
-from py.test import raises
-import struct
-
-
-class BaseArrayTests:
-    # XXX very incomplete
-
-    native_sizes = {'l': struct.calcsize('l')}
-
-    def test_attributes(self):
-        a = self.array.array('c')
-        assert a.typecode == 'c'
-        assert a.itemsize == 1
-        a = self.array.array('l')
-        assert a.typecode == 'l'
-        assert a.itemsize == self.native_sizes['l']
-
-    def test_imul(self):
-        a = self.array.array('i', [12, 34])
-        a *= 3
-        assert a.tolist() == [12, 34] * 3
-
-    def test_unicode(self):
-        a = self.array.array('u')
-        a.fromunicode(unichr(9999))
-        assert len(a) == 1
-        assert a.tolist() == [unichr(9999)]
-
-    def test_pickle(self):
-        import sys
-        if sys.version_info < (2, 5):
-            py.test.skip("array.array not picklable before python 2.5")
-        import pickle
-
-        for content in [[56, -12, 34], []]:
-            a = self.array.array('i', content)
-            a2 = pickle.loads(pickle.dumps(a))
-            assert type(a2) is self.array.array
-            assert list(a2) == content
-
-    def test_init_vs_new(self):
-        import sys
-        if sys.version_info < (2, 5):
-            py.test.skip("array.array constructor changed in 2.5")
-        class A(self.array.array):
-            def __init__(self, *args, **kwds):
-                self.args = args
-                self.kwds = kwds
-
-        a = A('c', foo='bar')
-        assert a.args == ('c',)
-        assert a.kwds == {'foo': 'bar'}
-        a = A('i', range(10), some=42)
-        assert a.args == ('i', range(10))
-        assert a.kwds == {'some': 42}
-        raises(TypeError, A)
-        raises(TypeError, A, 42)
-        raises(TypeError, A, 'i', [], [])
-        raises(TypeError, self.array.array, 'i', [], foo='bar')
-
-
-class TestCPythonsOwnArray(BaseArrayTests):
-
-    def setup_class(cls):
-        import array
-        cls.array = array
-
-
-## class TestArrayOnTopOfCPython(BaseArrayTests):
-
-##     def setup_class(cls):
-##         from pypy.tool.lib_pypy import LIB_PYPY
-##         if not hasattr(struct, 'pack_into'):
-##             py.test.skip("requires CPython >= 2.5")
-##         import new
-##         path = LIB_PYPY.join('array.py')
-##         myarraymodule = new.module('array')
-##         execfile(str(path), myarraymodule.__dict__)
-##         cls.array = myarraymodule
-
-##     def test_unicode(self):
-##         py.test.skip("no 'u' type code in CPython's struct module")
-
-##     def test_pickle(self):
-##         py.test.skip("pickle getting confused by the hack in setup_class()")
-
-
-class AppTestArray(BaseArrayTests):
-    spaceconfig = {'usemodules': ['struct', 'array', 'binascii']}
-
-    def setup_class(cls):
-        """Import the array module and make it available as self.array."""
-        cls.w_array = cls.space.getbuiltinmodule('array')
-        cls.w_native_sizes = cls.space.wrap(cls.native_sizes)
-
-
-## class AppTestArrayWithRawFFI(AppTestArray):
-##     """
-##     The same as the base class, but with a space that also includes the
-##     _rawffi module.  The array module internally uses it in this case.
-##     """
-##     spaceconfig = dict(usemodules=['struct', '_rawffi'])
-
-##     def test_buffer_info(self):
-##         a = self.array.array('l', [123, 456])
-##         assert a.itemsize == self.native_sizes['l']
-##         address, length = a.buffer_info()
-##         assert length == 2      # and not 2 * self.native_sizes['l']
-##         assert address != 0
-##         # should check the address via some unsafe peeking, but it's
-##         # not easy on top of py.py
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
@@ -79,11 +79,16 @@
 CONST_STRING = lltype.Ptr(lltype.Array(lltype.Char,
                                        hints={'nolength': True}),
                           use_cache=False)
+CONST_STRINGP = lltype.Ptr(lltype.Array(rffi.CCHARP,
+                                       hints={'nolength': True}),
+                          use_cache=False)
 CONST_WSTRING = lltype.Ptr(lltype.Array(lltype.UniChar,
                                         hints={'nolength': True}),
                            use_cache=False)
 assert CONST_STRING is not rffi.CCHARP
 assert CONST_STRING == rffi.CCHARP
+assert CONST_STRINGP is not rffi.CCHARPP
+assert CONST_STRINGP == rffi.CCHARPP
 assert CONST_WSTRING is not rffi.CWCHARP
 assert CONST_WSTRING == rffi.CWCHARP
 
@@ -1004,6 +1009,8 @@
     for i, argtype in enumerate(func.argtypes):
         if argtype is CONST_STRING:
             arg = 'const char *@'
+        elif argtype is CONST_STRINGP:
+            arg = 'const char **@'
         elif argtype is CONST_WSTRING:
             arg = 'const wchar_t *@'
         else:
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -10,6 +10,10 @@
     flags = pyobj.c_ob_type.c_tp_flags
     if (flags & Py_TPFLAGS_HAVE_NEWBUFFER and as_buffer.c_bf_getbuffer):
         return 1
+    name = rffi.charp2str(pyobj.c_ob_type.c_tp_name)
+    if  name in ('str', 'bytes'):
+        # XXX remove once wrapper of __buffer__ -> bf_getbuffer works
+        return 1
     return 0  
 
     
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -144,7 +144,7 @@
 
 /* Py3k buffer interface, adapted for PyPy */
 #define Py_MAX_NDIMS 32
-#define Py_MAX_FMT 5
+#define Py_MAX_FMT 128
 typedef struct bufferinfo {
     void *buf;
     PyObject *obj;        /* owned reference */
diff --git a/pypy/module/cpyext/memoryobject.py 
b/pypy/module/cpyext/memoryobject.py
--- a/pypy/module/cpyext/memoryobject.py
+++ b/pypy/module/cpyext/memoryobject.py
@@ -1,9 +1,10 @@
 from pypy.module.cpyext.api import (cpython_api, Py_buffer, CANNOT_FAIL,
                          Py_MAX_FMT, Py_MAX_NDIMS, build_type_checkers, 
Py_ssize_tP)
-from pypy.module.cpyext.pyobject import PyObject, make_ref, incref
+from pypy.module.cpyext.pyobject import PyObject, make_ref, incref, from_ref
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib.rarithmetic import widen
 from pypy.objspace.std.memoryobject import W_MemoryView
+from pypy.module.cpyext.import_ import PyImport_Import
 
 PyMemoryView_Check, PyMemoryView_CheckExact = 
build_type_checkers("MemoryView", "w_memoryview")
 
@@ -33,33 +34,43 @@
         view.c_buf = rffi.cast(rffi.VOIDP, buf.get_raw_address())
     except ValueError:
         raise BufferError("could not create buffer from object")
+    ret = fill_Py_buffer(space, buf, view)
     view.c_obj = make_ref(space, w_obj)
-    return fill_Py_buffer(space, buf, view)
+    return ret
 
-def fill_Py_buffer(space, buf, view):    
+def fill_Py_buffer(space, buf, view):
     # c_buf, c_obj have been filled in
     ndim = buf.getndim()
     view.c_len = buf.getlength()
     view.c_itemsize = buf.getitemsize()
     rffi.setintfield(view, 'c_ndim', ndim)
     view.c_format = rffi.cast(rffi.CCHARP, view.c__format)
-    view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
-    view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
     fmt = buf.getformat()
     n = Py_MAX_FMT - 1 # NULL terminated buffer
     if len(fmt) > n:
-        ### WARN?
-        pass
+        w_message = space.newbytes("PyPy specific Py_MAX_FMT is %d which is 
too "
+                           "small for buffer format, %d needed" % (
+                           Py_MAX_FMT, len(fmt)))
+        w_stacklevel = space.newint(1)
+        w_module = PyImport_Import(space, space.newbytes("warnings"))
+        w_warn = space.getattr(w_module, space.newbytes("warn"))
+        space.call_function(w_warn, w_message, space.w_None, w_stacklevel)
     else:
         n = len(fmt)
     for i in range(n):
         view.c_format[i] = fmt[i]
-    view.c_format[n] = '\x00'        
-    shape = buf.getshape()
-    strides = buf.getstrides()
-    for i in range(ndim):
-        view.c_shape[i] = shape[i]
-        view.c_strides[i] = strides[i]
+    view.c_format[n] = '\x00'
+    if ndim > 0:
+        view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+        view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+        shape = buf.getshape()
+        strides = buf.getstrides()
+        for i in range(ndim):
+            view.c_shape[i] = shape[i]
+            view.c_strides[i] = strides[i]
+    else:
+        view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
+        view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
     view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
     view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
     return 0
@@ -102,12 +113,12 @@
 
 @cpython_api([lltype.Ptr(Py_buffer), lltype.Char], rffi.INT_real, 
error=CANNOT_FAIL)
 def PyBuffer_IsContiguous(space, view, fort):
-    """Return 1 if the memory defined by the view is C-style (fortran is
-    'C') or Fortran-style (fortran is 'F') contiguous or either one
-    (fortran is 'A').  Return 0 otherwise."""
+    """Return 1 if the memory defined by the view is C-style (fort is
+    'C') or Fortran-style (fort is 'F') contiguous or either one
+    (fort is 'A').  Return 0 otherwise."""
     # traverse the strides, checking for consistent stride increases from
     # right-to-left (c) or left-to-right (fortran). Copied from cpython
-    if not view.c_suboffsets:
+    if view.c_suboffsets:
         return 0
     if (fort == 'C'):
         return _IsCContiguous(view)
@@ -121,11 +132,22 @@
 def PyMemoryView_FromObject(space, w_obj):
     return space.call_method(space.builtin, "memoryview", w_obj)
 
+@cpython_api([lltype.Ptr(Py_buffer)], PyObject)
+def PyMemoryView_FromBuffer(space, view):
+    """Create a memoryview object wrapping the given buffer-info structure 
view.
+    The memoryview object then owns the buffer, which means you shouldn't
+    try to release it yourself: it will be released on deallocation of the
+    memoryview object."""
+    w_obj = from_ref(space, view.c_obj)
+    if isinstance(w_obj, W_MemoryView):
+        return w_obj
+    return space.call_method(space.builtin, "memoryview", w_obj)
+
 @cpython_api([PyObject], PyObject)
 def PyMemoryView_GET_BASE(space, w_obj):
     # return the obj field of the Py_buffer created by PyMemoryView_GET_BUFFER
     # XXX needed for numpy on py3k
-    raise NotImplementedError('PyMemoryView_GET_BUFFER')
+    raise NotImplementedError('PyMemoryView_GET_BASE')
 
 @cpython_api([PyObject], lltype.Ptr(Py_buffer), error=CANNOT_FAIL)
 def PyMemoryView_GET_BUFFER(space, w_obj):
@@ -139,6 +161,7 @@
     if ndim >= Py_MAX_NDIMS:
         # XXX warn?
         return view
+    fill_Py_buffer(space, w_obj.buf, view)
     try:
         view.c_buf = rffi.cast(rffi.VOIDP, w_obj.buf.get_raw_address())
         view.c_obj = make_ref(space, w_obj)
@@ -147,8 +170,8 @@
     except ValueError:
         w_s = w_obj.descr_tobytes(space)
         view.c_obj = make_ref(space, w_s)
+        view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(space.str_w(w_s), 
track_allocation=False))
         rffi.setintfield(view, 'c_readonly', 1)
         isstr = True
-    fill_Py_buffer(space, w_obj.buf, view)     
     return view
 
diff --git a/pypy/module/cpyext/methodobject.py 
b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -311,7 +311,7 @@
 def PyClassMethod_New(space, w_func):
     return space.wrap(ClassMethod(w_func))
 
-@cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
+@cpython_api([PyTypeObjectPtr, lltype.Ptr(PyMethodDef)], PyObject)
 def PyDescr_NewMethod(space, w_type, method):
     return space.wrap(W_PyCMethodObject(space, method, w_type))
 
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -3,7 +3,7 @@
     cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
     PyVarObject, Py_buffer, size_t,
     Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
-    Py_GE, CONST_STRING, FILEP, fwrite)
+    Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
     get_typedescr, _Py_NewReference)
@@ -429,7 +429,7 @@
     is active then NULL is returned but PyErr_Occurred() will return false."""
     return space.call_function(space.builtin.get('dir'), w_o)
 
-@cpython_api([PyObject, rffi.CCHARPP, Py_ssize_tP], rffi.INT_real, error=-1)
+@cpython_api([PyObject, CONST_STRINGP, Py_ssize_tP], rffi.INT_real, error=-1)
 def PyObject_AsCharBuffer(space, obj, bufferp, sizep):
     """Returns a pointer to a read-only memory location usable as
     character-based input.  The obj argument must support the single-segment
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -150,12 +150,12 @@
     Return value: always NULL."""
     # XXX Doesn't actually do anything with PyErr_CheckSignals.
     if llfilename:
-        w_filename = rffi.charp2str(llfilename)
-        filename = space.wrap(w_filename)
+        filename = rffi.charp2str(llfilename)
+        w_filename = space.wrap(filename)
     else:
-        filename = space.w_None
+        w_filename = space.w_None
 
-    PyErr_SetFromErrnoWithFilenameObject(space, w_type, filename)
+    PyErr_SetFromErrnoWithFilenameObject(space, w_type, w_filename)
 
 @cpython_api([PyObject, PyObject], PyObject)
 @jit.dont_look_inside       # direct use of _get_errno()
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -15,6 +15,7 @@
     readbufferproc, getbufferproc, ssizessizeobjargproc)
 from pypy.module.cpyext.pyobject import from_ref, make_ref, Py_DecRef
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
+from pypy.module.cpyext.memoryobject import fill_Py_buffer
 from pypy.module.cpyext.state import State
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.argument import Arguments
@@ -349,6 +350,10 @@
     def getndim(self):
         return self.ndim
 
+    def setitem(self, index, char):
+        # absolutely no safety checks, what could go wrong?
+        self.ptr[index] = char
+
 def wrap_getreadbuffer(space, w_self, w_args, func):
     func_target = rffi.cast(readbufferproc, func)
     with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
@@ -358,6 +363,15 @@
             space.fromcache(State).check_and_raise_exception(always=True)
         return space.newbuffer(CPyBuffer(ptr[0], size, w_self))
 
+def wrap_getwritebuffer(space, w_self, w_args, func):
+    func_target = rffi.cast(readbufferproc, func)
+    with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
+        index = rffi.cast(Py_ssize_t, 0)
+        size = generic_cpy_call(space, func_target, w_self, index, ptr)
+        if size < 0:
+            space.fromcache(State).check_and_raise_exception(always=True)
+        return space.newbuffer(CPyBuffer(ptr[0], size, w_self, readonly=False))
+
 def wrap_getbuffer(space, w_self, w_args, func):
     func_target = rffi.cast(getbufferproc, func)
     with lltype.scoped_alloc(Py_buffer) as pybuf:
@@ -608,13 +622,27 @@
         @cpython_api([PyObject, Py_bufferP, rffi.INT_real], 
                 rffi.INT_real, header=None, error=-1)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
-        def buff_w(space, w_self, pybuf, flags):
-            # XXX this is wrong, needs a test
-            raise oefmt(space.w_NotImplemented, 
-                "calling bf_getbuffer on a builtin type not supported yet")
-            #args = Arguments(space, [w_self],
-            #                 w_stararg=w_args, w_starstararg=w_kwds)
-            #return space.call_args(space.get(buff_fn, w_self), args)
+        def buff_w(space, w_self, view, flags):
+            args = Arguments(space, [space.newint(flags)])
+            w_obj = space.call_args(space.get(buff_fn, w_self), args)
+            if view:
+                #like PyObject_GetBuffer
+                flags = widen(flags)
+                buf = space.buffer_w(w_obj, flags)
+                try:
+                    view.c_buf = rffi.cast(rffi.VOIDP, buf.get_raw_address())
+                    view.c_obj = make_ref(space, w_obj)
+                except ValueError:
+                    w_s = space.newbytes(buf.as_str())
+                    view.c_obj = make_ref(space, w_s)
+                    view.c_buf = rffi.cast(rffi.VOIDP, rffi.str2charp(
+                                    space.str_w(w_s), track_allocation=False))
+                    rffi.setintfield(view, 'c_readonly', 1)
+                ret = fill_Py_buffer(space, buf, view)
+                return ret
+            return 0
+        # XXX remove this when it no longer crashes a translated PyPy
+        return
         api_func = buff_w.api_func
     else:
         # missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce
@@ -924,13 +952,13 @@
 slotdefs = eval(slotdefs_str)
 # PyPy addition
 slotdefs += (
-    # XXX that might not be what we want!
     TPSLOT("__buffer__", "tp_as_buffer.c_bf_getbuffer", None, 
"wrap_getbuffer", ""),
 )
 
 if not PY3:
     slotdefs += (
-        TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, 
"wrap_getreadbuffer", ""),
+        TPSLOT("__rbuffer__", "tp_as_buffer.c_bf_getreadbuffer", None, 
"wrap_getreadbuffer", ""),
+        TPSLOT("__wbuffer__", "tp_as_buffer.c_bf_getwritebuffer", None, 
"wrap_getwritebuffer", ""),
     )
 
 
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -41,14 +41,6 @@
     given shape with the given number of bytes per element."""
     raise NotImplementedError
 
-@cpython_api([Py_buffer], PyObject)
-def PyMemoryView_FromBuffer(space, view):
-    """Create a memoryview object wrapping the given buffer-info structure 
view.
-    The memoryview object then owns the buffer, which means you shouldn't
-    try to release it yourself: it will be released on deallocation of the
-    memoryview object."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, rffi.INT_real, lltype.Char], PyObject)
 def PyMemoryView_GetContiguous(space, obj, buffertype, order):
     """Create a memoryview object to a contiguous chunk of memory (in either
diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c
--- a/pypy/module/cpyext/test/array.c
+++ b/pypy/module/cpyext/test/array.c
@@ -2394,14 +2394,29 @@
     (iternextfunc)arrayiter_next,               /* tp_iternext */
     0,                                          /* tp_methods */
 };
+static PyObject *
+readbuffer_as_string(PyObject *self, PyObject *args)
+{
+    PyObject *obj;
+    const void *ptr;
+    Py_ssize_t size;
+
+    if (!PyArg_ParseTuple(args, "O", &obj)) {
+        return NULL;
+    }
+    if (PyObject_AsReadBuffer(obj, &ptr, &size) < 0)
+        return NULL;
+    return PyString_FromStringAndSize((char*)ptr, size);
+}
+
 
 
 /*********************** Install Module **************************/
 
-/* No functions in array module. */
 static PyMethodDef a_methods[] = {
     {"_reconstruct",   (PyCFunction)_reconstruct, METH_VARARGS, NULL},
     {"switch_multiply",   (PyCFunction)switch_multiply, METH_NOARGS, NULL},
+    {"readbuffer_as_string",   (PyCFunction)readbuffer_as_string, 
METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
diff --git a/pypy/module/cpyext/test/test_abstract.py 
b/pypy/module/cpyext/test/test_abstract.py
--- a/pypy/module/cpyext/test/test_abstract.py
+++ b/pypy/module/cpyext/test/test_abstract.py
@@ -10,7 +10,7 @@
              """
                  char *ptr;
                  Py_ssize_t size;
-                 if (PyObject_AsCharBuffer(args, &ptr, &size) < 0)
+                 if (PyObject_AsCharBuffer(args, (const char **)&ptr, &size) < 
0)
                      return NULL;
                  return PyString_FromStringAndSize(ptr, size);
              """),
@@ -104,3 +104,17 @@
         assert raises(TypeError, buffer_support.readbuffer_as_string, 42)
         assert raises(TypeError, buffer_support.writebuffer_as_string, 42)
         assert raises(TypeError, buffer_support.charbuffer_as_string, 42)
+
+    def test_user_class(self):
+        class MyBuf(str):
+            pass
+        s = 'a\0x'
+        buf = MyBuf(s)
+        buffer_support = self.get_buffer_support()
+
+        assert buffer_support.check_readbuffer(buf)
+        assert s == buffer_support.readbuffer_as_string(buf)
+        assert raises(TypeError, buffer_support.writebuffer_as_string, buf)
+        assert s == buffer_support.charbuffer_as_string(buf)
+
+
diff --git a/pypy/module/cpyext/test/test_arraymodule.py 
b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -1,8 +1,17 @@
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-
+from pypy.conftest import option
 
 class AppTestArrayModule(AppTestCpythonExtensionBase):
-    enable_leak_checking = False
+    enable_leak_checking = True
+
+    def setup_class(cls):
+        from rpython.tool.udir import udir
+        AppTestCpythonExtensionBase.setup_class.im_func(cls)
+        if option.runappdirect:
+            cls.w_udir = str(udir)
+        else:
+            cls.w_udir = cls.space.wrap(str(udir))
+
 
     def test_basic(self):
         module = self.import_module(name='array')
@@ -90,6 +99,7 @@
         assert res == [2, 4, 6]
 
     def test_subclass(self):
+        import struct
         module = self.import_module(name='array')
         class Sub(module.array):
             pass
@@ -98,3 +108,37 @@
         res = [1, 2, 3] * arr
         assert res == [1, 2, 3, 1, 2, 3]
         
+        val = module.readbuffer_as_string(arr)
+        assert val == struct.pack('i', 2)
+
+    def test_unicode_readbuffer(self):
+        # Not really part of array, refactor
+        import struct
+        module = self.import_module(name='array')
+        val = module.readbuffer_as_string('abcd')
+        assert val == 'abcd'
+        val = module.readbuffer_as_string(u'\u03a3')
+        assert val is not None
+
+    def test_readinto(self):
+        module = self.import_module(name='array')
+        a = module.array('c')
+        a.fromstring('0123456789')
+        filename = self.udir + "/_test_file"
+        f = open(filename, 'w+b')
+        f.write('foobar')
+        f.seek(0)
+        n = f.readinto(a)
+        f.close()
+        assert n == 6
+        assert len(a) == 10
+        assert a.tostring() == 'foobar6789'
+
+    def test_iowrite(self):
+        module = self.import_module(name='array')
+        from io import BytesIO
+        a = module.array('c')
+        a.fromstring('0123456789')
+        fd = BytesIO()
+        # only test that it works
+        fd.write(a)
diff --git a/pypy/module/cpyext/test/test_bufferobject.py 
b/pypy/module/cpyext/test/test_bufferobject.py
--- a/pypy/module/cpyext/test/test_bufferobject.py
+++ b/pypy/module/cpyext/test/test_bufferobject.py
@@ -25,7 +25,7 @@
              """
                  char *ptr;
                  Py_ssize_t size;
-                 if (PyObject_AsCharBuffer(args, &ptr, &size) < 0)
+                 if (PyObject_AsCharBuffer(args, (const char **)&ptr, &size) < 
0)
                      return NULL;
                  return PyString_FromStringAndSize(ptr, size);
              """)
diff --git a/pypy/module/cpyext/test/test_getargs.py 
b/pypy/module/cpyext/test/test_getargs.py
--- a/pypy/module/cpyext/test/test_getargs.py
+++ b/pypy/module/cpyext/test/test_getargs.py
@@ -139,6 +139,12 @@
             return result;
             ''')
         assert 'foo\0bar\0baz' == pybuffer(buffer('foo\0bar\0baz'))
+        import sys
+        if '__pypy__' not in sys.builtin_module_names:
+            class A(object):
+                def __buffer__(self, flags):
+                    return buffer('123')
+            assert pybuffer(A()) == '123'
 
 
     def test_pyarg_parse_string_fails(self):
diff --git a/pypy/module/cpyext/test/test_memoryobject.py 
b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -1,8 +1,12 @@
+import pytest
+
 from rpython.rtyper.lltypesystem import rffi
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from rpython.rlib.buffer import StringBuffer
 
+only_pypy ="config.option.runappdirect and '__pypy__' not in 
sys.builtin_module_names" 
+
 class TestMemoryViewObject(BaseApiTest):
     def test_fromobject(self, space, api):
         w_hello = space.newbytes("hello")
@@ -23,6 +27,14 @@
         assert w_view.c_shape[0] == 5
         assert w_view.c_strides[0] == 1
         assert w_view.c_len == 5
+        o = rffi.charp2str(w_view.c_buf)
+        assert o == 'hello'
+        w_mv = api.PyMemoryView_FromBuffer(w_view)
+        for f in ('format', 'itemsize', 'ndim', 'readonly', 
+                  'shape', 'strides', 'suboffsets'):
+            w_f = space.wrap(f)
+            assert space.eq_w(space.getattr(w_mv, w_f), 
+                              space.getattr(w_memoryview, w_f))
 
 class AppTestBufferProtocol(AppTestCpythonExtensionBase):
     def test_buffer_protocol(self):
@@ -39,8 +51,12 @@
         viewlen = module.test_buffer(arr)
         assert viewlen == y.itemsize * len(y)
 
+    @pytest.mark.skipif(only_pypy, reason='pypy only test')
     def test_buffer_info(self):
-        from _numpypy import multiarray as np
+        try:
+            from _numpypy import multiarray as np
+        except ImportError:
+            skip('pypy built without _numpypy')
         module = self.import_module(name='buffer_test')
         get_buffer_info = module.get_buffer_info
         raises(ValueError, get_buffer_info, np.arange(5)[::2], ('SIMPLE',))
@@ -50,3 +66,29 @@
         arr = np.zeros((10, 1), order='C')
         shape, strides = get_buffer_info(arr, ['C_CONTIGUOUS'])
         assert strides[-1] == 8
+        dt1 = np.dtype(
+             [('a', 'b'), ('b', 'i'), 
+              ('sub0', np.dtype('b,i')), 
+              ('sub1', np.dtype('b,i')), 
+              ('sub2', np.dtype('b,i')), 
+              ('sub3', np.dtype('b,i')), 
+              ('sub4', np.dtype('b,i')), 
+              ('sub5', np.dtype('b,i')), 
+              ('sub6', np.dtype('b,i')), 
+              ('sub7', np.dtype('b,i')), 
+              ('c', 'i')],
+             )
+        x = np.arange(dt1.itemsize, dtype='int8').view(dt1)
+        # pytest can catch warnings from v2.8 and up, we ship 2.5
+        import warnings
+        warnings.filterwarnings("error")
+        try:
+            try:
+                y = get_buffer_info(x, ['SIMPLE'])
+            except UserWarning as e:
+                pass
+            else:
+                assert False ,"PyPy-specific UserWarning not raised" \
+                          " on too long format string"
+        finally:
+            warnings.resetwarnings()
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
@@ -514,10 +514,13 @@
 @cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
              header=None, error=-1)
 def bf_getreadbuffer(space, w_buf, segment, ref):
+    from rpython.rlib.buffer import StringBuffer
     if segment != 0:
         raise oefmt(space.w_SystemError,
                     "accessing non-existent segment")
     buf = space.readbuf_w(w_buf)
+    if isinstance(buf, StringBuffer):
+        return str_getreadbuffer(space, w_buf, segment, ref)
     address = buf.get_raw_address()
     ref[0] = address
     return len(buf)
@@ -533,7 +536,6 @@
     if segment != 0:
         raise oefmt(space.w_SystemError,
                     "accessing non-existent segment")
-
     buf = space.writebuf_w(w_buf)
     ref[0] = buf.get_raw_address()
     return len(buf)
@@ -551,6 +553,20 @@
     Py_DecRef(space, pyref)
     return space.len_w(w_str)
 
+@cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+             header=None, error=-1)
+def unicode_getreadbuffer(space, w_str, segment, ref):
+    from pypy.module.cpyext.unicodeobject import (
+                PyUnicode_AS_UNICODE, PyUnicode_GET_DATA_SIZE)
+    if segment != 0:
+        raise oefmt(space.w_SystemError,
+                    "accessing non-existent unicode segment")
+    pyref = make_ref(space, w_str)
+    ref[0] = PyUnicode_AS_UNICODE(space, pyref)
+    # Stolen reference: the object has better exist somewhere else
+    Py_DecRef(space, pyref)
+    return PyUnicode_GET_DATA_SIZE(space, w_str)
+
 @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
              header=None, error=-1)
 def str_getcharbuffer(space, w_buf, segment, ref):
@@ -574,8 +590,8 @@
 
 def setup_buffer_procs(space, w_type, pto):
     bufspec = w_type.layout.typedef.buffer
-    if bufspec is None:
-        # not a buffer
+    if bufspec is None and not space.is_w(w_type, space.w_unicode):
+        # not a buffer, but let w_unicode be a read buffer
         return
     c_buf = lltype.malloc(PyBufferProcs, flavor='raw', zero=True)
     lltype.render_immortal(c_buf)
@@ -591,6 +607,13 @@
         c_buf.c_bf_getcharbuffer = llhelper(
             str_getcharbuffer.api_func.functype,
             str_getcharbuffer.api_func.get_wrapper(space))
+    elif space.is_w(w_type, space.w_unicode):
+        # Special case: unicode doesn't support get_raw_address(), so we have a
+        # custom get*buffer that instead gives the address of the char* in the
+        # PyUnicodeObject*!
+        c_buf.c_bf_getreadbuffer = llhelper(
+            unicode_getreadbuffer.api_func.functype,
+            unicode_getreadbuffer.api_func.get_wrapper(space))
     elif space.is_w(w_type, space.w_buffer):
         # Special case: we store a permanent address on the cpyext wrapper,
         # so we'll reuse that.
@@ -706,7 +729,7 @@
     # uninitialized fields:
     # c_tp_print
     # XXX implement
-    # c_tp_compare and the following fields (see 
http://docs.python.org/c-api/typeobj.html )
+    # c_tp_compare and more?
     w_base = best_base(space, w_type.bases_w)
     pto.c_tp_base = rffi.cast(PyTypeObjectPtr, make_ref(space, w_base))
 
@@ -764,7 +787,6 @@
     return find_best_base(bases_w)
 
 def inherit_slots(space, pto, w_base):
-    # XXX missing: nearly everything
     base_pyo = make_ref(space, w_base)
     try:
         base = rffi.cast(PyTypeObjectPtr, base_pyo)
@@ -783,6 +805,23 @@
             pto.c_tp_getattro = base.c_tp_getattro
         if not pto.c_tp_as_buffer:
             pto.c_tp_as_buffer = base.c_tp_as_buffer
+        if base.c_tp_as_buffer:
+            # inherit base.c_tp_as_buffer functions not inherited from w_type
+            # note: builtin types are handled in setup_buffer_procs
+            pto_as = pto.c_tp_as_buffer
+            base_as = base.c_tp_as_buffer
+            if not pto_as.c_bf_getbuffer:
+                pto_as.c_bf_getbuffer = base_as.c_bf_getbuffer
+            if not pto_as.c_bf_getcharbuffer:
+                pto_as.c_bf_getcharbuffer = base_as.c_bf_getcharbuffer
+            if not pto_as.c_bf_getwritebuffer:
+                pto_as.c_bf_getwritebuffer = base_as.c_bf_getwritebuffer
+            if not pto_as.c_bf_getreadbuffer:
+                pto_as.c_bf_getreadbuffer = base_as.c_bf_getreadbuffer
+            if not pto_as.c_bf_getsegcount:
+                pto_as.c_bf_getsegcount = base_as.c_bf_getsegcount
+            if not pto_as.c_bf_releasebuffer:
+                pto_as.c_bf_releasebuffer = base_as.c_bf_releasebuffer
     finally:
         Py_DecRef(space, base_pyo)
 
@@ -812,13 +851,14 @@
 
     w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
     track_reference(space, py_obj, w_obj)
-    w_obj.__init__(space, py_type)
+    # __init__ wraps all slotdefs functions from py_type via add_operators
+    w_obj.__init__(space, py_type) 
     w_obj.ready()
 
     finish_type_2(space, py_type, w_obj)
-    # inheriting tp_as_* slots
     base = py_type.c_tp_base
     if base:
+        # XXX refactor - parts of this are done in finish_type_2 -> 
inherit_slots
         if not py_type.c_tp_as_number: 
             py_type.c_tp_as_number = base.c_tp_as_number
             py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES
@@ -827,7 +867,7 @@
             py_type.c_tp_as_sequence = base.c_tp_as_sequence
             py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS
         if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = 
base.c_tp_as_mapping
-        if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = 
base.c_tp_as_buffer
+        #if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = 
base.c_tp_as_buffer
 
     return w_obj
 
diff --git a/pypy/module/micronumpy/test/dummy_module.py 
b/pypy/module/micronumpy/test/dummy_module.py
--- a/pypy/module/micronumpy/test/dummy_module.py
+++ b/pypy/module/micronumpy/test/dummy_module.py
@@ -27,7 +27,8 @@
 globals()['uint'] = dtype('uint').type
 
 types = ['Generic', 'Number', 'Integer', 'SignedInteger', 'UnsignedInteger',
-         'Inexact', 'Floating', 'ComplexFloating', 'Flexible', 'Character']
+         'Inexact', 'Floating', 'ComplexFloating', 'Flexible', 'Character',
+        ]
 for t in types:
     globals()[t.lower()] = typeinfo[t]
 
@@ -40,4 +41,4 @@
     return a
 
 def isscalar(a):
-    return type(a) in [typeinfo[t] for t in types]
+    return any([isinstance(a, typeinfo[t]) for t in types])
diff --git a/pypy/module/micronumpy/test/test_ndarray.py 
b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -1486,7 +1486,7 @@
         assert d[1] == 12
 
     def test_sum(self):
-        from numpy import array, zeros, float16, complex64, str_
+        from numpy import array, zeros, float16, complex64, str_, isscalar, add
         a = array(range(5))
         assert a.sum() == 10
         assert a[:4].sum() == 6
@@ -1515,6 +1515,13 @@
 
         assert list(zeros((0, 2)).sum(axis=1)) == []
 
+        a = array([1, 2, 3, 4]).sum()
+        s = isscalar(a)
+        assert s is True
+        a = add.reduce([1.0, 2, 3, 4])
+        s = isscalar(a)
+        assert s is True,'%r is not a scalar' % type(a)
+
     def test_reduce_nd(self):
         from numpy import arange, array
         a = arange(15).reshape(5, 3)
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -288,10 +288,8 @@
 
         _, dtype, _ = self.find_specialization(space, dtype, dtype, out,
                                                    casting='unsafe')
-        call__array_wrap__ = True
         if shapelen == len(axes):
             if out:
-                call__array_wrap__ = False
                 if out.ndims() > 0:
                     raise oefmt(space.w_ValueError,
                                 "output parameter for reduction operation %s 
has "
@@ -302,15 +300,20 @@
             if out:
                 out.set_scalar_value(res)
                 return out
+            w_NDimArray = space.gettypefor(W_NDimArray)
+            call__array_wrap__ = False
             if keepdims:
                 shape = [1] * len(obj_shape)
                 out = W_NDimArray.from_shape(space, shape, dtype, 
w_instance=obj)
                 out.implementation.setitem(0, res)
+                call__array_wrap__ = True
                 res = out
-            elif not space.is_w(space.type(w_obj), 
space.gettypefor(W_NDimArray)):
+            elif (space.issubtype_w(space.type(w_obj), w_NDimArray) and 
+                  not space.is_w(space.type(w_obj), w_NDimArray)):
                 # subtypes return a ndarray subtype, not a scalar
                 out = W_NDimArray.from_shape(space, [1], dtype, w_instance=obj)
                 out.implementation.setitem(0, res)
+                call__array_wrap__ = True
                 res = out
             if call__array_wrap__:
                 res = space.call_method(obj, '__array_wrap__', res, 
space.w_None)
@@ -359,8 +362,7 @@
                 return out
             loop.reduce(
                 space, self.func, obj, axis_flags, dtype, out, self.identity)
-            if call__array_wrap__:
-                out = space.call_method(obj, '__array_wrap__', out, 
space.w_None)
+            out = space.call_method(obj, '__array_wrap__', out, space.w_None)
             return out
 
     def descr_outer(self, space, args_w):
diff --git a/pypy/module/operator/test/test_operator.py 
b/pypy/module/operator/test/test_operator.py
--- a/pypy/module/operator/test/test_operator.py
+++ b/pypy/module/operator/test/test_operator.py
@@ -251,6 +251,13 @@
         exc = raises(TypeError, operator.index, "abc")
         assert str(exc.value) == "'str' object cannot be interpreted as an 
index"
 
+    def test_index_int_subclass(self):
+        import operator
+        class myint(int):
+            def __index__(self):
+                return 13289
+        assert operator.index(myint(7)) == 7
+
     def test_compare_digest(self):
         import operator
 
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -522,6 +522,23 @@
     def isinstance(space, w_inst, w_type):
         return space.wrap(space.isinstance_w(w_inst, w_type))
 
+    def index(space, w_obj):
+        if (space.isinstance_w(w_obj, space.w_int) or
+            space.isinstance_w(w_obj, space.w_long)):
+            return w_obj
+        w_impl = space.lookup(w_obj, '__index__')
+        if w_impl is None:
+            raise oefmt(space.w_TypeError,
+                        "'%T' object cannot be interpreted as an index",
+                        w_obj)
+        w_result = space.get_and_call_function(w_impl, w_obj)
+
+        if (space.isinstance_w(w_result, space.w_int) or
+            space.isinstance_w(w_result, space.w_long)):
+            return w_result
+        raise oefmt(space.w_TypeError,
+                    "__index__ returned non-(int,long) (type '%T')", w_result)
+
 
 # helpers
 
@@ -797,17 +814,13 @@
 # more of the above manually-coded operations as well)
 
 for targetname, specialname, checkerspec in [
-    ('index', '__index__', ("space.w_int", "space.w_long")),
     ('long', '__long__', ("space.w_int", "space.w_long")),
     ('float', '__float__', ("space.w_float",))]:
 
     l = ["space.isinstance_w(w_result, %s)" % x
                 for x in checkerspec]
     checker = " or ".join(l)
-    if targetname == 'index':
-        msg = "'%%T' object cannot be interpreted as an index"
-    else:
-        msg = "unsupported operand type for %(targetname)s(): '%%T'"
+    msg = "unsupported operand type for %(targetname)s(): '%%T'"
     msg = msg % locals()
     source = """if 1:
         def %(targetname)s(space, w_obj):
diff --git a/pypy/objspace/std/bufferobject.py 
b/pypy/objspace/std/bufferobject.py
--- a/pypy/objspace/std/bufferobject.py
+++ b/pypy/objspace/std/bufferobject.py
@@ -32,6 +32,10 @@
     def charbuf_w(self, space):
         return self.buf.as_str()
 
+    def descr_getbuffer(self, space, w_flags):
+        space.check_buf_flags(space.int_w(w_flags), self.buf.readonly)
+        return self
+
     @staticmethod
     @unwrap_spec(offset=int, size=int)
     def descr_new_buffer(space, w_subtype, w_object, offset=0, size=-1):
@@ -160,6 +164,7 @@
     __mul__ = interp2app(W_Buffer.descr_mul),
     __rmul__ = interp2app(W_Buffer.descr_mul),
     __repr__ = interp2app(W_Buffer.descr_repr),
+    __buffer__ = interp2app(W_Buffer.descr_getbuffer),
     _pypy_raw_address = interp2app(W_Buffer.descr_pypy_raw_address),
 )
 W_Buffer.typedef.acceptable_as_base_class = False
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
@@ -605,6 +605,9 @@
     def descr_mod(self, space, w_values):
         return mod_format(space, self, w_values, do_unicode=False)
 
+    def descr_rmod(self, space, w_values):
+        return mod_format(space, w_values, self, do_unicode=False)
+
     def descr_eq(self, space, w_other):
         if space.config.objspace.std.withstrbuf:
             from pypy.objspace.std.strbufobject import W_StringBufferObject
@@ -937,6 +940,7 @@
     format = interpindirect2app(W_BytesObject.descr_format),
     __format__ = interpindirect2app(W_BytesObject.descr__format__),
     __mod__ = interpindirect2app(W_BytesObject.descr_mod),
+    __rmod__ = interpindirect2app(W_BytesObject.descr_rmod),
     __getnewargs__ = interpindirect2app(
         W_AbstractBytesObject.descr_getnewargs),
     _formatter_parser = interp2app(W_BytesObject.descr_formatter_parser),
diff --git a/pypy/objspace/std/memoryobject.py 
b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -131,9 +131,13 @@
         return space.newbool(bool(self.buf.readonly))
 
     def w_get_shape(self, space):
+        if self.buf.getndim() == 0:
+            return space.w_None
         return space.newtuple([space.wrap(x) for x in self.buf.getshape()])
 
     def w_get_strides(self, space):
+        if self.buf.getndim() == 0:
+            return space.w_None
         return space.newtuple([space.wrap(x) for x in self.buf.getstrides()])
 
     def w_get_suboffsets(self, space):
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
@@ -649,10 +649,10 @@
             return self._starts_ends_overflow(prefix)
         return endswith(value, prefix, start, end)
 
-    def _strip(self, space, w_chars, left, right):
+    def _strip(self, space, w_chars, left, right, name='strip'):
         "internal function called by str_xstrip methods"
         value = self._val(space)
-        chars = self._op_val(space, w_chars, strict='strip')
+        chars = self._op_val(space, w_chars, strict=name)
 
         lpos = 0
         rpos = len(value)
@@ -689,17 +689,17 @@
     def descr_strip(self, space, w_chars=None):
         if space.is_none(w_chars):
             return self._strip_none(space, left=1, right=1)
-        return self._strip(space, w_chars, left=1, right=1)
+        return self._strip(space, w_chars, left=1, right=1, name='strip')
 
     def descr_lstrip(self, space, w_chars=None):
         if space.is_none(w_chars):
             return self._strip_none(space, left=1, right=0)
-        return self._strip(space, w_chars, left=1, right=0)
+        return self._strip(space, w_chars, left=1, right=0, name='lstrip')
 
     def descr_rstrip(self, space, w_chars=None):
         if space.is_none(w_chars):
             return self._strip_none(space, left=0, right=1)
-        return self._strip(space, w_chars, left=0, right=1)
+        return self._strip(space, w_chars, left=0, right=1, name='rstrip')
 
     def descr_swapcase(self, space):
         selfvalue = self._val(space)
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
@@ -92,6 +92,7 @@
         raises(ValueError, 'a%Zb'.__mod__, ((23,),))
 
     def test_format(self):
+        import sys
         raises(TypeError, "foo".__mod__, "bar")
         raises(TypeError, u"foo".__mod__, "bar")
         raises(TypeError, "foo".__mod__, u"bar")
@@ -105,6 +106,22 @@
             assert result == "a foo b"
             assert isinstance(result, cls)
 
+        for format, arg, cls in [("a %s b", "foo", str),
+                                 (u"a %s b", u"foo", unicode)]:
+            raises(TypeError, arg.__rmod__, format[:2])
+            result = arg.__rmod__(format)
+            assert result == "a foo b"
+            assert isinstance(result, cls)
+        for format, arg, cls in [(u"a %s b", "foo", str),
+                                 ("a %s b", u"foo", unicode)]:
+            result = arg.__rmod__(format)
+            if '__pypy__' in sys.builtin_module_names:
+                raises(TypeError, arg.__rmod__, format[:2])
+                assert result == "a foo b"
+                assert isinstance(result, cls)
+            else:
+                assert result is NotImplemented
+
     def test_format_c_overflow(self):
         raises(OverflowError, b'{0:c}'.format, -1)
         raises(OverflowError, b'{0:c}'.format, 256)
@@ -114,6 +131,7 @@
             exc_info = raises(TypeError, int_format.__mod__, '123')
             expected = int_format + ' format: a number is required, not str'
             assert str(exc_info.value) == expected
+        raises(TypeError, "None % 'abc'") # __rmod__
 
     def test_split(self):
         assert b"".split() == []
@@ -258,9 +276,9 @@
         exc = raises(TypeError, s.strip, buffer(' '))
         assert str(exc.value) == 'strip arg must be None, str or unicode'
         exc = raises(TypeError, s.rstrip, buffer(' '))
-        assert str(exc.value) == 'strip arg must be None, str or unicode'
+        assert str(exc.value) == 'rstrip arg must be None, str or unicode'
         exc = raises(TypeError, s.lstrip, buffer(' '))
-        assert str(exc.value) == 'strip arg must be None, str or unicode'
+        assert str(exc.value) == 'lstrip arg must be None, str or unicode'
 
     def test_zfill(self):
         assert b'123'.zfill(2) == b'123'
@@ -809,6 +827,10 @@
         raises(TypeError, len, iter(iterable))
 
     def test___radd__(self):
+        raises(TypeError, "None + ''")
+        raises(AttributeError, "'abc'.__radd__('def')")
+
+
         class Foo(object):
             def __radd__(self, other):
                 return 42
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
@@ -335,9 +335,9 @@
         exc = raises(TypeError, s.strip, buffer(' '))
         assert str(exc.value) == 'strip arg must be None, unicode or str'
         exc = raises(TypeError, s.rstrip, buffer(' '))
-        assert str(exc.value) == 'strip arg must be None, unicode or str'
+        assert str(exc.value) == 'rstrip arg must be None, unicode or str'
         exc = raises(TypeError, s.lstrip, buffer(' '))
-        assert str(exc.value) == 'strip arg must be None, unicode or str'
+        assert str(exc.value) == 'lstrip arg must be None, unicode or str'
 
     def test_strip_str_unicode(self):
         x = "--abc--".strip(u"-")
@@ -748,7 +748,9 @@
         assert 'abc'.__add__(u'def') == u'abcdef'
         assert u'abc'.__add__(u'def') == u'abcdef'
         assert u'abc'.__add__('def') == u'abcdef'
-        # xxx CPython has no str.__radd__ and no unicode.__radd__
+        assert u'abc'.__rmod__(u'%s') == u'abc'
+        ret = u'abc'.__rmod__('%s')
+        raises(AttributeError, "u'abc'.__radd__(u'def')")
 
     def test_str_unicode_concat_overrides(self):
         "Test from Jython about being bug-compatible with CPython."
diff --git a/pypy/objspace/std/unicodeobject.py 
b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -319,6 +319,9 @@
     def descr_mod(self, space, w_values):
         return mod_format(space, self, w_values, do_unicode=True)
 
+    def descr_rmod(self, space, w_values):
+        return mod_format(space, w_values, self, do_unicode=True)
+
     def descr_translate(self, space, w_table):
         selfvalue = self._value
         w_sys = space.getbuiltinmodule('sys')
@@ -633,6 +636,9 @@
     def __mod__():
         """x.__mod__(y) <==> x%y"""
 
+    def __rmod__():
+        """x.__rmod__(y) <==> y%x"""
+
     def __mul__():
         """x.__mul__(n) <==> x*n"""
 
@@ -1096,6 +1102,8 @@
                             doc=UnicodeDocstrings.__format__.__doc__),
     __mod__ = interp2app(W_UnicodeObject.descr_mod,
                          doc=UnicodeDocstrings.__mod__.__doc__),
+    __rmod__ = interp2app(W_UnicodeObject.descr_rmod,
+                         doc=UnicodeDocstrings.__rmod__.__doc__),
     __getnewargs__ = interp2app(W_UnicodeObject.descr_getnewargs,
                                 doc=UnicodeDocstrings.__getnewargs__.__doc__),
     _formatter_parser = interp2app(W_UnicodeObject.descr_formatter_parser),
diff --git a/rpython/jit/backend/detect_cpu.py 
b/rpython/jit/backend/detect_cpu.py
--- a/rpython/jit/backend/detect_cpu.py
+++ b/rpython/jit/backend/detect_cpu.py
@@ -61,6 +61,7 @@
             'i86pc': MODEL_X86,    # Solaris/Intel
             'x86': MODEL_X86,      # Apple
             'Power Macintosh': MODEL_PPC_64,
+            'powerpc': MODEL_PPC_64, # freebsd
             'ppc64': MODEL_PPC_64,
             'ppc64le': MODEL_PPC_64,
             'x86_64': MODEL_X86,
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -510,6 +510,8 @@
 
 # ----------
 
+HASH_ALGORITHM = "rpython"  # XXX Is there a better name?
+
 def _hash_string(s):
     """The algorithm behind compute_hash() for a string or a unicode."""
     from rpython.rlib.rarithmetic import intmask
diff --git a/rpython/rlib/rlocale.py b/rpython/rlib/rlocale.py
--- a/rpython/rlib/rlocale.py
+++ b/rpython/rlib/rlocale.py
@@ -195,6 +195,7 @@
 
 isalpha = external('isalpha', [rffi.INT], rffi.INT)
 isupper = external('isupper', [rffi.INT], rffi.INT)
+toupper = external('toupper', [rffi.INT], rffi.INT)
 islower = external('islower', [rffi.INT], rffi.INT)
 tolower = external('tolower', [rffi.INT], rffi.INT)
 isalnum = external('isalnum', [rffi.INT], rffi.INT)
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -236,6 +236,8 @@
                 'utime.h', 'sys/time.h', 'sys/times.h',
                 'grp.h', 'dirent.h', 'sys/stat.h', 'fcntl.h',
                 'signal.h', 'sys/utsname.h', _ptyh]
+    if sys.platform.startswith('freebsd'):
+        includes.append('sys/ttycom.h')
     libraries = ['util']
 eci = ExternalCompilationInfo(
     includes=includes,
@@ -2306,6 +2308,7 @@
 
 _pipe2_syscall = ENoSysCache()
 
+post_include_bits=['int _cpu_count(void);']
 # cpu count for linux, windows and mac (+ bsds)
 # note that the code is copied from cpython and split up here
 if sys.platform.startswith('linux'):
@@ -2314,17 +2317,16 @@
             RPY_EXTERN int _cpu_count(void) {
                 return sysconf(_SC_NPROCESSORS_ONLN);
             }
-            """])
+            """], post_include_bits=post_include_bits)
 elif sys.platform == "win32":
     cpucount_eci = ExternalCompilationInfo(includes=["Windows.h"],
             separate_module_sources=["""
         RPY_EXTERN int _cpu_count(void) {
-            int ncpu = 0;
             SYSTEM_INFO sysinfo;
             GetSystemInfo(&sysinfo);
             return sysinfo.dwNumberOfProcessors;
         }
-        """])
+        """], post_include_bits=post_include_bits)
 else:
     cpucount_eci = ExternalCompilationInfo(includes=["sys/types.h", 
"sys/sysctl.h"],
             separate_module_sources=["""
@@ -2344,8 +2346,10 @@
             #endif
                 return ncpu;
             }
-            """])
+            """], post_include_bits=post_include_bits)
 
-cpu_count = rffi.llexternal('_cpu_count', [], rffi.INT_real,
+_cpu_count = rffi.llexternal('_cpu_count', [], rffi.INT_real,
                             compilation_info=cpucount_eci)
 
+def cpu_count():
+    return rffi.cast(lltype.Signed, _cpu_count())
diff --git a/rpython/rlib/rsre/rpy/sre_constants.py 
b/rpython/rlib/rsre/rpy/sre_constants.py
--- a/rpython/rlib/rsre/rpy/sre_constants.py
+++ b/rpython/rlib/rsre/rpy/sre_constants.py
@@ -58,6 +58,7 @@
 REPEAT_ONE = "repeat_one"
 SUBPATTERN = "subpattern"
 MIN_REPEAT_ONE = "min_repeat_one"
+RANGE_IGNORE = "range_ignore"
 
 # positions
 AT_BEGINNING = "at_beginning"
@@ -119,8 +120,8 @@
     REPEAT,
     REPEAT_ONE,
     SUBPATTERN,
-    MIN_REPEAT_ONE
-
+    MIN_REPEAT_ONE,
+    RANGE_IGNORE,
 ]
 
 ATCODES = [
diff --git a/rpython/rlib/rsre/rsre_char.py b/rpython/rlib/rsre/rsre_char.py
--- a/rpython/rlib/rsre/rsre_char.py
+++ b/rpython/rlib/rsre/rsre_char.py
@@ -2,7 +2,7 @@
 Character categories and charsets.
 """
 import sys
-from rpython.rlib.rlocale import tolower, isalnum
+from rpython.rlib.rlocale import tolower, toupper, isalnum
 from rpython.rlib.unroll import unrolling_iterable
 from rpython.rlib import jit
 from rpython.rlib.rarithmetic import int_between
@@ -67,6 +67,19 @@
             char_ord += ord('a') - ord('A')
     return char_ord
 
+def getupper(char_ord, flags):
+    if flags & SRE_FLAG_LOCALE:
+        if char_ord < 256:      # cheating!  Well, CPython does too.
+            char_ord = toupper(char_ord)
+        return char_ord
+    elif flags & SRE_FLAG_UNICODE:
+        assert unicodedb is not None
+        char_ord = unicodedb.toupper(char_ord)
+    else:
+        if int_between(ord('a'), char_ord, ord('z') + 1):   # ASCII upper
+            char_ord += ord('A') - ord('a')
+    return char_ord
+
 #### Category helpers
 
 is_a_word = [(chr(i).isalnum() or chr(i) == '_') for i in range(256)]
@@ -139,16 +152,17 @@
 ##### Charset evaluation
 
 @jit.unroll_safe
-def check_charset(pattern, ppos, char_code):
+def check_charset(ctx, ppos, char_code):
     """Checks whether a character matches set of arbitrary length.
     The set starts at pattern[ppos]."""
     negated = False
     result = False
+    pattern = ctx.pattern
     while True:
         opcode = pattern[ppos]
         for i, function in set_dispatch_unroll:
             if opcode == i:
-                newresult, ppos = function(pattern, ppos, char_code)
+                newresult, ppos = function(ctx, ppos, char_code)
                 result |= newresult
                 break
         else:
@@ -163,18 +177,21 @@
         return not result
     return result
 
-def set_literal(pat, index, char_code):
+def set_literal(ctx, index, char_code):
     # <LITERAL> <code>
+    pat = ctx.pattern
     match = pat[index+1] == char_code
     return match, index + 2
 
-def set_category(pat, index, char_code):
+def set_category(ctx, index, char_code):
     # <CATEGORY> <code>
+    pat = ctx.pattern
     match = category_dispatch(pat[index+1], char_code)
     return match, index + 2
 
-def set_charset(pat, index, char_code):
+def set_charset(ctx, index, char_code):
     # <CHARSET> <bitmap> (16 bits per code word)
+    pat = ctx.pattern
     if CODESIZE == 2:
         match = char_code < 256 and \
                 (pat[index+1+(char_code >> 4)] & (1 << (char_code & 15)))
@@ -184,13 +201,25 @@
                 (pat[index+1+(char_code >> 5)] & (1 << (char_code & 31)))
         return match, index + 9   # skip bitmap
 
-def set_range(pat, index, char_code):
+def set_range(ctx, index, char_code):
     # <RANGE> <lower> <upper>
+    pat = ctx.pattern
     match = int_between(pat[index+1], char_code, pat[index+2] + 1)
     return match, index + 3
 
-def set_bigcharset(pat, index, char_code):
+def set_range_ignore(ctx, index, char_code):
+    # <RANGE_IGNORE> <lower> <upper>
+    # the char_code is already lower cased
+    pat = ctx.pattern
+    lower = pat[index + 1]
+    upper = pat[index + 2]
+    match1 = int_between(lower, char_code, upper + 1)
+    match2 = int_between(lower, getupper(char_code, ctx.flags), upper + 1)
+    return match1 | match2, index + 3
+
+def set_bigcharset(ctx, index, char_code):
     # <BIGCHARSET> <blockcount> <256 blockindices> <blocks>
+    pat = ctx.pattern
     count = pat[index+1]
     index += 2
 
@@ -224,7 +253,7 @@
     index += count * (32 / CODESIZE)  # skip blocks
     return match, index
 
-def set_unicode_general_category(pat, index, char_code):
+def set_unicode_general_category(ctx, index, char_code):
     # Unicode "General category property code" (not used by Python).
     # A general category is two letters.  'pat[index+1]' contains both
     # the first character, and the second character shifted by 8.
@@ -233,6 +262,7 @@
     # Negative matches are triggered by bit number 7.
     assert unicodedb is not None
     cat = unicodedb.category(char_code)
+    pat = ctx.pattern
     category_code = pat[index + 1]
     first_character = category_code & 0x7F
     second_character = (category_code >> 8) & 0x7F
@@ -260,6 +290,7 @@
     11: set_bigcharset,
     19: set_literal,
     27: set_range,
+    32: set_range_ignore,
     70: set_unicode_general_category,
 }
 set_dispatch_unroll = unrolling_iterable(sorted(set_dispatch_table.items()))
diff --git a/rpython/rlib/rsre/rsre_core.py b/rpython/rlib/rsre/rsre_core.py
--- a/rpython/rlib/rsre/rsre_core.py
+++ b/rpython/rlib/rsre/rsre_core.py
@@ -40,6 +40,7 @@
 OPCODE_REPEAT_ONE         = 29
 #OPCODE_SUBPATTERN        = 30
 OPCODE_MIN_REPEAT_ONE     = 31
+OPCODE_RANGE_IGNORE       = 32
 
 # not used by Python itself
 OPCODE_UNICODE_GENERAL_CATEGORY = 70
@@ -640,8 +641,7 @@
         elif op == OPCODE_IN:
             # match set member (or non_member)
             # <IN> <skip> <set>
-            if ptr >= ctx.end or not rsre_char.check_charset(ctx.pattern,
-                                                             ppos+1,
+            if ptr >= ctx.end or not rsre_char.check_charset(ctx, ppos+1,
                                                              ctx.str(ptr)):
                 return
             ppos += ctx.pat(ppos)
@@ -650,8 +650,7 @@
         elif op == OPCODE_IN_IGNORE:
             # match set member (or non_member), ignoring case
             # <IN> <skip> <set>
-            if ptr >= ctx.end or not rsre_char.check_charset(ctx.pattern,
-                                                             ppos+1,
+            if ptr >= ctx.end or not rsre_char.check_charset(ctx, ppos+1,
                                                              ctx.lowstr(ptr)):
                 return
             ppos += ctx.pat(ppos)
@@ -871,10 +870,10 @@
     return True    # match anything (including a newline)
 @specializectx
 def match_IN(ctx, ptr, ppos):
-    return rsre_char.check_charset(ctx.pattern, ppos+2, ctx.str(ptr))
+    return rsre_char.check_charset(ctx, ppos+2, ctx.str(ptr))
 @specializectx
 def match_IN_IGNORE(ctx, ptr, ppos):
-    return rsre_char.check_charset(ctx.pattern, ppos+2, ctx.lowstr(ptr))
+    return rsre_char.check_charset(ctx, ppos+2, ctx.lowstr(ptr))
 @specializectx
 def match_LITERAL(ctx, ptr, ppos):
     return ctx.str(ptr) == ctx.pat(ppos+1)
@@ -1134,7 +1133,7 @@
     while start < ctx.end:
         ctx.jitdriver_CharsetSearch.jit_merge_point(ctx=ctx, start=start,
                                                     base=base)
-        if rsre_char.check_charset(ctx.pattern, 5, ctx.str(start)):
+        if rsre_char.check_charset(ctx, 5, ctx.str(start)):
             if sre_match(ctx, base, start, None) is not None:
                 ctx.match_start = start
                 return True
diff --git a/rpython/rlib/rsre/test/test_char.py 
b/rpython/rlib/rsre/test/test_char.py
--- a/rpython/rlib/rsre/test/test_char.py
+++ b/rpython/rlib/rsre/test/test_char.py
@@ -34,6 +34,22 @@
     assert rsre_char.getlower(UPPER_PI, SRE_FLAG_LOCALE | SRE_FLAG_UNICODE) \
                                                          == UPPER_PI
 
+def test_getupper():
+    assert rsre_char.getupper(ord('A'), 0) == ord('A')
+    assert rsre_char.getupper(ord('b'), 0) == ord('B')
+    assert rsre_char.getupper(10, 0) == 10
+    assert rsre_char.getupper(LOWER_PI, 0) == LOWER_PI
+    #
+    assert rsre_char.getupper(ord('a'), SRE_FLAG_UNICODE) == ord('A')
+    assert rsre_char.getupper(ord('2'), SRE_FLAG_UNICODE) == ord('2')
+    assert rsre_char.getupper(10, SRE_FLAG_UNICODE) == 10
+    assert rsre_char.getupper(LOWER_PI, SRE_FLAG_UNICODE) == UPPER_PI
+    #
+    assert rsre_char.getupper(LOWER_PI, SRE_FLAG_LOCALE) == LOWER_PI
+    assert rsre_char.getupper(LOWER_PI, SRE_FLAG_LOCALE | SRE_FLAG_UNICODE) \
+                                                         == LOWER_PI
+
+
 def test_is_word():
     assert rsre_char.is_word(ord('A'))
     assert rsre_char.is_word(ord('_'))
@@ -128,6 +144,10 @@
     assert     cat(CHCODES["category_uni_not_digit"], DINGBAT_CIRCLED)
 
 
+class Ctx:
+    def __init__(self, pattern):
+        self.pattern = pattern
+
 def test_general_category():
     from rpython.rlib.unicodedata import unicodedb
 
@@ -137,12 +157,12 @@
         pat_neg = [70, ord(cat) | 0x80, 0]
         for c in positive:
             assert unicodedb.category(ord(c)).startswith(cat)
-            assert rsre_char.check_charset(pat_pos, 0, ord(c))
-            assert not rsre_char.check_charset(pat_neg, 0, ord(c))
+            assert rsre_char.check_charset(Ctx(pat_pos), 0, ord(c))
+            assert not rsre_char.check_charset(Ctx(pat_neg), 0, ord(c))
         for c in negative:
             assert not unicodedb.category(ord(c)).startswith(cat)
-            assert not rsre_char.check_charset(pat_pos, 0, ord(c))
-            assert rsre_char.check_charset(pat_neg, 0, ord(c))
+            assert not rsre_char.check_charset(Ctx(pat_pos), 0, ord(c))
+            assert rsre_char.check_charset(Ctx(pat_neg), 0, ord(c))
 
     def cat2num(cat):
         return ord(cat[0]) | (ord(cat[1]) << 8)
@@ -153,17 +173,17 @@
         pat_neg = [70, cat2num(cat) | 0x80, 0]
         for c in positive:
             assert unicodedb.category(ord(c)) == cat
-            assert rsre_char.check_charset(pat_pos, 0, ord(c))
-            assert not rsre_char.check_charset(pat_neg, 0, ord(c))
+            assert rsre_char.check_charset(Ctx(pat_pos), 0, ord(c))
+            assert not rsre_char.check_charset(Ctx(pat_neg), 0, ord(c))
         for c in negative:
             assert unicodedb.category(ord(c)) != cat
-            assert not rsre_char.check_charset(pat_pos, 0, ord(c))
-            assert rsre_char.check_charset(pat_neg, 0, ord(c))
+            assert not rsre_char.check_charset(Ctx(pat_pos), 0, ord(c))
+            assert rsre_char.check_charset(Ctx(pat_neg), 0, ord(c))
 
     # test for how the common 'L&' pattern might be compiled
     pat = [70, cat2num('Lu'), 70, cat2num('Ll'), 70, cat2num('Lt'), 0]
-    assert rsre_char.check_charset(pat, 0, 65)    # Lu
-    assert rsre_char.check_charset(pat, 0, 99)    # Ll
-    assert rsre_char.check_charset(pat, 0, 453)   # Lt
-    assert not rsre_char.check_charset(pat, 0, 688)    # Lm
-    assert not rsre_char.check_charset(pat, 0, 5870)   # Nl
+    assert rsre_char.check_charset(Ctx(pat), 0, 65)    # Lu
+    assert rsre_char.check_charset(Ctx(pat), 0, 99)    # Ll
+    assert rsre_char.check_charset(Ctx(pat), 0, 453)   # Lt
+    assert not rsre_char.check_charset(Ctx(pat), 0, 688)    # Lm
+    assert not rsre_char.check_charset(Ctx(pat), 0, 5870)   # Nl
diff --git a/rpython/rlib/rsre/test/test_match.py 
b/rpython/rlib/rsre/test/test_match.py
--- a/rpython/rlib/rsre/test/test_match.py
+++ b/rpython/rlib/rsre/test/test_match.py
@@ -1,5 +1,5 @@
 import re, random, py
-from rpython.rlib.rsre import rsre_core
+from rpython.rlib.rsre import rsre_core, rsre_char
 from rpython.rlib.rsre.rpy import get_code, VERSION
 
 
@@ -299,3 +299,12 @@
         assert rsre_core.fullmatch(r, "ab")
         r = get_code(r"(?!a)..")
         assert not rsre_core.fullmatch(r, "ab")
+
+    def test_range_ignore(self):
+        from rpython.rlib.unicodedata import unicodedb
+        rsre_char.set_unicode_db(unicodedb)
+        #
+        r = get_code(u"[\U00010428-\U0001044f]", re.I)
+        assert r.count(27) == 1       # OPCODE_RANGE
+        r[r.index(27)] = 32           # => OPCODE_RANGE_IGNORE
+        assert rsre_core.match(r, u"\U00010428")
diff --git a/rpython/rlib/rtime.py b/rpython/rlib/rtime.py
--- a/rpython/rlib/rtime.py
+++ b/rpython/rlib/rtime.py
@@ -29,7 +29,8 @@
                 'sys/types.h', 'unistd.h',
                 'sys/time.h', 'sys/resource.h']
 
-    if not sys.platform.startswith("openbsd"):
+    if not sys.platform.startswith("openbsd") and \
+       not sys.platform.startswith("freebsd"):
         includes.append('sys/timeb.h')
 
     need_rusage = True
diff --git a/rpython/tool/runsubprocess.py b/rpython/tool/runsubprocess.py
--- a/rpython/tool/runsubprocess.py
+++ b/rpython/tool/runsubprocess.py
@@ -8,9 +8,15 @@
 import os
 from subprocess import PIPE, Popen
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to