[pypy-svn] r48858 - in pypy/dist/pypy: module/__builtin__ module/__builtin__/test objspace/std

fijal at codespeak.net fijal at codespeak.net
Tue Nov 20 18:47:30 CET 2007


Author: fijal
Date: Tue Nov 20 18:47:29 2007
New Revision: 48858

Added:
   pypy/dist/pypy/module/__builtin__/descriptor.py   (contents, props changed)
Modified:
   pypy/dist/pypy/module/__builtin__/__init__.py
   pypy/dist/pypy/module/__builtin__/app_descriptor.py
   pypy/dist/pypy/module/__builtin__/test/test_descriptor.py
   pypy/dist/pypy/objspace/std/objspace.py
   pypy/dist/pypy/objspace/std/typeobject.py
Log:
(anto, fijal) Move super() from app-level to interp-level


Modified: pypy/dist/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/__init__.py	(original)
+++ pypy/dist/pypy/module/__builtin__/__init__.py	Tue Nov 20 18:47:29 2007
@@ -58,7 +58,6 @@
         'property'      : 'app_descriptor.property',
         'staticmethod'  : 'app_descriptor.staticmethod',
         'classmethod'   : 'app_descriptor.classmethod',
-        'super'         : 'app_descriptor.super',
 
         'complex'       : 'app_complex.complex',
 
@@ -127,6 +126,7 @@
         'xrange'        : 'functional.W_XRange',
         'all'           : 'functional.all',
         'any'           : 'functional.any',
+        'super'         : 'descriptor.W_Super',
     }
 
     def pick_builtin(self, w_globals):

Modified: pypy/dist/pypy/module/__builtin__/app_descriptor.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/app_descriptor.py	(original)
+++ pypy/dist/pypy/module/__builtin__/app_descriptor.py	Tue Nov 20 18:47:29 2007
@@ -142,62 +142,3 @@
         self.fdel(obj)
 
 docstring.capture(property, 'slot__doc__')
-
-
-# super is a modified version from Guido's tutorial
-#     http://www.python.org/2.2.3/descrintro.html
-# it exposes the same special attributes as CPython's.
-class super(object):
-    """super(type) -> unbound super object
-super(type, obj) -> bound super object; requires isinstance(obj, type)
-super(type, type2) -> bound super object; requires issubclass(type2, type)
-
-Typical use to call a cooperative superclass method:
-
-class C(B):
-    def meth(self, arg):
-        super(C, self).meth(arg)"""
-    __slots__ = ['__thisclass__', '__self__', '__self_class__']
-    def __init__(self, typ, obj=None):
-        if obj is None:
-            objcls = None        # unbound super object
-        elif _issubtype(type(obj), type) and _issubtype(obj, typ):
-            objcls = obj         # special case for class methods
-        elif _issubtype(type(obj), typ):
-            objcls = type(obj)   # normal case
-        else:
-            objcls = getattr(obj, '__class__', type(obj))
-            if not _issubtype(objcls, typ):
-                raise TypeError, ("super(type, obj): "
-                                  "obj must be an instance or subtype of type")
-        self.__thisclass__ = typ
-        self.__self__ = obj
-        self.__self_class__ = objcls
-    def __get__(self, obj, type=None):
-        if obj is None or super.__self__.__get__(self) is not None:
-            return self
-        else:
-            return self.__class__(super.__thisclass__.__get__(self), obj)
-    def __getattribute__(self, attr):
-        _self_class_ = super.__self_class__.__get__(self)
-        if (attr != '__class__' # we want super().__class__ to be the real class
-              and _self_class_ is not None): # no magic for unbound type objects
-            _thisclass_ = super.__thisclass__.__get__(self)
-            mro = iter(_self_class_.__mro__)
-            for cls in mro:
-                if cls is _thisclass_:
-                    break
-            # Note: mro is an iterator, so the second loop
-            # picks up where the first one left off!
-            for cls in mro:
-                try:                
-                    x = cls.__dict__[attr]
-                except KeyError:
-                    continue
-                if hasattr(x, '__get__'):
-                    _self_ = super.__self__.__get__(self)
-                    if _self_ is _self_class_:
-                        _self_ = None   # performs an unbound __get__
-                    x = x.__get__(_self_, _self_class_)
-                return x
-        return object.__getattribute__(self, attr)     # fall-back

