[pypy-commit] pypy py3k: Fix a bug that caused e.g. None.__eq__ to evaluate to an unbound function.
mjacob
noreply at buildbot.pypy.org
Fri Jun 12 05:39:33 CEST 2015
Author: Manuel Jacob <me at manueljacob.de>
Branch: py3k
Changeset: r78038:36f6f45e781a
Date: 2015-06-12 05:39 +0200
http://bitbucket.org/pypy/pypy/changeset/36f6f45e781a/
Log: Fix a bug that caused e.g. None.__eq__ to evaluate to an unbound
function.
diff --git a/pypy/module/__builtin__/test/test_builtin.py b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -839,6 +839,22 @@
raises(TypeError, setattr, A(), 42, 'x')
raises(TypeError, delattr, A(), 42)
+ def test_getattr_None(self):
+ from types import FunctionType, MethodType
+ assert isinstance(getattr(type(None), '__eq__'), FunctionType)
+ assert isinstance(getattr(None, '__eq__'), MethodType)
+
+ def test_getattr_userobject(self):
+ from types import FunctionType, MethodType
+ class A(object):
+ def __eq__(self, other):
+ pass
+ a = A()
+ assert isinstance(getattr(A, '__eq__'), FunctionType)
+ assert isinstance(getattr(a, '__eq__'), MethodType)
+ a.__eq__ = 42
+ assert a.__eq__ == 42
+
class AppTestGetattrWithGetAttributeShortcut(AppTestGetattr):
spaceconfig = {"objspace.std.getattributeshortcut": True}
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -102,6 +102,13 @@
if w_value is not None:
return w_value
if w_descr is not None:
+ typ = type(w_descr)
+ if typ is Function or typ is FunctionWithFixedCode:
+ # This shortcut is necessary if w_obj is None. Otherwise e.g.
+ # None.__eq__ would return an unbound function because calling
+ # __get__ with None as the first argument returns the attribute
+ # as if it was accessed through the owner (type(None).__eq__).
+ return Method(space, w_descr, w_obj)
return space.get(w_descr, w_obj)
raiseattrerror(space, w_obj, w_name)
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -2,6 +2,7 @@
from pypy.interpreter import special
from pypy.interpreter.baseobjspace import ObjSpace, W_Root
from pypy.interpreter.error import OperationError, oefmt
+from pypy.interpreter.function import Function, Method, FunctionWithFixedCode
from pypy.interpreter.typedef import get_unique_interplevel_subclass
from pypy.objspace.std import frame, transparent, callmethod
from pypy.objspace.descroperation import (
@@ -572,6 +573,13 @@
return w_value
if not is_data:
w_get = self.lookup(w_descr, "__get__")
+ typ = type(w_descr)
+ if typ is Function or typ is FunctionWithFixedCode:
+ # This shortcut is necessary if w_obj is None. Otherwise e.g.
+ # None.__eq__ would return an unbound function because calling
+ # __get__ with None as the first argument returns the attribute
+ # as if it was accessed through the owner (type(None).__eq__).
+ return Method(self, w_descr, w_obj)
if w_get is not None:
# __get__ is allowed to raise an AttributeError to trigger
# use of __getattr__.
More information about the pypy-commit
mailing list