← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/ztm-murder into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/ztm-murder into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/ztm-murder/+merge/75949

This branch is hopefully the penultimate phase of my ZopelessTransactionManager extermination campaign. It has been reduced to two public methods: initZopeless and uninstall. It is no longer a transaction manager -- just a database configuration modifier.

LaunchpadScript and ZopelessLayer set self.txn = transaction instead of using ZTM, and ZTM's begin/commit/abort methods are gone. sqlbase's begin/rollback/expire_from_cache convenience methods have also died, but commit() remains because it has many callsites, to be purged in another branch.

initZopeless also no longer returns ZTM.
-- 
https://code.launchpad.net/~wgrant/launchpad/ztm-murder/+merge/75949
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/ztm-murder into lp:launchpad.
=== modified file 'lib/canonical/database/ftests/script_isolation.py'
--- lib/canonical/database/ftests/script_isolation.py	2011-09-19 04:08:10 +0000
+++ lib/canonical/database/ftests/script_isolation.py	2011-09-19 04:53:24 +0000
@@ -16,6 +16,8 @@
     'ignore', '.*(md5|sha|sets)', DeprecationWarning,
     )
 
+import transaction
+
 from canonical.database.sqlbase import (
     cursor,
     ISOLATION_LEVEL_SERIALIZABLE,
@@ -31,8 +33,8 @@
     cur.execute("SHOW transaction_isolation")
     print cur.fetchone()[0]
 
-    txn.abort()
-    txn.begin()
+    transaction.abort()
+    transaction.begin()
 
     cur = cursor()
     cur.execute("UPDATE Person SET homepage_content='bar' WHERE name='mark'")
@@ -40,12 +42,14 @@
     print cur.fetchone()[0]
 
 # First confirm the default isolation level
-txn = ZopelessTransactionManager.initZopeless(dbuser='launchpad_main')
+ZopelessTransactionManager.initZopeless(dbuser='launchpad_main')
 check()
-txn.uninstall()
+ZopelessTransactionManager.uninstall()
 
-txn = ZopelessTransactionManager.initZopeless(
+# We run the checks twice to ensure that both methods of setting the
+# isolation level stick across transaction boundaries.
+ZopelessTransactionManager.initZopeless(
     dbuser='launchpad_main',
     isolation=ISOLATION_LEVEL_SERIALIZABLE)
 check()
-txn.uninstall()
+ZopelessTransactionManager.uninstall()

=== modified file 'lib/canonical/database/ftests/test_zopelesstransactionmanager.txt'
--- lib/canonical/database/ftests/test_zopelesstransactionmanager.txt	2011-09-19 04:08:10 +0000
+++ lib/canonical/database/ftests/test_zopelesstransactionmanager.txt	2011-09-19 04:53:24 +0000
@@ -12,19 +12,12 @@
 class method.
 
     >>> from canonical.database.sqlbase import ZopelessTransactionManager
-    >>> ztm = ZopelessTransactionManager.initZopeless(
-    ...     dbuser='launchpad_main')
-
-The returned transaction manager happens to be the same as the
-ZopelessTransactionManager class:
-
-    >>> ztm is ZopelessTransactionManager
-    True
+    >>> ZopelessTransactionManager.initZopeless(dbuser='launchpad_main')
 
 After initZopeless() has been called, the '_installed' attribute of
 ZopelessTransactionManager will be set to the transaction manager:
 
-    >>> ZopelessTransactionManager._installed is ztm
+    >>> ZopelessTransactionManager._installed is ZopelessTransactionManager
     True
 
 The initZopeless() call defaults to read committed isolation:
@@ -35,47 +28,30 @@
     >>> print c.fetchone()[0]
     read committed
 
-We can commit transactions:
-
-    >>> c.execute("UPDATE person SET name = 'something' WHERE id = 1")
-    >>> ztm.commit()
-
-We can also explicitly start transactions with begin(), and abort
-transactions:
-
-    >>> ztm.begin()
-    >>> c = cursor()
-    >>> c.execute("UPDATE person SET name = 'blah' WHERE id = 1")
-    >>> ztm.abort()
-    >>> c = cursor()
-    >>> c.execute("SELECT name FROM person WHERE id = 1")
-    >>> print c.fetchone()[0]
-    something
-
 The uninstall() method can be used to uninstall the transaction
 manager:
 
-    >>> ztm.uninstall()
+    >>> ZopelessTransactionManager.uninstall()
     >>> print ZopelessTransactionManager._installed
     None
 
 We can log in as alternative users with initZopeless():
 
-    >>> ztm = ZopelessTransactionManager.initZopeless(dbuser='testadmin')
+    >>> ZopelessTransactionManager.initZopeless(dbuser='testadmin')
     >>> c = cursor()
     >>> c.execute("SELECT current_user")
     >>> print c.fetchone()[0]
     testadmin
-    >>> ztm.uninstall()
+    >>> ZopelessTransactionManager.uninstall()
 
 Or we can specify other transaction isolation modes:
 
     >>> from canonical.database.sqlbase import (
     ...     ISOLATION_LEVEL_SERIALIZABLE)
-    >>> ztm = ZopelessTransactionManager.initZopeless(
+    >>> ZopelessTransactionManager.initZopeless(
     ...     dbuser='librarian', isolation=ISOLATION_LEVEL_SERIALIZABLE)
     >>> c = cursor()
     >>> c.execute("SHOW transaction_isolation")
     >>> print c.fetchone()[0]
     serializable
-    >>> ztm.uninstall()
+    >>> ZopelessTransactionManager.uninstall()

=== modified file 'lib/canonical/database/sqlbase.py'
--- lib/canonical/database/sqlbase.py	2011-09-18 08:11:37 +0000
+++ lib/canonical/database/sqlbase.py	2011-09-19 04:53:24 +0000
@@ -4,7 +4,6 @@
 __metaclass__ = type
 __all__ = [
     'alreadyInstalledMsg',
-    'begin',
     'block_implicit_flushes',
     'clear_current_connection_cache',
     'commit',
@@ -12,7 +11,6 @@
     'connect',
     'convert_storm_clause_to_string',
     'cursor',
-    'expire_from_cache',
     'flush_database_caches',
     'flush_database_updates',
     'get_transaction_timestamp',
@@ -25,7 +23,6 @@
     'quoteIdentifier',
     'quote_identifier',
     'reset_store',
-    'rollback',
     'session_store',
     'SQLBase',
     'sqlvalues',
@@ -328,7 +325,6 @@
             cls._isolation = isolation
             cls._reset_stores()
             cls._installed = cls
-        return cls._installed
 
     @staticmethod
     def _reset_stores():
@@ -370,21 +366,6 @@
         cls._reset_stores()
         cls._installed = None
 
-    @staticmethod
-    def begin():
-        """Begin a transaction."""
-        transaction.begin()
-
-    @staticmethod
-    def commit():
-        """Commit the current transaction."""
-        transaction.commit()
-
-    @staticmethod
-    def abort():
-        """Abort the current transaction."""
-        transaction.abort()
-
 
 def clear_current_connection_cache():
     """Clear SQLObject's object cache. SQLObject compatibility - DEPRECATED.
@@ -392,12 +373,6 @@
     _get_sqlobject_store().invalidate()
 
 
-def expire_from_cache(obj):
-    """Expires a single object from the SQLObject cache.
-    SQLObject compatibility - DEPRECATED."""
-    _get_sqlobject_store().invalidate(obj)
-
-
 def get_transaction_timestamp():
     """Get the timestamp for the current transaction on the MAIN DEFAULT
     store. DEPRECATED - if needed it should become a method on the store.
@@ -695,18 +670,7 @@
     return mergeFunctionMetadata(func, reset_store_decorator)
 
 
-# Some helpers intended for use with initZopeless.  These allow you to avoid
-# passing the transaction manager all through your code.
-
-def begin():
-    """Begins a transaction."""
-    transaction.begin()
-
-
-def rollback():
-    transaction.abort()
-
-
+# DEPRECATED -- use transaction.commit() directly.
 def commit():
     transaction.commit()
 

=== modified file 'lib/canonical/database/tests/test_zopeless_transaction_manager.py'
--- lib/canonical/database/tests/test_zopeless_transaction_manager.py	2011-09-13 12:14:00 +0000
+++ lib/canonical/database/tests/test_zopeless_transaction_manager.py	2011-09-19 04:53:24 +0000
@@ -50,17 +50,16 @@
         warnings.warn = self.warn_hooked
         self.warned = False
         try:
-            # Calling initZopeless with the same arguments twice should return
-            # the exact same object twice, but also emit a warning.
+            # Calling initZopeless with the same arguments twice should emit
+            # a warning.
             try:
-                tm1 = ZopelessTransactionManager.initZopeless(
-                    dbuser='launchpad')
-                tm2 = ZopelessTransactionManager.initZopeless(
-                    dbuser='launchpad')
-                self.failUnless(tm1 is tm2)
+                ZopelessTransactionManager.initZopeless(
+                    dbuser='launchpad')
+                ZopelessTransactionManager.initZopeless(
+                    dbuser='launchpad')
                 self.failUnless(self.warned)
             finally:
-                tm1.uninstall()
+                ZopelessTransactionManager.uninstall()
         finally:
             # Put the warnings module back the way we found it.
             warnings.warn = original_warn

=== modified file 'lib/canonical/testing/layers.py'
--- lib/canonical/testing/layers.py	2011-09-18 07:15:22 +0000
+++ lib/canonical/testing/layers.py	2011-09-19 04:53:24 +0000
@@ -1510,7 +1510,7 @@
     """
 
     isSetUp = False
-    txn = ZopelessTransactionManager
+    txn = transaction
 
     @classmethod
     @profiled

=== modified file 'lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt'
--- lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt	2010-10-14 17:37:39 +0000
+++ lib/lp/archiveuploader/tests/nascentupload-epoch-handling.txt	2011-09-19 04:53:24 +0000
@@ -78,8 +78,8 @@
 
 Clean up this change and carry on:
 
-    >>> from canonical.database.sqlbase import rollback
-    >>> rollback()
+    >>> import transaction
+    >>> transaction.abort()
 
 
 === Collision in queue DONE ===
@@ -182,7 +182,7 @@
 
 Clean up this change and carry on:
 
-    >>> rollback()
+    >>> transaction.abort()
 
 
 == Dealing with Epochs and diverging binary versions ==

=== modified file 'lib/lp/bugs/doc/bug-export.txt'
--- lib/lp/bugs/doc/bug-export.txt	2010-10-18 22:24:59 +0000
+++ lib/lp/bugs/doc/bug-export.txt	2011-09-19 04:53:24 +0000
@@ -81,10 +81,8 @@
 the bugs for a product.  The export_bugtasks() function does this by
 successively serialising each of the tasks for that product.
 
-  >>> from canonical.database.sqlbase import ZopelessTransactionManager
-  >>> ztm = ZopelessTransactionManager._installed
-
-  >>> export_bugtasks(ztm, firefox, sys.stdout)
+  >>> import transaction
+  >>> export_bugtasks(transaction, firefox, sys.stdout)
   <launchpad-bugs xmlns="https://launchpad.net/xmlns/2006/bugs";>
   <bug id="1">
   ...
@@ -128,7 +126,7 @@
   ...                    'Added attachment', 'hello.txt',
   ...                    description='"Hello World" attachment')
   <BugAttachment ...>
-  >>> ztm.commit()
+  >>> transaction.commit()
 
 A reference to the attachment is included with the new comment with
 the attachment contents encoded using base-64:
@@ -163,13 +161,13 @@
 
   >>> bug1.setPrivate(True, getUtility(ILaunchBag).user)
   True
-  >>> ztm.commit()
+  >>> transaction.commit()
 
 
 Now we'll do a dump not including private bugs:
 
   >>> output = StringIO()
-  >>> export_bugtasks(ztm, firefox, output)
+  >>> export_bugtasks(transaction, firefox, output)
   >>> '<bug id="1">' in output.getvalue()
   False
 
@@ -177,6 +175,6 @@
 However, bug #1 will appear in the export if we include private bugs:
 
   >>> output = StringIO()
-  >>> export_bugtasks(ztm, firefox, output, include_private=True)
+  >>> export_bugtasks(transaction, firefox, output, include_private=True)
   >>> '<bug id="1">' in output.getvalue()
   True

=== modified file 'lib/lp/bugs/doc/checkwatches-cli-switches.txt'
--- lib/lp/bugs/doc/checkwatches-cli-switches.txt	2011-03-23 16:28:51 +0000
+++ lib/lp/bugs/doc/checkwatches-cli-switches.txt	2011-09-19 04:53:24 +0000
@@ -5,8 +5,7 @@
 the updateBugTrackers() method.
 
     >>> import transaction
-    >>> from canonical.database.sqlbase import (
-    ...     cursor, sqlvalues, ZopelessTransactionManager)
+    >>> from canonical.database.sqlbase import cursor, sqlvalues
     >>> from canonical.database.constants import UTC_NOW
     >>> from lp.services.log.logger import FakeLogger
     >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster
@@ -19,8 +18,7 @@
     ...     sqlvalues(UTC_NOW))
     >>> transaction.commit()
 
-    >>> transactionmgr = ZopelessTransactionManager._installed
-    >>> updater = CheckwatchesMaster(transactionmgr, logger=FakeLogger())
+    >>> updater = CheckwatchesMaster(transaction, logger=FakeLogger())
 
     >>> updater.updateBugTrackers(['debbugs', 'gnome-bugzilla'])
     DEBUG...No watches to update on http://bugs.debian.org
@@ -52,7 +50,7 @@
     ...     def __init__(self, name, dbuser=None, test_args=None):
     ...         super(TestCheckWatchesCronScript, self).__init__(
     ...             name, dbuser, test_args)
-    ...         self.txn = ZopelessTransactionManager
+    ...         self.txn = transaction
     ...
     ...     def handle_options(self):
     ...         self.logger = FakeLogger()

=== modified file 'lib/lp/bugs/mail/handler.py'
--- lib/lp/bugs/mail/handler.py	2011-09-15 17:25:54 +0000
+++ lib/lp/bugs/mail/handler.py	2011-09-19 04:53:24 +0000
@@ -13,11 +13,11 @@
 
 from lazr.lifecycle.event import ObjectCreatedEvent
 from lazr.lifecycle.interfaces import IObjectCreatedEvent
+import transaction
 from zope.component import getUtility
 from zope.event import notify
 from zope.interface import implements
 
-from canonical.database.sqlbase import rollback
 from canonical.launchpad.helpers import get_email_template
 from canonical.launchpad.mailnotification import (
     MailWrapper,
@@ -300,7 +300,7 @@
                     processing_errors.append((error, command))
                     if error.stop_processing:
                         commands = []
-                        rollback()
+                        transaction.abort()
                     else:
                         continue
 
@@ -431,7 +431,7 @@
                 notify(bugtask_event)
 
     def handleNoAffectsTarget(self):
-        rollback()
+        transaction.abort()
         raise IncomingEmailError(
             get_error_message(
                 'no-affects-target-on-submit.txt',

=== modified file 'lib/lp/codehosting/scanner/tests/test_bzrsync.py'
--- lib/lp/codehosting/scanner/tests/test_bzrsync.py	2011-08-18 15:33:25 +0000
+++ lib/lp/codehosting/scanner/tests/test_bzrsync.py	2011-09-19 04:53:24 +0000
@@ -24,6 +24,7 @@
 from zope.security.proxy import removeSecurityProxy
 
 from canonical.config import config
+from canonical.database.sqlbase import ZopelessTransactionManager
 from canonical.launchpad.interfaces.lpstorm import IStore
 from canonical.testing.layers import LaunchpadZopelessLayer
 from lp.code.interfaces.branchjob import IRosettaUploadJobSource
@@ -65,7 +66,7 @@
     def _run_with_different_user(f):
 
         def decorated(*args, **kwargs):
-            current_user = LaunchpadZopelessLayer.txn._dbuser
+            current_user = ZopelessTransactionManager._dbuser
             if current_user == username:
                 return f(*args, **kwargs)
             LaunchpadZopelessLayer.switchDbUser(username)

=== modified file 'lib/lp/services/scripts/base.py'
--- lib/lp/services/scripts/base.py	2011-09-18 07:20:04 +0000
+++ lib/lp/services/scripts/base.py	2011-09-19 04:53:24 +0000
@@ -30,6 +30,7 @@
     LockAlreadyAcquired,
     )
 import pytz
+import transaction
 from zope.component import getUtility
 
 from canonical.config import config, dbconfig
@@ -359,8 +360,9 @@
         if dbuser is None:
             connstr = ConnectionString(dbconfig.main_master)
             dbuser = connstr.user or dbconfig.dbuser
-        self.txn = ZopelessTransactionManager.initZopeless(
+        ZopelessTransactionManager.initZopeless(
             dbuser=dbuser, isolation=isolation)
+        self.txn = transaction
 
     def record_activity(self, date_started, date_completed):
         """Hook to record script activity."""

=== modified file 'lib/lp/testing/dbuser.py'
--- lib/lp/testing/dbuser.py	2011-02-07 20:41:06 +0000
+++ lib/lp/testing/dbuser.py	2011-09-19 04:53:24 +0000
@@ -11,29 +11,34 @@
 
 from contextlib import contextmanager
 
+import transaction
+
+from canonical.database.sqlbase import ZopelessTransactionManager
 from canonical.testing.layers import LaunchpadZopelessLayer
 
+
 @contextmanager
 def dbuser(temporary_name):
     """A context manager that temporarily changes the dbuser.
-    
+
     Use with the LaunchpadZopelessLayer layer and subclasses.
-    
+
     temporary_name is the name of the dbuser that should be in place for the
     code in the "with" block.
     """
-    restore_name = LaunchpadZopelessLayer.txn._dbuser
-    LaunchpadZopelessLayer.txn.commit()
+    restore_name = ZopelessTransactionManager._dbuser
+    transaction.commit()
     # Note that this will raise an assertion error if the
     # LaunchpadZopelessLayer is not already set up.
     LaunchpadZopelessLayer.switchDbUser(temporary_name)
     yield
-    LaunchpadZopelessLayer.txn.commit()
+    transaction.commit()
     LaunchpadZopelessLayer.switchDbUser(restore_name)
 
+
 def lp_dbuser():
     """A context manager that temporarily changes to the launchpad dbuser.
-    
+
     Use with the LaunchpadZopelessLayer layer and subclasses.
     """
     return dbuser('launchpad')

=== modified file 'lib/lp/translations/utilities/tests/helpers.py'
--- lib/lp/translations/utilities/tests/helpers.py	2011-05-27 19:53:20 +0000
+++ lib/lp/translations/utilities/tests/helpers.py	2011-09-19 04:53:24 +0000
@@ -13,10 +13,6 @@
 import transaction
 from zope.component import getUtility
 
-from canonical.database.sqlbase import (
-    commit,
-    ZopelessTransactionManager,
-    )
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.services.log.logger import FakeLogger
 from lp.translations.enums import RosettaImportStatus
@@ -66,10 +62,7 @@
                 potemplate=potemplate)
         target = potemplate
     # Allow Librarian to see the change.
-    if ZopelessTransactionManager._installed is None:
-        transaction.commit()
-    else:
-        commit()
+    transaction.commit()
 
     entry.setStatus(RosettaImportStatus.APPROVED,
                     getUtility(ILaunchpadCelebrities).rosetta_experts)


Follow ups