Commits

Amaury Forgeot d'Arc committed 98a287f

Split the large api.py, and move cross-language functions calls into gateway.py

Comments (0)

Files changed (41)

pypy/module/cpyext/api.py

 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.translator.gensupp import NameManager
 from pypy.tool.udir import udir
+from pypy.tool.sourcetools import func_with_new_name
 from pypy.translator import platform
-from pypy.module.cpyext.state import State
-from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.baseobjspace import W_Root, ObjSpace
+from pypy.interpreter.error import operationerrfmt
+from pypy.interpreter.baseobjspace import ObjSpace
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.nestedscope import Cell
 from pypy.interpreter.module import Module
 from pypy.module.exceptions import interp_exceptions
 # CPython 2.4 compatibility
 from py.builtin import BaseException
-from pypy.tool.sourcetools import func_with_new_name
-from pypy.rpython.lltypesystem.lloperation import llop
 
 DEBUG_WRAPPER = True
 
     def get_interpret(self, space):
         raise NotImplementedError
 
-def copy_header_files():
-    for name in ("pypy_decl.h", "pypy_macros.h"):
-        udir.join(name).copy(interfaces_dir / name)
-
-_NOT_SPECIFIED = object()
-CANNOT_FAIL = object()
-
-# The same function can be called in three different contexts:
-# (1) from C code
-# (2) in the test suite, though the "api" object
-# (3) from RPython code, for example in the implementation of another function.
-#
-# In contexts (2) and (3), a function declaring a PyObject argument type will
-# receive a wrapped pypy object if the parameter name starts with 'w_', a
-# reference (= rffi pointer) otherwise; conversion is automatic.  Context (2)
-# only allows calls with a wrapped object.
-#
-# Functions with a PyObject return type should return a wrapped object.
-#
-# Functions may raise exceptions.  In context (3), the exception flows normally
-# through the calling function.  In context (1) and (2), the exception is
-# caught; if it is an OperationError, it is stored in the thread state; other
-# exceptions generate a OperationError(w_SystemError); and the funtion returns
-# the error value specifed in the API.
-#
-
 cpyext_namespace = NameManager('cpyext_')
 
 class ApiFunction(BaseApiObject):
-    def __init__(self, argtypes, restype, callable, error=_NOT_SPECIFIED,
-                 c_name=None):
+    def __init__(self, argtypes, restype, callable, error, c_name=None):
         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 user code object
 
     def get_llpointer(self, space):
         "Returns a C function pointer"
-        assert not we_are_translated()
+        assert not we_are_translated() # NOT_RPYTHON??
         llh = getattr(self, '_llhelper', None)
         if llh is None:
             llh = llhelper(self.functype, self._get_wrapper(space))
     def _get_wrapper(self, space):
         wrapper = getattr(self, '_wrapper', None)
         if wrapper is None:
+            from pypy.module.cpyext.gateway import make_wrapper
             wrapper = make_wrapper(space, self.callable)
             self._wrapper = wrapper
             wrapper.relax_sig_check = True
                 wrapper.c_name = cpyext_namespace.uniquename(self.c_name)
         return wrapper
 
-def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True):
-    """
-    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.
-    - set `external` to False to get a C function pointer, but not exported by
-      the API headers.
-    """
-    if error is _NOT_SPECIFIED:
-        if restype is PyObject:
-            error = lltype.nullptr(restype.TO)
-        elif restype is lltype.Void:
-            error = CANNOT_FAIL
-    if type(error) is int:
-        error = rffi.cast(restype, error)
+def FUNCTION_declare(name, api_func):
+    assert name not in FUNCTIONS, "%s already registered" % (name,)
+    FUNCTIONS[name] = api_func
 
-    def decorate(func):
-        func_name = func.func_name
-        if external:
-            c_name = None
-        else:
-            c_name = func_name
-        api_function = ApiFunction(argtypes, restype, func, error, c_name=c_name)
-        func.api_func = api_function
+def INTERPLEVEL_declare(name, obj):
+    INTERPLEVEL_API[name] = obj
 
-        if external:
-            assert func_name not in FUNCTIONS, (
-                "%s already registered" % func_name)
-
-        if error is _NOT_SPECIFIED:
-            raise ValueError("function %s has no return value for exceptions"
-                             % func)
-        def make_unwrapper(catch_exception):
-            names = api_function.argnames
-            types_names_enum_ui = unrolling_iterable(enumerate(
-                zip(api_function.argtypes,
-                    [tp_name.startswith("w_") for tp_name in names])))
-
-            @specialize.ll()
-            def unwrapper(space, *args):
-                from pypy.module.cpyext.pyobject import Py_DecRef
-                from pypy.module.cpyext.pyobject import make_ref, from_ref
-                from pypy.module.cpyext.pyobject import BorrowPair
-                newargs = ()
-                to_decref = []
-                assert len(args) == len(api_function.argtypes)
-                for i, (ARG, is_wrapped) in types_names_enum_ui:
-                    input_arg = args[i]
-                    if is_PyObject(ARG) and not is_wrapped:
-                        # build a reference
-                        if input_arg is None:
-                            arg = lltype.nullptr(PyObject.TO)
-                        elif isinstance(input_arg, W_Root):
-                            ref = make_ref(space, input_arg)
-                            to_decref.append(ref)
-                            arg = rffi.cast(ARG, ref)
-                        else:
-                            arg = input_arg
-                    elif is_PyObject(ARG) and is_wrapped:
-                        # convert to a wrapped object
-                        if input_arg is None:
-                            arg = input_arg
-                        elif isinstance(input_arg, W_Root):
-                            arg = input_arg
-                        else:
-                            arg = from_ref(space,
-                                           rffi.cast(PyObject, input_arg))
-                    else:
-                        arg = input_arg
-                    newargs += (arg, )
-                try:
-                    try:
-                        res = func(space, *newargs)
-                    except OperationError, e:
-                        if not catch_exception:
-                            raise
-                        if not hasattr(api_function, "error_value"):
-                            raise
-                        state = space.fromcache(State)
-                        state.set_exception(e)
-                        if is_PyObject(restype):
-                            return None
-                        else:
-                            return api_function.error_value
-                    if res is None:
-                        return None
-                    elif isinstance(res, BorrowPair):
-                        return res.w_borrowed
-                    else:
-                        return res
-                finally:
-                    for arg in to_decref:
-                        Py_DecRef(space, arg)
-            unwrapper.func = func
-            unwrapper.api_func = api_function
-            unwrapper._always_inline_ = True
-            return unwrapper
-
-        unwrapper_catch = make_unwrapper(True)
-        unwrapper_raise = make_unwrapper(False)
-        if external:
-            FUNCTIONS[func_name] = api_function
-        INTERPLEVEL_API[func_name] = unwrapper_catch # used in tests
-        return unwrapper_raise # used in 'normal' RPython code.
-    return decorate
+def copy_header_files():
+    for name in ("pypy_decl.h", "pypy_macros.h"):
+        udir.join(name).copy(interfaces_dir / name)
 
 def cpython_struct(name, fields, forward=None):
     configname = name.replace(' ', '__')
 PyVarObject = lltype.Ptr(PyVarObjectStruct)
 PyObjectP = rffi.CArrayPtr(PyObject)
 
