diff --git a/fix_32-bit_timestamp_hashcode.patch b/fix_32-bit_timestamp_hashcode.patch new file mode 100644 index 0000000..06cebdf --- /dev/null +++ b/fix_32-bit_timestamp_hashcode.patch @@ -0,0 +1,131 @@ +fix timestamp hash computation on 32-bit platform. +Patch extracted from PR #22 and #23, see: +https://github.com/zopefoundation/persistent/issues/21 +https://github.com/zopefoundation/persistent/pull/22 +https://github.com/zopefoundation/persistent/pull/23 + +--- + persistent/tests/test_timestamp.py | 64 +++++++++++++++++++++++++++++++++---- + persistent/timestamp.py | 4 +- + 2 files changed, 60 insertions(+), 8 deletions(-) + +Index: persistent-4.0.9/persistent/tests/test_timestamp.py +=================================================================== +--- persistent-4.0.9.orig/persistent/tests/test_timestamp.py ++++ persistent-4.0.9/persistent/tests/test_timestamp.py +@@ -253,9 +253,45 @@ class PyAndCComparisonTests(unittest.Tes + 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 ++ # call __hash__ directly to avoid interpreter truncation ++ # in hash() on 32-bit platforms ++ self.assertEqual(py.__hash__(), 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 ++ import persistent.timestamp ++ import ctypes ++ is_32_bit = persistent.timestamp.c_long == ctypes.c_int32 ++ + c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x00\x00\x00\x00') + self.assertEqual(hash(c), 8) + self.assertEqual(hash(c), hash(py)) +@@ -268,25 +304,41 @@ class PyAndCComparisonTests(unittest.Tes + self.assertEqual(hash(c), 1000011) + self.assertEqual(hash(c), hash(py)) + ++ # overflow kicks in here on 32-bit platforms + c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x00\x01\x00\x00') +- self.assertEqual(hash(c), 1000006000001) ++ if is_32_bit: ++ self.assertEqual(hash(c), -721379967) ++ else: ++ self.assertEqual(hash(c), 1000006000001) + self.assertEqual(hash(c), hash(py)) + + c, py = self._make_C_and_Py(b'\x00\x00\x00\x00\x01\x00\x00\x00') +- self.assertEqual(hash(c), 1000009000027000019) ++ if is_32_bit: ++ self.assertEqual(hash(c), 583896275) ++ else: ++ self.assertEqual(hash(c), 1000009000027000019) + self.assertEqual(hash(c), hash(py)) + +- # Overflow kicks in at this point ++ # Overflow kicks in at this point on 64-bit platforms + c, py = self._make_C_and_Py(b'\x00\x00\x00\x01\x00\x00\x00\x00') +- self.assertEqual(hash(c), -4442925868394654887) ++ if is_32_bit: ++ self.assertEqual(hash(c), 1525764953) ++ else: ++ self.assertEqual(hash(c), -4442925868394654887) + self.assertEqual(hash(c), hash(py)) + + c, py = self._make_C_and_Py(b'\x00\x00\x01\x00\x00\x00\x00\x00') +- self.assertEqual(hash(c), -3993531167153147845) ++ if is_32_bit: ++ self.assertEqual(hash(c), -429739973) ++ else: ++ self.assertEqual(hash(c), -3993531167153147845) + self.assertEqual(hash(c), hash(py)) + + c, py = self._make_C_and_Py(b'\x01\x00\x00\x00\x00\x00\x00\x00') +- self.assertEqual(hash(c), -3099646879006235965) ++ if is_32_bit: ++ self.assertEqual(hash(c), 263152323) ++ else: ++ self.assertEqual(hash(c), -3099646879006235965) + self.assertEqual(hash(c), hash(py)) + + def test_ordering(self): +Index: persistent-4.0.9/persistent/timestamp.py +=================================================================== +--- persistent-4.0.9.orig/persistent/timestamp.py ++++ persistent-4.0.9/persistent/timestamp.py +@@ -13,7 +13,7 @@ + ############################################################################## + __all__ = ('TimeStamp',) + +-from ctypes import c_int64 ++from ctypes import c_long + import datetime + import math + import struct +@@ -158,7 +158,7 @@ class pyTimeStamp(object): + + # 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 diff --git a/persistent-4.0.6.tar.gz b/persistent-4.0.6.tar.gz deleted file mode 100644 index dcab948..0000000 --- a/persistent-4.0.6.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2b890d6ac22ba576cf50a4b2be229a7fe4d1d834a2f777bde22260a11e13f6fe -size 75968 diff --git a/persistent-4.0.9.tar.gz b/persistent-4.0.9.tar.gz new file mode 100644 index 0000000..6ef88b7 --- /dev/null +++ b/persistent-4.0.9.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c64f2efc2b40cce38a0683ef7ca715afeb1d69a156619d454462f0e1861cf28a +size 675350 diff --git a/python-persistent.changes b/python-persistent.changes index 2fdc178..3439a6d 100644 --- a/python-persistent.changes +++ b/python-persistent.changes @@ -1,3 +1,43 @@ +------------------------------------------------------------------- +Sun May 10 19:46:51 UTC 2015 - benoit.monin@gmx.fr + +- update to version 4.0.9: + * Make the C and Python TimeStamp objects behave more alike + * Intern keys of object state in __setstate__ to reduce memory + usage when unpickling multiple objects with the same attributes + * Add support for PyPy3 + * 100% branch coverage +- additional changes from version 4.0.8: + * Add support for Python 3.4 + * In pure-Python Persistent, avoid loading state in _p_activate + for non-ghost objects (which could corrupt their state). (PR #9) + * In pure-Python, and don’t throw POSKeyError if _p_activate is + called on an object that has never been committed. (PR #9) + * In pure-Python Persistent, avoid calling a subclass’s + __setattr__ at instance creation time. (PR #8) + * Make it possible to delete _p_jar / _p_oid of a pure-Python + Persistent object which has been removed from the jar’s cache + (fixes aborting a ZODB Connection that has added objects). + (PR #7) +- additional changes from version 4.0.7: + * Avoid a KeyError from _p_accessed() on newly-created objects + under pure-Python: these objects may be assigned to a jar, but + not yet added to its cache. (PR #6) + * Avoid a failure in Persistent.__setstate__ when the state dict + contains exactly two keys. (PR #5) + * Fix a hang in picklecache invalidation if OIDs are manually + passed out-of-order. (PR #4) + * Add PURE_PYTHON environment variable support: if set, the C + extensions will not be built, imported, or tested +- update project URL +- point the source URL to pypi +- drop type-mismatch.patch: fixed upstream +- add fix_32-bit_timestamp_hashcode.patch: fix timestamp hash + computation on 32 bit platform +- pass -q to test to avoid spamming the build log +- rename CHANGES.txt and README.txt to CHANGES.rst and README.rst: + changed upstream + ------------------------------------------------------------------- Fri Mar 21 23:02:35 UTC 2014 - schwab@linux-m68k.org diff --git a/python-persistent.spec b/python-persistent.spec index 6634021..8a639b1 100644 --- a/python-persistent.spec +++ b/python-persistent.spec @@ -1,7 +1,7 @@ # # spec file for package python-persistent # -# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2013 LISA GmbH, Bingen, Germany. # # All modifications and additions to the file contributed by third parties @@ -18,15 +18,15 @@ Name: python-persistent -Version: 4.0.6 +Version: 4.0.9 Release: 0 -Url: http://www.python.org/pypi/persistent +Url: https://github.com/zopefoundation/persistent Summary: Translucent persistent objects License: ZPL-2.1 Group: Development/Languages/Python -Source: persistent-%{version}.tar.gz -# PATCH-FIX-UPSTREAM https://github.com/zopefoundation/persistent/commit/33daf91246f85c3248658c4d81d768bd78617003 -Patch: type-mismatch.patch +Source: https://pypi.python.org/packages/source/p/persistent/persistent-%{version}.tar.gz +# PATCH-FIX-UPSTREAM fix_32-bit_timestamp_hashcode.patch -- fix timestamp hash computation on 32-bit platform +Patch: fix_32-bit_timestamp_hashcode.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: python-devel BuildRequires: python-setuptools @@ -75,11 +75,11 @@ python setup.py install --prefix=%{_prefix} --root=%{buildroot} rm %{buildroot}%python_sitearch/persistent/*.c %check -python setup.py test +python setup.py -q test %files %defattr(-,root,root,-) -%doc CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt +%doc CHANGES.rst COPYRIGHT.txt LICENSE.txt README.rst %exclude %python_sitearch/persistent/*.h %python_sitearch/* diff --git a/type-mismatch.patch b/type-mismatch.patch deleted file mode 100644 index 2225c7b..0000000 --- a/type-mismatch.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 33daf91246f85c3248658c4d81d768bd78617003 Mon Sep 17 00:00:00 2001 -From: Tres Seaver -Date: Mon, 24 Mar 2014 13:39:46 -0400 -Subject: [PATCH] Use Py_ssize_t rather than PY_LONG_LONG for sizes. - ---- - persistent/cPersistence.h | 2 +- - persistent/cPickleCache.c | 18 +++++++++--------- - 2 files changed, 10 insertions(+), 10 deletions(-) - -diff --git a/persistent/cPersistence.h b/persistent/cPersistence.h -index 52d3bad..ac9a885 100644 ---- a/persistent/cPersistence.h -+++ b/persistent/cPersistence.h -@@ -24,7 +24,7 @@ - PyObject_HEAD \ - CPersistentRing ring_home; \ - int non_ghost_count; \ -- PY_LONG_LONG total_estimated_size; -+ Py_ssize_t total_estimated_size; - - struct ccobject_head_struct; - -diff --git a/persistent/cPickleCache.c b/persistent/cPickleCache.c -index 5753922..57f33bf 100644 ---- a/persistent/cPickleCache.c -+++ b/persistent/cPickleCache.c -@@ -123,7 +123,7 @@ typedef struct - PyObject *data; /* oid -> object dict */ - PyObject *jar; /* Connection object */ - int cache_size; /* target number of items in cache */ -- PY_LONG_LONG cache_size_bytes; /* target total estimated size of -+ Py_ssize_t cache_size_bytes; /* target total estimated size of - items in cache */ - - /* Most of the time the ring contains only: -@@ -176,7 +176,7 @@ unlink_from_ring(CPersistentRing *self) - } - - static int --scan_gc_items(ccobject *self, int target, PY_LONG_LONG target_bytes) -+scan_gc_items(ccobject *self, int target, Py_ssize_t target_bytes) - { - /* This function must only be called with the ring lock held, - because it places non-object placeholders in the ring. -@@ -262,7 +262,7 @@ Done: - } - - static PyObject * --lockgc(ccobject *self, int target_size, PY_LONG_LONG target_size_bytes) -+lockgc(ccobject *self, int target_size, Py_ssize_t target_size_bytes) - { - /* This is thread-safe because of the GIL, and there's nothing - * in between checking the ring_lock and acquiring it that calls back -@@ -292,7 +292,7 @@ cc_incrgc(ccobject *self, PyObject *args) - int obsolete_arg = -999; - int starting_size = self->non_ghost_count; - int target_size = self->cache_size; -- PY_LONG_LONG target_size_bytes = self->cache_size_bytes; -+ Py_ssize_t target_size_bytes = self->cache_size_bytes; - - if (self->cache_drain_resistance >= 1) - { -@@ -850,10 +850,10 @@ static int - cc_init(ccobject *self, PyObject *args, PyObject *kwds) - { - int cache_size = 100; -- PY_LONG_LONG cache_size_bytes = 0; -+ Py_ssize_t cache_size_bytes = 0; - PyObject *jar; - -- if (!PyArg_ParseTuple(args, "O|iL", &jar, &cache_size, &cache_size_bytes)) -+ if (!PyArg_ParseTuple(args, "O|in", &jar, &cache_size, &cache_size_bytes)) - return -1; - - self->jar = NULL; -@@ -1245,9 +1245,9 @@ static PyGetSetDef cc_getsets[] = - static PyMemberDef cc_members[] = - { - {"cache_size", T_INT, offsetof(ccobject, cache_size)}, -- {"cache_size_bytes", T_LONG, offsetof(ccobject, cache_size_bytes)}, -- {"total_estimated_size", T_LONG, offsetof(ccobject, total_estimated_size), -- READONLY}, -+ {"cache_size_bytes", T_PYSSIZET, offsetof(ccobject, cache_size_bytes)}, -+ {"total_estimated_size", T_PYSSIZET, -+ offsetof(ccobject, total_estimated_size), READONLY}, - {"cache_drain_resistance", T_INT, - offsetof(ccobject, cache_drain_resistance)}, - {"cache_non_ghost_count", T_INT, offsetof(ccobject, non_ghost_count), --- -1.9.1 -