[pypy-commit] pypy py3.3: Implement abstract methods and properties: they simply fetch the

amauryfa noreply at buildbot.pypy.org
Tue Dec 30 22:27:16 CET 2014


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3.3
Changeset: r75173:f215d396c1f4
Date: 2014-12-30 22:25 +0100
http://bitbucket.org/pypy/pypy/changeset/f215d396c1f4/

Log:	Implement abstract methods and properties: they simply fetch the
	__isabstractmethod__ property from the underlying callables.

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1139,6 +1139,15 @@
         # Equivalent to 'obj.__class__'.
         return self.type(w_obj)
 
+    def isabstractmethod_w(self, w_obj):
+        try:
+            w_result = self.getattr(w_obj, self.wrap("__isabstractmethod__"))
+        except OperationError, e:
+            if e.match(self, self.w_AttributeError):
+                return False
+            raise
+        return self.bool_w(self.nonzero(w_result))
+
     # CPython rules allows subclasses of BaseExceptions to be exceptions.
     # This is slightly less general than the case above, so we prefix
     # it with exception_
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -588,6 +588,9 @@
         instance.__init__(w_function)
         return space.wrap(instance)
 
+    def descr_isabstract(self, space):
+        return space.newbool(space.isabstractmethod_w(self.w_function))
+
 
 class ClassMethod(W_Root):
     """The classmethod objects."""
@@ -606,6 +609,10 @@
         instance.__init__(w_function)
         return space.wrap(instance)
 
+    def descr_isabstract(self, space):
+        return space.newbool(space.isabstractmethod_w(self.w_function))
+
+
 class FunctionWithFixedCode(Function):
     can_change_code = False
 
diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py
--- a/pypy/interpreter/test/test_objspace.py
+++ b/pypy/interpreter/test/test_objspace.py
@@ -352,6 +352,37 @@
                         else:
                             assert w_res is space.w_False
 
+    def test_isabstract(self, space):
+        w_A = space.appexec([], """():
+            class A:
+               def f(): pass
+               f.__isabstractmethod__ = True
+
+               def g(): pass
+               g.__isabstractmethod__ = True
+               g = classmethod(g)
+
+               def h(): pass
+               h.__isabstractmethod__ = True
+               h = staticmethod(h)
+            return A""")
+        w_B = space.appexec([], """():
+            class B:
+               def f(): pass
+
+               @classmethod
+               def g(): pass
+
+               @staticmethod
+               def h(): pass
+            return B""")
+        assert space.isabstractmethod_w(space.getattr(w_A, space.wrap('f')))
+        assert space.isabstractmethod_w(space.getattr(w_A, space.wrap('g')))
+        assert space.isabstractmethod_w(space.getattr(w_A, space.wrap('h')))
+        assert not space.isabstractmethod_w(space.getattr(w_B, space.wrap('f')))
+        assert not space.isabstractmethod_w(space.getattr(w_B, space.wrap('g')))
+        assert not space.isabstractmethod_w(space.getattr(w_B, space.wrap('h')))
+
 class TestModuleMinimal: 
     def test_sys_exists(self):
         assert self.space.sys
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -882,6 +882,7 @@
     __get__ = interp2app(StaticMethod.descr_staticmethod_get),
     __new__ = interp2app(StaticMethod.descr_staticmethod__new__.im_func),
     __func__= interp_attrproperty_w('w_function', cls=StaticMethod),
+    __isabstractmethod__ = GetSetProperty(StaticMethod.descr_isabstract),
     )
 
 ClassMethod.typedef = TypeDef(
@@ -889,6 +890,7 @@
     __new__ = interp2app(ClassMethod.descr_classmethod__new__.im_func),
     __get__ = interp2app(ClassMethod.descr_classmethod_get),
     __func__= interp_attrproperty_w('w_function', cls=ClassMethod),
+    __isabstractmethod__ = GetSetProperty(ClassMethod.descr_isabstract),
     __doc__ = """classmethod(function) -> class method
 
 Convert a function to be a class method.
diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -2,8 +2,8 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.function import StaticMethod, ClassMethod
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
-from pypy.interpreter.typedef import (TypeDef, interp_attrproperty_w,
-    generic_new_descr)
+from pypy.interpreter.typedef import (
+    TypeDef, interp_attrproperty_w, generic_new_descr, GetSetProperty)
 from pypy.objspace.descroperation import object_getattribute
 
 
@@ -199,6 +199,11 @@
         w_type = self.getclass(space)
         return space.call_function(w_type, w_getter, w_setter, w_deleter, w_doc)
 
+    def descr_isabstract(self, space):
+        return space.newbool(space.isabstractmethod_w(self.w_fget) or
+                             space.isabstractmethod_w(self.w_fset) or
+                             space.isabstractmethod_w(self.w_fdel))
+
 W_Property.typedef = TypeDef(
     'property',
     __doc__ = '''property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
@@ -216,6 +221,7 @@
     __get__ = interp2app(W_Property.get),
     __set__ = interp2app(W_Property.set),
     __delete__ = interp2app(W_Property.delete),
+    __isabstractmethod__ = GetSetProperty(W_Property.descr_isabstract),
     fdel = interp_attrproperty_w('w_fdel', W_Property),
     fget = interp_attrproperty_w('w_fget', W_Property),
     fset = interp_attrproperty_w('w_fset', W_Property),
diff --git a/pypy/module/__builtin__/test/test_descriptor.py b/pypy/module/__builtin__/test/test_descriptor.py
--- a/pypy/module/__builtin__/test/test_descriptor.py
+++ b/pypy/module/__builtin__/test/test_descriptor.py
@@ -401,6 +401,12 @@
         del x.x
         assert x.z == 42
 
+    def test_abstract_property(self):
+        def foo(self): pass
+        foo.__isabstractmethod__ = True
+        foo = property(foo)
+        assert foo.__isabstractmethod__ is True
+
     def test___class___variable(self):
         class X:
             def f(self):


More information about the pypy-commit mailing list