Skip to content

Commit

Permalink
p64 and p64 are faster and create more informative exceptions.
Browse files Browse the repository at this point in the history
Fixes #216.
  • Loading branch information
jamadden committed Aug 22, 2018
1 parent 6abde06 commit 1b1025c
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 13 deletions.
13 changes: 9 additions & 4 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@

- Add support for Python 3.7.

- Make the internal support functions for dealing with OIDs (``p64``
and ``u64``) somewhat faster and raise more informative
exceptions on certain types of bad input. See `issue 216
<https://github.com/zopefoundation/ZODB/issues/216>`_.

5.4.0 (2018-03-26)
==================

Expand Down Expand Up @@ -57,10 +62,10 @@
cost of being very slightly less efficient for old-style classes.

.. note:: On Python 2, this will now allow open ``file`` objects
(but **not** open blobs or sockets) to be pickled (loading
the object will result in a closed file); previously this
would result in a ``TypeError``. Doing so is not
recommended as they cannot be loaded in Python 3.
(but **not** open blobs or sockets) to be pickled (loading
the object will result in a closed file); previously this
would result in a ``TypeError``. Doing so is not
recommended as they cannot be loaded in Python 3.

See `issue 179 <https://github.com/zopefoundation/ZODB/pull/179>`_.

Expand Down
30 changes: 26 additions & 4 deletions src/ZODB/tests/testUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,34 @@ def test_get_pickle_metadata_w_protocol_3_class_pickle(self):
self.assertEqual(get_pickle_metadata(pickle),
(__name__, ExampleClass.__name__))

def test_p64_bad_object(self):
with self.assertRaises(ValueError) as exc:
p64(2 ** 65)

e = exc.exception
# The args will be whatever the struct.error args were,
# which vary from version to version and across implementations,
# followed by the bad value
self.assertEqual(e.args[-1], 2 ** 65)

def test_u64_bad_object(self):
with self.assertRaises(ValueError) as exc:
u64(b'123456789')

e = exc.exception
# The args will be whatever the struct.error args were,
# which vary from version to version and across implementations,
# followed by the bad value
self.assertEqual(e.args[-1], b'123456789')



class ExampleClass(object):
pass

def test_suite():
return unittest.TestSuite((
unittest.makeSuite(TestUtils),
doctest.DocFileSuite('../utils.txt', checker=checker),
))
suite = unittest.defaultTestLoader.loadTestsFromName(__name__)
suite.addTest(
doctest.DocFileSuite('../utils.txt', checker=checker)
)
return suite
21 changes: 16 additions & 5 deletions src/ZODB/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
import time
import threading
from binascii import hexlify, unhexlify
from struct import pack, unpack

from tempfile import mkstemp

from persistent.TimeStamp import TimeStamp
from persistent.timestamp import TimeStamp

from ZODB._compat import Unpickler
from ZODB._compat import BytesIO
Expand Down Expand Up @@ -84,13 +84,24 @@ def byte_chr(int):
# The distinction between ints and longs is blurred in Python 2.2,
# so u64() are U64() really the same.

_OID_STRUCT = struct.Struct('>Q')
_OID_PACK = _OID_STRUCT.pack
_OID_UNPACK = _OID_STRUCT.unpack


def p64(v):
"""Pack an integer or long into a 8-byte string"""
return pack(">Q", v)
"""Pack an integer or long into a 8-byte string."""
try:
return _OID_PACK(v)
except struct.error as e:
raise ValueError(*(e.args + (v,)))

def u64(v):
"""Unpack an 8-byte string into a 64-bit long integer."""
return unpack(">Q", v)[0]
try:
return _OID_UNPACK(v)[0]
except struct.error as e:
raise ValueError(*(e.args + (v,)))

U64 = u64

Expand Down

0 comments on commit 1b1025c

Please sign in to comment.