[Checkins] SVN: transaction/trunk/ Merge chrism-py3 branch via:
Chris McDonough
chrism at plope.com
Wed Oct 12 05:05:09 EST 2011
Log message for revision 123062:
Merge chrism-py3 branch via:
svn merge -r122935:123061 svn+ssh://svn.zope.org/repos/main/transaction/branches/chrism-py3
Changed:
_U transaction/trunk/
U transaction/trunk/bootstrap.py
U transaction/trunk/setup.py
U transaction/trunk/transaction/__init__.py
U transaction/trunk/transaction/_transaction.py
A transaction/trunk/transaction/compat.py
U transaction/trunk/transaction/interfaces.py
U transaction/trunk/transaction/tests/convenience.txt
U transaction/trunk/transaction/tests/doom.txt
U transaction/trunk/transaction/tests/savepoint.txt
U transaction/trunk/transaction/tests/savepointsample.py
U transaction/trunk/transaction/tests/test_transaction.py
U transaction/trunk/transaction/tests/test_weakset.py
-=-
Property changes on: transaction/trunk
___________________________________________________________________
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/trunk/bootstrap.py
===================================================================
--- transaction/trunk/bootstrap.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/bootstrap.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -16,53 +16,263 @@
Simply run this script in a directory containing a buildout.cfg.
The script accepts buildout command-line options, so you can
use the -c option to specify an alternate configuration file.
-
-$Id$
"""
-import os, shutil, sys, tempfile, urllib2
+import os, shutil, sys, tempfile, textwrap
+try:
+ import urllib.request as urllib2
+except ImportError:
+ import urllib2
+import subprocess
+from optparse import OptionParser
-tmpeggs = tempfile.mkdtemp()
+if sys.platform == 'win32':
+ def quote(c):
+ if ' ' in c:
+ return '"%s"' % c # work around spawn lamosity on windows
+ else:
+ return c
+else:
+ quote = str
-ez = {}
-exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
- ).read() in ez
-ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments.
+stdout, stderr = subprocess.Popen(
+ [sys.executable, '-S', '-c',
+ 'try:\n'
+ ' import pickle\n'
+ 'except ImportError:\n'
+ ' print(1)\n'
+ 'else:\n'
+ ' print(0)\n'],
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+has_broken_dash_S = bool(int(stdout.strip()))
-import pkg_resources
+# In order to be more robust in the face of system Pythons, we want to
+# run without site-packages loaded. This is somewhat tricky, in
+# particular because Python 2.6's distutils imports site, so starting
+# with the -S flag is not sufficient. However, we'll start with that:
+if not has_broken_dash_S and 'site' in sys.modules:
+ # We will restart with python -S.
+ args = sys.argv[:]
+ args[0:0] = [sys.executable, '-S']
+ args = list(map(quote, args))
+ os.execv(sys.executable, args)
+# Now we are running with -S. We'll get the clean sys.path, import site
+# because distutils will do it later, and then reset the path and clean
+# out any namespace packages from site-packages that might have been
+# loaded by .pth files.
+clean_path = sys.path[:]
+import site
+sys.path[:] = clean_path
+for k, v in list(sys.modules.items()):
+ if k in ('setuptools', 'pkg_resources') or (
+ hasattr(v, '__path__') and
+ len(v.__path__)==1 and
+ not os.path.exists(os.path.join(v.__path__[0],'__init__.py'))):
+ # This is a namespace package. Remove it.
+ sys.modules.pop(k)
+
is_jython = sys.platform.startswith('java')
-if is_jython:
- import subprocess
+setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py'
+distribute_source = 'http://python-distribute.org/distribute_setup.py'
-cmd = 'from setuptools.command.easy_install import main; main()'
-if sys.platform == 'win32':
- cmd = '"%s"' % cmd # work around spawn lamosity on windows
+# parsing arguments
+def normalize_to_url(option, opt_str, value, parser):
+ if value:
+ if '://' not in value: # It doesn't smell like a URL.
+ value = 'file://%s' % (
+ urllib2.pathname2url(
+ os.path.abspath(os.path.expanduser(value))),)
+ if opt_str == '--download-base' and not value.endswith('/'):
+ # Download base needs a trailing slash to make the world happy.
+ value += '/'
+ else:
+ value = None
+ name = opt_str[2:].replace('-', '_')
+ setattr(parser.values, name, value)
+usage = '''\
+[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
+
+Bootstraps a buildout-based project.
+
+Simply run this script in a directory containing a buildout.cfg, using the
+Python that you want bin/buildout to use.
+
+Note that by using --setup-source and --download-base to point to
+local resources, you can keep this script from going over the network.
+'''
+
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--version", dest="version",
+ help="use a specific zc.buildout version")
+parser.add_option("--setup-version", dest="setup_version",
+ help="The version of setuptools or distribute to use.")
+parser.add_option("-d", "--distribute",
+ action="store_true", dest="use_distribute",
+ default= sys.version_info[0] >= 3,
+ help="Use Distribute rather than Setuptools.")
+parser.add_option("--setup-source", action="callback", dest="setup_source",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or file location for the setup file. "
+ "If you use Setuptools, this will default to " +
+ setuptools_source + "; if you use Distribute, this "
+ "will default to " + distribute_source +"."))
+parser.add_option("--download-base", action="callback", dest="download_base",
+ callback=normalize_to_url, nargs=1, type="string",
+ help=("Specify a URL or directory for downloading "
+ "zc.buildout and either Setuptools or Distribute. "
+ "Defaults to PyPI."))
+parser.add_option("--eggs",
+ help=("Specify a directory for storing eggs. Defaults to "
+ "a temporary directory that is deleted when the "
+ "bootstrap script completes."))
+parser.add_option("-t", "--accept-buildout-test-releases",
+ dest='accept_buildout_test_releases',
+ action="store_true",
+ default=sys.version_info[0] > 2,
+ help=("Normally, if you do not specify a --version, the "
+ "bootstrap script and buildout gets the newest "
+ "*final* versions of zc.buildout and its recipes and "
+ "extensions for you. If you use this flag, "
+ "bootstrap and buildout will get the newest releases "
+ "even if they are alphas or betas."))
+parser.add_option("-c", None, action="store", dest="config_file",
+ help=("Specify the path to the buildout configuration "
+ "file to be used."))
+
+options, args = parser.parse_args()
+
+# if -c was provided, we push it back into args for buildout's main function
+if options.config_file is not None:
+ args += ['-c', options.config_file]
+
+if options.eggs:
+ eggs_dir = os.path.abspath(os.path.expanduser(options.eggs))
+else:
+ eggs_dir = tempfile.mkdtemp()
+
+if options.setup_source is None:
+ if options.use_distribute:
+ options.setup_source = distribute_source
+ else:
+ options.setup_source = setuptools_source
+
+if options.accept_buildout_test_releases:
+ args.append('buildout:accept-buildout-test-releases=true')
+args.append('bootstrap')
+
+try:
+ import pkg_resources
+ import setuptools # A flag. Sometimes pkg_resources is installed alone.
+ if not hasattr(pkg_resources, '_distribute'):
+ raise ImportError
+except ImportError:
+ ez_code = urllib2.urlopen(
+ options.setup_source).read().replace('\r\n'.encode(), '\n'.encode())
+ ez = {}
+ exec(ez_code, ez)
+ setup_args = dict(to_dir=eggs_dir, download_delay=0)
+ if options.download_base:
+ setup_args['download_base'] = options.download_base
+ if options.setup_version:
+ setup_args['version'] = options.setup_version
+ if options.use_distribute:
+ setup_args['no_fake'] = True
+ ez['use_setuptools'](**setup_args)
+ if 'pkg_resources' in sys.modules:
+ if sys.version_info[0] >= 3:
+ import imp
+ reload_ = imp.reload
+ else:
+ reload_ = reload
+
+ reload_(sys.modules['pkg_resources'])
+ import pkg_resources
+ # This does not (always?) update the default working set. We will
+ # do it.
+ for path in sys.path:
+ if path not in pkg_resources.working_set.entries:
+ pkg_resources.working_set.add_entry(path)
+
+cmd = [quote(sys.executable),
+ '-c',
+ quote('from setuptools.command.easy_install import main; main()'),
+ '-mqNxd',
+ quote(eggs_dir)]
+
+if not has_broken_dash_S:
+ cmd.insert(1, '-S')
+
+find_links = options.download_base
+if not find_links:
+ find_links = os.environ.get('bootstrap-testing-find-links')
+if find_links:
+ cmd.extend(['-f', quote(find_links)])
+
+if options.use_distribute:
+ setup_requirement = 'distribute'
+else:
+ setup_requirement = 'setuptools'
ws = pkg_resources.working_set
+setup_requirement_path = ws.find(
+ pkg_resources.Requirement.parse(setup_requirement)).location
+env = dict(
+ os.environ,
+ PYTHONPATH=setup_requirement_path)
+requirement = 'zc.buildout'
+version = options.version
+if version is None and not options.accept_buildout_test_releases:
+ # Figure out the most recent final version of zc.buildout.
+ import setuptools.package_index
+ _final_parts = '*final-', '*final'
+ def _final_version(parsed_version):
+ for part in parsed_version:
+ if (part[:1] == '*') and (part not in _final_parts):
+ return False
+ return True
+ index = setuptools.package_index.PackageIndex(
+ search_path=[setup_requirement_path])
+ if find_links:
+ index.add_find_links((find_links,))
+ req = pkg_resources.Requirement.parse(requirement)
+ if index.obtain(req) is not None:
+ best = []
+ bestv = None
+ for dist in index[req.project_name]:
+ distv = dist.parsed_version
+ if _final_version(distv):
+ if bestv is None or distv > bestv:
+ best = [dist]
+ bestv = distv
+ elif distv == bestv:
+ best.append(dist)
+ if best:
+ best.sort()
+ version = best[-1].version
+if version:
+ requirement = '=='.join((requirement, version))
+cmd.append(requirement)
+
if is_jython:
- assert subprocess.Popen(
- [sys.executable] + ['-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout'],
- env = dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse('setuptools')).location
- ),
- ).wait() == 0
+ import subprocess
+ exitcode = subprocess.Popen(cmd, env=env).wait()
+else: # Windows prefers this, apparently; otherwise we would prefer subprocess
+ exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env]))
+if exitcode != 0:
+ sys.stdout.flush()
+ sys.stderr.flush()
+ print("An error occurred when trying to install zc.buildout. "
+ "Look above this message for any errors that "
+ "were output by easy_install.")
+ sys.exit(exitcode)
-else:
- assert os.spawnle(
- os.P_WAIT, sys.executable, sys.executable,
- '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
- dict(os.environ,
- PYTHONPATH=
- ws.find(pkg_resources.Requirement.parse('setuptools')).location
- ),
- ) == 0
-
-ws.add_entry(tmpeggs)
-ws.require('zc.buildout')
+ws.add_entry(eggs_dir)
+ws.require(requirement)
import zc.buildout.buildout
-zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
-shutil.rmtree(tmpeggs)
+zc.buildout.buildout.main(args)
+if not options.eggs: # clean up temporary egg directory
+ shutil.rmtree(eggs_dir)
Modified: transaction/trunk/setup.py
===================================================================
--- transaction/trunk/setup.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/setup.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/__init__.py
===================================================================
--- transaction/trunk/transaction/__init__.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/__init__.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/_transaction.py
===================================================================
--- transaction/trunk/transaction/_transaction.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/_transaction.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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]
@@ -312,7 +315,8 @@
def commit(self):
if self.status is Status.DOOMED:
- raise interfaces.DoomedTransaction()
+ raise interfaces.DoomedTransaction(
+ 'transaction doomed, cannot commit')
if self._savepoint2index:
self._invalidate_all_savepoints()
@@ -335,7 +339,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 +375,7 @@
tb = None
try:
t, v, tb = self._saveAndGetCommitishError()
- raise t, v, tb
+ reraise(t, v, tb)
finally:
del t, v, tb
@@ -435,7 +439,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 +470,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 +519,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 +592,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 +618,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
@@ -694,7 +701,8 @@
def rollback(self):
transaction = self.transaction
if transaction is None:
- raise interfaces.InvalidSavepointRollbackError
+ raise interfaces.InvalidSavepointRollbackError(
+ 'invalidated by a later savepoint')
transaction._remove_and_invalidate_after(self)
try:
Copied: transaction/trunk/transaction/compat.py (from rev 123061, transaction/branches/chrism-py3/transaction/compat.py)
===================================================================
--- transaction/trunk/transaction/compat.py (rev 0)
+++ transaction/trunk/transaction/compat.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/interfaces.py
===================================================================
--- transaction/trunk/transaction/interfaces.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/interfaces.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/tests/convenience.txt
===================================================================
--- transaction/trunk/transaction/tests/convenience.txt 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/convenience.txt 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/tests/doom.txt
===================================================================
--- transaction/trunk/transaction/tests/doom.txt 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/doom.txt 2011-10-12 10:05:08 UTC (rev 123062)
@@ -77,14 +77,12 @@
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
+ DoomedTransaction: transaction doomed, cannot commit
+ >>> txn.commit() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
- ...
- DoomedTransaction
+ DoomedTransaction: transaction doomed, cannot commit
But still leaves the data manager unchanged:
Modified: transaction/trunk/transaction/tests/savepoint.txt
===================================================================
--- transaction/trunk/transaction/tests/savepoint.txt 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/savepoint.txt 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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,15 +184,15 @@
>>> dm['bob-balance']
100.0
- >>> savepoint2.rollback()
+ >>> savepoint2.rollback() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
- InvalidSavepointRollbackError
+ InvalidSavepointRollbackError: invalidated by a later savepoint
- >>> savepoint1.rollback()
+ >>> savepoint1.rollback() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
- InvalidSavepointRollbackError
+ InvalidSavepointRollbackError: invalidated by a later savepoint
>>> transaction.abort()
@@ -207,7 +207,7 @@
>>> dm_no_sp['name'] = 'bob'
>>> transaction.commit()
>>> dm_no_sp['name'] = 'sally'
- >>> savepoint = transaction.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/trunk/transaction/tests/savepointsample.py
===================================================================
--- transaction/trunk/transaction/tests/savepointsample.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/savepointsample.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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/trunk/transaction/tests/test_transaction.py
===================================================================
--- transaction/trunk/transaction/tests/test_transaction.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/test_transaction.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -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',), {})]
@@ -462,7 +463,7 @@
... pass
>>> class FailingDataManager:
... def tpc_begin(self, txn, sub=False):
- ... raise CommitFailure
+ ... raise CommitFailure('failed')
... def abort(self, txn):
... pass
@@ -470,10 +471,10 @@
>>> t.join(FailingDataManager())
>>> t.addBeforeCommitHook(hook, '2')
- >>> t.commit()
+ >>> t.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
- CommitFailure
+ CommitFailure: failed
>>> log
["arg '2' kw1 'no_kw1' kw2 'no_kw2'"]
>>> reset_log()
@@ -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',), {})]
@@ -599,7 +601,7 @@
... pass
>>> class FailingDataManager:
... def tpc_begin(self, txn):
- ... raise CommitFailure
+ ... raise CommitFailure('failed')
... def abort(self, txn):
... pass
@@ -607,10 +609,10 @@
>>> t.join(FailingDataManager())
>>> t.addAfterCommitHook(hook, '2')
- >>> t.commit()
+ >>> t.commit() #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
- CommitFailure
+ CommitFailure: failed
>>> log
["False arg '2' kw1 'no_kw1' kw2 'no_kw2'"]
>>> reset_log()
@@ -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']
"""
Modified: transaction/trunk/transaction/tests/test_weakset.py
===================================================================
--- transaction/trunk/transaction/tests/test_weakset.py 2011-10-12 09:25:44 UTC (rev 123061)
+++ transaction/trunk/transaction/tests/test_weakset.py 2011-10-12 10:05:08 UTC (rev 123062)
@@ -56,7 +56,7 @@
del dummy3
L = [x() for x in w.as_weakref_list()]
# L is a list, but it does not have a guaranteed order.
- self.assert_(list, type(L))
+ self.assertTrue(list, type(L))
self.assertEqual(set(L), set([dummy, dummy2]))
def test_map(self):
More information about the checkins
mailing list