From f7b96aea8d0d2a2f249ba62f48384c764b92c18c Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Tue, 6 Apr 2004 21:47:12 +0000 Subject: [PATCH] ZODB.utils grows a new function positive_id(), which returns the id() of an object as a non-negative integer. Code trying to pass addresses to an %x format uses positive_id(), and this avoids a Python FutureWarning about applying %x to negative ints. The primary difference between this and the last stab is that positive_id() should work OK on 64-bit boxes too. What we really want here is C's %p format code, but in Python we can't even reliably know the width of native addresses. --- src/BTrees/check.py | 6 +++--- src/ZODB/Connection.py | 8 +++----- src/ZODB/tests/testTransaction.py | 7 +++++-- src/ZODB/utils.py | 23 +++++++++++++++++++++++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/BTrees/check.py b/src/BTrees/check.py index fb17a29ca..e87080d11 100644 --- a/src/BTrees/check.py +++ b/src/BTrees/check.py @@ -39,6 +39,8 @@ from BTrees.IOBTree import IOBTree, IOBucket, IOSet, IOTreeSet from BTrees.IIBTree import IIBTree, IIBucket, IISet, IITreeSet +from ZODB.utils import positive_id + TYPE_UNKNOWN, TYPE_BTREE, TYPE_BUCKET = range(3) _type2kind = {IOBTree: (TYPE_BTREE, True), @@ -198,9 +200,7 @@ def crack_bucket(b, is_mapping): return keys, values def type_and_adr(obj): - # Force the address to look positive. A negative address will - # show up as signed in Python 2.4, and in 2.3 raises FutureWarning. - return "%s (0x%x)" % (type(obj).__name__, id(obj) & 0xffffffffL) + return "%s (0x%x)" % (type(obj).__name__, positive_id(obj)) # Walker implements a depth-first search of a BTree (or TreeSet or Set or # Bucket). Subclasses must implement the visit_btree() and visit_bucket() diff --git a/src/ZODB/Connection.py b/src/ZODB/Connection.py index 99496910b..e37af2749 100644 --- a/src/ZODB/Connection.py +++ b/src/ZODB/Connection.py @@ -13,7 +13,7 @@ ############################################################################## """Database connection support -$Id: Connection.py,v 1.143 2004/04/06 20:21:55 tim_one Exp $""" +$Id: Connection.py,v 1.144 2004/04/06 21:47:12 tim_one Exp $""" import logging import sys @@ -33,7 +33,7 @@ from ZODB.POSException \ import ConflictError, ReadConflictError, InvalidObjectReference from ZODB.TmpStore import TmpStore -from ZODB.utils import oid_repr, z64 +from ZODB.utils import oid_repr, z64, positive_id from ZODB.serialize import ObjectWriter, ConnectionObjectReader, myhasattr global_reset_counter = 0 @@ -223,9 +223,7 @@ def __repr__(self): ver = ' (in version %s)' % `self._version` else: ver = '' - # Force the address to look positive. A negative address will - # show up as signed in Python 2.4, and in 2.3 raises FutureWarning. - return '' % (id(self) & 0xffffffffL, ver) + return '' % (positive_id(self), ver) def get(self, oid): """Return the persistent object with oid 'oid'. diff --git a/src/ZODB/tests/testTransaction.py b/src/ZODB/tests/testTransaction.py index c49772735..677c37b38 100644 --- a/src/ZODB/tests/testTransaction.py +++ b/src/ZODB/tests/testTransaction.py @@ -36,11 +36,12 @@ add in tests for objects which are modified multiple times, for example an object that gets modified in multiple sub txns. -$Id: testTransaction.py,v 1.23 2004/04/06 01:06:41 tim_one Exp $ +$Id: testTransaction.py,v 1.24 2004/04/06 21:47:12 tim_one Exp $ """ import unittest import transaction +from ZODB.utils import positive_id class TransactionTests(unittest.TestCase): @@ -532,7 +533,9 @@ def __init__(self, errors=(), tracing=0): self.ccommit_sub = 0 def __repr__(self): - return "<%s %X %s>" % (self.__class__.__name__, id(self), self.errors) + return "<%s %X %s>" % (self.__class__.__name__, + positive_id(self), + self.errors) def sortKey(self): # All these jars use the same sort key, and Python's list.sort() diff --git a/src/ZODB/utils.py b/src/ZODB/utils.py index 9dda0cbfd..7fa0cf103 100644 --- a/src/ZODB/utils.py +++ b/src/ZODB/utils.py @@ -69,3 +69,26 @@ def oid_repr(oid): return repr(oid) serial_repr = oid_repr + +# Addresses can "look negative" on some boxes, some of the time. If you +# feed a "negative address" to an %x format, Python 2.3 displays it as +# unsigned, but produces a FutureWarning, because Python 2.4 will display +# it as signed. So when you want to prodce an address, use positive_id() to +# obtain it. +def positive_id(obj): + """Return id(obj) as a non-negative integer.""" + + result = id(obj) + if result < 0: + # This is a puzzle: there's no way to know the natural width of + # addresses on this box (in particular, there's no necessary + # relation to sys.maxint). Try 32 bits first (and on a 32-bit + # box, adding 2**32 gives a positive number with the same hex + # representation as the original result). + result += 1L << 32 + if result < 0: + # Undo that, and try 64 bits. + result -= 1L << 32 + result += 1L << 64 + assert result >= 0 # else addresses are fatter than 64 bits + return result