-@specialize.memo()
-def is_PyObject(TYPE):
-    if not isinstance(TYPE, lltype.Ptr):
-        return False
-    return hasattr(TYPE.TO, 'c_ob_refcnt') and hasattr(TYPE.TO, 'c_ob_type')
-
 def configure_types():
     for name, TYPE in rffi_platform.configure(CConfig).iteritems():
         if name in TYPES:
             TYPES[name].become(TYPE)
 
+
 def build_type_checkers(type_name, cls=None):
     """
     Builds two api functions: Py_XxxCheck() and Py_XxxCheckExact().
         w_type = get_w_type(space)
         return space.is_w(w_obj_type, w_type)
 
+    from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
     check = cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)(
         func_with_new_name(check, check_name))
     check_exact = cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)(
         func_with_new_name(check_exact, check_name + "Exact"))
     return check, check_exact
 
-pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void)
-
-# Make the wrapper for the cases (1) and (2)
-def make_wrapper(space, callable):
-    "NOT_RPYTHON"
-    names = callable.api_func.argnames
-    argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
-        [name.startswith("w_") for name in names])))
-    fatal_value = callable.api_func.restype._defl()
-
-    @specialize.ll()
-    def wrapper(*args):
-        from pypy.module.cpyext.pyobject import make_ref, from_ref
-        from pypy.module.cpyext.pyobject import BorrowPair
-        # we hope that malloc removal removes the newtuple() that is
-        # inserted exactly here by the varargs specializer
-        llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
-        rffi.stackcounter.stacks_counter += 1
-        retval = fatal_value
-        boxed_args = ()
-        try:
-            if not we_are_translated() and DEBUG_WRAPPER:
-                print >>sys.stderr, callable,
-            assert len(args) == len(callable.api_func.argtypes)
-            for i, (typ, is_wrapped) in argtypes_enum_ui:
-                arg = args[i]
-                if is_PyObject(typ) and is_wrapped:
-                    if arg:
-                        arg_conv = from_ref(space, rffi.cast(PyObject, arg))
-                    else:
-                        arg_conv = None
-                else:
-                    arg_conv = arg
-                boxed_args += (arg_conv, )
-            state = space.fromcache(State)
-            try:
-                result = callable(space, *boxed_args)
-                if not we_are_translated() and DEBUG_WRAPPER:
-                    print >>sys.stderr, " DONE"
-            except OperationError, e:
-                failed = True
-                state.set_exception(e)
-            except BaseException, e:
-                failed = True
-                if not we_are_translated():
-                    message = repr(e)
-                    import traceback
-                    traceback.print_exc()
-                else:
-                    message = str(e)
-                state.set_exception(OperationError(space.w_SystemError,
-                                                   space.wrap(message)))
-            else:
-                failed = False
-
-            if failed:
-                error_value = callable.api_func.error_value
-                if error_value is CANNOT_FAIL:
-                    raise SystemError("The function '%s' was not supposed to fail"
-                                      % (callable.__name__,))
-                retval = error_value
-
-            elif is_PyObject(callable.api_func.restype):
-                if result is None:
-                    retval = make_ref(space, None)
-                elif isinstance(result, BorrowPair):
-                    retval = result.get_ref(space)
-                elif not rffi._isllptr(result):
-                    retval = rffi.cast(callable.api_func.restype,
-                                       make_ref(space, result))
-                else:
-                    retval = result
-            elif callable.api_func.restype is not lltype.Void:
-                retval = rffi.cast(callable.api_func.restype, result)
-        except Exception, e:
-            if not we_are_translated():
-                import traceback
-                traceback.print_exc()
-                print str(e)
-                # we can't do much here, since we're in ctypes, swallow
-            else:
-                print str(e)
-                pypy_debug_catch_fatal_exception()
-        rffi.stackcounter.stacks_counter -= 1
-        return retval
-    callable._always_inline_ = True
-    wrapper.__name__ = "wrapper for %r" % (callable, )
-    return wrapper
-
 def setup_init_functions(eci):
     init_buffer = rffi.llexternal('init_bufferobject', [], lltype.Void, compilation_info=eci)
     init_pycobject = rffi.llexternal('init_pycobject', [], lltype.Void, compilation_info=eci)
 initfunctype = lltype.Ptr(lltype.FuncType([], lltype.Void))
 @unwrap_spec(ObjSpace, str, str)
 def load_extension_module(space, path, name):
+    from pypy.module.cpyext.state import State
+    from pypy.module.cpyext.gateway import generic_cpy_call
     state = space.fromcache(State)
     state.package_context = name
     try:
     finally:
         state.package_context = None
 
-@specialize.ll()
-def generic_cpy_call(space, func, *args):
-    FT = lltype.typeOf(func).TO
-    return make_generic_cpy_call(FT, True, False)(space, func, *args)
-
-@specialize.ll()
-def generic_cpy_call_dont_decref(space, func, *args):
-    FT = lltype.typeOf(func).TO
-    return make_generic_cpy_call(FT, False, False)(space, func, *args)
-
-@specialize.ll()    
-def generic_cpy_call_expect_null(space, func, *args):
-    FT = lltype.typeOf(func).TO
-    return make_generic_cpy_call(FT, True, True)(space, func, *args)
-
-@specialize.memo()
-def make_generic_cpy_call(FT, decref_args, expect_null):
-    from pypy.module.cpyext.pyobject import make_ref, from_ref, Py_DecRef
-    from pypy.module.cpyext.pyobject import RefcountState
-    from pypy.module.cpyext.pyerrors import PyErr_Occurred
-    unrolling_arg_types = unrolling_iterable(enumerate(FT.ARGS))
-    RESULT_TYPE = FT.RESULT
-
-    # copied and modified from rffi.py
-    # We need tons of care to ensure that no GC operation and no
-    # exception checking occurs in call_external_function.
-    argnames = ', '.join(['a%d' % i for i in range(len(FT.ARGS))])
-    source = py.code.Source("""
-        def call_external_function(funcptr, %(argnames)s):
-            # NB. it is essential that no exception checking occurs here!
-            res = funcptr(%(argnames)s)
-            return res
-    """ % locals())
-    miniglobals = {'__name__':    __name__, # for module name propagation
-                   }
-    exec source.compile() in miniglobals
-    call_external_function = miniglobals['call_external_function']
-    call_external_function._dont_inline_ = True
-    call_external_function._annspecialcase_ = 'specialize:ll'
-    call_external_function._gctransformer_hint_close_stack_ = True
-    call_external_function = func_with_new_name(call_external_function,
-                                                'ccall_' + name)
-    # don't inline, as a hack to guarantee that no GC pointer is alive
-    # anywhere in call_external_function
-
-    @specialize.ll()
-    def generic_cpy_call(space, func, *args):
-        boxed_args = ()
-        to_decref = []
-        assert len(args) == len(FT.ARGS)
-        for i, ARG in unrolling_arg_types:
-            arg = args[i]
-            if is_PyObject(ARG):
-                if arg is None:
-                    boxed_args += (lltype.nullptr(PyObject.TO),)
-                elif isinstance(arg, W_Root):
-                    ref = make_ref(space, arg)
-                    boxed_args += (ref,)
-                    if decref_args:
-                        to_decref.append(ref)
-                else:
-                    boxed_args += (arg,)
-            else:
-                boxed_args += (arg,)
-
-        try:
-            # create a new container for borrowed references
-            state = space.fromcache(RefcountState)
-            old_container = state.swap_borrow_container(None)
-            try:
-                # Call the function
-                result = call_external_function(func, *boxed_args)
-            finally:
-                state.swap_borrow_container(old_container)
-
-            if is_PyObject(RESULT_TYPE):
-                if result is None:
-                    ret = result
-                elif isinstance(result, W_Root):
-                    ret = result
-                else:
-                    ret = from_ref(space, result)
-                    # The object reference returned from a C function
-                    # that is called from Python must be an owned reference
-                    # - ownership is transferred from the function to its caller.
-                    if result:
-                        Py_DecRef(space, result)
-
-                # Check for exception consistency
-                has_error = PyErr_Occurred(space) is not None
-                has_result = ret is not None
-                if has_error and has_result:
-                    raise OperationError(space.w_SystemError, space.wrap(
-                        "An exception was set, but function returned a value"))
-                elif not expect_null and not has_error and not has_result:
-                    raise OperationError(space.w_SystemError, space.wrap(
-                        "Function returned a NULL result without setting an exception"))
-
-                if has_error:
-                    state = space.fromcache(State)
-                    state.check_and_raise_exception()
-
-                return ret
-            return result
-        finally:
-            if decref_args:
-                for ref in to_decref:
-                    Py_DecRef(space, ref)
-    return generic_cpy_call
-

pypy/module/cpyext/boolobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (cpython_api, PyObject, CANNOT_FAIL,
-                                    build_type_checkers)
+from pypy.module.cpyext.gateway import (
+    cpython_api, CANNOT_FAIL)
+from pypy.module.cpyext.api import PyObject, build_type_checkers
 
 # Inheriting from bool isn't actually possible.
 PyBool_Check = build_type_checkers("Bool")[1]

pypy/module/cpyext/classobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 from pypy.module.cpyext.api import (
-    PyObjectFields, CANNOT_FAIL,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
-from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref, Py_DecRef, make_typedescr
+    PyObjectFields, bootstrap_function, cpython_struct, build_type_checkers)
+from pypy.module.cpyext.pyobject import (
+    PyObject, make_ref, from_ref, Py_DecRef, make_typedescr)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
-from pypy.module.__builtin__.interp_classobj import W_ClassObject, W_InstanceObject
+from pypy.module.__builtin__.interp_classobj import (
+    W_ClassObject, W_InstanceObject)
 
 PyClass_Check, PyClass_CheckExact = build_type_checkers("Class", W_ClassObject)
 PyInstance_Check, PyInstance_CheckExact = build_type_checkers("Instance", W_InstanceObject)

pypy/module/cpyext/complexobject.py

 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, PyObject, build_type_checkers)
+from pypy.module.cpyext.gateway import cpython_api
+from pypy.module.cpyext.api import cpython_struct, build_type_checkers
+from pypy.module.cpyext.pyobject import PyObject
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.floatobject import PyFloat_AsDouble
 from pypy.objspace.std.complexobject import W_ComplexObject

pypy/module/cpyext/datetime.py

 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.pyobject import PyObject, make_ref
-from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import cpython_struct, PyObjectFields
 from pypy.module.cpyext.import_ import PyImport_Import
 from pypy.module.cpyext.typeobject import PyTypeObjectPtr
 from pypy.interpreter.error import OperationError

pypy/module/cpyext/dictobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, build_type_checkers, Py_ssize_t,
-    Py_ssize_tP, CONST_STRING)
-from pypy.module.cpyext.pyobject import PyObject, PyObjectP, borrow_from
-from pypy.module.cpyext.pyobject import RefcountState
+    build_type_checkers, Py_ssize_t, Py_ssize_tP, CONST_STRING)
+from pypy.module.cpyext.pyobject import (
+    PyObject, PyObjectP, borrow_from, RefcountState)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.interpreter.error import OperationError
 

pypy/module/cpyext/eval.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, fread, feof, Py_ssize_tP)
+    CONST_STRING, FILEP, fread, feof, Py_ssize_tP)
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
 from pypy.module.cpyext.pyerrors import PyErr_SetFromErrno
 from pypy.module.__builtin__ import compiling

pypy/module/cpyext/floatobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (CANNOT_FAIL, cpython_api, PyObject,
-                                    build_type_checkers)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import PyObject, build_type_checkers
 from pypy.interpreter.error import OperationError
 
 PyFloat_Check, PyFloat_CheckExact = build_type_checkers("Float")

pypy/module/cpyext/funcobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api, generic_cpy_call
 from pypy.module.cpyext.api import (
-    PyObjectFields, generic_cpy_call,
-    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+    cpython_struct, build_type_checkers, PyObjectFields, bootstrap_function)
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, from_ref, Py_DecRef, make_typedescr, borrow_from)
 from pypy.interpreter.function import Function, Method

pypy/module/cpyext/gateway.py

+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.error import OperationError
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rlib.objectmodel import specialize, we_are_translated
+from pypy.module.cpyext.api import (
+    ApiFunction, FUNCTION_declare, INTERPLEVEL_declare, PyObject)
+from pypy.module.cpyext.state import State
+from pypy.rlib.unroll import unrolling_iterable
+import sys
+import py
+
+# The same function can be called in three different contexts:
+# (1) from C code
+# (2) in the test suite, though the "api" object
+# (3) from RPython code, for example in the implementation of another function.
+#
+# In contexts (2) and (3), a function declaring a PyObject argument type will
+# receive a wrapped pypy object if the parameter name starts with 'w_', a
+# reference (= rffi pointer) otherwise; conversion is automatic.  Context (2)
+# only allows calls with a wrapped object.
+#
+# Functions with a PyObject return type should return a wrapped object.
+#
+# Functions may raise exceptions.  In context (3), the exception flows normally
+# through the calling function.  In context (1) and (2), the exception is
+# caught; if it is an OperationError, it is stored in the thread state; other
+# exceptions generate a OperationError(w_SystemError); and the funtion returns
+# the error value specifed in the API.
+#
+
+DEBUG_WRAPPER = True
+
+_NOT_SPECIFIED = object()
+CANNOT_FAIL = object()
+
+pypy_debug_catch_fatal_exception = rffi.llexternal('pypy_debug_catch_fatal_exception', [], lltype.Void)
+
+@specialize.memo()
+def is_PyObject(TYPE):
+    if not isinstance(TYPE, lltype.Ptr):
+        return False
+    return hasattr(TYPE.TO, 'c_ob_refcnt') and hasattr(TYPE.TO, 'c_ob_type')
+
+def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True):
+    """
+    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.
+    - set `external` to False to get a C function pointer, but not exported by
+      the API headers.
+    """
+    if error is _NOT_SPECIFIED:
+        if restype is PyObject:
+            error = lltype.nullptr(restype.TO)
+        elif restype is lltype.Void:
+            error = CANNOT_FAIL
+    if type(error) is int:
+        error = rffi.cast(restype, error)
+
+    def decorate(func):
+        func_name = func.func_name
+        if external:
+            c_name = None
+        else:
+            c_name = func_name
+        api_function = ApiFunction(argtypes, restype, func, error, c_name=c_name)
+        func.api_func = api_function
+
+        if error is _NOT_SPECIFIED:
+            raise ValueError("function %s has no return value for exceptions"
+                             % func)
+        def make_unwrapper(catch_exception):
+            names = api_function.argnames
+            types_names_enum_ui = unrolling_iterable(enumerate(
+                zip(api_function.argtypes,
+                    [tp_name.startswith("w_") for tp_name in names])))
+
+            @specialize.ll()
+            def unwrapper(space, *args):
+                from pypy.module.cpyext.pyobject import Py_DecRef
+                from pypy.module.cpyext.pyobject import make_ref, from_ref
+                from pypy.module.cpyext.pyobject import BorrowPair
+                newargs = ()
+                to_decref = []
+                assert len(args) == len(api_function.argtypes)
+                for i, (ARG, is_wrapped) in types_names_enum_ui:
+                    input_arg = args[i]
+                    if is_PyObject(ARG) and not is_wrapped:
+                        # build a reference
+                        if input_arg is None:
+                            arg = lltype.nullptr(PyObject.TO)
+                        elif isinstance(input_arg, W_Root):
+                            ref = make_ref(space, input_arg)
+                            to_decref.append(ref)
+                            arg = rffi.cast(ARG, ref)
+                        else:
+                            arg = input_arg
+                    elif is_PyObject(ARG) and is_wrapped:
+                        # convert to a wrapped object
+                        if input_arg is None:
+                            arg = input_arg
+                        elif isinstance(input_arg, W_Root):
+                            arg = input_arg
+                        else:
+                            arg = from_ref(space,
+                                           rffi.cast(PyObject, input_arg))
+                    else:
+                        arg = input_arg
+                    newargs += (arg, )
+                try:
+                    try:
+                        res = func(space, *newargs)
+                    except OperationError, e:
+                        if not catch_exception:
+                            raise
+                        state = space.fromcache(State)
+                        state.set_exception(e)
+                        if is_PyObject(restype):
+                            return None
+                        else:
+                            if api_function.error_value is _NOT_SPECIFIED:
+                                raise
+                            return api_function.error_value
+                    if res is None:
+                        return None
+                    elif isinstance(res, BorrowPair):
+                        return res.w_borrowed
+                    else:
+                        return res
+                finally:
+                    for arg in to_decref:
+                        Py_DecRef(space, arg)
+            unwrapper.func = func
+            unwrapper.api_func = api_function
+            unwrapper._always_inline_ = True
+            return unwrapper
+
+        unwrapper_catch = make_unwrapper(True)
+        unwrapper_raise = make_unwrapper(False)
+        if external:
+            FUNCTION_declare(func_name, api_function)
+        INTERPLEVEL_declare(func_name, unwrapper_catch) # used in tests
+        return unwrapper_raise # used in 'normal' RPython code.
+    return decorate
+
+# Make the wrapper for the cases (1) and (2)
+def make_wrapper(space, callable):
+    "NOT_RPYTHON"
+    names = callable.api_func.argnames
+    argtypes_enum_ui = unrolling_iterable(enumerate(zip(callable.api_func.argtypes,
+        [name.startswith("w_") for name in names])))
+    fatal_value = callable.api_func.restype._defl()
+
+    @specialize.ll()
+    def wrapper(*args):
+        from pypy.module.cpyext.pyobject import make_ref, from_ref
+        from pypy.module.cpyext.pyobject import BorrowPair
+        # we hope that malloc removal removes the newtuple() that is
+        # inserted exactly here by the varargs specializer
+        llop.gc_stack_bottom(lltype.Void)   # marker for trackgcroot.py
+        rffi.stackcounter.stacks_counter += 1
+        retval = fatal_value
+        boxed_args = ()
+        try:
+            if not we_are_translated() and DEBUG_WRAPPER:
+                print >>sys.stderr, callable,
+            assert len(args) == len(callable.api_func.argtypes)
+            for i, (typ, is_wrapped) in argtypes_enum_ui:
+                arg = args[i]
+                if is_PyObject(typ) and is_wrapped:
+                    if arg:
+                        arg_conv = from_ref(space, rffi.cast(PyObject, arg))
+                    else:
+                        arg_conv = None
+                else:
+                    arg_conv = arg
+                boxed_args += (arg_conv, )
+            state = space.fromcache(State)
+            try:
+                result = callable(space, *boxed_args)
+                if not we_are_translated() and DEBUG_WRAPPER:
+                    print >>sys.stderr, " DONE"
+            except OperationError, e:
+                failed = True
+                state.set_exception(e)
+            except BaseException, e:
+                failed = True
+                if not we_are_translated():
+                    message = repr(e)
+                    import traceback
+                    traceback.print_exc()
+                else:
+                    message = str(e)
+                state.set_exception(OperationError(space.w_SystemError,
+                                                   space.wrap(message)))
+            else:
+                failed = False
+
+            if failed:
+                error_value = callable.api_func.error_value
+                if error_value is CANNOT_FAIL:
+                    raise SystemError("The function '%s' was not supposed to fail"
+                                      % (callable.__name__,))
+                retval = error_value
+
+            elif is_PyObject(callable.api_func.restype):
+                if result is None:
+                    retval = make_ref(space, None)
+                elif isinstance(result, BorrowPair):
+                    retval = result.get_ref(space)
+                elif not rffi._isllptr(result):
+                    retval = rffi.cast(callable.api_func.restype,
+                                       make_ref(space, result))
+                else:
+                    retval = result
+            elif callable.api_func.restype is not lltype.Void:
+                retval = rffi.cast(callable.api_func.restype, result)
+        except Exception, e:
+            if not we_are_translated():
+                import traceback
+                traceback.print_exc()
+                print str(e)
+                # we can't do much here, since we're in ctypes, swallow
+            else:
+                print str(e)
+                pypy_debug_catch_fatal_exception()
+        rffi.stackcounter.stacks_counter -= 1
+        return retval
+    callable._always_inline_ = True
+    wrapper.__name__ = "wrapper for %r" % (callable, )
+    return wrapper
+
+@specialize.ll()
+def generic_cpy_call(space, func, *args):
+    FT = lltype.typeOf(func).TO
+    return make_generic_cpy_call(FT, True, False)(space, func, *args)
+
+@specialize.ll()
+def generic_cpy_call_dont_decref(space, func, *args):
+    FT = lltype.typeOf(func).TO
+    return make_generic_cpy_call(FT, False, False)(space, func, *args)
+
+@specialize.ll()    
+def generic_cpy_call_expect_null(space, func, *args):
+    FT = lltype.typeOf(func).TO
+    return make_generic_cpy_call(FT, True, True)(space, func, *args)
+
+@specialize.memo()
+def make_generic_cpy_call(FT, decref_args, expect_null):
+    from pypy.module.cpyext.pyobject import make_ref, from_ref, Py_DecRef
+    from pypy.module.cpyext.pyobject import RefcountState
+    from pypy.module.cpyext.pyerrors import PyErr_Occurred
+    unrolling_arg_types = unrolling_iterable(enumerate(FT.ARGS))
+    RESULT_TYPE = FT.RESULT
+
+    # copied and modified from rffi.py
+    # We need tons of care to ensure that no GC operation and no
+    # exception checking occurs in call_external_function.
+    argnames = ', '.join(['a%d' % i for i in range(len(FT.ARGS))])
+    source = py.code.Source("""
+        def call_cpyext_external_function(funcptr, %(argnames)s):
+            # NB. it is essential that no exception checking occurs here!
+            res = funcptr(%(argnames)s)
+            return res
+    """ % locals())
+    miniglobals = {'__name__':    __name__, # for module name propagation
+                   }
+    exec source.compile() in miniglobals
+    call_external_function = miniglobals['call_cpyext_external_function']
+    call_external_function._dont_inline_ = True
+    call_external_function._annspecialcase_ = 'specialize:ll'
+    call_external_function._gctransformer_hint_close_stack_ = True
+    # don't inline, as a hack to guarantee that no GC pointer is alive
+    # anywhere in call_external_function
+
+    @specialize.ll()
+    def generic_cpy_call(space, func, *args):
+        boxed_args = ()
+        to_decref = []
+        assert len(args) == len(FT.ARGS)
+        for i, ARG in unrolling_arg_types:
+            arg = args[i]
+            if is_PyObject(ARG):
+                if arg is None:
+                    boxed_args += (lltype.nullptr(PyObject.TO),)
+                elif isinstance(arg, W_Root):
+                    ref = make_ref(space, arg)
+                    boxed_args += (ref,)
+                    if decref_args:
+                        to_decref.append(ref)
+                else:
+                    boxed_args += (arg,)
+            else:
+                boxed_args += (arg,)
+
+        try:
+            # create a new container for borrowed references
+            state = space.fromcache(RefcountState)
+            old_container = state.swap_borrow_container(None)
+            try:
+                # Call the function
+                result = call_external_function(func, *boxed_args)
+            finally:
+                state.swap_borrow_container(old_container)
+
+            if is_PyObject(RESULT_TYPE):
+                if result is None:
+                    ret = result
+                elif isinstance(result, W_Root):
+                    ret = result
+                else:
+                    ret = from_ref(space, result)
+                    # The object reference returned from a C function
+                    # that is called from Python must be an owned reference
+                    # - ownership is transferred from the function to its caller.
+                    if result:
+                        Py_DecRef(space, result)
+
+                # Check for exception consistency
+                has_error = PyErr_Occurred(space) is not None
+                has_result = ret is not None
+                if has_error and has_result:
+                    raise OperationError(space.w_SystemError, space.wrap(
+                        "An exception was set, but function returned a value"))
+                elif not expect_null and not has_error and not has_result:
+                    raise OperationError(space.w_SystemError, space.wrap(
+                        "Function returned a NULL result without setting an exception"))
+
+                if has_error:
+                    state = space.fromcache(State)
+                    state.check_and_raise_exception()
+
+                return ret
+            return result
+        finally:
+            if decref_args:
+                for ref in to_decref:
+                    Py_DecRef(space, ref)
+    return generic_cpy_call

pypy/module/cpyext/import_.py

 from pypy.interpreter import module
-from pypy.module.cpyext.api import (
-    generic_cpy_call, cpython_api, PyObject, CONST_STRING)
+from pypy.module.cpyext.gateway import cpython_api, generic_cpy_call
+from pypy.module.cpyext.api import PyObject, CONST_STRING
 from pypy.rpython.lltypesystem import rffi
 from pypy.interpreter.error import OperationError
 

pypy/module/cpyext/intobject.py

 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (cpython_api, PyObject, CANNOT_FAIL,
-                                    build_type_checkers, Py_ssize_t)
-
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import PyObject, Py_ssize_t, build_type_checkers
 
 PyInt_Check, PyInt_CheckExact = build_type_checkers("Int")
 

pypy/module/cpyext/iterator.py

 from pypy.interpreter.error import OperationError
-from pypy.module.cpyext.api import (generic_cpy_call, cpython_api, PyObject,
-    CANNOT_FAIL)
+from pypy.module.cpyext.gateway import (
+    generic_cpy_call, cpython_api, CANNOT_FAIL)
+from pypy.module.cpyext.pyobject import PyObject
 import pypy.module.__builtin__.operation as operation
 from pypy.rpython.lltypesystem import rffi
 

pypy/module/cpyext/listobject.py

 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, Py_ssize_t,
-                                    build_type_checkers)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import Py_ssize_t, build_type_checkers
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.module.cpyext.pyobject import Py_DecRef, PyObject, borrow_from
 from pypy.objspace.std.listobject import W_ListObject

pypy/module/cpyext/longobject.py

 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module.cpyext.api import (cpython_api, PyObject, build_type_checkers,
-                                    CONST_STRING, ADDR)
+from pypy.module.cpyext.gateway import cpython_api
+from pypy.module.cpyext.api import (
+    PyObject, CONST_STRING, ADDR, build_type_checkers)
 from pypy.objspace.std.longobject import W_LongObject
 from pypy.interpreter.error import OperationError
 

pypy/module/cpyext/mapping.py

 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, CONST_STRING, Py_ssize_t)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import CONST_STRING, Py_ssize_t
 from pypy.module.cpyext.pyobject import PyObject
 
 

pypy/module/cpyext/methodobject.py

 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter.function import BuiltinFunction, Method, StaticMethod
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.pyobject import (PyObject, from_ref, make_ref,
-                                         make_typedescr, Py_DecRef)
+from pypy.module.cpyext.pyobject import (
+    PyObject, from_ref, make_ref, make_typedescr, Py_DecRef)
+from pypy.module.cpyext.gateway import cpython_api, generic_cpy_call
 from pypy.module.cpyext.api import (
-    generic_cpy_call, cpython_api, PyObject, cpython_struct, METH_KEYWORDS,
-    METH_O, CONST_STRING, METH_CLASS, METH_STATIC, METH_COEXIST, METH_NOARGS,
-    METH_VARARGS, build_type_checkers, PyObjectFields, bootstrap_function)
+    PyObject, cpython_struct, PyObjectFields, bootstrap_function,
+    build_type_checkers, METH_KEYWORDS, METH_O, METH_CLASS,
+    METH_STATIC, METH_COEXIST, METH_NOARGS, METH_VARARGS,
+    CONST_STRING)
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.tupleobject import W_TupleObject

pypy/module/cpyext/modsupport.py

 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, cpython_struct, \
-        METH_STATIC, METH_CLASS, METH_COEXIST, CANNOT_FAIL, CONST_STRING
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import (
+    cpython_struct, METH_STATIC, METH_CLASS, METH_COEXIST, CONST_STRING)
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
 from pypy.interpreter.module import Module
 from pypy.module.cpyext.methodobject import (

pypy/module/cpyext/number.py

 from pypy.interpreter.error import OperationError
-from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, Py_ssize_t
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import Py_ssize_t
 from pypy.module.cpyext.pyobject import PyObject
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.tool.sourcetools import func_with_new_name

pypy/module/cpyext/object.py

 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import (
+    cpython_api, generic_cpy_call, CANNOT_FAIL)
 from pypy.module.cpyext.api import (
-    cpython_api, generic_cpy_call, CANNOT_FAIL, Py_ssize_t, Py_ssize_tP,
-    PyVarObject, Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT,
-    Py_GE, CONST_STRING, FILEP, fwrite)
+    Py_ssize_t, Py_ssize_tP, PyVarObject, CONST_STRING,
+    Py_TPFLAGS_HEAPTYPE, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE,
+    FILEP, fwrite)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
     track_reference, get_typedescr, RefcountState)

pypy/module/cpyext/pyerrors.py

 
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.interpreter.error import OperationError
-from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL, CONST_STRING
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import CONST_STRING
 from pypy.module.exceptions.interp_exceptions import W_RuntimeWarning
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, make_ref, Py_DecRef, borrow_from)

pypy/module/cpyext/pyobject.py

 
 from pypy.interpreter.baseobjspace import W_Root, SpaceCache
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import (
+    cpython_api, CANNOT_FAIL)
 from pypy.module.cpyext.api import (
-    cpython_api, bootstrap_function, PyObject, PyObjectP, ADDR,
-    CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr)
+    bootstrap_function, PyObject, PyObjectP, ADDR,
+    Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr)
 from pypy.module.cpyext.state import State
 from pypy.objspace.std.typeobject import W_TypeObject
 from pypy.rlib.objectmodel import specialize, we_are_translated
     obj.c_ob_refcnt = 1
 
 def _Py_Dealloc(space, obj):
-    from pypy.module.cpyext.api import generic_cpy_call_dont_decref
+    from pypy.module.cpyext.gateway import generic_cpy_call_dont_decref
     pto = obj.c_ob_type
     #print >>sys.stderr, "Calling dealloc slot", pto.c_tp_dealloc, "of", obj, \
     #      "'s type which is", rffi.charp2str(pto.c_tp_name)

pypy/module/cpyext/pystate.py

-from pypy.module.cpyext.api import cpython_api, generic_cpy_call, CANNOT_FAIL,\
-        cpython_struct
+from pypy.module.cpyext.gateway import (
+    cpython_api, generic_cpy_call, CANNOT_FAIL)
+from pypy.module.cpyext.api import cpython_struct
 from pypy.rpython.lltypesystem import rffi, lltype
 
 

pypy/module/cpyext/pythonrun.py

 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 
 @cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
 def Py_IsInitialized(space):

pypy/module/cpyext/sequence.py

 
 from pypy.interpreter.error import OperationError
-from pypy.module.cpyext.api import (
-    cpython_api, CANNOT_FAIL, CONST_STRING, Py_ssize_t)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import CONST_STRING, Py_ssize_t
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.objspace.std import listobject, tupleobject

pypy/module/cpyext/sliceobject.py

 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
-    CANNOT_FAIL, Py_ssize_t, Py_ssize_tP, PyObjectFields)
+    cpython_struct, build_type_checkers, bootstrap_function,
+    Py_ssize_t, Py_ssize_tP, PyObjectFields)
 from pypy.module.cpyext.pyobject import (
     Py_DecRef, PyObject, make_ref, make_typedescr)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall

pypy/module/cpyext/slotdefs.py

 import re
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import generic_cpy_call, cpython_api, PyObject
+from pypy.module.cpyext.gateway import (
+    cpython_api, generic_cpy_call, generic_cpy_call_expect_null)
+from pypy.module.cpyext.pyobject import PyObject
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
     getattrfunc, setattrofunc, lenfunc, ssizeargfunc, ssizessizeargfunc,
     return generic_cpy_call(space, func_target, w_self, start, end)
 
 def wrap_next(space, w_self, w_args, func):
-    from pypy.module.cpyext.api import generic_cpy_call_expect_null
     func_target = rffi.cast(iternextfunc, func)
     check_num_args(space, w_args, 0)
     w_res = generic_cpy_call_expect_null(space, func_target, w_self)

pypy/module/cpyext/stringobject.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.gateway import cpython_api
 from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
+    cpython_struct, build_type_checkers, bootstrap_function,
     PyObjectFields, Py_ssize_t, CONST_STRING)
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,

pypy/module/cpyext/structmember.py

 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext import structmemberdefs
-from pypy.module.cpyext.api import ADDR, PyObjectP, cpython_api
+from pypy.module.cpyext.api import ADDR, PyObjectP
+from pypy.module.cpyext.gateway import cpython_api
 from pypy.module.cpyext.intobject import PyInt_AsLong, PyInt_AsUnsignedLong
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.pyobject import PyObject, Py_DecRef, from_ref, make_ref

pypy/module/cpyext/stubsactive.py

 from pypy.module.cpyext.pyobject import PyObject
-from pypy.module.cpyext.api import cpython_api, Py_ssize_t, CANNOT_FAIL, CConfig
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import Py_ssize_t, CConfig
 from pypy.module.cpyext.object import FILEP
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.cpyext.pystate import PyThreadState, PyInterpreterState

pypy/module/cpyext/sysmodule.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import CANNOT_FAIL, cpython_api, CONST_STRING
+from pypy.module.cpyext.gateway import CANNOT_FAIL, cpython_api
+from pypy.module.cpyext.api import CONST_STRING
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
 
 @cpython_api([CONST_STRING], PyObject, error=CANNOT_FAIL)

pypy/module/cpyext/test/test_api.py

 from pypy.conftest import gettestobjspace
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.interpreter.baseobjspace import W_Root
+from pypy.module.cpyext.api import INTERPLEVEL_API
 from pypy.module.cpyext.state import State
-from pypy.module.cpyext import api
+from pypy.module.cpyext.gateway import cpython_api
+from pypy.module.cpyext.pyobject import PyObject
 from pypy.module.cpyext.test.test_cpyext import freeze_refcnts, LeakCheckingTest
-PyObject = api.PyObject
 from pypy.interpreter.error import OperationError
 from pypy.module.cpyext.state import State
 import os
 
-@api.cpython_api([PyObject], lltype.Void)
+@cpython_api([PyObject], lltype.Void)
 def PyPy_GetWrapped(space, w_arg):
     assert isinstance(w_arg, W_Root)
-@api.cpython_api([PyObject], lltype.Void)
+@cpython_api([PyObject], lltype.Void)
 def PyPy_GetReference(space, arg):
     assert lltype.typeOf(arg) ==  PyObject
 
             def __getattr__(self, name):
                 return getattr(cls.space, name)
         cls.api = CAPI()
-        CAPI.__dict__.update(api.INTERPLEVEL_API)
+        CAPI.__dict__.update(INTERPLEVEL_API)
 
     def raises(self, space, api, expected_exc, f, *args):
         if not callable(f):

pypy/module/cpyext/test/test_borrow.py

                 g = PyTuple_GetItem(t, 0); // borrows reference again
                 printf("Refcnt4: %i\\n", f->ob_refcnt);
                 printf("COMPARE: %i\\n", f == g);
+                fflush(stdout);
                 Py_DECREF(t);
                 Py_RETURN_TRUE;
              """),

