Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ctypes.c_long to get the native long type on all platforms; fixes 32-bit TimeStamp hashcode #22

Merged
merged 4 commits into from
Apr 9, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
4.0.10 (unreleased)
-------------------

- TBD
- Fix the hashcode of the Python ``TimeStamp`` on 32-bit platforms.

4.0.9 (2015-04-08)
------------------
Expand Down
30 changes: 30 additions & 0 deletions persistent/tests/test_timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,36 @@ def test_hash_equal(self):
c, py = self._make_C_and_Py(*self.now_ts_args)
self.assertEqual(hash(c), hash(py))

def test_py_hash_32_64_bit(self):
# We happen to know that on a 32-bit platform, the hashcode
# of the c version should be exactly
# -1419374591
# and the 64-bit should be exactly:
# -3850693964765720575
# Fake out the python version to think it's on a 32-bit
# platform and test the same; also verify 64 bit
bit_32_hash = -1419374591
bit_64_hash = -3850693964765720575
import persistent.timestamp
import ctypes
orig_c_long = persistent.timestamp.c_long
try:
persistent.timestamp.c_long = ctypes.c_int32
py = self._makePy(*self.now_ts_args)
self.assertEqual(hash(py), bit_32_hash)

persistent.timestamp.c_long = ctypes.c_int64
self.assertEqual(hash(py), bit_64_hash)
finally:
persistent.timestamp.c_long = orig_c_long

if orig_c_long is ctypes.c_int32:
self.assertEqual(py.__hash__(), bit_32_hash)
elif orig_c_long is ctypes.c_int64:
self.assertEqual(py.__hash__(), bit_64_hash)
else:
self.fail("Unknown bitness")

def test_hash_equal_constants(self):
# The simple constants make it easier to diagnose
# a difference in algorithms
Expand Down
4 changes: 2 additions & 2 deletions persistent/timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
##############################################################################
__all__ = ('TimeStamp',)

from ctypes import c_int64
from ctypes import c_long
import datetime
import math
import struct
Expand Down Expand Up @@ -158,7 +158,7 @@ def __hash__(self):

# Make sure to overflow and wraparound just
# like the C code does.
x = c_int64(x).value
x = c_long(x).value
if x == -1: #pragma: no cover
# The C version has this condition, but it's not clear
# why; it's also not immediately obvious what bytestring
Expand Down