Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r89500:d33af2cf0f9f
Date: 2017-01-11 18:43 +0000
http://bitbucket.org/pypy/pypy/changeset/d33af2cf0f9f/

Log:    hg merge default

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
@@ -98,6 +98,7 @@
 is readonly) without pinning it.
 
 .. branch: cpyext-cleanup
+.. branch: api_func-refactor
 
 Refactor cpyext initialisation.
 
@@ -105,3 +106,7 @@
 
 Fix a test failure introduced by strbuf-as-buffer
 
+.. branch: cpyext-FromBuffer
+
+Do not recreate the object in PyMemoryView_FromBuffer, rather pass it to
+the returned PyMemoryViewObject, to take ownership of it. Fixes a ref leak.
diff --git a/pypy/module/cppyy/test/conftest.py 
b/pypy/module/cppyy/test/conftest.py
--- a/pypy/module/cppyy/test/conftest.py
+++ b/pypy/module/cppyy/test/conftest.py
@@ -23,6 +23,10 @@
 def pytest_ignore_collect(path, config):
     if py.path.local.sysfind('genreflex') is None and 
config.option.runappdirect:
         return True          # "can't run dummy tests in -A"
+    if disabled:
+        return True
+
+disabled = None
 
 def pytest_configure(config):
     if py.path.local.sysfind('genreflex') is None:
@@ -37,7 +41,7 @@
             # build dummy backend (which has reflex info and calls hard-wired)
             import os
             from rpython.translator.tool.cbuild import ExternalCompilationInfo
-            from rpython.translator.platform import platform
+            from rpython.translator.platform import platform, CompilationError
             from rpython.translator import cdir
 
             from rpython.rtyper.lltypesystem import rffi
@@ -55,9 +59,16 @@
                 use_cpp_linker=True,
             )
 
-            soname = platform.compile(
-                [], eci,
-                outputfilename='libcppyy_dummy_backend',
-                standalone=False)
+            try:
+                soname = platform.compile(
+                    [], eci,
+                    outputfilename='libcppyy_dummy_backend',
+                    standalone=False)
+            except CompilationError as e:
+                if '-std=c++11' in str(e):
+                    global disabled
+                    disabled = str(e)
+                    return
+                raise
 
             lcapi.reflection_library = str(soname)
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
@@ -124,6 +124,7 @@
 Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
 Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_MAX_NDIMS
 Py_CLEANUP_SUPPORTED