Added: pypy/dist/pypy/module/__builtin__/descriptor.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/__builtin__/descriptor.py	Tue Nov 20 18:47:29 2007
@@ -0,0 +1,91 @@
+
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
+from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable, \
+     Arguments
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.error import OperationError
+# XXX
+from pypy.interpreter.callmethod import object_getattribute
+
+class W_Super(Wrappable):
+    def __init__(self, space, w_selftype, w_starttype, w_type, w_self):
+        self.w_selftype = w_selftype
+        self.w_starttype = w_starttype
+        self.w_type = w_type
+        self.w_self = w_self
+
+    def get(self, space, w_obj, w_type=None):
+        w = space.wrap
+        if self.w_self is None or space.is_w(w_obj, space.w_None):
+            return w(self)
+        else:
+            return space.call(self.w_selftype, space.newlist([
+                self.w_starttype, w_obj]))
+    get.unwrap_spec = ['self', ObjSpace, W_Root, W_Root]
+
+    def getattribute(self, space, name):
+        w = space.wrap
+        if name == '__class__':
+            return self.w_selftype
+        if self.w_type is None:
+            return space.call(object_getattribute(space),
+                              space.newlist([w(self), w(name)]))
+            
+        w_value = space.lookup_in_type_starting_at(self.w_type,
+                                                   self.w_starttype,
+                                                   name)
+        if w_value is None:
+            return space.getattr(w(self), w(name))
+
+        try:
+            w_get = space.getattr(w_value, space.wrap('__get__'))
+            if space.is_w(self.w_self, self.w_type):
+                w_self = None
+            else:
+                w_self = self.w_self
+        except OperationError, o:
+            if not o.match(space, space.w_AttributeError):
+                raise
+            return w_value
+        return space.call(w_get, space.newlist([w_self, self.w_type]))
+    getattribute.unwrap_spec = ['self', ObjSpace, str]
+
+def descr_new_super(space, w_self, w_starttype, w_obj_or_type=None):
+    if space.is_w(w_obj_or_type, space.w_None):
+        w_type = None  # unbound super object
+    else:
+        w_objtype = space.type(w_obj_or_type)
+        if space.is_true(space.issubtype(w_objtype, space.w_type)) and \
+            space.is_true(space.issubtype(w_obj_or_type, w_starttype)):
+            w_type = w_obj_or_type # special case for class methods
+        elif space.is_true(space.issubtype(w_objtype, w_starttype)):
+            w_type = w_objtype # normal case
+        else:
+            try:
+                w_type = space.getattr(w_obj_or_type, space.wrap('__class__'))
+            except OperationError, o:
+                if not o.match(space, space.w_AttributeError):
+                    raise
+                w_type = w_objtype
+            if not space.is_true(space.issubtype(w_type, w_starttype)):
+                raise OperationError(space.w_TypeError,
+                    space.wrap("super(type, obj): "
+                               "obj must be an instance or subtype of type"))
+    return space.wrap(W_Super(space, w_self, w_starttype, w_type, w_obj_or_type))
+descr_new_super.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root]
+
+W_Super.typedef = TypeDef(
+    'super',
+    __new__          = interp2app(descr_new_super),
+    __getattribute__ = interp2app(W_Super.getattribute),
+    __get__          = interp2app(W_Super.get),
+    __doc__          =     """super(type) -> unbound super object
+super(type, obj) -> bound super object; requires isinstance(obj, type)
+super(type, type2) -> bound super object; requires issubclass(type2, type)
+
+Typical use to call a cooperative superclass method:
+
+class C(B):
+    def meth(self, arg):
+        super(C, self).meth(arg)"""
+)

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	Tue Nov 20 18:47:29 2007
@@ -87,3 +87,109 @@
         except TypeError, e:
             message = e.args[0]
             assert message.startswith('super(type, obj): obj must be an instance or subtype of type')