pypy/module/cpyext/test/test_cpyext.py

 from pypy.translator.gensupp import uniquemodulename
 from pypy.tool.udir import udir
 from pypy.module.cpyext import api
+from pypy.module.cpyext.gateway import cpython_api
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext.pyobject import RefcountState
 from pypy.module.cpyext.pyobject import Py_DecRef, InvalidPointerException
 from pypy.translator.goal import autopath
 from pypy.lib.identity_dict import identity_dict
 
-@api.cpython_api([], api.PyObject)
+@cpython_api([], api.PyObject)
 def PyPy_Crash1(space):
     1/0
 
-@api.cpython_api([], lltype.Signed, error=-1)
+@cpython_api([], lltype.Signed, error=-1)
 def PyPy_Crash2(space):
     1/0
 
             Py_DECREF(true);
             Py_DECREF(true);
             fprintf(stderr, "REFCNT %i %i\\n", refcnt, refcnt_after);
+            fflush(stderr);
             return PyBool_FromLong(refcnt_after == refcnt+2 && refcnt < 3);
         }
         static PyObject* foo_bar(PyObject* self, PyObject *args)
             refcnt_after = true->ob_refcnt;
             Py_DECREF(tup);
             fprintf(stderr, "REFCNT2 %i %i\\n", refcnt, refcnt_after);