+PyBUF_FORMAT PyBUF_ND PyBUF_STRIDES
 """.split()
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
@@ -248,14 +249,13 @@
 cpyext_namespace = NameManager('cpyext_')
 
 class ApiFunction(object):
-    def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
+    def __init__(self, argtypes, restype, callable, error=CANNOT_FAIL,
                  c_name=None, gil=None, result_borrowed=False, 
result_is_ll=False):
         self.argtypes = argtypes
         self.restype = restype
         self.functype = lltype.Ptr(lltype.FuncType(argtypes, restype))
         self.callable = callable
-        if error is not _NOT_SPECIFIED:
-            self.error_value = error
+        self.error_value = error
         self.c_name = c_name
 
         # extract the signature from the (CPython-level) code object
@@ -300,7 +300,7 @@
 
         argtypesw = zip(self.argtypes,
                         [_name.startswith("w_") for _name in self.argnames])
-        error_value = getattr(self, "error_value", CANNOT_FAIL)
+        error_value = self.error_value
         if (isinstance(self.restype, lltype.Ptr)
                 and error_value is not CANNOT_FAIL):
             assert lltype.typeOf(error_value) == self.restype
@@ -332,66 +332,19 @@
             wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
         return wrapper
 
-DEFAULT_HEADER = 'pypy_decl.h'
-def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header=DEFAULT_HEADER,
-                gil=None, result_borrowed=False, result_is_ll=False):
-    """
-    Declares a function to be exported.
-    - `argtypes`, `restype` are lltypes and describe the function signature.
-    - `error` is the value returned when an applevel exception is raised. The
-      special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual
-      exception into a wrapped SystemError.  Unwrapped exceptions also cause a
-      SytemError.
-    - `header` is the header file to export the function in, Set to None to get
-      a C function pointer, but not exported by the API headers.
-    - set `gil` to "acquire", "release" or "around" to acquire the GIL,
-      release the GIL, or both
-    """
-    if isinstance(restype, lltype.Typedef):
-        real_restype = restype.OF
-    else:
-        real_restype = restype
-
-    if error is _NOT_SPECIFIED:
-        if isinstance(real_restype, lltype.Ptr):
-            error = lltype.nullptr(real_restype.TO)
-        elif real_restype is lltype.Void:
-            error = CANNOT_FAIL
-    if type(error) is int:
-        error = rffi.cast(real_restype, error)
-    expect_integer = (isinstance(real_restype, lltype.Primitive) and
-                      rffi.cast(restype, 0) == 0)
-
-    def decorate(func):
-        func._always_inline_ = 'try'
-        func_name = func.func_name
-        if header is not None:
-            c_name = None
-            if func_name in FUNCTIONS_BY_HEADER[header]:
-                raise ValueError("%s already registered" % func_name)
-        else:
-            c_name = func_name
-        api_function = ApiFunction(argtypes, restype, func, error,
-                                   c_name=c_name, gil=gil,
-                                   result_borrowed=result_borrowed,
-                                   result_is_ll=result_is_ll)
-        func.api_func = api_function
-
-        if error is _NOT_SPECIFIED:
-            raise ValueError("function %s has no return value for exceptions"
-                             % func)
-        names = api_function.argnames
-        types_names_enum_ui = unrolling_iterable(enumerate(
-            zip(api_function.argtypes,
-                [tp_name.startswith("w_") for tp_name in names])))
+    def get_unwrapper(self):
+        names = self.argnames
+        argtypesw = zip(self.argtypes,
+                        [_name.startswith("w_") for _name in self.argnames])
+        types_names_enum_ui = unrolling_iterable(enumerate(argtypesw))
 
         @specialize.ll()
         def unwrapper(space, *args):
-            from pypy.module.cpyext.pyobject import Py_DecRef, is_pyobj
+            from pypy.module.cpyext.pyobject import is_pyobj
             from pypy.module.cpyext.pyobject import from_ref, as_pyobj
             newargs = ()
             keepalives = ()
-            assert len(args) == len(api_function.argtypes)
+            assert len(args) == len(self.argtypes)
             for i, (ARG, is_wrapped) in types_names_enum_ui:
                 input_arg = args[i]
                 if is_PyObject(ARG) and not is_wrapped:
@@ -416,33 +369,81 @@
                         arg = from_ref(space, input_arg)
                     else:
                         arg = input_arg
-
-                        ## ZZZ: for is_pyobj:
-                        ## try:
-                        ##     arg = from_ref(space,
-                        ##                rffi.cast(PyObject, input_arg))
-                        ## except TypeError, e:
-                        ##     err = oefmt(space.w_TypeError,
-                        ##                 "could not cast arg to PyObject")
-                        ##     if not catch_exception:
-                        ##         raise err
-                        ##     state = space.fromcache(State)
-                        ##     state.set_exception(err)
-                        ##     if is_PyObject(restype):
-                        ##         return None
-                        ##     else:
-                        ##         return api_function.error_value
                 else:
                     # arg is not declared as PyObject, no magic
                     arg = input_arg
                 newargs += (arg, )
             try:
-                return func(space, *newargs)
+                return self.callable(space, *newargs)
             finally:
                 keepalive_until_here(*keepalives)
+        return unwrapper
 
-        unwrapper.func = func
-        unwrapper.api_func = api_function
+    def get_c_restype(self, c_writer):
+        return c_writer.gettype(self.restype).replace('@', '').strip()
+
+    def get_c_args(self, c_writer):
+        args = []
+        for i, argtype in enumerate(self.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:
+                arg = c_writer.gettype(argtype)
+            arg = arg.replace('@', 'arg%d' % (i,)).strip()
+            args.append(arg)
+        args = ', '.join(args) or "void"
+        return args
+
+    def get_api_decl(self, name, c_writer):
+        restype = self.get_c_restype(c_writer)
+        args = self.get_c_args(c_writer)
+        return "PyAPI_FUNC({restype}) {name}({args});".format(**locals())
+
+    def get_ptr_decl(self, name, c_writer):
+        restype = self.get_c_restype(c_writer)
+        args = self.get_c_args(c_writer)
+        return "{restype} (*{name})({args});".format(**locals())
+
+    def get_ctypes_impl(self, name, c_writer):
+        restype = self.get_c_restype(c_writer)
+        args = self.get_c_args(c_writer)
+        callargs = ', '.join('arg%d' % (i,)
+                            for i in range(len(self.argtypes)))
+        if self.restype is lltype.Void:
+            body = "{ _pypyAPI.%s(%s); }" % (name, callargs)
+        else:
+            body = "{ return _pypyAPI.%s(%s); }" % (name, callargs)
+        return '%s %s(%s)\n%s' % (restype, name, args, body)
+
+
+DEFAULT_HEADER = 'pypy_decl.h'
+def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, header=DEFAULT_HEADER,
+                gil=None, result_borrowed=False, result_is_ll=False):
+    """
+    Declares a function to be exported.
+    - `argtypes`, `restype` are lltypes and describe the function signature.
+    - `error` is the value returned when an applevel exception is raised. The
+      special value 'CANNOT_FAIL' (also when restype is Void) turns an eventual
+      exception into a wrapped SystemError.  Unwrapped exceptions also cause a
+      SytemError.
+    - `header` is the header file to export the function in.
+    - set `gil` to "acquire", "release" or "around" to acquire the GIL,
+      release the GIL, or both
+    """
+    assert header is not None
+    def decorate(func):
+        if func.__name__ in FUNCTIONS_BY_HEADER[header]:
+            raise ValueError("%s already registered" % func.__name__)
+        func._always_inline_ = 'try'
+        api_function = ApiFunction(
+            argtypes, restype, func,
+            error=_compute_error(error, restype), gil=gil,
+            result_borrowed=result_borrowed, result_is_ll=result_is_ll)
+        FUNCTIONS_BY_HEADER[header][func.__name__] = api_function
 
         # ZZZ is this whole logic really needed???  It seems to be only
         # for RPython code calling PyXxx() functions directly.  I would
@@ -452,25 +453,61 @@
             try:
                 res = unwrapper(space, *args)
             except OperationError as e:
-                if not hasattr(api_function, "error_value"):
+                if not hasattr(unwrapper.api_func, "error_value"):
                     raise
                 state = space.fromcache(State)
                 state.set_exception(e)
                 if is_PyObject(restype):
                     return None
                 else:
-                    return api_function.error_value
+                    return unwrapper.api_func.error_value
             got_integer = isinstance(res, (int, long, float))
+            if isinstance(restype, lltype.Typedef):
+                real_restype = restype.OF
+            else:
+                real_restype = restype
+            expect_integer = (isinstance(real_restype, lltype.Primitive) and
+                            rffi.cast(restype, 0) == 0)
             assert got_integer == expect_integer, (
                 'got %r not integer' % (res,))
             return res
+        INTERPLEVEL_API[func.__name__] = unwrapper_catch  # used in tests
 
-        if header is not None:
-            FUNCTIONS_BY_HEADER[header][func_name] = api_function
-        INTERPLEVEL_API[func_name] = unwrapper_catch  # used in tests
-        return unwrapper  # used in 'normal' RPython code.
+        unwrapper = api_function.get_unwrapper()
+        unwrapper.func = func
+        unwrapper.api_func = api_function
+        return unwrapper
     return decorate
 
+def slot_function(argtypes, restype, error=_NOT_SPECIFIED):
+    def decorate(func):
+        func._always_inline_ = 'try'
+        api_function = ApiFunction(
+            argtypes, restype, func,
+            error=_compute_error(error, restype),
+            c_name=func.__name__)
+        unwrapper = api_function.get_unwrapper()
+        unwrapper.func = func
+        unwrapper.api_func = api_function
+        return unwrapper
+    return decorate
+
+def _compute_error(error, restype):
+    """Convert error specification to actual error value of type restype."""
+    if isinstance(restype, lltype.Typedef):
+        real_restype = restype.OF
+    else:
+        real_restype = restype
+    if error is _NOT_SPECIFIED:
+        if isinstance(real_restype, lltype.Ptr):
+            error = lltype.nullptr(real_restype.TO)
+        elif real_restype is lltype.Void:
+            error = CANNOT_FAIL
+    if type(error) is int:
+        error = rffi.cast(real_restype, error)
+    return error
+
+
 def cpython_struct(name, fields, forward=None, level=1):
     configname = name.replace(' ', '__')
     if level == 1:
@@ -981,23 +1018,6 @@
     for func in BOOTSTRAP_FUNCTIONS:
         func(space)
 
-def c_function_signature(db, func):
-    restype = db.gettype(func.restype).replace('@', '').strip()
-    args = []
-    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:
-            arg = db.gettype(argtype)
-        arg = arg.replace('@', 'arg%d' % (i,)).strip()
-        args.append(arg)
-    args = ', '.join(args) or "void"
-    return restype, args
-
 #_____________________________________________________
 # Build the bridge DLL, Allow extension DLLs to call
 # back into Pypy space functions
@@ -1017,15 +1037,8 @@
     structindex = {}
     for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
         for name, func in header_functions.iteritems():
-            restype, args = c_function_signature(db, func)
-            callargs = ', '.join('arg%d' % (i,)
-                                for i in range(len(func.argtypes)))
-            if func.restype is lltype.Void:
-                body = "{ _pypyAPI.%s(%s); }" % (name, callargs)
-            else:
-                body = "{ return _pypyAPI.%s(%s); }" % (name, callargs)
-            functions.append('%s %s(%s)\n%s' % (restype, name, args, body))
-            members.append('%s (*%s)(%s);' % (restype, name, args))
+            functions.append(func.get_ctypes_impl(name, db))
+            members.append(func.get_ptr_decl(name, db))
             structindex[name] = len(structindex)
     structmembers = '\n'.join(members)
     struct_declaration_code = """\
