[pypy-svn] r49038 - in pypy/dist/pypy/module/__builtin__: . test

fijal at codespeak.net fijal at codespeak.net
Sat Nov 24 14:55:24 CET 2007


Author: fijal
Date: Sat Nov 24 14:55:24 2007
New Revision: 49038

Modified:
   pypy/dist/pypy/module/__builtin__/__init__.py
   pypy/dist/pypy/module/__builtin__/descriptor.py
   pypy/dist/pypy/module/__builtin__/test/test_descriptor.py
Log:
Move property to interp-level + port tests from cpython


Modified: pypy/dist/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/dist/pypy/module/__builtin__/__init__.py	Sat Nov 24 14:55:24 2007
@@ -55,8 +55,6 @@
         'vars'          : 'app_inspect.vars',
         'dir'           : 'app_inspect.dir',
 
-        'property'      : 'app_descriptor.property',
-
         'complex'       : 'app_complex.complex',
 
         'buffer'        : 'app_buffer.buffer',
@@ -127,6 +125,8 @@
         'super'         : 'descriptor.W_Super',
         'staticmethod'  : 'descriptor.StaticMethod',
         'classmethod'   : 'descriptor.W_ClassMethod',
+        'property'      : 'descriptor.W_Property',
+
     }
 
     def pick_builtin(self, w_globals):

Modified: pypy/dist/pypy/module/__builtin__/descriptor.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/descriptor.py	(original)
+++ pypy/dist/pypy/module/__builtin__/descriptor.py	Sat Nov 24 14:55:24 2007
@@ -6,6 +6,8 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.callmethod import object_getattribute
 from pypy.interpreter.function import StaticMethod, Method
+from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \
+     descr_set_dict
 
 class W_Super(Wrappable):
     def __init__(self, space, w_selftype, w_starttype, w_type, w_self):