+            fflush(stderr);
             return PyBool_FromLong(refcnt_after == refcnt);
         }
 

pypy/module/cpyext/test/test_methodobject.py

         """
         def func(space, w_self, w_args):
             return space.w_None
-        c_func = ApiFunction([PyObject, PyObject], PyObject, func)
+        c_func = ApiFunction([PyObject, PyObject], PyObject, func, error=None)
         func.api_func = c_func
         ml = lltype.malloc(PyMethodDef, flavor='raw', zero=True)
         namebuf = rffi.str2charp('func')

pypy/module/cpyext/test/test_translate.py

 from pypy.translator.c.test.test_genc import compile
-import pypy.module.cpyext.api
-from pypy.module.cpyext.api import cpython_api
+import pypy.module.cpyext.gateway
+from pypy.module.cpyext.gateway import cpython_api
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.lltypesystem import lltype
 from pypy.rlib.objectmodel import specialize
         def wrapper():
             return func(space)
         return wrapper
-    monkeypatch.setattr(pypy.module.cpyext.api, 'make_wrapper', make_wrapper)
+    monkeypatch.setattr(pypy.module.cpyext.gateway, 'make_wrapper', make_wrapper)
 
     @specialize.memo()
     def get_tp_function(space, typedef):

pypy/module/cpyext/thread.py

 
 from pypy.module.thread import ll_thread
-from pypy.module.cpyext.api import CANNOT_FAIL, cpython_api
+from pypy.module.cpyext.gateway import CANNOT_FAIL, cpython_api
 from pypy.rpython.lltypesystem import rffi
 
 @cpython_api([], rffi.LONG, error=CANNOT_FAIL)

pypy/module/cpyext/tupleobject.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (cpython_api, Py_ssize_t, CANNOT_FAIL,
-                                    build_type_checkers)
-from pypy.module.cpyext.pyobject import (PyObject, PyObjectP, Py_DecRef,
-    borrow_from, make_ref, from_ref)
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.api import Py_ssize_t, build_type_checkers
+from pypy.module.cpyext.pyobject import (
+    PyObject, PyObjectP, Py_DecRef, borrow_from, make_ref, from_ref)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.tupleobject import W_TupleObject
 

pypy/module/cpyext/typeobject.py

 from pypy.interpreter.baseobjspace import DescrMismatch
 from pypy.objspace.std.typeobject import W_TypeObject, _CPYTYPE
 from pypy.interpreter.typedef import GetSetProperty
+from pypy.module.cpyext.gateway import (
+    cpython_api, generic_cpy_call, CANNOT_FAIL)
 from pypy.module.cpyext.api import (
-    cpython_api, cpython_struct, bootstrap_function, Py_ssize_t,
-    generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
-    Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
-    PyBufferProcs, build_type_checkers)
+    cpython_struct, build_type_checkers, bootstrap_function,
+    Py_ssize_t, PyBufferProcs, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
+    Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS)
+
 from pypy.module.cpyext.pyobject import (
     PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
     track_reference, RefcountState, borrow_from)

pypy/module/cpyext/unicodeobject.py

 from pypy.interpreter.error import OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.module.unicodedata import unicodedb_4_1_0 as unicodedb
+from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
 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)
+    cpython_struct, build_type_checkers, bootstrap_function,
+    PyObjectFields, Py_ssize_t, CONST_STRING, CONST_WSTRING)
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import PyObject, from_ref, make_typedescr
 from pypy.module.sys.interp_encoding import setdefaultencoding

pypy/module/cpyext/weakrefobject.py

-from pypy.module.cpyext.api import cpython_api
+from pypy.module.cpyext.gateway import cpython_api
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
 from pypy.module._weakref.interp__weakref import W_Weakref
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.