@@ -1220,8 +1233,7 @@
         for name, func in sorted(header_functions.iteritems()):
             _name = mangle_name(prefix, name)
             header.append("#define %s %s" % (name, _name))
-            restype, args = c_function_signature(db, func)
-            header.append("PyAPI_FUNC(%s) %s(%s);" % (restype, name, args))
+            header.append(func.get_api_decl(name, db))
 
     for name, (typ, expr) in GLOBALS.iteritems():
         if '#' in name:
diff --git a/pypy/module/cpyext/bytesobject.py 
b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -2,7 +2,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
-    PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
+    PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL, slot_function)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
@@ -25,14 +25,14 @@
 ##
 ## In the PyBytesObject returned, the ob_sval buffer may be modified as
 ## long as the freshly allocated PyBytesObject is not "forced" via a call
-## to any of the more sophisticated C-API functions. 
+## to any of the more sophisticated C-API functions.
 ##
 ## Care has been taken in implementing the functions below, so that
-## if they are called with a non-forced PyBytesObject, they will not 
+## if they are called with a non-forced PyBytesObject, they will not
 ## unintentionally force the creation of a RPython object. As long as only 
these
 ## are used, the ob_sval buffer is still modifiable:
-## 
-## PyBytes_AsString / PyString_AsString 
+##
+## PyBytes_AsString / PyString_AsString
 ## PyBytes_AS_STRING / PyString_AS_STRING
 ## PyBytes_AsStringAndSize / PyString_AsStringAndSize
 ## PyBytes_Size / PyString_Size
@@ -40,7 +40,7 @@
 ## _PyBytes_Resize / _PyString_Resize (raises if called with a forced object)
 ##
 ## - There could be an (expensive!) check in from_ref() that the buffer still
-##   corresponds to the pypy gc-managed string, 
+##   corresponds to the pypy gc-managed string,
 ##
 
 PyBytesObjectStruct = lltype.ForwardReference()
@@ -105,7 +105,7 @@
     track_reference(space, py_obj, w_obj)
     return w_obj
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def bytes_dealloc(space, py_obj):
     """Frees allocated PyBytesObject resources.
     """
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -6,8 +6,8 @@
 from pypy.module.cpyext.api import (
     cpython_api, CANNOT_FAIL, build_type_checkers, Py_ssize_t,
     Py_ssize_tP, CONST_STRING, PyObjectFields, cpython_struct,
-    bootstrap_function)
-from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj, 
+    bootstrap_function, slot_function)
+from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, as_pyobj,
         make_typedescr, track_reference, create_ref, from_ref, decref,
         Py_IncRef)
 from pypy.module.cpyext.object import _dealloc
@@ -36,7 +36,7 @@
     py_dict.c__tmpkeys = lltype.nullptr(PyObject.TO)
     # Problems: if this dict is a typedict, we may have unbound GetSetProperty
     # functions in the dict. The corresponding PyGetSetDescrObject must be
-    # bound to a class, but the actual w_type will be unavailable later on. 
+    # bound to a class, but the actual w_type will be unavailable later on.
     # Solution: use the w_userdata argument when assigning a PyTypeObject's
     # tp_dict slot to pass a w_type in, and force creation of the pair here
     if not space.is_w(w_userdata, space.gettypefor(GetSetProperty)):
@@ -55,7 +55,7 @@
     w_obj = space.newdict()
     track_reference(space, py_obj, w_obj)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def dict_dealloc(space, py_obj):
     py_dict = rffi.cast(PyDictObject, py_obj)
     decref(space, py_dict.c__tmpkeys)
diff --git a/pypy/module/cpyext/frameobject.py 
b/pypy/module/cpyext/frameobject.py
--- a/pypy/module/cpyext/frameobject.py
+++ b/pypy/module/cpyext/frameobject.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, bootstrap_function, PyObjectFields, cpython_struct,
-    CANNOT_FAIL)
+    CANNOT_FAIL, slot_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, Py_DecRef, make_ref, from_ref, track_reference,
     make_typedescr, get_typedescr)
@@ -39,7 +39,7 @@
     py_frame.c_f_locals = make_ref(space, frame.get_w_locals())
     rffi.setintfield(py_frame, 'c_f_lineno', frame.getorcreatedebug().f_lineno)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def frame_dealloc(space, py_obj):
     py_frame = rffi.cast(PyFrameObject, py_obj)
     py_code = rffi.cast(PyObject, py_frame.c_f_code)
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -1,7 +1,8 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+    cpython_api, bootstrap_function, cpython_struct, build_type_checkers,
+    slot_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, Py_DecRef, make_typedescr)
 from rpython.rlib.unroll import unrolling_iterable
@@ -56,7 +57,7 @@
     assert isinstance(w_obj, Function)
     py_func.c_func_name = make_ref(space, space.wrap(w_obj.name))
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def function_dealloc(space, py_obj):
     py_func = rffi.cast(PyFunctionObject, py_obj)
     Py_DecRef(space, py_func.c_func_name)
