Author: Amaury Forgeot d'Arc <amaur...@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): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit