[pypy-commit] pypy py3k: Remove unbound methods. see CPython change 48af6375207e
amauryfa
noreply at buildbot.pypy.org
Thu Oct 13 01:33:42 CEST 2011
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r48006:9d18583f7fc4
Date: 2011-10-13 01:09 +0200
http://bitbucket.org/pypy/pypy/changeset/9d18583f7fc4/
Log: Remove unbound methods. see CPython change 48af6375207e
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -420,87 +420,40 @@
"""functionobject.__get__(obj[, type]) -> method"""
# this is not defined as a method on Function because it's generally
# useful logic: w_function can be any callable. It is used by Method too.
- asking_for_bound = (space.is_w(w_cls, space.w_None) or
- not space.is_w(w_obj, space.w_None) or
- space.is_w(w_cls, space.type(space.w_None)))
- if asking_for_bound:
- return space.wrap(Method(space, w_function, w_obj, w_cls))
+ if w_obj is None or space.is_w(w_obj, space.w_None):
+ return w_function
else:
- return space.wrap(Method(space, w_function, None, w_cls))
+ return space.wrap(Method(space, w_function, w_obj))
class Method(Wrappable):
- """A method is a function bound to a specific instance or class."""
- _immutable_fields_ = ['w_function', 'w_instance', 'w_class']
+ """A method is a function bound to a specific instance."""
+ _immutable_fields_ = ['w_function', 'w_instance']
- def __init__(self, space, w_function, w_instance, w_class):
+ def __init__(self, space, w_function, w_instance):
self.space = space
self.w_function = w_function
- self.w_instance = w_instance # or None
- self.w_class = w_class # possibly space.w_None
+ self.w_instance = w_instance
- def descr_method__new__(space, w_subtype, w_function, w_instance, w_class=None):
+ def descr_method__new__(space, w_subtype, w_function, w_instance):
if space.is_w(w_instance, space.w_None):
w_instance = None
- if w_instance is None and space.is_w(w_class, space.w_None):
+ if w_instance is None:
raise OperationError(space.w_TypeError,
- space.wrap("unbound methods must have class"))
+ space.wrap("self must not be None"))
method = space.allocate_instance(Method, w_subtype)
- Method.__init__(method, space, w_function, w_instance, w_class)
+ Method.__init__(method, space, w_function, w_instance)
return space.wrap(method)
def __repr__(self):
- if self.w_instance:
- pre = "bound"
- else:
- pre = "unbound"
- return "%s method %s" % (pre, self.w_function.getname(self.space))
+ return "bound method %s" % (self.w_function.getname(self.space),)
def call_args(self, args):
space = self.space
- if self.w_instance is not None:
- # bound method
- return space.call_obj_args(self.w_function, self.w_instance, args)
-
- # unbound method
- w_firstarg = args.firstarg()
- if w_firstarg is not None and (
- space.abstract_isinstance_w(w_firstarg, self.w_class)):
- pass # ok
- else:
- myname = self.getname(space, "")
- clsdescr = self.w_class.getname(space, "")
- if clsdescr:
- clsdescr += " instance"
- else:
- clsdescr = "instance"
- if w_firstarg is None:
- instdescr = "nothing"
- else:
- instname = space.abstract_getclass(w_firstarg).getname(space,
- "")
- if instname:
- instdescr = instname + " instance"
- else:
- instdescr = "instance"
- msg = ("unbound method %s() must be called with %s "
- "as first argument (got %s instead)")
- raise operationerrfmt(space.w_TypeError, msg,
- myname, clsdescr, instdescr)
- return space.call_args(self.w_function, args)
+ return space.call_obj_args(self.w_function, self.w_instance, args)
def descr_method_get(self, w_obj, w_cls=None):
- space = self.space
- if self.w_instance is not None:
- return space.wrap(self) # already bound
- else:
- # only allow binding to a more specific class than before
- if (w_cls is not None and
- not space.is_w(w_cls, space.w_None) and
- not space.abstract_issubclass_w(w_cls, self.w_class)):
- return space.wrap(self) # subclass test failed
- else:
- return descr_function_get(space, self.w_function, w_obj, w_cls)
+ return self.space.wrap(self) # already bound
def descr_method_call(self, __args__):
return self.call_args(__args__)
@@ -508,19 +461,11 @@
def descr_method_repr(self):
space = self.space
name = self.w_function.getname(self.space)
- # XXX do we handle all cases sanely here?
- if space.is_w(self.w_class, space.w_None):
- w_class = space.type(self.w_instance)
- else:
- w_class = self.w_class
+ w_class = space.type(self.w_instance)
typename = w_class.getname(self.space)
- if self.w_instance is None:
- s = "<unbound method %s.%s>" % (typename, name)
- return space.wrap(s)
- else:
- objrepr = space.str_w(space.repr(self.w_instance))
- s = '<bound method %s.%s of %s>' % (typename, name, objrepr)
- return space.wrap(s)
+ objrepr = space.str_w(space.repr(self.w_instance))
+ s = '<bound method %s.%s of %s>' % (typename, name, objrepr)
+ return space.wrap(s)
def descr_method_getattribute(self, w_attr):
space = self.space
@@ -539,21 +484,14 @@
other = space.interpclass_w(w_other)
if not isinstance(other, Method):
return space.w_NotImplemented
- if self.w_instance is None:
- if other.w_instance is not None:
- return space.w_False
- else:
- if other.w_instance is None:
- return space.w_False
- if not space.eq_w(self.w_instance, other.w_instance):
- return space.w_False
+ if not space.eq_w(self.w_instance, other.w_instance):
+ return space.w_False
return space.eq(self.w_function, other.w_function)
def descr_method_hash(self):
space = self.space
w_result = space.hash(self.w_function)
- if self.w_instance is not None:
- w_result = space.xor(w_result, space.hash(self.w_instance))
+ w_result = space.xor(w_result, space.hash(self.w_instance))
return w_result
def descr_method__reduce__(self, space):
@@ -561,20 +499,15 @@
from pypy.interpreter.gateway import BuiltinCode
w_mod = space.getbuiltinmodule('_pickle_support')
mod = space.interp_w(MixedModule, w_mod)
- new_inst = mod.get('method_new')
w = space.wrap
w_instance = self.w_instance or space.w_None
function = space.interpclass_w(self.w_function)
if isinstance(function, Function) and isinstance(function.code, BuiltinCode):
new_inst = mod.get('builtin_method_new')
- if space.is_w(w_instance, space.w_None):
- tup = [self.w_class, space.wrap(function.name)]
- else:
- tup = [w_instance, space.wrap(function.name)]
- elif space.is_w( self.w_class, space.w_None ):
+ tup = [w_instance, space.wrap(function.name)]
+ else:
+ new_inst = mod.get('method_new')
tup = [self.w_function, w_instance]
- else:
- tup = [self.w_function, w_instance, self.w_class]
return space.newtuple([new_inst, space.newtuple(tup)])
class StaticMethod(Wrappable):
@@ -603,7 +536,7 @@
def descr_classmethod_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))
+ return space.wrap(Method(space, self.w_function, w_klass))
def descr_classmethod__new__(space, w_subtype, w_function):
instance = space.allocate_instance(ClassMethod, w_subtype)
diff --git a/pypy/interpreter/test/test_function.py b/pypy/interpreter/test/test_function.py
--- a/pypy/interpreter/test/test_function.py
+++ b/pypy/interpreter/test/test_function.py
@@ -101,11 +101,11 @@
def test_set_module_to_name_eagerly(self):
skip("fails on PyPy but works on CPython. Unsure we want to care")
- exec '''if 1:
+ exec('''if 1:
__name__ = "foo"
def f(): pass
__name__ = "bar"
- assert f.__module__ == "foo"''' in {}
+ assert f.__module__ == "foo"''')
class AppTestFunction:
@@ -295,9 +295,9 @@
def test_unicode_docstring(self):
def f():
- u"hi"
- assert f.__doc__ == u"hi"
- assert type(f.__doc__) is unicode
+ "hi"
+ assert f.__doc__ == "hi"
+ assert type(f.__doc__) is str
def test_subclassing(self):
# cannot subclass 'function' or 'builtin_function'
@@ -418,13 +418,11 @@
class A(object):
def f(self):
pass
- assert repr(A.f) == "<unbound method A.f>"
assert repr(A().f).startswith("<bound method A.f of <")
assert repr(A().f).endswith(">>")
class B:
def f(self):
pass
- assert repr(B.f) == "<unbound method B.f>"
assert repr(B().f).startswith("<bound method B.f of <")
assert repr(A().f).endswith(">>")
@@ -451,69 +449,6 @@
im = types.MethodType(A(), 3)
assert map(im, [4]) == [7]
- def test_unbound_typecheck(self):
- class A(object):
- def foo(self, *args):
- return args
- class B(A):
- pass
- class C(A):
- pass
-
- assert A.foo(A(), 42) == (42,)
- assert A.foo(B(), 42) == (42,)
- raises(TypeError, A.foo, 5)
- raises(TypeError, B.foo, C())
- try:
- class Fun:
- __metaclass__ = A.foo
- assert 0 # should have raised
- except TypeError:
- pass
- class Fun:
- __metaclass__ = A().foo
- assert Fun[:2] == ('Fun', ())
-
- def test_unbound_abstract_typecheck(self):
- import types
- def f(*args):
- return args
- m = types.MethodType(f, None, "foobar")
- raises(TypeError, m)
- raises(TypeError, m, None)
- raises(TypeError, m, "egg")
-
- m = types.MethodType(f, None, (str, int)) # really obscure...
- assert m(4) == (4,)
- assert m("uh") == ("uh",)
- raises(TypeError, m, [])
-
- class MyBaseInst(object):
- pass
- class MyInst(MyBaseInst):
- def __init__(self, myclass):
- self.myclass = myclass
- def __class__(self):
- if self.myclass is None:
- raise AttributeError
- return self.myclass
- __class__ = property(__class__)
- class MyClass(object):
- pass
- BBase = MyClass()
- BSub1 = MyClass()
- BSub2 = MyClass()
- BBase.__bases__ = ()
- BSub1.__bases__ = (BBase,)
- BSub2.__bases__ = (BBase,)
- x = MyInst(BSub1)
- m = types.MethodType(f, None, BSub1)
- assert m(x) == (x,)
- raises(TypeError, m, MyInst(BBase))
- raises(TypeError, m, MyInst(BSub2))
- raises(TypeError, m, MyInst(None))
- raises(TypeError, m, MyInst(42))
-
def test_invalid_creation(self):
import types
def f(): pass
@@ -590,14 +525,7 @@
# Check method returned from unbound_method.__get__()
w_meth3 = descr_function_get(space, func, None, space.type(obj2))
meth3 = space.unwrap(w_meth3)
- w_meth4 = meth3.descr_method_get(obj2, space.w_None)
- meth4 = space.unwrap(w_meth4)
- assert isinstance(meth4, Method)
- assert meth4.call_args(args) == obj2
- # Check method returned from unbound_method.__get__()
- # --- with an incompatible class
- w_meth5 = meth3.descr_method_get(space.wrap('hello'), space.w_str)
- assert space.is_w(w_meth5, w_meth3)
+ assert meth3 is func
class TestShortcuts(object):
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -109,13 +109,6 @@
return borrow_from(w_method, w_method.w_instance)
@cpython_api([PyObject], PyObject)
-def PyMethod_Class(space, w_method):
- """Return the class object from which the method meth was created; if this was
- created from an instance, it will be the class of the instance."""
- assert isinstance(w_method, Method)
- return borrow_from(w_method, w_method.w_class)
-
- at cpython_api([PyObject], PyObject)
def PyClassMethod_New(space, w_function):
return space.call_method(space.builtin, "classmethod", w_function)
diff --git a/pypy/module/cpyext/include/funcobject.h b/pypy/module/cpyext/include/funcobject.h
--- a/pypy/module/cpyext/include/funcobject.h
+++ b/pypy/module/cpyext/include/funcobject.h
@@ -16,7 +16,6 @@
#define PyMethod_GET_FUNCTION(obj) PyMethod_Function((PyObject*)(obj))
#define PyMethod_GET_SELF(obj) PyMethod_Self((PyObject*)(obj))
-#define PyMethod_GET_CLASS(obj) PyMethod_Class((PyObject*)(obj))
#ifdef __cplusplus
}
More information about the pypy-commit
mailing list