Author: Ronan Lamy <[email protected]>
Branch: online-transforms
Changeset: r74180:6b3f07cf2406
Date: 2014-10-24 18:00 +0200
http://bitbucket.org/pypy/pypy/changeset/6b3f07cf2406/

Log:    Add helper to normalize CPython's zoo of method-like objects

diff --git a/rpython/tool/descriptor.py b/rpython/tool/descriptor.py
--- a/rpython/tool/descriptor.py
+++ b/rpython/tool/descriptor.py
@@ -1,3 +1,5 @@
+import sys, types
+
 class InstanceMethod(object):
     "Like types.InstanceMethod, but with a reasonable (structural) equality."
 
@@ -27,3 +29,39 @@
 
     def __hash__(self):
         return hash((self.im_func, self.im_self))
+
+if '__pypy__' in sys.modules:
+    def normalize_method(method):
+        '''Turn everything that behaves like a method into an InstanceMethod 
object'''
+        if isinstance(method, types.MethodType):
+            return InstanceMethod(method.__func__, method.__self__, 
method.im_class)
+        else:
+            raise ValueError('Not a method')
+
+else:
+    slot_wrapper = type(object.__init__)
+    method_wrapper = type(object().__init__)
+    method_descriptor = type(str.join)
+
+    def normalize_method(method):
+        '''Turn everything that behaves like a method into an InstanceMethod 
object'''
+        if isinstance(method, types.MethodType):
+            return InstanceMethod(method.__func__, method.__self__, 
method.im_class)
+        elif isinstance(method, types.BuiltinMethodType):
+            im_self = method.__self__
+            desc = getattr(type(im_self), method.__name__)
+            return InstanceMethod(desc, im_self, type(im_self))
+        elif isinstance(method, slot_wrapper):
+            baseslot = getattr(method.__objclass__, method.__name__)
+            cls = method.__objclass__
+            return InstanceMethod(baseslot, None, baseslot.__objclass__)
+        elif isinstance(method, method_wrapper):
+            slot = getattr(method.__objclass__, method.__name__)
+            return InstanceMethod(slot, method.__self__, slot.__objclass__)
+        elif isinstance(method, method_descriptor):
+            cls = method.__objclass__
+            return InstanceMethod(method, None, method.__objclass__)
+        else:
+            raise ValueError('Not a method')
+
+
diff --git a/rpython/tool/test/test_descriptor.py 
b/rpython/tool/test/test_descriptor.py
--- a/rpython/tool/test/test_descriptor.py
+++ b/rpython/tool/test/test_descriptor.py
@@ -1,4 +1,5 @@
 from rpython.tool.descriptor import InstanceMethod
+from rpython.tool.descriptor import normalize_method as norm
 
 class X(object):
     def f(self, *args, **kwds):
@@ -27,3 +28,30 @@
     d = {meth1: 123, meth2: 456}
     assert len(d) == 2
     assert d[meth1bis] == 123
+
+def test_normalize_unbound_method():
+    class A(object):
+        pass
+    class B(A):
+        def __init__(self):
+            pass
+
+    assert norm(A.__init__) == norm(object.__init__)
+    assert norm(A().__init__).im_func == norm(object().__init__).im_func
+    assert norm(A.__init__) != norm(B.__init__)
+
+    class C(str):
+        pass
+
+    assert norm(C.join) == norm(str.join)
+    assert norm(C().join).im_func == norm(str().join).im_func
+
+    class D(object):
+        def foo(self):
+            pass
+
+    class E(D):
+        pass
+
+    assert norm(E.foo) == norm(D.foo)
+    assert norm(E().foo).im_func == norm(D().foo).im_func
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to