[pypy-commit] pypy identity-dict-strategy: add a way to check whether a type has custom versions of __eq__, __hash__ or __cmp__
antocuni
noreply at buildbot.pypy.org
Tue Jul 19 18:44:18 CEST 2011
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: identity-dict-strategy
Changeset: r45740:a2ad83608b4b
Date: 2011-07-19 17:02 +0200
http://bitbucket.org/pypy/pypy/changeset/a2ad83608b4b/
Log: add a way to check whether a type has custom versions of __eq__,
__hash__ or __cmp__
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -327,6 +327,9 @@
BoolOption("mutable_builtintypes",
"Allow the changing of builtin types", default=False,
requires=[("objspace.std.builtinshortcut", True)]),
+ BoolOption("trackcomparebyidentity",
+ "track types that override __hash__, __eq__ or __cmp__",
+ default=True),
]),
])
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -28,6 +28,13 @@
return w_delattr
object_delattr._annspecialcase_ = 'specialize:memo'
+def object_hash(space):
+ "Utility that returns the app-level descriptor object.__hash__."
+ w_src, w_hash = space.lookup_in_type_where(space.w_object,
+ '__hash__')
+ return w_hash
+object_hash._annspecialcase_ = 'specialize:memo'
+
def raiseattrerror(space, w_obj, name, w_descr=None):
w_type = space.type(w_obj)
typename = w_type.getname(space)
diff --git a/pypy/objspace/std/test/test_typeobject.py b/pypy/objspace/std/test/test_typeobject.py
--- a/pypy/objspace/std/test/test_typeobject.py
+++ b/pypy/objspace/std/test/test_typeobject.py
@@ -1199,3 +1199,37 @@
return x + 1
a = A()
assert a.f(1) == 2
+
+
+class AppTestTrackCompareByIdentity:
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(
+ **{"objspace.std.trackcomparebyidentity": True})
+
+ def compares_by_identity(space, w_cls):
+ return space.wrap(w_cls.compares_by_identity())
+
+ cls.w_compares_by_identity = cls.space.wrap(interp2app(compares_by_identity))
+
+ def test_compares_by_identity(self):
+ class Plain(object):
+ pass
+
+ class CustomEq(object):
+ def __eq__(self, other):
+ return True
+
+ class CustomCmp (object):
+ def __cmp__(self, other):
+ return 0
+
+ class CustomHash(object):
+ def __hash__(self):
+ return 0
+
+
+ assert self.compares_by_identity(Plain)
+ assert not self.compares_by_identity(CustomEq)
+ assert not self.compares_by_identity(CustomCmp)
+ assert not self.compares_by_identity(CustomHash)
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -102,6 +102,10 @@
# (False is a conservative default, fixed during real usage)
uses_object_getattribute = False
+ # for config.objspace.std.trackcomparebyidentity
+ # (True is a conservative default, fixed during real usage)
+ overrides_hash_eq_or_cmp = True
+
# used to cache the type __new__ function if it comes from a builtin type
# != 'type', in that case call__Type will also assumes the result
# of the __new__ is an instance of the type
@@ -207,6 +211,21 @@
def has_object_getattribute(w_self):
return w_self.getattribute_if_not_from_object() is None
+ def compares_by_identity(w_self):
+ from pypy.objspace.descroperation import object_hash
+ track = w_self.space.config.objspace.std.trackcomparebyidentity
+ if not track:
+ return False # conservative
+ #
+ if not w_self.overrides_hash_eq_or_cmp:
+ return True # fast path
+ #
+ default_hash = object_hash(w_self.space)
+ w_self.overrides_hash_eq_or_cmp = (w_self.lookup('__eq__') or
+ w_self.lookup('__cmp__') or
+ w_self.lookup('__hash__') is not default_hash)
+ return not w_self.overrides_hash_eq_or_cmp
+
def ready(w_self):
for w_base in w_self.bases_w:
if not isinstance(w_base, W_TypeObject):
More information about the pypy-commit
mailing list