+
+    def test_super_various(self):
+        
+        class A(object):
+            def meth(self, a):
+                return "A(%r)" % a
+
+        class B(A):
+            def __init__(self):
+                self.__super = super(B, self)
+            def meth(self, a):
+                return "B(%r)" % a + self.__super.meth(a)
+
+        assert B().meth(2) == "B(2)A(2)"
+
+        class C(A):
+            def meth(self, a):
+                return "C(%r)" % a + self.__super.meth(a)
+        C._C__super = super(C)
+
+        assert C().meth(3) == "C(3)A(3)"
+
+        class D(C, B):
+            def meth(self, a):
+                return "D(%r)" % a + super(D, self).meth(a)
+
+        assert D().meth(4) == "D(4)C(4)B(4)A(4)"
+
+        # subclasses
+        class mysuper(super):
+            def __init__(self, *args):
+                return super(mysuper, self).__init__(*args)
+
+        class E(D):
+            def meth(self, a):
+                return "E(%r)" % a + mysuper(E, self).meth(a)
+
+        assert E().meth(5) == "E(5)D(5)C(5)B(5)A(5)"
+
+        class F(E):
+            def meth(self, a):
+                s = self.__super # == mysuper(F, self)
+                return "F(%r)[%s]" % (a, s.__class__.__name__) + s.meth(a)
+        F._F__super = mysuper(F)
+
+        assert F().meth(6) == "F(6)[mysuper]E(6)D(6)C(6)B(6)A(6)"
+
+
+    def test_super_lookup(self):
+        class DDbase(object):
+            def getx(self):
+                return 42
+            x = property(getx)
+
+        class DDsub(DDbase):
+            def getx(self):
+                return "hello"
+            x = property(getx)
+
+        dd = DDsub()
+        assert dd.x == "hello"
+        assert super(DDsub, dd).x == 42
+
+    def test_super_lookup2(self):
+
+        class Base(object):
+            aProp = property(lambda self: "foo")
+
+        class Sub(Base):
+            def test(klass):
+                return super(Sub,klass).aProp
+            test = classmethod(test)
+
+        assert Sub.test() is Base.aProp
+
+    def test_proxy_super(self):
+        class Proxy(object):
+            def __init__(self, obj):
+                self.__obj = obj
+            def __getattribute__(self, name):
+                if name.startswith("_Proxy__"):
+                    return object.__getattribute__(self, name)
+                else:
+                    return getattr(self.__obj, name)
+
+        class B(object):
+            def f(self):
+                return "B.f"
+
+        class C(B):
+            def f(self):
+                return super(C, self).f() + "->C.f"
+
+        obj = C()
+        p = Proxy(obj)
+        assert C.__dict__["f"](p) == "B.f->C.f"
+
+    def test_super_errors(self):
+        class C:
+            pass
+        class D(C):
+            pass
+        raises(TypeError, "super(D, 42)")
+        raises(TypeError, "super(D, C())")
+        raises(TypeError, "super(D).__get__(12)")
+        raises(TypeError, "super(D).__get__(C())")

Modified: pypy/dist/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/dist/pypy/objspace/std/objspace.py	(original)
+++ pypy/dist/pypy/objspace/std/objspace.py	Tue Nov 20 18:47:29 2007
@@ -541,6 +541,14 @@
         return w_type.lookup_where(name)
     lookup_in_type_where._annspecialcase_ = 'specialize:lookup_in_type_where'
 
+    def lookup_in_type_starting_at(self, w_type, w_starttype, name):
+        """ Only supposed to be used to implement super, w_starttype
+        and w_type are the same as for super(starttype, type)
+        """
+        assert isinstance(w_type, W_TypeObject)
+        assert isinstance(w_starttype, W_TypeObject)
+        return w_type.lookup_starting_at(w_starttype, name)
+
     def allocate_instance(self, cls, w_subtype):
         """Allocate the memory needed for an instance of an internal or
         user-defined type, without actually __init__ializing the instance."""

Modified: pypy/dist/pypy/objspace/std/typeobject.py
==============================================================================
--- pypy/dist/pypy/objspace/std/typeobject.py	(original)
+++ pypy/dist/pypy/objspace/std/typeobject.py	Tue Nov 20 18:47:29 2007
@@ -294,6 +294,20 @@
 
         return w_self._lookup_where(name)
 
+    def lookup_starting_at(w_self, w_starttype, name):
+        space = w_self.space
+        # XXX Optimize this with method cache
+        look = False
+        for w_class in w_self.mro_w:
+            if w_class is w_starttype:
+                look = True
+            elif look:
+                w_value = w_class.getdictvalue_w(space, name)
+                if w_value is not None:
+                    return w_value
+        return None
+                
+
     def _lookup(w_self, key):
         space = w_self.space
         for w_class in w_self.mro_w:



More information about the Pypy-commit mailing list