Author: Amaury Forgeot d'Arc <[email protected]>
Branch: py3k
Changeset: r59193:6cb72bc5a0b9
Date: 2012-12-01 23:21 +0100
http://bitbucket.org/pypy/pypy/changeset/6cb72bc5a0b9/

Log:    cpyext: implement PyInstanceMethod type and functions.

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -60,6 +60,7 @@
 import pypy.module.cpyext.weakrefobject
 import pypy.module.cpyext.funcobject
 import pypy.module.cpyext.frameobject
+import pypy.module.cpyext.classobject
 import pypy.module.cpyext.pypyintf
 import pypy.module.cpyext.exception
 import pypy.module.cpyext.memoryobject
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -434,7 +434,8 @@
         'Slice': 'space.gettypeobject(W_SliceObject.typedef)',
         'StaticMethod': 'space.gettypeobject(StaticMethod.typedef)',
         'CFunction': 
'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
-        'WrapperDescr': 
'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)'
+        'WrapperDescr': 
'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)',
+        'InstanceMethod': 
'space.gettypeobject(cpyext.classobject.InstanceMethod.typedef)',
         }.items():
         GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
 
diff --git a/pypy/module/cpyext/classobject.py 
b/pypy/module/cpyext/classobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/classobject.py
@@ -0,0 +1,74 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import cpython_api, CANNOT_FAIL
+from pypy.module.cpyext.pyobject import PyObject
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.interpreter.function import Method
+from pypy.interpreter.typedef import TypeDef, interp_attrproperty_w
+from pypy.interpreter.gateway import interp2app
+
+
+class InstanceMethod(Wrappable):
+    """The instancemethod facade."""
+    _immutable_fields_ = ['w_function']
+
+    def __init__(self, w_function):
+        self.w_function = w_function
+
+    @staticmethod
+    def descr_new(space, w_subtype, w_function):
+        # instancemethod is not subclassable
+        return space.wrap(InstanceMethod(w_function))
+
+    def descr_get(self, space, w_obj, w_klass=None):
+        if space.is_none(w_obj):
+            return self.w_function
+        return space.wrap(Method(space, self.w_function, w_obj))
+
+    def descr_call(self, space, __args__):
+        return space.call_args(self.w_function, __args__)
+
+    def descr_repr(self, space):
+        name = space.str_w(
+            space.getattr(self.w_function, space.wrap('__name__')))
+        return self.getrepr(space, '<instancemethod %s>' % (name,))
+
+InstanceMethod.typedef = TypeDef("instancemethod",
+    __new__ = interp2app(InstanceMethod.descr_new),
+    __call__ = interp2app(InstanceMethod.descr_call,
+                          descrmismatch='__call__'),
+    __get__ = interp2app(InstanceMethod.descr_get),
+    __repr__ = interp2app(InstanceMethod.descr_repr,
+                          descrmismatch='__repr__'),
+    __func__= interp_attrproperty_w('w_function', cls=InstanceMethod),
+)
+InstanceMethod.typedef.acceptable_as_base_class = False
+
+@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyInstanceMethod_Check(space, w_o):
+    """Return true if o is an instance method object (has type
+    PyInstanceMethod_Type).  The parameter must not be NULL."""
+    return space.isinstance_w(w_o,
+                              space.gettypeobject(InstanceMethod.typedef))
+    
+
+@cpython_api([PyObject], PyObject)
+def PyInstanceMethod_New(space, w_func):
+    """Return a new instance method object, with func being any
+    callable object func is the function that will be called when the
+    instance method is called."""
+    return space.wrap(InstanceMethod(w_func))
+    
+
+@cpython_api([PyObject], PyObject)
+def PyInstanceMethod_Function(space, w_im):
+    """Return the function object associated with the instance method im."""
+    return space.interp_w(InstanceMethod, w_im).w_function
+    
+
+@cpython_api([PyObject], PyObject)
+def PyInstanceMethod_GET_FUNCTION(space, w_im):
+    """Macro version of PyInstanceMethod_Function() which avoids error
+    checking."""
+    return space.interp_w(InstanceMethod, w_im).w_function
+    
+
diff --git a/pypy/module/cpyext/test/test_classobject.py 
b/pypy/module/cpyext/test/test_classobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_classobject.py
@@ -0,0 +1,29 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestInstanceMethod(AppTestCpythonExtensionBase):
+    def test_instancemethod(self):
+        module = self.import_extension('foo', [
+            ("instancemethod", "METH_O",
+             """
+                 return PyInstanceMethod_New(args);
+             """)])
+
+        def testfunction(self):
+            """some doc"""
+            return self
+
+        class InstanceMethod:
+            id = module.instancemethod(id)
+            testmethod = module.instancemethod(testfunction)
+
+        inst = InstanceMethod()
+        assert id(inst) == inst.id()
+        assert inst.testmethod() is inst
+        assert InstanceMethod.testmethod(inst) is inst
+        assert InstanceMethod.__dict__['testmethod'](inst) is inst
+        assert inst.testmethod.__doc__ == testfunction.__doc__
+        assert InstanceMethod.testmethod.__doc__ == testfunction.__doc__
+
+        InstanceMethod.testmethod.attribute = "test"
+        assert testfunction.attribute == "test"
+        raises(AttributeError, setattr, inst.testmethod, "attribute", "test")
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to