@@ -129,3 +131,89 @@
 If a class method is called for a derived class, the derived class
 object is passed as the implied first argument.""",
 )
+
+class W_Property(Wrappable):
+    def __init__(self, space, w_fget, w_fset, w_fdel, doc):
+        self.w_fget = w_fget
+        self.w_fset = w_fset
+        self.w_fdel = w_fdel
+        self.doc = doc
+        # eh...
+        w = space.wrap
+        self.w_dict = space.newdict()
+        for w_item, w_value in [(w('fget'), w_fget), (w('fset'), w_fset),
+                                (w('fdel'), w_fdel)]:
+            space.setitem(self.w_dict, w_item, w_value)
+
+    def new(space, w_type, w_fget=None, w_fset=None, w_fdel=None, doc=''):
+        return W_Property(space, w_fget, w_fset, w_fdel, doc)
+    new.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root, W_Root, str]
+
+    def get(self, space, w_obj, w_objtype=None):
+        if space.is_w(w_obj, space.w_None):
+            return space.wrap(self)
+        if space.is_w(self.w_fget, space.w_None):
+            raise OperationError(space.w_AttributeError, space.wrap(
+                "unreadable attribute"))
+        return space.call_function(self.w_fget, w_obj)
+    get.unwrap_spec = ['self', ObjSpace, W_Root, W_Root]
+
+    def set(self, space, w_obj, w_value):
+        if space.is_w(self.w_fset, space.w_None):
+            raise OperationError(space.w_AttributeError, space.wrap(
+                "can't set attribute"))
+        space.call_function(self.w_fset, w_obj, w_value)
+        return space.w_None
+    set.unwrap_spec = ['self', ObjSpace, W_Root, W_Root]
+
+    def delete(self, space, w_obj):
+        if space.is_w(self.w_fdel, space.w_None):
+            raise OperationError(space.w_AttributeError, space.wrap(
+                "can't delete attribute"))
+        space.call_function(self.w_fdel, w_obj)
+        return space.w_None
+    delete.unwrap_spec = ['self', ObjSpace, W_Root]
+
+    def getattribute(self, space, attr):
+        if attr == '__doc__':
+            return space.wrap(self.doc)
+        # shortcuts
+        elif attr == 'fget':
+            return self.w_fget
+        elif attr == 'fset':
+            return self.w_fset
+        elif attr == 'fdel':
+            return self.w_fdel
+        return space.call_function(object_getattribute(space),
+                                   space.wrap(self), space.wrap(attr))
+    getattribute.unwrap_spec = ['self', ObjSpace, str]
+
+    def setattr(self, space, attr, w_value):
+        raise OperationError(space.w_TypeError, space.wrap(
+            "Trying to set readonly attribute %s on property" % (attr,)))
+    setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
+
+    def descr_get_dict(space, self):
+        return self.w_dict
+
+W_Property.typedef = TypeDef(
+    'property',
+    __doc__ = '''property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
+
+fget is a function to be used for getting an attribute value, and likewise
+fset is a function for setting, and fdel a function for deleting, an
+attribute.  Typical use is to define a managed attribute x:
+class C(object):
+    def getx(self): return self.__x
+    def setx(self, value): self.__x = value
+    def delx(self): del self.__x
+    x = property(getx, setx, delx, "I am the 'x' property.")''',
+    __new__ = interp2app(W_Property.new.im_func),
+    __get__ = interp2app(W_Property.get),
+    __set__ = interp2app(W_Property.set),
+    __delete__ = interp2app(W_Property.delete),
+    __getattribute__ = interp2app(W_Property.getattribute),
+    __dict__ = GetSetProperty(W_Property.descr_get_dict),
+    __setattr__ = interp2app(W_Property.setattr),
+)
+

Modified: pypy/dist/pypy/module/__builtin__/test/test_descriptor.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/test/test_descriptor.py	(original)
+++ pypy/dist/pypy/module/__builtin__/test/test_descriptor.py	Sat Nov 24 14:55:24 2007
@@ -224,3 +224,71 @@
 
         raises(TypeError, "classmethod(1).__get__(1)")
 
+    def test_property_docstring(self):
+        assert property.__doc__.startswith('property')
+
+        class A:
+            pass
+
+        A.x = property(lambda x: x, lambda x, y: x, lambda x:x, 'xxx')
+        assert A.x.__doc__ == 'xxx'
+
+    def test_property(self):
+        class C(object):
+            def getx(self):
+                return self.__x
+            def setx(self, value):
+                self.__x = value
+            def delx(self):
+                del self.__x
+            x = property(getx, setx, delx, doc="I'm the x property.")
+        a = C()
+        assert not hasattr(a, "x")
+        a.x = 42
+        assert a._C__x == 42
+        assert a.x == 42
+        del a.x
+        assert not hasattr(a, "x")
+        assert not hasattr(a, "_C__x")
+        C.x.__set__(a, 100)
+        assert C.x.__get__(a) == 100
+        C.x.__delete__(a)
+        assert not hasattr(a, "x")
+
+        raw = C.__dict__['x']
+        assert isinstance(raw, property)
+
+        attrs = dir(raw)
+        assert "__doc__" in attrs
+        assert "fget" in attrs
+        assert "fset" in attrs
+        assert "fdel" in attrs
+
+        assert raw.__doc__ == "I'm the x property."
+        assert raw.fget is C.__dict__['getx']
+        assert raw.fset is C.__dict__['setx']
+        assert raw.fdel is C.__dict__['delx']
+
+        for attr in "__doc__", "fget", "fset", "fdel":
+            try:
+                setattr(raw, attr, 42)
+            except TypeError, msg:
+                if str(msg).find('readonly') < 0:
+                    raise Exception("when setting readonly attr %r on a "
+                                    "property, got unexpected TypeError "
+                                    "msg %r" % (attr, str(msg)))
+            else:
+                raise Exception("expected TypeError from trying to set "
+                                "readonly %r attr on a property" % attr)
+
+        class D(object):
+            __getitem__ = property(lambda s: 1/0)
+
+        d = D()
+        try:
+            for i in d:
+                str(i)
+        except ZeroDivisionError:
+            pass
+        else:
+            raise Exception, "expected ZeroDivisionError from bad property"



More information about the Pypy-commit mailing list