One small change in Python 2.5 is the __hash__ method behavior. In earlier versions the __hash__ method was supposed to return a normal integer always, but now due to changes in the id() builtin function the __hash__ method behavior was changed and it can return a long or an int.
This was easy to change in PyPy, the hash() builtin function implementation is part of the ObjectSpace as almost all the builtin functions and types.
It’s in pypy/objspace/descroperation.py:
def hash(space, w_obj):
w_hash = space.lookup(w_obj, '__hash__')
if w_hash is None:
if space.lookup(w_obj, '__eq__') is not None or \
space.lookup(w_obj, '__cmp__') is not None:
raise OperationError(space.w_TypeError,
space.wrap("unhashable type"))
return default_identity_hash(space, w_obj)
w_result = space.get_and_call_function(w_hash, w_obj)
if space.is_true(space.isinstance(w_result, space.w_int)):
return w_result
else:
raise OperationError(space.w_TypeError,
space.wrap("__hash__() should return an int or long"))
One don’t even need to know PyPy well to understand that the lines
if space.is_true(space.isinstance(w_result, space.w_int)):
return w_result
else:
raise OperationError(space.w_TypeError,
space.wrap("__hash__() should return an int or long"))
are responsible for raising a TypeError when the returning value from __hash__ is not an integer.
So just changing the condition
space.is_true(space.isinstance(w_result, space.w_int)):
to
(space.is_true(space.isinstance(w_result, space.w_int)) or
space.is_true(space.isinstance(w_result, space.w_long))):
will solve this, I hope!
But that’s not all the code needed, I promised Carl to write tests for everything, but as I like to use TDD (test-driven development) it was already done.
Oh, and should I mention that I love PyPy’s documentation? Thanks guys!