[pypy-svn] r75069 - in pypy/trunk/pypy/module/cpyext: . test
Maciej Fijalkowski
fijall at gmail.com
Thu Jun 3 21:07:48 CEST 2010
On Thu, Jun 3, 2010 at 11:57 AM, <afa at codespeak.net> wrote:
> Author: afa
> Date: Thu Jun 3 19:57:09 2010
> New Revision: 75069
>
> Added:
> pypy/trunk/pypy/module/cpyext/test/test_translate.py
> Modified:
> pypy/trunk/pypy/module/cpyext/api.py
> pypy/trunk/pypy/module/cpyext/slotdefs.py
> pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
> pypy/trunk/pypy/module/cpyext/typeobject.py
> Log:
> Various hacks to correctly expose different tp_function slots for different builtin types.
> For now only tp_setattro is correctly set,
> more refactoring will be needed, but this code *works*.
>
> llhelper() is really hard to use.
There is a reason why it was not meant to be used for translations.
if WRAPPER is None:
> wrapper = None
> @@ -201,23 +240,22 @@
> wrapper = wrap_getattr
>
> function = globals().get(FUNCTION, None)
> - slotname = ("c_" + SLOT).split(".")
> assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
> if FLAGS:
> if wrapper is Ellipsis:
> + @func_renamer(WRAPPER)
> def wrapper(space, w_self, w_args, func, w_kwds):
> raise NotImplementedError("Wrapper for slot " + NAME)
> - wrapper = func_with_new_name(wrapper, WRAPPER)
> wrapper1 = None
> wrapper2 = wrapper
> else:
> if wrapper is Ellipsis:
> + @func_renamer(WRAPPER)
> def wrapper(space, w_self, w_args, func):
> raise NotImplementedError("Wrapper for slot " + NAME)
> - wrapper = func_with_new_name(wrapper, WRAPPER)
> wrapper1 = wrapper
> wrapper2 = None
> - return (NAME, slotname, function, wrapper1, wrapper2, DOC)
> + return TypeSlot(NAME, SLOT, function, wrapper1, wrapper2, DOC)
>
> def TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC):
> return FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, 0)
> @@ -470,7 +508,12 @@
> for regex, repl in slotdef_replacements:
> slotdefs_str = re.sub(regex, repl, slotdefs_str)
>
> -slotdefs = unrolling_iterable(eval(slotdefs_str))
> +slotdefs_for_tp_slots = unrolling_iterable(
> + [(x.method_name, x.slot_name, x.slot_names, x.slot_func)
> + for x in eval(slotdefs_str)])
> +slotdefs_for_wrappers = unrolling_iterable(
> + [(x.method_name, x.slot_names, x.wrapper_func, x.wrapper_func_kwds, x.doc)
> + for x in eval(slotdefs_str)])
>
> if __name__ == "__main__":
> print slotdefs_str
>
> Added: pypy/trunk/pypy/module/cpyext/test/test_translate.py
> ==============================================================================
> --- (empty file)
> +++ pypy/trunk/pypy/module/cpyext/test/test_translate.py Thu Jun 3 19:57:09 2010
> @@ -0,0 +1,71 @@
> +from pypy.translator.c.test.test_genc import compile
> +import pypy.module.cpyext.api
> +from pypy.module.cpyext.api import cpython_api
> +from pypy.rpython.annlowlevel import llhelper
> +from pypy.rpython.lltypesystem import lltype
> +from pypy.rlib.objectmodel import specialize
> +from pypy.rlib.nonconst import NonConstant
> +
> +def test_llhelper(monkeypatch):
> + """Show how to get function pointers used in type slots"""
> + FT = lltype.FuncType([], lltype.Signed)
> + FTPTR = lltype.Ptr(FT)
> +
> + def make_wrapper(space, func):
> + def wrapper():
> + return func(space)
> + return wrapper
> + monkeypatch.setattr(pypy.module.cpyext.api, 'make_wrapper', make_wrapper)
> +
> + @specialize.memo()
> + def get_tp_function(space, typedef):
> + @cpython_api([], lltype.Signed, error=-1, external=False)
> + def slot_tp_function(space):
> + return typedef.value
> +
> + api_func = slot_tp_function.api_func
> + return lambda: llhelper(api_func.functype, api_func.get_wrapper(space))
> +
> + class Space:
> + _cache = {}
> + @specialize.memo()
> + def fromcache(self, key):
> + try:
> + return self._cache[key]
> + except KeyError:
> + result = self._cache[key] = self.build(key)
> + return result
> + def _freeze_(self):
> + return True
> + class TypeDef:
> + def __init__(self, value):
> + self.value = value
> + def _freeze_(self):
> + return True
> + class W_Type:
> + def __init__(self, typedef):
> + self.instancetypedef = typedef
> + def _freeze(self):
> + try:
> + del self.funcptr
> + except AttributeError:
> + pass
> + return False
> +
> + w_type1 = W_Type(TypeDef(123))
> + w_type2 = W_Type(TypeDef(456))
> + space = Space()
> +
> + def run(x):
> + if x:
> + w_type = w_type1
> + else:
> + w_type = w_type2
> + typedef = w_type.instancetypedef
> + w_type.funcptr = get_tp_function(space, typedef)()
> + return w_type.funcptr()
> +
> + fn = compile(run, [bool])
> + assert fn(True) == 123
> + assert fn(False) == 456
> +
>
> Modified: pypy/trunk/pypy/module/cpyext/test/test_typeobject.py
> ==============================================================================
> --- pypy/trunk/pypy/module/cpyext/test/test_typeobject.py (original)
> +++ pypy/trunk/pypy/module/cpyext/test/test_typeobject.py Thu Jun 3 19:57:09 2010
> @@ -240,11 +240,17 @@
> PyErr_SetString(PyExc_ValueError, "missing tp_setattro");
> return NULL;
> }
> + if (args->ob_type->tp_setattro ==
> + args->ob_type->tp_base->tp_setattro)
> + {
> + PyErr_SetString(PyExc_ValueError, "recursive tp_setattro");
> + return NULL;
> + }
> Py_RETURN_TRUE;
> '''
> )
> ])
> - assert module.test_type(None)
> + assert module.test_type(type(None))
>
> def test_nb_int(self):
> module = self.import_extension('foo', [
>
> Modified: pypy/trunk/pypy/module/cpyext/typeobject.py
> ==============================================================================
> --- pypy/trunk/pypy/module/cpyext/typeobject.py (original)
> +++ pypy/trunk/pypy/module/cpyext/typeobject.py Thu Jun 3 19:57:09 2010
> @@ -25,7 +25,8 @@
> from pypy.module.cpyext.typeobjectdefs import (
> PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
> PyNumberMethods)
> -from pypy.module.cpyext.slotdefs import slotdefs
> +from pypy.module.cpyext.slotdefs import (
> + slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
> from pypy.interpreter.error import OperationError
> from pypy.rlib.rstring import rsplit
> from pypy.rlib.objectmodel import specialize
> @@ -102,48 +103,60 @@
>
> def update_all_slots(space, w_type, pto):
> # XXX fill slots in pto
> - for method_name, slot_name, slot_func, _, _, _ in slotdefs:
> +
> + typedef = w_type.instancetypedef
> + for method_name, slot_name, slot_names, slot_func in slotdefs_for_tp_slots:
> w_descr = w_type.lookup(method_name)
> if w_descr is None:
> # XXX special case iternext
> continue
> - if slot_func is None:
> +
> + slot_func_helper = None
> +
> + if slot_func is None and typedef is not None:
> + get_slot = get_slot_tp_function(space, typedef, slot_name)
> + if get_slot:
> + slot_func_helper = get_slot()
> + elif slot_func:
> + slot_func_helper = llhelper(slot_func.api_func.functype,
> + slot_func.api_func.get_wrapper(space))
> +
> + if slot_func_helper is None:
> if WARN_ABOUT_MISSING_SLOT_FUNCTIONS:
> os.write(2, method_name + " defined by the type but no slot function defined!\n")
> continue
> - slot_func_helper = llhelper(slot_func.api_func.functype,
> - slot_func.api_func.get_wrapper(space))
> +
> # XXX special case wrapper-functions and use a "specific" slot func
>
> - if len(slot_name) == 1:
> - setattr(pto, slot_name[0], slot_func_helper)
> + if len(slot_names) == 1:
> + setattr(pto, slot_names[0], slot_func_helper)
> else:
> - assert len(slot_name) == 2
> - struct = getattr(pto, slot_name[0])
> + assert len(slot_names) == 2
> + struct = getattr(pto, slot_names[0])
> if not struct:
> - if slot_name[0] == 'c_tp_as_number':
> + if slot_names[0] == 'c_tp_as_number':
> STRUCT_TYPE = PyNumberMethods
> else:
> raise AssertionError(
> - "Structure not allocated: %s" % (slot_name[0],))
> + "Structure not allocated: %s" % (slot_names[0],))
> struct = lltype.malloc(STRUCT_TYPE, flavor='raw', zero=True)
> - setattr(pto, slot_name[0], struct)
> + setattr(pto, slot_names[0], struct)
>
> - setattr(struct, slot_name[1], slot_func_helper)
> + setattr(struct, slot_names[1], slot_func_helper)
>
> def add_operators(space, dict_w, pto):
> # XXX support PyObject_HashNotImplemented
> - for method_name, slot_name, _, wrapper_func, wrapper_func_kwds, doc in slotdefs:
> + for method_name, slot_names, wrapper_func, wrapper_func_kwds, doc in slotdefs_for_wrappers:
> if method_name in dict_w:
> continue
> - if len(slot_name) == 1:
> - func = getattr(pto, slot_name[0])
> + if len(slot_names) == 1:
> + func = getattr(pto, slot_names[0])
> else:
> - assert len(slot_name) == 2
> - struct = getattr(pto, slot_name[0])
> + assert len(slot_names) == 2
> + struct = getattr(pto, slot_names[0])
> if not struct:
> continue
> - func = getattr(struct, slot_name[1])
> + func = getattr(struct, slot_names[1])
> func_voidp = rffi.cast(rffi.VOIDP_real, func)
> if not func:
> continue
> @@ -494,6 +507,8 @@
> # XXX check for correct GC flags!
> if not pto.c_tp_free:
> pto.c_tp_free = base.c_tp_free
> + if not pto.c_tp_setattro:
> + pto.c_tp_setattro = base.c_tp_setattro
> finally:
> Py_DecRef(space, base_pyo)
>
> @@ -558,6 +573,12 @@
> for w_base in space.fixedview(from_ref(space, pto.c_tp_bases)):
> inherit_slots(space, pto, w_base)
>
> + if not pto.c_tp_setattro:
> + from pypy.module.cpyext.object import PyObject_GenericSetAttr
> + pto.c_tp_setattro = llhelper(
> + PyObject_GenericSetAttr.api_func.functype,
> + PyObject_GenericSetAttr.api_func.get_wrapper(space))
> +
> @cpython_api([PyTypeObjectPtr, PyTypeObjectPtr], rffi.INT_real, error=CANNOT_FAIL)
> def PyType_IsSubtype(space, a, b):
> """Return true if a is a subtype of b.
> _______________________________________________
> pypy-svn mailing list
> pypy-svn at codespeak.net
> http://codespeak.net/mailman/listinfo/pypy-svn
>
More information about the Pypy-commit
mailing list