[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