[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