@@ -75,7 +76,7 @@
     rffi.setintfield(py_code, 'c_co_flags', co_flags)
     rffi.setintfield(py_code, 'c_co_argcount', w_obj.co_argcount)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def code_dealloc(space, py_obj):
     py_code = rffi.cast(PyCodeObject, py_obj)
     Py_DecRef(space, py_code.c_co_name)
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,10 +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, PyObjectFields, cpython_struct,
-                         generic_cpy_call,
-                         bootstrap_function, Py_bufferP)
-from pypy.module.cpyext.pyobject import (PyObject, make_ref, as_pyobj, incref,
-             decref, from_ref, make_typedescr)
+from pypy.module.cpyext.api import (
+    cpython_api, Py_buffer, CANNOT_FAIL, Py_MAX_FMT, Py_MAX_NDIMS,
+    build_type_checkers, Py_ssize_tP, PyObjectFields, cpython_struct,
+    bootstrap_function, Py_bufferP, generic_cpy_call, slot_function)
+from pypy.module.cpyext.pyobject import (
+    PyObject, make_ref, as_pyobj, incref, decref, from_ref, make_typedescr,
+    get_typedescr, track_reference)
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib.rarithmetic import widen
 from pypy.interpreter.error import oefmt
@@ -30,7 +30,7 @@
                    basestruct=PyMemoryViewObject.TO,
                    attach=memory_attach,
                    dealloc=memory_dealloc,
-                   #realize=memory_realize,
+                   realize=memory_realize,
                   )
 
 def memory_attach(space, py_obj, w_obj, w_userdata=None):
@@ -56,13 +56,37 @@
                                              track_allocation=False))
         rffi.setintfield(view, 'c_readonly', 1)
 
-def memory_realize(space, py_obj):
+def memory_realize(space, obj):
     """
     Creates the memory object in the interpreter
     """
-    raise oefmt(space.w_NotImplementedError, "cannot call this yet")
+    from pypy.module.cpyext.slotdefs import CPyBuffer, fq
+    py_mem = rffi.cast(PyMemoryViewObject, obj)
+    view = py_mem.c_view
+    ndim = widen(view.c_ndim)
+    shape = None
+    if view.c_shape:
+        shape = [view.c_shape[i] for i in range(ndim)]
+    strides = None
+    if view.c_strides:
+        strides = [view.c_strides[i] for i in range(ndim)]
+    format = 'B'
+    if view.c_format:
+        format = rffi.charp2str(view.c_format)
+    buf = CPyBuffer(space, view.c_buf, view.c_len, from_ref(space, view.c_obj),
+                    format=format, shape=shape, strides=strides,
+                    ndim=ndim, itemsize=view.c_itemsize,
+                    readonly=widen(view.c_readonly))
+    # Ensure view.c_buf is released upon object finalization
+    fq.register_finalizer(buf)
+    # Allow subclassing W_MemeoryView
+    w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+    w_obj = space.allocate_instance(W_MemoryView, w_type)
+    w_obj.__init__(buf)
+    track_reference(space, obj, w_obj)
+    return w_obj
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def memory_dealloc(space, py_obj):
     mem_obj = rffi.cast(PyMemoryViewObject, py_obj)
     if mem_obj.c_view.c_obj:
@@ -199,17 +223,41 @@
     py_memview = make_ref(space, w_memview, w_obj)
     return py_memview
 
-@cpython_api([Py_bufferP], PyObject)
+@cpython_api([Py_bufferP], PyObject, result_is_ll=True)
 def PyMemoryView_FromBuffer(space, view):
     """Create a memoryview object wrapping the given buffer structure view.
     The memoryview object then owns the buffer represented by view, which
     means you shouldn't try to call PyBuffer_Release() yourself: it
     will be done on deallocation of the memoryview object."""
-    assert view.c_obj
-    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)
+    # XXX this should allocate a PyMemoryViewObject and
+    # copy view into obj.c_view, without creating a new view.c_obj
+    typedescr = get_typedescr(W_MemoryView.typedef)
+    py_obj = typedescr.allocate(space, space.w_memoryview)
+    py_mem = rffi.cast(PyMemoryViewObject, py_obj)
+    mview = py_mem.c_view
+    mview.c_buf = view.c_buf
+    mview.c_obj = view.c_obj
+    mview.c_len = view.c_len
+    mview.c_itemsize = view.c_itemsize
+    mview.c_readonly = view.c_readonly
+    mview.c_ndim = view.c_ndim
+    mview.c_format = view.c_format
+    if view.c_strides == rffi.cast(Py_ssize_tP, view.c__strides):
+        py_mem.c_view.c_strides = rffi.cast(Py_ssize_tP, 
py_mem.c_view.c__strides)
+        for i in range(view.c_ndim):
+            py_mem.c_view.c_strides[i] = view.c_strides[i]
+    else:
+        # some externally allocated memory chunk
+        py_mem.c_view.c_strides = view.c_strides
+    if view.c_shape == rffi.cast(Py_ssize_tP, view.c__shape):
+        py_mem.c_view.c_shape = rffi.cast(Py_ssize_tP, py_mem.c_view.c__shape)
+        for i in range(view.c_ndim):
+            py_mem.c_view.c_shape[i] = view.c_shape[i]
+    else:
+        # some externally allocated memory chunk
+        py_mem.c_view.c_shape = view.c_shape
+    # XXX ignore suboffsets?
+    return py_obj
 
 @cpython_api([PyObject], PyObject)
 def PyMemoryView_GET_BASE(space, w_obj):
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
@@ -11,7 +11,7 @@
     CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O,
     METH_STATIC, METH_VARARGS, PyObject, PyObjectFields, bootstrap_function,
     build_type_checkers, cpython_api, cpython_struct, generic_cpy_call,
-    PyTypeObjectPtr)
+    PyTypeObjectPtr, slot_function)
 from pypy.module.cpyext.pyobject import (
     Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr)
 
@@ -51,7 +51,7 @@
     py_func.c_m_self = make_ref(space, w_obj.w_self)
     py_func.c_m_module = make_ref(space, w_obj.w_module)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def cfunction_dealloc(space, py_obj):
     py_func = rffi.cast(PyCFunctionObject, py_obj)
     Py_DecRef(space, py_func.c_m_self)
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
@@ -1,7 +1,8 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
-    PyVarObject, Py_buffer, size_t,
+    PyVarObject, Py_buffer, size_t, slot_function,
+    PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES,
     Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
     Py_GE, CONST_STRING, CONST_STRINGP, FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
@@ -58,7 +59,7 @@
         w_obj = PyObject_InitVar(space, py_objvar, type, itemcount)
     return py_obj
 
-@cpython_api([PyObject], lltype.Void)
+@slot_function([PyObject], lltype.Void)
 def PyObject_dealloc(space, obj):
     return _dealloc(space, obj)
 
