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

fijal at codespeak.net fijal at codespeak.net
Tue Nov 20 19:47:22 CET 2007


Author: fijal
Date: Tue Nov 20 19:47:22 2007
New Revision: 48868

Modified:
   pypy/dist/pypy/module/__builtin__/__init__.py
   pypy/dist/pypy/module/__builtin__/app_descriptor.py
   pypy/dist/pypy/module/__builtin__/descriptor.py
   pypy/dist/pypy/module/__builtin__/test/test_descriptor.py
Log:
Move staticmethod and classmethod to rpython


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 19:47:22 2007
@@ -56,8 +56,6 @@
         'dir'           : 'app_inspect.dir',
 
         'property'      : 'app_descriptor.property',
-        'staticmethod'  : 'app_descriptor.staticmethod',
-        'classmethod'   : 'app_descriptor.classmethod',
 
         'complex'       : 'app_complex.complex',
 
@@ -127,6 +125,8 @@
         'all'           : 'functional.all',
         'any'           : 'functional.any',
         'super'         : 'descriptor.W_Super',
+        'staticmethod'  : 'descriptor.StaticMethod',
+        'classmethod'   : 'descriptor.W_ClassMethod',
     }
 
     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 19:47:22 2007
@@ -5,65 +5,6 @@
 # Descriptor code, shamelessly stolen from Raymond Hettinger:
 #    http://users.rcn.com/python/download/Descriptor.htm
 
-
-# XXX there is an interp-level pypy.interpreter.function.StaticMethod
-# XXX because __new__ needs to be a StaticMethod early.
-class staticmethod(object):
-    """staticmethod(function) -> static method
-
-Convert a function to be a static method.
-
-A static method does not receive an implicit first argument.
-To declare a static method, use this idiom:
-
-     class C:
-         def f(arg1, arg2, ...): ...
-         f = staticmethod(f)
-
-It can be called either on the class (e.g. C.f()) or on an instance
-(e.g. C().f()).  The instance is ignored except for its class."""
-    __slots__ = ['_f']
-
-    def __init__(self, f):
-        self._f = f
-
-    def __get__(self, obj, objtype=None):
-        return self._f
-
-
-class classmethod(object):
-    """classmethod(function) -> class method
-
-Convert a function to be a class method.
-
-A class method receives the class as implicit first argument,
-just like an instance method receives the instance.
-To declare a class method, use this idiom:
-
-  class C:
-      def f(cls, arg1, arg2, ...): ...
-      f = classmethod(f)
-
-It can be called either on the class (e.g. C.f()) or on an instance
-(e.g. C().f()).  The instance is ignored except for its class.
-If a class method is called for a derived class, the derived class
-object is passed as the implied first argument."""
-    __slots__ = ['_f']
-
-    def __init__(self, f):
-        if not callable(f):
-            raise TypeError, "'%s' object is not callable" % type(f).__name__
-        self._f = f
-
-    def __get__(self, obj, klass=None):
-        if klass is None:
-            klass = type(obj)
-        return MethodType(self._f, klass)
-
-def dummy(): pass
-MethodType = type(dummy.__get__(42))
-del dummy
-
 # It's difficult to have a class that has both a docstring and a slot called
 # '__doc__', but not impossible...
 class docstring(object):

Modified: pypy/dist/pypy/module/__builtin__/descriptor.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/descriptor.py	(original)
+++ pypy/dist/pypy/module/__builtin__/descriptor.py	Tue Nov 20 19:47:22 2007
@@ -5,6 +5,7 @@
 from pypy.interpreter.gateway import interp2app
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.callmethod import object_getattribute
+from pypy.interpreter.function import StaticMethod, Method
 
 class W_Super(Wrappable):
     def __init__(self, space, w_selftype, w_starttype, w_type, w_self):
@@ -89,3 +90,42 @@
         super(C, self).meth(arg)"""
 )
 
+class W_ClassMethod(Wrappable):
+    def __init__(self, w_function):
+        self.w_function = w_function
+
+    def new(space, w_type, w_function):
+        if not space.is_true(space.callable(w_function)):
+            name = space.getattr(space.type(w_function), space.wrap('__name__'))
+            raise OperationError(space.w_TypeError, space.wrap(
+                                 "'%s' object is not callable" % name))
+        return W_ClassMethod(w_function)
+
+    def get(self, space, w_obj, w_klass=None):
+        if space.is_w(w_klass, space.w_None):
+            w_klass = space.type(w_obj)
+        return space.wrap(Method(space, self.w_function, w_klass, space.w_None))
+
+W_ClassMethod.typedef = TypeDef(
+    'classmethod',
+    __new__ = interp2app(W_ClassMethod.new.im_func,
+                         unwrap_spec=[ObjSpace, W_Root, W_Root]),
+    __get__ = interp2app(W_ClassMethod.get,
+                         unwrap_spec=['self', ObjSpace, W_Root, W_Root]),
+    __doc__ = """classmethod(function) -> class method
+
+Convert a function to be a class method.
+
+A class method receives the class as implicit first argument,
+just like an instance method receives the instance.
+To declare a class method, use this idiom:
+
+  class C:
+      def f(cls, arg1, arg2, ...): ...
+      f = classmethod(f)
+
+It can be called either on the class (e.g. C.f()) or on an instance
+(e.g. C().f()).  The instance is ignored except for its class.
+If a class method is called for a derived class, the derived class
+object is passed as the implied first argument.""",
+)

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 19:47:22 2007
@@ -193,3 +193,34 @@
         raises(TypeError, "super(D, C())")
         raises(TypeError, "super(D).__get__(12)")
         raises(TypeError, "super(D).__get__(C())")
+
+    def test_classmethods_various(self):
+        class C(object):
+            def foo(*a): return a
+            goo = classmethod(foo)
+        c = C()
+        assert C.goo(1) == (C, 1)
+        assert c.goo(1) == (C, 1)
+        
+        assert c.foo(1) == (c, 1)
+        class D(C):
+            pass
+        d = D()
+        assert D.goo(1) == (D, 1)
+        assert d.goo(1) == (D, 1)
+        assert d.foo(1) == (d, 1)
+        assert D.foo(d, 1) == (d, 1)
+        def f(cls, arg): return (cls, arg)
+        ff = classmethod(f)
+        assert ff.__get__(0, int)(42) == (int, 42)
+        assert ff.__get__(0)(42) == (int, 42)
+
+        assert C.goo.im_self is C
+        assert D.goo.im_self is D
+        assert super(D,D).goo.im_self is D
+        assert super(D,d).goo.im_self is D
+        assert super(D,D).goo() == (D,)
+        assert super(D,d).goo() == (D,)
+
+        raises(TypeError, "classmethod(1).__get__(1)")
+



More information about the Pypy-commit mailing list