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