[pypy-svn] r26600 - in pypy/dist/pypy: interpreter objspace/cpy objspace/cpy/test
arigo at codespeak.net
arigo at codespeak.net
Sun Apr 30 16:00:26 CEST 2006
Author: arigo
Date: Sun Apr 30 16:00:22 2006
New Revision: 26600
Added:
pypy/dist/pypy/objspace/cpy/ctypes_base.py (contents, props changed)
Modified:
pypy/dist/pypy/interpreter/error.py
pypy/dist/pypy/objspace/cpy/ann_policy.py
pypy/dist/pypy/objspace/cpy/capi.py
pypy/dist/pypy/objspace/cpy/objspace.py
pypy/dist/pypy/objspace/cpy/test/test_objspace.py
pypy/dist/pypy/objspace/cpy/test/test_wrappable.py
pypy/dist/pypy/objspace/cpy/wrappable.py
Log:
Start supporting exceptions in the CPyObjSpace: the idea is
that in RPython there are only a few exception classes, which
represent internal errors and shouldn't escape, apart from
the OperationError, which represents an app-level exception.
- when calling C API functions, wrap any exception into
an OperationError back for the RPython caller;
- when wrapping an RPython function to expose it to the
C API, unwrap OperationErrors generated by RPython.
Some more rctypes support seems to be needed for the first point.
Modified: pypy/dist/pypy/interpreter/error.py
==============================================================================
--- pypy/dist/pypy/interpreter/error.py (original)
+++ pypy/dist/pypy/interpreter/error.py Sun Apr 30 16:00:22 2006
@@ -11,8 +11,8 @@
OperationError instances have three public attributes (and no .args),
w_type, w_value and application_traceback, which contain the wrapped
- type and value describing the exception, and the unwrapped list of
- (frame, instruction_position) making the application-level traceback.
+ type and value describing the exception, and a chained list of
+ PyTraceback objects making the application-level traceback.
"""
def __init__(self, w_type, w_value, tb=None):
Modified: pypy/dist/pypy/objspace/cpy/ann_policy.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/ann_policy.py (original)
+++ pypy/dist/pypy/objspace/cpy/ann_policy.py Sun Apr 30 16:00:22 2006
@@ -1,5 +1,8 @@
from pypy.translator.goal.ann_override import PyPyAnnotatorPolicy
from pypy.annotation.pairtype import pair
+from pypy.annotation import model as annmodel
+from pypy.interpreter.error import OperationError
+from pypy.objspace.cpy.ctypes_base import W_Object
class CPyAnnotatorPolicy(PyPyAnnotatorPolicy):
"""Annotation policy to compile CPython extension modules with
@@ -8,7 +11,6 @@
def __init__(self, space):
PyPyAnnotatorPolicy.__init__(self, single_space=space)
- self.spaces = {}
def no_more_blocks_to_annotate(self, annotator):
PyPyAnnotatorPolicy.no_more_blocks_to_annotate(self, annotator)
@@ -26,3 +28,10 @@
w_obj)
# restart this loop: for all we know follow_annotations()
# could have found new objects
+
+ # force w_type, w_value attributes into the OperationError class
+ classdef = annotator.bookkeeper.getuniqueclassdef(OperationError)
+ s_instance = annmodel.SomeInstance(classdef=classdef)
+ for name in ['w_type', 'w_value']:
+ s_instance.setattr(annotator.bookkeeper.immutablevalue(name),
+ annotator.bookkeeper.valueoftype(W_Object))
Modified: pypy/dist/pypy/objspace/cpy/capi.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/capi.py (original)
+++ pypy/dist/pypy/objspace/cpy/capi.py Sun Apr 30 16:00:22 2006
@@ -1,16 +1,12 @@
+"""
+CTypes declarations for the CPython API.
+"""
import sys
import ctypes
from ctypes import *
from pypy.rpython.rctypes.tool import ctypes_platform
-from pypy.rpython.rctypes import apyobject
##from pypy.rpython.rctypes.implementation import CALLBACK_FUNCTYPE
-
-class W_Object(py_object):
- "A py_object subclass, representing wrapped objects for the CPyObjSpace."
- def __repr__(self):
- return 'W_Object(%r)' % (self.value,)
-
-apyobject.register_py_object_subclass(W_Object)
+from pypy.objspace.cpy.ctypes_base import W_Object, cpyapi
###############################################################
@@ -54,51 +50,63 @@
###########################################################
# ____________________ Object Protocol ____________________
-PyObject_GetAttr = pythonapi.PyObject_GetAttr
+PyObject_GetAttr = cpyapi.PyObject_GetAttr
PyObject_GetAttr.argtypes = [W_Object, W_Object]
PyObject_GetAttr.restype = W_Object
-PyObject_GetItem = pythonapi.PyObject_GetItem
+PyObject_GetItem = cpyapi.PyObject_GetItem
PyObject_GetItem.argtypes = [W_Object, W_Object]
PyObject_GetItem.restype = W_Object
-PyObject_SetItem = pythonapi.PyObject_SetItem
+PyObject_SetItem = cpyapi.PyObject_SetItem
PyObject_SetItem.argtypes = [W_Object, W_Object, W_Object]
PyObject_SetItem.restype = c_int
-PyObject_Call = pythonapi.PyObject_Call
+PyObject_Call = cpyapi.PyObject_Call
PyObject_Call.argtypes = [W_Object, W_Object, W_Object]
PyObject_Call.restype = W_Object
-PyObject_CallFunctionObjArgs = pythonapi.PyObject_CallFunctionObjArgs
+PyObject_CallFunctionObjArgs = cpyapi.PyObject_CallFunctionObjArgs
PyObject_CallFunctionObjArgs.restype = W_Object
#PyObject_CallFunctionObjArgs.argtypes = [W_Object, ..., final NULL]
-PyObject_RichCompare = pythonapi.PyObject_RichCompare
+PyObject_RichCompare = cpyapi.PyObject_RichCompare
PyObject_RichCompare.argtypes = [W_Object, W_Object, c_int]
PyObject_RichCompare.restype = W_Object
-PyObject_RichCompareBool = pythonapi.PyObject_RichCompareBool
+PyObject_RichCompareBool = cpyapi.PyObject_RichCompareBool
PyObject_RichCompareBool.argtypes = [W_Object, W_Object, c_int]
PyObject_RichCompareBool.restype = c_int
-PyObject_GetIter = pythonapi.PyObject_GetIter
+PyObject_GetIter = cpyapi.PyObject_GetIter
PyObject_GetIter.argtypes = [W_Object]
PyObject_GetIter.restype = W_Object
-PyIter_Next = pythonapi.PyIter_Next
+PyIter_Next = cpyapi.PyIter_Next
PyIter_Next.argtypes = [W_Object]
PyIter_Next.restype = W_Object
+###########################################################
+# ____________________ Number Protocol ____________________
+
+PyNumber_Add = cpyapi.PyNumber_Add
+PyNumber_Add.argtypes = [W_Object, W_Object]
+PyNumber_Add.restype = W_Object
+
+PyNumber_Subtract = cpyapi.PyNumber_Subtract
+PyNumber_Subtract.argtypes = [W_Object, W_Object]
+PyNumber_Subtract.restype = W_Object
+
+
#############################################################
# ____________________ Sequence Protocol ____________________
-PySequence_Tuple = pythonapi.PySequence_Tuple
+PySequence_Tuple = cpyapi.PySequence_Tuple
PySequence_Tuple.argtypes = [W_Object]
PySequence_Tuple.restype = W_Object
-PySequence_SetItem = pythonapi.PySequence_SetItem
+PySequence_SetItem = cpyapi.PySequence_SetItem
PySequence_SetItem.argtypes = [W_Object, Py_ssize_t, W_Object]
PySequence_SetItem.restype = c_int
@@ -106,11 +114,11 @@
###########################################################
# ____________________ Numeric Objects ____________________
-PyInt_FromLong = pythonapi.PyInt_FromLong
+PyInt_FromLong = cpyapi.PyInt_FromLong
PyInt_FromLong.argtypes = [c_long]
PyInt_FromLong.restype = W_Object
-PyInt_AsLong = pythonapi.PyInt_AsLong
+PyInt_AsLong = cpyapi.PyInt_AsLong
PyInt_AsLong.argtypes = [W_Object]
PyInt_AsLong.restype = c_long
@@ -118,15 +126,15 @@
###################################################
# ____________________ Strings ____________________
-PyString_FromStringAndSize = pythonapi.PyString_FromStringAndSize
+PyString_FromStringAndSize = cpyapi.PyString_FromStringAndSize
PyString_FromStringAndSize.argtypes = [c_char_p, Py_ssize_t]
PyString_FromStringAndSize.restype = W_Object
-PyString_InternInPlace = pythonapi.PyString_InternInPlace
+PyString_InternInPlace = cpyapi.PyString_InternInPlace
PyString_InternInPlace.argtypes = [POINTER(W_Object)]
PyString_InternInPlace.restype = None
-PyString_AsString = pythonapi.PyString_AsString
+PyString_AsString = cpyapi.PyString_AsString
PyString_AsString.argtypes = [W_Object]
PyString_AsString.restype = c_char_p
@@ -134,7 +142,7 @@
##################################################
# ____________________ Tuples ____________________
-PyTuple_New = pythonapi.PyTuple_New
+PyTuple_New = cpyapi.PyTuple_New
PyTuple_New.argtypes = [Py_ssize_t]
PyTuple_New.restype = W_Object
@@ -142,11 +150,11 @@
#################################################
# ____________________ Lists ____________________
-PyList_New = pythonapi.PyList_New
+PyList_New = cpyapi.PyList_New
PyList_New.argtypes = [Py_ssize_t]
PyList_New.restype = W_Object
-PyList_Append = pythonapi.PyList_Append
+PyList_Append = cpyapi.PyList_Append
PyList_Append.argtypes = [W_Object, W_Object]
PyList_Append.restype = c_int
@@ -154,11 +162,11 @@
########################################################
# ____________________ Dictionaries ____________________
-PyDict_New = pythonapi.PyDict_New
+PyDict_New = cpyapi.PyDict_New
PyDict_New.argtypes = []
PyDict_New.restype = W_Object
-PyDict_SetItem = pythonapi.PyDict_SetItem
+PyDict_SetItem = cpyapi.PyDict_SetItem
PyDict_SetItem.argtypes = [W_Object, W_Object, W_Object]
PyDict_SetItem.restype = c_int
@@ -166,23 +174,30 @@
#####################################################
# ____________________ Utilities ____________________
-PyImport_ImportModule = pythonapi.PyImport_ImportModule
+PyImport_ImportModule = cpyapi.PyImport_ImportModule
PyImport_ImportModule.argtypes = [c_char_p]
PyImport_ImportModule.restype = W_Object
+# "RAW" because it comes from pythonapi instead of cpyapi
+# which makes it raise the set exception directly instead
+# of wrapping it into an OperationError
+RAW_PyErr_SetObject = pythonapi.PyErr_SetObject
+RAW_PyErr_SetObject.argtypes = [W_Object, W_Object]
+RAW_PyErr_SetObject.restype = None
+
##############################################################
# ____________________ Built-in functions ____________________
-PyArg_ParseTuple = pythonapi.PyArg_ParseTuple
+PyArg_ParseTuple = cpyapi.PyArg_ParseTuple
PyArg_ParseTuple.restype = c_int
#PyArg_ParseTuple.argtypes = [W_Object, c_char_p, ...]
-PyArg_ParseTupleAndKeywords = pythonapi.PyArg_ParseTupleAndKeywords
+PyArg_ParseTupleAndKeywords = cpyapi.PyArg_ParseTupleAndKeywords
PyArg_ParseTupleAndKeywords.restype = c_int
#PyArg_ParseTupleAndKeywords.argtypes = [W_Object, W_Object,
# c_char_p, POINTER(c_char_p), ...]
-##PyCFunction_NewEx = pythonapi.PyCFunction_NewEx
+##PyCFunction_NewEx = cpyapi.PyCFunction_NewEx
##PyCFunction_NewEx.argtypes = [POINTER(PyMethodDef), W_Object, W_Object]
##PyCFunction_NewEx.restype = W_Object
Added: pypy/dist/pypy/objspace/cpy/ctypes_base.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/objspace/cpy/ctypes_base.py Sun Apr 30 16:00:22 2006
@@ -0,0 +1,50 @@
+"""
+CTypes base classes to support the particularities of the CPyObjSpace
+when it uses the CPython API: the W_Object class and the cpyapi accessor.
+"""
+
+import sys
+from ctypes import *
+from pypy.rpython.rctypes import apyobject
+from pypy.interpreter.error import OperationError
+from pypy.tool.sourcetools import func_with_new_name
+
+
+class W_Object(py_object):
+ """A py_object subclass, representing wrapped objects for the CPyObjSpace.
+ The reason we don't use py_object directly is that if py_object is
+ specified as the restype of a function, the function call unwraps it
+ automatically. With W_Object, however, the function call returns a
+ W_Object instance.
+ """
+ def __repr__(self):
+ return 'W_Object(%r)' % (self.value,)
+
+apyobject.register_py_object_subclass(W_Object)
+
+
+class LevelError(Exception):
+ pass
+
+class CPyAPI(PyDLL):
+ """Class of the singleton 'cpyapi' object, out of which C functions
+ are getattr'd. It returns C function whose exception behavior matches
+ the one required for the CPyObjSpace: exceptions are wrapped in
+ OperationErrors.
+ """
+ class _FuncPtr(PyDLL._FuncPtr):
+ _flags_ = PyDLL._FuncPtr._flags_
+
+ def __call__(*args, **kwds):
+ try:
+ return PyDLL._FuncPtr.__call__(*args, **kwds)
+ except OperationError, e:
+ raise LevelError, "unexpected OperationError: %r" % (e,)
+ except:
+ exc, val, tb = sys.exc_info()
+ raise OperationError(W_Object(exc),
+ W_Object(val),
+ W_Object(tb))
+
+cpyapi = CPyAPI.__new__(CPyAPI)
+cpyapi.__dict__ = pythonapi.__dict__.copy()
Modified: pypy/dist/pypy/objspace/cpy/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/objspace.py (original)
+++ pypy/dist/pypy/objspace/cpy/objspace.py Sun Apr 30 16:00:22 2006
@@ -5,7 +5,7 @@
class CPyObjSpace(baseobjspace.ObjSpace):
- from pypy.objspace.cpy.capi import W_Object
+ from pypy.objspace.cpy.ctypes_base import W_Object
def initialize(self):
self.options.geninterp = True
@@ -16,6 +16,7 @@
self.w_type = W_Object(type)
self.w_Exception = W_Object(Exception)
self.w_StopIteration = W_Object(StopIteration)
+ self.w_TypeError = W_Object(TypeError)
self.wrap_cache = {}
self.rev_wrap_cache = {}
@@ -71,6 +72,9 @@
str_w = staticmethod(PyString_AsString)
iter = staticmethod(PyObject_GetIter)
+ add = staticmethod(PyNumber_Add)
+ sub = staticmethod(PyNumber_Subtract)
+
def call_function(self, w_callable, *args_w):
args_w += (None,)
return PyObject_CallFunctionObjArgs(w_callable, *args_w)
Modified: pypy/dist/pypy/objspace/cpy/test/test_objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/test/test_objspace.py (original)
+++ pypy/dist/pypy/objspace/cpy/test/test_objspace.py Sun Apr 30 16:00:22 2006
@@ -1,4 +1,5 @@
from pypy.objspace.cpy.objspace import CPyObjSpace
+from pypy.tool.pytest.appsupport import raises_w
def test_simple():
space = CPyObjSpace()
@@ -15,3 +16,9 @@
w_time = demo.measuretime(space, 10, CPyObjSpace.W_Object(int))
assert isinstance(w_time, CPyObjSpace.W_Object)
assert isinstance(w_time.value, int)
+
+def test_exception():
+ space = CPyObjSpace()
+ w1 = space.wrap('abc')
+ w2 = space.wrap(11)
+ raises_w(space, space.w_TypeError, space.sub, w1, w2)
Modified: pypy/dist/pypy/objspace/cpy/test/test_wrappable.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/test/test_wrappable.py (original)
+++ pypy/dist/pypy/objspace/cpy/test/test_wrappable.py Sun Apr 30 16:00:22 2006
@@ -1,4 +1,5 @@
from pypy.objspace.cpy.objspace import CPyObjSpace
+from pypy.tool.pytest.appsupport import raises_w
from pypy.interpreter.function import BuiltinFunction
from pypy.interpreter.gateway import interp2app, ObjSpace, W_Root
from pypy.interpreter.argument import Arguments
@@ -29,3 +30,11 @@
w_result = space.call_args(w_entrypoint, args)
result = space.int_w(w_result)
assert result == -21
+
+def test_exception():
+ space = CPyObjSpace()
+ func = interp2app(entrypoint1).__spacebind__(space)
+ bltin = BuiltinFunction(func)
+ w_entrypoint = space.wrap(bltin)
+ w1 = space.wrap('not an int')
+ raises_w(space, space.w_TypeError, space.call_function, w_entrypoint, w1)
Modified: pypy/dist/pypy/objspace/cpy/wrappable.py
==============================================================================
--- pypy/dist/pypy/objspace/cpy/wrappable.py (original)
+++ pypy/dist/pypy/objspace/cpy/wrappable.py Sun Apr 30 16:00:22 2006
@@ -7,6 +7,7 @@
from pypy.annotation.pairtype import pair, pairtype
from pypy.objspace.cpy.capi import *
from pypy.objspace.cpy.objspace import CPyObjSpace
+from pypy.interpreter.error import OperationError
from pypy.interpreter.function import Function
from pypy.interpreter.gateway import BuiltinCode, ObjSpace, W_Root
from pypy.interpreter.gateway import UnwrapSpecRecipe, Signature
@@ -71,16 +72,25 @@
sourcelines = ['def trampoline(%s):' % (', '.join(tramp.inputargs),)]
for line in tramp.wrappings:
sourcelines.append(' ' + line)
- sourcelines.append(' w_result = ___bltin(%s)' % (
+ sourcelines.append(' try:')
+ sourcelines.append(' w_result = ___bltin(%s)' % (
', '.join(tramp.passedargs),))
+ sourcelines.append(' except ___OperationError, e:')
+ sourcelines.append(' ___PyErr_SetObject(e.w_type.value,')
+ sourcelines.append(' e.w_value.value)')
+ sourcelines.append(' return None') # should never be seen
+ sourcelines.append(' #except ___Exception, e:')
+ sourcelines.append(' # raise ___RPythonError(XXX)')
sourcelines.append(' return w_result.value')
sourcelines.append('')
miniglobals = {
- '___space': space,
- '___W_Object': CPyObjSpace.W_Object,
- '___PyInt_AsLong': PyInt_AsLong,
- '___bltin': bltin,
+ '___space': space,
+ '___W_Object': CPyObjSpace.W_Object,
+ '___PyInt_AsLong': PyInt_AsLong,
+ '___bltin': bltin,
+ '___OperationError': OperationError,
+ '___PyErr_SetObject': RAW_PyErr_SetObject,
}
exec py.code.Source('\n'.join(sourcelines)).compile() in miniglobals
More information about the Pypy-commit
mailing list