@@ -489,22 +490,28 @@
     Fills in a buffer-info structure correctly for an exporter that can only
     share a contiguous chunk of memory of "unsigned bytes" of the given
     length. Returns 0 on success and -1 (with raising an error) on error.
-
-    This is not a complete re-implementation of the CPython API; it only
-    provides a subset of CPython's behavior.
     """
     if rffi.cast(lltype.Signed, flags) & PyBUF_WRITABLE and readonly:
         raise oefmt(space.w_ValueError, "Object is not writable")
     view.c_buf = buf
     view.c_len = length
     view.c_obj = obj
-    Py_IncRef(space, obj)
+    if obj:
+        Py_IncRef(space, obj)
     view.c_itemsize = 1
     rffi.setintfield(view, 'c_readonly', readonly)
-    rffi.setintfield(view, 'c_ndim', 0)
+    rffi.setintfield(view, 'c_ndim', 1)
     view.c_format = lltype.nullptr(rffi.CCHARP.TO)
+    if (flags & PyBUF_FORMAT) == PyBUF_FORMAT:
+        view.c_format = rffi.str2charp("B")
     view.c_shape = lltype.nullptr(Py_ssize_tP.TO)
+    if (flags & PyBUF_ND) == PyBUF_ND:
+        view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape)
+        view.c_shape[0] = view.c_len
     view.c_strides = lltype.nullptr(Py_ssize_tP.TO)
+    if (flags & PyBUF_STRIDES) == PyBUF_STRIDES:
+        view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides)
+        view.c_strides[0] = view.c_itemsize
     view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO)
     view.c_internal = lltype.nullptr(rffi.VOIDP.TO)
 
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -87,7 +87,7 @@
     alloc     : allocate and basic initialization of a raw PyObject
     attach    : Function called to tie a raw structure to a pypy object
     realize   : Function called to create a pypy object from a raw struct
-    dealloc   : a cpython_api(header=None), similar to PyObject_dealloc
+    dealloc   : a @slot_function(), similar to PyObject_dealloc
     """
 
     tp_basestruct = kw.pop('basestruct', PyObject.TO)
diff --git a/pypy/module/cpyext/pytraceback.py 
b/pypy/module/cpyext/pytraceback.py
--- a/pypy/module/cpyext/pytraceback.py
+++ b/pypy/module/cpyext/pytraceback.py
@@ -1,7 +1,8 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+    cpython_api, bootstrap_function, cpython_struct, build_type_checkers,
+    slot_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, Py_DecRef, make_typedescr)
 from pypy.module.cpyext.frameobject import PyFrameObject
@@ -40,7 +41,7 @@
     rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti)
     rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno())
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def traceback_dealloc(space, py_obj):
     py_traceback = rffi.cast(PyTracebackObject, py_obj)
     Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next))
diff --git a/pypy/module/cpyext/sliceobject.py 
b/pypy/module/cpyext/sliceobject.py
--- a/pypy/module/cpyext/sliceobject.py
+++ b/pypy/module/cpyext/sliceobject.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
     cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
-    CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyObjectFields)
+    CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyObjectFields, slot_function)
 from pypy.module.cpyext.pyobject import (
     Py_DecRef, PyObject, make_ref, make_typedescr)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
@@ -36,7 +36,7 @@
     py_slice.c_stop = make_ref(space, w_obj.w_stop)
     py_slice.c_step = make_ref(space, w_obj.w_step)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def slice_dealloc(space, py_obj):
     """Frees allocated PySliceObject resources.
     """
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
@@ -6,7 +6,7 @@
 from rpython.rlib.rarithmetic import widen
 from rpython.rlib import rgc # Force registration of gc.collect
 from pypy.module.cpyext.api import (
-    cpython_api, generic_cpy_call, PyObject, Py_ssize_t,
+    slot_function, generic_cpy_call, PyObject, Py_ssize_t,
     pypy_decl, Py_buffer, Py_bufferP)
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
@@ -64,7 +64,7 @@
 
 @not_rpython
 def llslot(space, func):
-    return llhelper(func.api_func.functype, func.api_func.get_wrapper(space))
+    return func.api_func.get_llhelper(space)
 
 @register_flow_sc(llslot)
 def sc_llslot(ctx, v_space, v_func):
@@ -315,7 +315,7 @@
 
     def __init__(self, space, ptr, size, w_obj, format='B', shape=None,
                 strides=None, ndim=1, itemsize=1, readonly=True,
-                releasebuffer=None):
+                releasebufferproc=rffi.cast(rffi.VOIDP, 0)):
         self.space = space
         self.ptr = ptr
         self.size = size
@@ -333,7 +333,7 @@
         self.ndim = ndim
         self.itemsize = itemsize
         self.readonly = readonly
-        self.releasebufferproc = releasebuffer
+        self.releasebufferproc = releasebufferproc
 
     def releasebuffer(self):
         if self.pyobj:
@@ -351,7 +351,10 @@
                 for i in range(self.ndim):
                     pybuf.c_shape[i] = self.shape[i]
                     pybuf.c_strides[i] = self.strides[i]
-                pybuf.c_format = rffi.str2charp(self.format)
+                if self.format:
+                    pybuf.c_format = rffi.str2charp(self.format)
+                else:
+                    pybuf.c_format = rffi.str2charp("B")
                 generic_cpy_call(self.space, func_target, self.pyobj, pybuf)
             self.releasebufferproc = rffi.cast(rffi.VOIDP, 0)
 
@@ -398,9 +401,9 @@
     func_target = rffi.cast(readbufferproc, func)
     py_obj = make_ref(space, w_self)
     py_type = py_obj.c_ob_type
-    releasebuffer = rffi.cast(rffi.VOIDP, 0)
+    rbp = rffi.cast(rffi.VOIDP, 0)
     if py_type.c_tp_as_buffer:
-        releasebuffer = rffi.cast(rffi.VOIDP, 
py_type.c_tp_as_buffer.c_bf_releasebuffer)
+        rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer)
     decref(space, py_obj)
     with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
         index = rffi.cast(Py_ssize_t, 0)
@@ -408,7 +411,7 @@
         if size < 0:
             space.fromcache(State).check_and_raise_exception(always=True)
         buf = CPyBuffer(space, ptr[0], size, w_self,
-                               releasebuffer=releasebuffer)
+                               releasebufferproc=rbp)
         fq.register_finalizer(buf)
         return space.newbuffer(buf)
 
@@ -417,16 +420,16 @@
     py_obj = make_ref(space, w_self)
     py_type = py_obj.c_ob_type
     decref(space, py_obj)
