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