[Checkins] SVN: transaction/branches/chrism-py3/ prelim py3 support
Chris McDonough
chrism at plope.com
Sun Sep 25 17:16:09 EST 2011
Log message for revision 122936:
prelim py3 support
Changed:
_U transaction/branches/chrism-py3/
U transaction/branches/chrism-py3/setup.py
U transaction/branches/chrism-py3/transaction/__init__.py
U transaction/branches/chrism-py3/transaction/_transaction.py
A transaction/branches/chrism-py3/transaction/compat.py
U transaction/branches/chrism-py3/transaction/interfaces.py
U transaction/branches/chrism-py3/transaction/tests/convenience.txt
U transaction/branches/chrism-py3/transaction/tests/doom.txt
U transaction/branches/chrism-py3/transaction/tests/savepoint.txt
U transaction/branches/chrism-py3/transaction/tests/savepointsample.py
U transaction/branches/chrism-py3/transaction/tests/test_transaction.py
-=-
Property changes on: transaction/branches/chrism-py3
___________________________________________________________________
Modified: svn:ignore
- *.egg
*.egg-info
build
dist
bin
parts
eggs
develop-eggs
.installed.cfg
+ *.egg
*.egg-info
build
dist
bin
parts
eggs
develop-eggs
.installed.cfg
.coverage
Modified: transaction/branches/chrism-py3/setup.py
===================================================================
--- transaction/branches/chrism-py3/setup.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/setup.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -16,9 +16,6 @@
import os
-from ez_setup import use_setuptools
-use_setuptools()
-
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
Modified: transaction/branches/chrism-py3/transaction/__init__.py
===================================================================
--- transaction/branches/chrism-py3/transaction/__init__.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/__init__.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -20,6 +20,11 @@
from transaction._manager import TransactionManager
from transaction._manager import ThreadTransactionManager
+# NB: "with transaction:" does not work under Python 3 because they worked
+# really hard to break looking up special methods like __enter__ and __exit__
+# via getattr and getattribute; see http://bugs.python.org/issue12022. On
+# Python 3, you must use ``with transaction.manager`` instead.
+
manager = ThreadTransactionManager()
get = __enter__ = manager.get
begin = manager.begin
Modified: transaction/branches/chrism-py3/transaction/_transaction.py
===================================================================
--- transaction/branches/chrism-py3/transaction/_transaction.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/_transaction.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -100,13 +100,16 @@
import binascii
import logging
import sys
-import thread
import weakref
import traceback
-from cStringIO import StringIO
from zope import interface
+from transaction.compat import reraise
+from transaction.compat import get_thread_ident
+from transaction.compat import native_
+from transaction.compat import bytes_
+from transaction.compat import StringIO
from transaction.weakset import WeakSet
from transaction.interfaces import TransactionFailedError
from transaction import interfaces
@@ -174,7 +177,7 @@
# directly by storages, leading underscore notwithstanding.
self._extension = {}
- self.log = logging.getLogger("txn.%d" % thread.get_ident())
+ self.log = logging.getLogger("txn.%d" % get_thread_ident())
self.log.debug("new transaction")
# If a commit fails, the traceback is saved in _failure_traceback.
@@ -272,8 +275,8 @@
def _remove_and_invalidate_after(self, savepoint):
savepoint2index = self._savepoint2index
index = savepoint2index[savepoint]
- # use items() to make copy to avoid mutating while iterating
- for savepoint, i in savepoint2index.items():
+ # use list(items()) to make copy to avoid mutating while iterating
+ for savepoint, i in list(savepoint2index.items()):
if i > index:
savepoint.transaction = None # invalidate
del savepoint2index[savepoint]
@@ -335,7 +338,7 @@
try:
t, v, tb = self._saveAndGetCommitishError()
self._callAfterCommitHooks(status=False)
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
else:
@@ -371,7 +374,7 @@
tb = None
try:
t, v, tb = self._saveAndGetCommitishError()
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
@@ -435,7 +438,7 @@
# Execute the two-phase commit protocol.
L = list(self._resources)
- L.sort(rm_cmp)
+ L.sort(key=rm_key)
try:
for rm in L:
rm.tpc_begin(self)
@@ -466,7 +469,7 @@
self._cleanup(L)
finally:
self._synchronizers.map(lambda s: s.afterCompletion(self))
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
@@ -515,7 +518,7 @@
self.log.debug("abort")
if tb is not None:
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
@@ -588,12 +591,14 @@
object_hint(o), exc_info=sys.exc_info())
if tb is not None:
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
-def rm_cmp(rm1, rm2):
- return cmp(rm1.sortKey(), rm2.sortKey())
+def rm_key(rm):
+ func = getattr(rm, 'sortKey', None)
+ if func is not None:
+ return func()
def object_hint(o):
"""Return a string describing the object.
@@ -612,7 +617,8 @@
def oid_repr(oid):
if isinstance(oid, str) and len(oid) == 8:
# Convert to hex and strip leading zeroes.
- as_hex = binascii.hexlify(oid).lstrip('0')
+ as_hex = native_(
+ binascii.hexlify(bytes_(oid, 'ascii')), 'ascii').lstrip('0')
# Ensure two characters per input byte.
if len(as_hex) & 1:
as_hex = '0' + as_hex
Added: transaction/branches/chrism-py3/transaction/compat.py
===================================================================
--- transaction/branches/chrism-py3/transaction/compat.py (rev 0)
+++ transaction/branches/chrism-py3/transaction/compat.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -0,0 +1,92 @@
+import sys
+import types
+
+PY3 = sys.version_info[0] == 3
+
+if PY3: # pragma: no cover
+ string_types = str,
+ integer_types = int,
+ class_types = type,
+ text_type = str
+ binary_type = bytes
+ long = int
+else:
+ string_types = basestring,
+ integer_types = (int, long)
+ class_types = (type, types.ClassType)
+ text_type = unicode
+ binary_type = str
+ long = long
+
+def text_(s, encoding='latin-1', errors='strict'):
+ if isinstance(s, binary_type):
+ return s.decode(encoding, errors)
+ return s # pragma: no cover
+
+def bytes_(s, encoding='latin-1', errors='strict'):
+ if isinstance(s, text_type):
+ return s.encode(encoding, errors)
+ return s
+
+if PY3: # pragma: no cover
+ def native_(s, encoding='latin-1', errors='strict'):
+ if isinstance(s, text_type):
+ return s
+ return str(s, encoding, errors)
+else:
+ def native_(s, encoding='latin-1', errors='strict'):
+ if isinstance(s, text_type):
+ return s.encode(encoding, errors)
+ return str(s)
+
+if PY3:
+ from io import StringIO
+else:
+ from io import BytesIO as StringIO
+
+if PY3:
+ from collections import MutableMapping
+else:
+ from UserDict import UserDict as MutableMapping
+
+if PY3: # pragma: no cover
+ import builtins
+ exec_ = getattr(builtins, "exec")
+
+
+ def reraise(tp, value, tb=None):
+ if value.__traceback__ is not tb:
+ raise value.with_traceback(tb)
+ raise value
+
+else: # pragma: no cover
+ def exec_(code, globs=None, locs=None):
+ """Execute code in a namespace."""
+ if globs is None:
+ frame = sys._getframe(1)
+ globs = frame.f_globals
+ if locs is None:
+ locs = frame.f_locals
+ del frame
+ elif locs is None:
+ locs = globs
+ exec("""exec code in globs, locs""")
+
+ exec_("""def reraise(tp, value, tb=None):
+ raise tp, value, tb
+""")
+
+
+if PY3:
+ from threading import _get_ident as get_thread_ident
+else:
+ from thread import get_ident as get_thread_ident
+
+
+if PY3:
+ def func_name(func):
+ return func.__name__
+else:
+ def func_name(func):
+ return func.func_name
+
Modified: transaction/branches/chrism-py3/transaction/interfaces.py
===================================================================
--- transaction/branches/chrism-py3/transaction/interfaces.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/interfaces.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -486,6 +486,7 @@
invoking abort() on the transaction, or begin() on its transaction
manager.
"""
+
class DoomedTransaction(TransactionError):
"""A commit was attempted on a transaction that was doomed."""
Modified: transaction/branches/chrism-py3/transaction/tests/convenience.txt
===================================================================
--- transaction/branches/chrism-py3/transaction/tests/convenience.txt 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/tests/convenience.txt 2011-09-25 22:16:09 UTC (rev 122936)
@@ -12,31 +12,9 @@
>>> import transaction.tests.savepointsample
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
- >>> dm.keys()
+ >>> list(dm.keys())
[]
-We can use the transaction module directly:
-
- >>> with transaction as t:
- ... dm['z'] = 1
- ... t.note('test 1')
-
- >>> dm['z']
- 1
-
- >>> dm.last_note
- 'test 1'
-
- >>> with transaction:
- ... dm['z'] = 2
- ... xxx
- Traceback (most recent call last):
- ...
- NameError: name 'xxx' is not defined
-
- >>> dm['z']
- 1
-
We can use it with a manager:
>>> with transaction.manager as t:
@@ -49,7 +27,7 @@
>>> dm.last_note
'test 3'
- >>> with transaction:
+ >>> with transaction.manager:
... dm['z'] = 4
... xxx
Traceback (most recent call last):
@@ -59,6 +37,10 @@
>>> dm['z']
3
+On Python 2, you can also abbreviate ``with transaction.manager:`` as ``with
+transaction:``. This does not work on Python 3 (see see
+http://bugs.python.org/issue12022).
+
Retries
-------
@@ -68,7 +50,7 @@
for i in range(3):
try:
- with transaction:
+ with transaction.manager:
... some something ...
except SomeTransientException:
contine
@@ -82,7 +64,7 @@
>>> ntry = 0
- >>> with transaction:
+ >>> with transaction.manager:
... dm['ntry'] = 0
>>> import transaction.interfaces
@@ -92,7 +74,7 @@
>>> for attempt in transaction.manager.attempts():
... with attempt as t:
... t.note('test')
- ... print dm['ntry'], ntry
+ ... print("%s %s" % (dm['ntry'], ntry))
... ntry += 1
... dm['ntry'] = ntry
... if ntry % 3:
@@ -143,7 +125,7 @@
>>> for attempt in transaction.attempts():
... with attempt as t:
... t.note('test')
- ... print dm['ntry'], ntry
+ ... print("%s %s" % (dm['ntry'], ntry))
... ntry += 1
... dm['ntry'] = ntry
... if ntry % 3:
@@ -165,11 +147,11 @@
>>> ntry = 0
>>> dm2 = DM()
- >>> with transaction:
+ >>> with transaction.manager:
... dm2['ntry'] = 0
>>> for attempt in transaction.manager.attempts():
... with attempt:
- ... print dm['ntry'], ntry
+ ... print("%s %s" % (dm['ntry'], ntry))
... ntry += 1
... dm['ntry'] = ntry
... dm2['ntry'] = ntry
Modified: transaction/branches/chrism-py3/transaction/tests/doom.txt
===================================================================
--- transaction/branches/chrism-py3/transaction/tests/doom.txt 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/tests/doom.txt 2011-09-25 22:16:09 UTC (rev 122936)
@@ -77,13 +77,11 @@
Attempting to commit a doomed transaction any number of times raises a
DoomedTransaction:
- >>> txn.commit() # doctest: +ELLIPSIS
+ >>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
- ...
DoomedTransaction
- >>> txn.commit() # doctest: +ELLIPSIS
+ >>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
- ...
DoomedTransaction
But still leaves the data manager unchanged:
Modified: transaction/branches/chrism-py3/transaction/tests/savepoint.txt
===================================================================
--- transaction/branches/chrism-py3/transaction/tests/savepoint.txt 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/tests/savepoint.txt 2011-09-25 22:16:09 UTC (rev 122936)
@@ -75,14 +75,14 @@
... try:
... dm[name+'-balance'] += amount
... validate_account(name)
- ... except ValueError, error:
+ ... except ValueError as error:
... entry_savepoint.rollback()
- ... print 'Error', str(error)
+ ... print("%s %s" % ('Error', str(error)))
... else:
- ... print 'Updated', name
- ... except Exception, error:
+ ... print("%s %s" % ('Updated', name))
+ ... except Exception as error:
... savepoint.rollback()
- ... print 'Unexpected exception', error
+ ... print("%s %s" % ('Unexpected exception', error))
Now let's try applying some entries:
@@ -184,12 +184,12 @@
>>> dm['bob-balance']
100.0
- >>> savepoint2.rollback()
+ >>> savepoint2.rollback() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
InvalidSavepointRollbackError
- >>> savepoint1.rollback()
+ >>> savepoint1.rollback() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
InvalidSavepointRollbackError
@@ -207,7 +207,7 @@
>>> dm_no_sp['name'] = 'bob'
>>> transaction.commit()
>>> dm_no_sp['name'] = 'sally'
- >>> savepoint = transaction.savepoint()
+ >>> savepoint = transaction.savepoint() #doctest +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError: ('Savepoints unsupported', {'name': 'bob'})
@@ -228,8 +228,8 @@
>>> dm_no_sp['name'] = 'sam'
>>> savepoint = transaction.savepoint(1)
- >>> savepoint.rollback()
- Traceback (most recent call last):
+ >>> savepoint.rollback() #doctest +IGNORE_EXCEPTION_DETAIL
+ Traceback (most recent call last):
...
TypeError: ('Savepoints unsupported', {'name': 'sam'})
@@ -245,7 +245,7 @@
In the previous example, we got an error when we tried to rollback the
savepoint. If we try to commit the transaction, the commit will fail:
- >>> transaction.commit() # doctest: +ELLIPSIS
+ >>> transaction.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TransactionFailedError: An operation previously failed, with traceback:
@@ -262,12 +262,12 @@
>>> dm_no_sp['name'] = 'sally'
>>> dm['name'] = 'sally'
- >>> savepoint = transaction.savepoint()
+ >>> savepoint = transaction.savepoint() # doctest +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TypeError: ('Savepoints unsupported', {'name': 'sue'})
- >>> transaction.commit() # doctest: +ELLIPSIS
+ >>> transaction.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
TransactionFailedError: An operation previously failed, with traceback:
Modified: transaction/branches/chrism-py3/transaction/tests/savepointsample.py
===================================================================
--- transaction/branches/chrism-py3/transaction/tests/savepointsample.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/tests/savepointsample.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -19,11 +19,11 @@
See savepoint.txt in the transaction package.
"""
-import UserDict
from zope import interface
import transaction.interfaces
-class SampleDataManager(UserDict.DictMixin):
+ at interface.implementer(transaction.interfaces.IDataManager)
+class SampleDataManager(object):
"""Sample implementation of data manager that doesn't support savepoints
This data manager stores named simple values, like strings and numbers.
@@ -71,6 +71,17 @@
def keys(self):
return self.uncommitted.keys()
+ __iter__ = keys
+
+ def __contains__(self, k):
+ return k in self.uncommitted
+
+ def __len__(self):
+ return len(self.keys())
+
+ def __repr__(self):
+ return repr(self.uncommitted)
+
#
#######################################################################
@@ -151,6 +162,7 @@
#
#######################################################################
+ at interface.implementer(transaction.interfaces.ISavepointDataManager)
class SampleSavepointDataManager(SampleDataManager):
"""Sample implementation of a savepoint-supporting data manager
@@ -172,6 +184,7 @@
# savepoint was done again. IOW, copy() is necessary.
self.uncommitted = savepoint.data.copy()
+ at interface.implementer(transaction.interfaces.IDataManagerSavepoint)
class SampleSavepoint:
interface.implements(transaction.interfaces.IDataManagerSavepoint)
Modified: transaction/branches/chrism-py3/transaction/tests/test_transaction.py
===================================================================
--- transaction/branches/chrism-py3/transaction/tests/test_transaction.py 2011-09-25 20:29:37 UTC (rev 122935)
+++ transaction/branches/chrism-py3/transaction/tests/test_transaction.py 2011-09-25 22:16:09 UTC (rev 122936)
@@ -307,7 +307,7 @@
def check(self, method):
if self.tracing:
- print '%s calling method %s'%(str(self.tracing),method)
+ print('%s calling method %s'%(str(self.tracing),method))
if method in self.errors:
raise TestTxnException("error %s" % method)
@@ -402,13 +402,14 @@
Now register the hook with a transaction.
+ >>> from transaction.compat import func_name
>>> import transaction
>>> t = transaction.begin()
>>> t.addBeforeCommitHook(hook, '1')
We can see that the hook is indeed registered.
- >>> [(hook.func_name, args, kws)
+ >>> [(func_name(hook), args, kws)
... for hook, args, kws in t.getBeforeCommitHooks()]
[('hook', ('1',), {})]
@@ -470,7 +471,7 @@
>>> t.join(FailingDataManager())
>>> t.addBeforeCommitHook(hook, '2')
- >>> t.commit()
+ >>> t.commit() #doctest +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
CommitFailure
@@ -486,7 +487,7 @@
They are returned in the same order by getBeforeCommitHooks.
- >>> [(hook.func_name, args, kws) #doctest: +NORMALIZE_WHITESPACE
+ >>> [(func_name(hook), args, kws) #doctest: +NORMALIZE_WHITESPACE
... for hook, args, kws in t.getBeforeCommitHooks()]
[('hook', ('4',), {'kw1': '4.1'}),
('hook', ('5',), {'kw2': '5.2'})]
@@ -539,13 +540,14 @@
Now register the hook with a transaction.
+ >>> from transaction.compat import func_name
>>> import transaction
>>> t = transaction.begin()
>>> t.addAfterCommitHook(hook, '1')
We can see that the hook is indeed registered.
- >>> [(hook.func_name, args, kws)
+ >>> [(func_name(hook), args, kws)
... for hook, args, kws in t.getAfterCommitHooks()]
[('hook', ('1',), {})]
@@ -607,7 +609,7 @@
>>> t.join(FailingDataManager())
>>> t.addAfterCommitHook(hook, '2')
- >>> t.commit()
+ >>> t.commit() #doctest +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
CommitFailure
@@ -623,7 +625,7 @@
They are returned in the same order by getAfterCommitHooks.
- >>> [(hook.func_name, args, kws) #doctest: +NORMALIZE_WHITESPACE
+ >>> [(func_name(hook), args, kws) #doctest: +NORMALIZE_WHITESPACE
... for hook, args, kws in t.getAfterCommitHooks()]
[('hook', ('4',), {'kw1': '4.1'}),
('hook', ('5',), {'kw2': '5.2'})]
@@ -711,18 +713,18 @@
>>> import transaction.tests.savepointsample
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
- >>> dm.keys()
+ >>> list(dm.keys())
[]
>>> class Sync:
... def __init__(self, label):
... self.label = label
... def beforeCompletion(self, t):
- ... print self.label, 'before'
+ ... print('%s %s' % (self.label, 'before'))
... def afterCompletion(self, t):
- ... print self.label, 'after'
+ ... print('%s %s' % (self.label, 'after'))
... def newTransaction(self, t):
- ... print self.label, 'new'
+ ... print('%s %s' % (self.label, 'new'))
>>> sync = Sync(1)
>>> import threading
@@ -742,11 +744,11 @@
... def second():
... transaction.abort() # should do nothing.
- >>> dm.keys()
+ >>> list(dm.keys())
['a']
>>> dm = transaction.tests.savepointsample.SampleSavepointDataManager()
- >>> dm.keys()
+ >>> list(dm.keys())
[]
>>> @run_in_thread
@@ -754,7 +756,7 @@
... dm['a'] = 1
>>> transaction.abort() # should do nothing
- >>> dm.keys()
+ >>> list(dm.keys())
['a']
"""
More information about the checkins
mailing list