-    releasebuffer = rffi.cast(rffi.VOIDP, 0)
+    rbp = rffi.cast(rffi.VOIDP, 0)
     if py_type.c_tp_as_buffer:
-        releasebuffer = rffi.cast(rffi.VOIDP, 
py_type.c_tp_as_buffer.c_bf_releasebuffer)
+        rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer)
     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)
         buf = CPyBuffer(space, ptr[0], size, w_self, readonly=False,
-                               releasebuffer=releasebuffer)
+                               releasebufferproc=rbp)
         fq.register_finalizer(buf)
         return space.newbuffer(buf)
 
@@ -434,9 +437,9 @@
     func_target = rffi.cast(getbufferproc, func)
     py_obj = make_ref(space, w_self)
     py_type = py_obj.c_ob_type
-    releasebuffer = rffi.cast(rffi.VOIDP, 0)
+    rbp = rffi.cast(rffi.VOIDP, 0)
     if py_type.c_tp_as_buffer:
-        releasebuffer = rffi.cast(rffi.VOIDP, 
py_type.c_tp_as_buffer.c_bf_releasebuffer)
+        rbp = rffi.cast(rffi.VOIDP, py_type.c_tp_as_buffer.c_bf_releasebuffer)
     decref(space, py_obj)
     with lltype.scoped_alloc(Py_buffer) as pybuf:
         _flags = 0
@@ -465,7 +468,7 @@
                             ndim=ndim, shape=shape, strides=strides,
                             itemsize=pybuf.c_itemsize,
                             readonly=widen(pybuf.c_readonly),
-                            releasebuffer = releasebuffer)
+                            releasebufferproc = rbp)
         fq.register_finalizer(buf)
         return space.newbuffer(buf)
 
@@ -515,9 +518,6 @@
 def build_slot_tp_function(space, typedef, name):
     w_type = space.gettypeobject(typedef)
 
-    header = pypy_decl
-    if not (name.startswith('Py') or name.startswith('_Py')):
-        header = None
     handled = False
     # unary functions
     for tp_name, attr in [('tp_as_number.c_nb_int', '__int__'),
@@ -537,7 +537,7 @@
             if slot_fn is None:
                 return
 
-            @cpython_api([PyObject], PyObject, header=header)
+            @slot_function([PyObject], PyObject)
             @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
             def slot_func(space, w_self):
                 return space.call_function(slot_fn, w_self)
@@ -563,7 +563,7 @@
             if slot_fn is None:
                 return
 
-            @cpython_api([PyObject, PyObject], PyObject, header=header)
+            @slot_function([PyObject, PyObject], PyObject)
             @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
             def slot_func(space, w_self, w_arg):
                 return space.call_function(slot_fn, w_self, w_arg)
@@ -580,7 +580,7 @@
             if slot_fn is None:
                 return
 
-            @cpython_api([PyObject, Py_ssize_t], PyObject, header=header)
+            @slot_function([PyObject, Py_ssize_t], PyObject)
             @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
             def slot_func(space, w_self, arg):
                 return space.call_function(slot_fn, w_self, space.wrap(arg))
@@ -594,7 +594,7 @@
             if slot_fn is None:
                 return
 
-            @cpython_api([PyObject, PyObject, PyObject], PyObject, 
header=header)
+            @slot_function([PyObject, PyObject, PyObject], PyObject)
             @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
             def slot_func(space, w_self, w_arg1, w_arg2):
                 return space.call_function(slot_fn, w_self, w_arg1, w_arg2)
@@ -608,8 +608,8 @@
         if setattr_fn is None:
             return
 
-        @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
-                     error=-1, header=header)
+        @slot_function([PyObject, PyObject, PyObject], rffi.INT_real,
+                     error=-1)
         @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,))
         def slot_tp_setattro(space, w_self, w_name, w_value):
             if w_value is not None:
@@ -623,7 +623,7 @@
         if getattr_fn is None:
             return
 
-        @cpython_api([PyObject, PyObject], PyObject, header=header)
+        @slot_function([PyObject, PyObject], PyObject)
         @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,))
         def slot_tp_getattro(space, w_self, w_name):
             return space.call_function(getattr_fn, w_self, w_name)
@@ -634,7 +634,7 @@
         if call_fn is None:
             return
 
-        @cpython_api([PyObject, PyObject, PyObject], PyObject, header=header)
+        @slot_function([PyObject, PyObject, PyObject], PyObject)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
         def slot_tp_call(space, w_self, w_args, w_kwds):
             args = Arguments(space, [w_self],
@@ -647,7 +647,7 @@
         if iternext_fn is None:
             return
 
-        @cpython_api([PyObject], PyObject, header=header)
+        @slot_function([PyObject], PyObject)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
         def slot_tp_iternext(space, w_self):
             try:
@@ -663,8 +663,7 @@
         if init_fn is None:
             return
 
-        @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1,
-                     header=header)
+        @slot_function([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
         def slot_tp_init(space, w_self, w_args, w_kwds):
             args = Arguments(space, [w_self],
@@ -677,7 +676,7 @@
         if new_fn is None:
             return
 
-        @cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, 
header=None)
+        @slot_function([PyTypeObjectPtr, PyObject, PyObject], PyObject)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
         def slot_tp_new(space, w_self, w_args, w_kwds):
             args = Arguments(space, [w_self],
@@ -688,8 +687,8 @@
         buff_fn = w_type.getdictvalue(space, '__buffer__')
         if buff_fn is None:
             return
-        @cpython_api([PyObject, Py_bufferP, rffi.INT_real],
-                rffi.INT_real, header=None, error=-1)
+        @slot_function([PyObject, Py_bufferP, rffi.INT_real],
+                rffi.INT_real, error=-1)
         @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
         def buff_w(space, w_self, view, flags):
             args = Arguments(space, [space.newint(flags)])
diff --git a/pypy/module/cpyext/test/test_api.py 
b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -2,20 +2,14 @@
 from rpython.rtyper.lltypesystem import lltype
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.module.cpyext.state import State
-from pypy.module.cpyext import api
+from pypy.module.cpyext.api import (
+    slot_function, cpython_api, copy_header_files, INTERPLEVEL_API,
+    Py_ssize_t, Py_ssize_tP, PyObject)
 from pypy.module.cpyext.test.test_cpyext import freeze_refcnts, 
LeakCheckingTest
-PyObject = api.PyObject
 from pypy.interpreter.error import OperationError
 from rpython.rlib import rawrefcount
 import os
 
-@api.cpython_api([PyObject], lltype.Void)
-def PyPy_GetWrapped(space, w_arg):
-    assert isinstance(w_arg, W_Root)
-@api.cpython_api([PyObject], lltype.Void)
-def PyPy_GetReference(space, arg):
-    assert lltype.typeOf(arg) ==  PyObject
-
 class BaseApiTest(LeakCheckingTest):
     def setup_class(cls):
         space = cls.space
@@ -35,7 +29,7 @@
             def __getattr__(self, name):
                 return getattr(cls.space, name)
         cls.api = CAPI()
-        CAPI.__dict__.update(api.INTERPLEVEL_API)
+        CAPI.__dict__.update(INTERPLEVEL_API)
 
         print 'DONT_FREE_ANY_MORE'
         rawrefcount._dont_free_any_more()
@@ -71,31 +65,39 @@
         if self.check_and_print_leaks():
             assert False, "Test leaks or loses object(s)."
 
-@api.cpython_api([api.Py_ssize_t], api.Py_ssize_t, error=-1)
+@slot_function([PyObject], lltype.Void)
+def PyPy_GetWrapped(space, w_arg):
+    assert isinstance(w_arg, W_Root)
+
+@slot_function([PyObject], lltype.Void)
+def PyPy_GetReference(space, arg):
+    assert lltype.typeOf(arg) ==  PyObject
+
+@cpython_api([Py_ssize_t], Py_ssize_t, error=-1)
 def PyPy_TypedefTest1(space, arg):
-    assert lltype.typeOf(arg) == api.Py_ssize_t
+    assert lltype.typeOf(arg) == Py_ssize_t
     return 0
 
-@api.cpython_api([api.Py_ssize_tP], api.Py_ssize_tP)
+@cpython_api([Py_ssize_tP], Py_ssize_tP)
 def PyPy_TypedefTest2(space, arg):
-    assert lltype.typeOf(arg) == api.Py_ssize_tP
+    assert lltype.typeOf(arg) == Py_ssize_tP
     return None
 
 class TestConversion(BaseApiTest):
-    def test_conversions(self, space, api):
-        api.PyPy_GetWrapped(space.w_None)
-        api.PyPy_GetReference(space.w_None)
+    def test_conversions(self, space):
+        PyPy_GetWrapped(space, space.w_None)
+        PyPy_GetReference(space, space.w_None)
 
     def test_typedef(self, space):
         from rpython.translator.c.database import LowLevelDatabase
         db = LowLevelDatabase()
-        assert (api.c_function_signature(db, PyPy_TypedefTest1.api_func)
-                == ('Py_ssize_t', 'Py_ssize_t arg0'))
-        assert (api.c_function_signature(db, PyPy_TypedefTest2.api_func)
-                == ('Py_ssize_t *', 'Py_ssize_t *arg0'))
+        assert PyPy_TypedefTest1.api_func.get_c_restype(db) == 'Py_ssize_t'
+        assert PyPy_TypedefTest1.api_func.get_c_args(db) == 'Py_ssize_t arg0'
+        assert PyPy_TypedefTest2.api_func.get_c_restype(db) == 'Py_ssize_t *'
+        assert PyPy_TypedefTest2.api_func.get_c_args(db) == 'Py_ssize_t *arg0'
 
         PyPy_TypedefTest1(space, 0)
-        ppos = lltype.malloc(api.Py_ssize_tP.TO, 1, flavor='raw')
+        ppos = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw')
         ppos[0] = 0
         PyPy_TypedefTest2(space, ppos)
         lltype.free(ppos, flavor='raw')
@@ -103,7 +105,7 @@
 @pytest.mark.skipif(os.environ.get('USER')=='root',
                     reason='root can write to all files')
 def test_copy_header_files(tmpdir):
-    api.copy_header_files(tmpdir, True)
+    copy_header_files(tmpdir, True)
     def check(name):
         f = tmpdir.join(name)
         assert f.check(file=True)
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
@@ -30,7 +30,7 @@
         assert view.c_len == 5
         o = rffi.charp2str(view.c_buf)
         assert o == 'hello'
-        w_mv = api.PyMemoryView_FromBuffer(view)
+        w_mv = from_ref(space, api.PyMemoryView_FromBuffer(view))
         for f in ('format', 'itemsize', 'ndim', 'readonly',
                   'shape', 'strides', 'suboffsets'):
             w_f = space.wrap(f)
@@ -43,6 +43,7 @@
                 ("fillinfo", "METH_VARARGS",
                  """
                  Py_buffer buf;
+                 PyObject * ret = NULL;
                  PyObject *str = PyBytes_FromString("hello, world.");
                  if (PyBuffer_FillInfo(&buf, str, PyBytes_AsString(str), 13,
                                        0, 0)) {
@@ -54,7 +55,14 @@
                   */
                  Py_DECREF(str);
 
-                 return PyMemoryView_FromBuffer(&buf);
+                 ret = PyMemoryView_FromBuffer(&buf);
+                 if (((PyMemoryViewObject*)ret)->view.obj != buf.obj)
+                 {
+                    PyErr_SetString(PyExc_ValueError, "leaked ref");
+                    Py_DECREF(ret);
+                    return NULL;
+                 }
+                 return ret;
                  """)])
         result = module.fillinfo()
         assert b"hello, world." == result
diff --git a/pypy/module/cpyext/test/test_translate.py 
b/pypy/module/cpyext/test/test_translate.py
--- a/pypy/module/cpyext/test/test_translate.py
+++ b/pypy/module/cpyext/test/test_translate.py
@@ -1,6 +1,6 @@
 from rpython.translator.c.test.test_genc import compile
 import pypy.module.cpyext.api
-from pypy.module.cpyext.api import cpython_api
+from pypy.module.cpyext.api import slot_function
 from rpython.rtyper.annlowlevel import llhelper
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rlib.objectmodel import specialize
@@ -19,7 +19,7 @@
 
     @specialize.memo()
     def get_tp_function(space, typedef):
-        @cpython_api([], lltype.Signed, error=-1, header=None)
+        @slot_function([], lltype.Signed, error=-1)
         def slot_tp_function(space):
             return typedef.value
 
diff --git a/pypy/module/cpyext/tupleobject.py 
b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -1,11 +1,11 @@
 from pypy.interpreter.error import oefmt
 from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.debug import fatalerror_notb
-from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL,
-                                    build_type_checkers, PyVarObjectFields,
-                                    cpython_struct, bootstrap_function)
-from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
-    make_ref, from_ref, decref, incref, pyobj_has_w_obj,
+from pypy.module.cpyext.api import (
+    cpython_api, Py_ssize_t, build_type_checkers,
+    PyVarObjectFields, cpython_struct, bootstrap_function, slot_function)
+from pypy.module.cpyext.pyobject import (
+    PyObject, PyObjectP, make_ref, from_ref, decref, incref,
     track_reference, make_typedescr, get_typedescr)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.tupleobject import W_TupleObject
@@ -74,7 +74,7 @@
     if py_tup.c_ob_size < length:
         raise oefmt(space.w_ValueError,
             "tuple_attach called on object with ob_size %d but trying to store 
%d",
-            py_tup.c_ob_size, length) 
+            py_tup.c_ob_size, length)
     i = 0
     try:
         while i < length:
@@ -113,7 +113,7 @@
     track_reference(space, py_obj, w_obj)
     return w_obj
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def tuple_dealloc(space, py_obj):
     """Frees allocated PyTupleObject resources.
     """
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
@@ -2,21 +2,20 @@
 
 from rpython.rlib import jit
 from rpython.rlib.objectmodel import specialize
-from rpython.rlib.rstring import rsplit
 from rpython.rtyper.lltypesystem import rffi, lltype
 
 from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
 from pypy.interpreter.error import oefmt
-from pypy.interpreter.typedef import (GetSetProperty, TypeDef,
-        interp_attrproperty, interp_attrproperty, interp2app)
+from pypy.interpreter.typedef import (
+    GetSetProperty, TypeDef, interp_attrproperty, interp2app)
 from pypy.module.__builtin__.abstractinst import abstract_issubclass_w
 from pypy.module.cpyext import structmemberdefs
 from pypy.module.cpyext.api import (
     cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
-    generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, Py_buffer,
+    slot_function, generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING, 
Py_buffer,
     Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
-    Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
-    PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr,
+    Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers,
+    PyObjectFields, PyTypeObject, PyTypeObjectPtr,
     Py_TPFLAGS_HAVE_INPLACEOPS)
 from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
     W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
@@ -345,7 +344,7 @@
     if pto.c_tp_new:
         add_tp_new_wrapper(space, dict_w, pto)
 
-@cpython_api([PyObject, PyObject, PyObject], PyObject, header=None)
+@slot_function([PyObject, PyObject, PyObject], PyObject)
 def tp_new_wrapper(space, self, w_args, w_kwds):
     self_pytype = rffi.cast(PyTypeObjectPtr, self)
     tp_new = self_pytype.c_tp_new
@@ -504,7 +503,7 @@
                    realize=type_realize,
                    dealloc=type_dealloc)
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def subtype_dealloc(space, obj):
     pto = obj.c_ob_type
     base = pto
@@ -519,8 +518,7 @@
     # hopefully this does not clash with the memory model assumed in
     # extension modules
 
-@cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real,
-              header=None, error=-1)
+@slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], 
rffi.INT_real, error=-1)
 def bytes_getbuffer(space, w_str, view, flags):
     from pypy.module.cpyext.bytesobject import PyBytes_AsString
     from pypy.module.cpyext.object import PyBuffer_FillInfo
@@ -528,8 +526,7 @@
     return PyBuffer_FillInfo(space, view, w_str, c_buf,
                              space.len_w(w_str), 1, flags)
 
-@cpython_api([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], rffi.INT_real,
-              header=None, error=-1)
+@slot_function([PyObject, lltype.Ptr(Py_buffer), rffi.INT_real], 
rffi.INT_real, error=-1)
 def bf_getbuffer(space, w_obj, view, flags):
     from pypy.module.cpyext.object import PyBuffer_FillInfo
     buf = space.buffer_w(w_obj, rffi.cast(lltype.Signed, flags))
@@ -550,7 +547,7 @@
     pto.c_tp_as_buffer = c_buf
     pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def type_dealloc(space, obj):
     from pypy.module.cpyext.object import _dealloc
     obj_pto = rffi.cast(PyTypeObjectPtr, obj)
diff --git a/pypy/module/cpyext/unicodeobject.py 
b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -4,7 +4,7 @@
 from pypy.module.cpyext.api import (
     CANNOT_FAIL, Py_ssize_t, build_type_checkers, cpython_api,
     bootstrap_function, PyObjectFields, cpython_struct, CONST_STRING,
-    CONST_WSTRING, Py_CLEANUP_SUPPORTED)
+    CONST_WSTRING, Py_CLEANUP_SUPPORTED, slot_function)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
@@ -78,7 +78,7 @@
     track_reference(space, py_obj, w_obj)
     return w_obj
 
-@cpython_api([PyObject], lltype.Void, header=None)
+@slot_function([PyObject], lltype.Void)
 def unicode_dealloc(space, py_obj):
     py_unicode = rffi.cast(PyUnicodeObject, py_obj)
     if py_unicode.c_buffer:
diff --git a/rpython/rlib/test/test_rposix_stat.py 
b/rpython/rlib/test/test_rposix_stat.py
--- a/rpython/rlib/test/test_rposix_stat.py
+++ b/rpython/rlib/test/test_rposix_stat.py
@@ -29,7 +29,10 @@
             check(os.environ['TEMP'])
         else:
             check('/')
-            check('/tmp')
+            check('/dev')
+            # don't test with /tmp, because if another process is also
+            # creating files in /tmp it is more likely that the mtime
+            # we get during successive calls was actually changed
         check(sys.executable)
 
     def test_fstat(self):
diff --git a/rpython/rlib/unicodedata/test/test_unicodedata.py 
b/rpython/rlib/unicodedata/test/test_unicodedata.py
--- a/rpython/rlib/unicodedata/test/test_unicodedata.py
+++ b/rpython/rlib/unicodedata/test/test_unicodedata.py
@@ -5,7 +5,8 @@
 import py
 
 from rpython.rlib.unicodedata import (
-    unicodedb_3_2_0, unicodedb_5_2_0, unicodedb_6_0_0, unicodedb_6_2_0)
+    unicodedb_3_2_0, unicodedb_5_2_0, unicodedb_6_0_0, unicodedb_6_2_0,
+    unicodedb_8_0_0)
 
 
 class TestUnicodeData(object):
@@ -141,3 +142,9 @@
 
     def test_islower(self):
         assert unicodedb_6_2_0.islower(0x2177)
+
+
+class TestUnicodeData800(object):
+    def test_changed_in_version_8(self):
+        assert unicodedb_6_2_0.toupper_full(0x025C) == [0x025C]
+        assert unicodedb_8_0_0.toupper_full(0x025C) == [0xA7AB]
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to