← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~bryceharrington/launchpad/lp-176906-importance into lp:launchpad/devel

 

Bryce Harrington has proposed merging lp:~bryceharrington/launchpad/lp-176906-importance into lp:launchpad/devel.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers): code
Related bugs:
  #176906 Display imported Bugzilla Severity field (instead of Unknown)
  https://bugs.launchpad.net/bugs/176906


Currently, bug watches display Status but not Importance for the upstream bug.  This branch implements the functionality to show the 'priority' and 'severity' in the Importance field.

Also provided is a function to convert Bugzilla severities (or priority if severity is not available) into Launchpad importance.

Please note that this also modifies the sample data, to add severity and priority to several bug watches.


I had a pre-implementation meeting with gmb at the Epic to go through the existing bugtracker codebase and go over what was needed.

The code changes themselves are fairly straightforward and modest, the test updates are more extensive, mainly because they're testing a range of different Bugzilla variants.

My local testing has mostly been done using the command: `./bin/test -t bugzilla`.  One other affected test case is caught by `test -t bug-xx`.  I've also run `test -m bugs` locally, and the full test suite via EC2 to verify the testsuites pass.

For Q/A, when this change is on staging, bugs with bug watches should all start displaying something other than "Unknown".  For instance, the bug watch on lp #137234 should show 'Medium Major'.

I've lint checked the code and cleaned up a bunch of pre-existing lint issues, particularly in the doctests, so this branch has a resultant net reduction in lint errors.  There were some lint errors in the existing code caused by whitespace which I've left as is because I think the whitespace makes the code more readable.


-- 
https://code.launchpad.net/~bryceharrington/launchpad/lp-176906-importance/+merge/32511
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~bryceharrington/launchpad/lp-176906-importance into lp:launchpad/devel.
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql	2010-08-10 05:50:08 +0000
+++ database/sampledata/current-dev.sql	2010-08-12 20:06:35 +0000
@@ -1571,6 +1571,28 @@
 ALTER TABLE bugjob ENABLE TRIGGER ALL;
 
 
+<<<<<<< TREE
+=======
+ALTER TABLE bugwatch DISABLE TRIGGER ALL;
+
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (1, 2, 1, '42', 'FUBAR', '2004-09-24 20:58:04.740841', '2004-09-24 20:58:04.740841', '2004-09-24 20:58:04.740841', 12, NULL, 'BAZBAZ', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (2, 1, 1, '2000', '', '2004-10-04 01:00:00', '2004-10-04 01:00:00', '2004-10-04 01:00:00', 1, NULL, '', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (3, 1, 1, '123543', '', '2004-10-04 00:00:00', '2004-10-04 00:00:00', '2004-10-04 00:00:00', 1, NULL, '', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (4, 2, 2, '3224', '', '2004-10-05 00:00:00', '2004-10-05 00:00:00', '2004-10-05 00:00:00', 1, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (5, 1, 1, '42', 'FUBAR', '2004-09-24 20:59:04.740841', '2004-09-24 20:59:04.740841', '2004-09-24 20:59:04.740841', 12, NULL, 'BAZBAZ', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (6, 9, 4, '1234', NULL, '2006-02-23 16:43:25.744534', NULL, '2006-02-23 16:43:25.744534', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (7, 7, 3, '280883', NULL, '2006-03-29 16:45:45.054836', NULL, '2006-03-29 16:45:45.054836', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (8, 1, 3, '304014', NULL, '2006-03-29 16:46:54.407686', NULL, '2006-03-29 16:46:54.407686', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (9, 2, 3, '327452', NULL, '2006-03-29 16:47:51.515017', NULL, '2006-03-29 16:47:51.515017', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (10, 3, 3, '327549', NULL, '2006-03-29 16:48:18.807764', NULL, '2006-03-29 16:48:18.807764', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (11, 15, 3, '308994', 'open important', '2007-12-18 16:31:34.790641', '2007-12-18 16:31:34.790641', '2007-12-18 16:30:47.889614', 16, NULL, 'UNKNOWN', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (12, 15, 2, '304070', NULL, NULL, NULL, '2007-12-18 16:31:34.790641', 243614, 2, NULL, NULL, NULL);
+
+
+ALTER TABLE bugwatch ENABLE TRIGGER ALL;
+
+
+>>>>>>> MERGE-SOURCE
 ALTER TABLE bugmessage DISABLE TRIGGER ALL;
 
 INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (1, 2, 1, NULL, NULL, true);

=== modified file 'database/sampledata/current.sql'
--- database/sampledata/current.sql	2010-08-10 05:50:08 +0000
+++ database/sampledata/current.sql	2010-08-12 20:06:35 +0000
@@ -1552,6 +1552,28 @@
 ALTER TABLE bugjob ENABLE TRIGGER ALL;
 
 
+<<<<<<< TREE
+=======
+ALTER TABLE bugwatch DISABLE TRIGGER ALL;
+
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (1, 2, 1, '42', 'FUBAR', '2004-09-24 20:58:04.740841', '2004-09-24 20:58:04.740841', '2004-09-24 20:58:04.740841', 12, NULL, 'BAZBAZ', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (2, 1, 1, '2000', '', '2004-10-04 01:00:00', '2004-10-04 01:00:00', '2004-10-04 01:00:00', 1, NULL, '', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (3, 1, 1, '123543', '', '2004-10-04 00:00:00', '2004-10-04 00:00:00', '2004-10-04 00:00:00', 1, NULL, '', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (4, 2, 2, '3224', '', '2004-10-05 00:00:00', '2004-10-05 00:00:00', '2004-10-05 00:00:00', 1, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (5, 1, 1, '42', 'FUBAR', '2004-09-24 20:59:04.740841', '2004-09-24 20:59:04.740841', '2004-09-24 20:59:04.740841', 12, NULL, 'BAZBAZ', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (6, 9, 4, '1234', NULL, '2006-02-23 16:43:25.744534', NULL, '2006-02-23 16:43:25.744534', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (7, 7, 3, '280883', NULL, '2006-03-29 16:45:45.054836', NULL, '2006-03-29 16:45:45.054836', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (8, 1, 3, '304014', NULL, '2006-03-29 16:46:54.407686', NULL, '2006-03-29 16:46:54.407686', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (9, 2, 3, '327452', NULL, '2006-03-29 16:47:51.515017', NULL, '2006-03-29 16:47:51.515017', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (10, 3, 3, '327549', NULL, '2006-03-29 16:48:18.807764', NULL, '2006-03-29 16:48:18.807764', 12, NULL, NULL, NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (11, 15, 3, '308994', 'open important', '2007-12-18 16:31:34.790641', '2007-12-18 16:31:34.790641', '2007-12-18 16:30:47.889614', 16, NULL, 'UNKNOWN', NULL, NULL);
+INSERT INTO bugwatch (id, bug, bugtracker, remotebug, remotestatus, lastchanged, lastchecked, datecreated, owner, last_error_type, remote_importance, remote_lp_bug_id, next_check) VALUES (12, 15, 2, '304070', NULL, NULL, NULL, '2007-12-18 16:31:34.790641', 243614, 2, NULL, NULL, NULL);
+
+
+ALTER TABLE bugwatch ENABLE TRIGGER ALL;
+
+
+>>>>>>> MERGE-SOURCE
 ALTER TABLE bugmessage DISABLE TRIGGER ALL;
 
 INSERT INTO bugmessage (id, bug, message, bugwatch, remote_comment_id, visible) VALUES (1, 2, 1, NULL, NULL, true);

=== modified file 'database/sampledata/malone.sql'
--- database/sampledata/malone.sql	2009-06-24 21:17:33 +0000
+++ database/sampledata/malone.sql	2010-08-12 20:06:35 +0000
@@ -196,10 +196,11 @@
     (SELECT id FROM Person WHERE displayname='Sample Person'),
     'Carrier pidgeon only'
     );
-INSERT INTO BugWatch (bug, bugsystem, remotebug, remotestatus, owner) VALUES (
+INSERT INTO BugWatch (bug, bugsystem, remotebug, remotestatus, remote_importance, owner) VALUES (
     (SELECT id FROM Bug WHERE name='blackhole'),
     (SELECT id FROM BugSystem WHERE name='mozilla.org'),
     '42',
     'FUBAR',
+    'BAZBAZ',
     (SELECT id FROM Person WHERE displayname='Sample Person')
     );

=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt	2010-04-20 15:44:58 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-api.txt	2010-08-12 20:06:35 +0000
@@ -246,6 +246,15 @@
     >>> print bugzilla.getRemoteStatus(2)
     NEW
 
+Similarly with BugzillaAPI.getRemoteStatus(), which returns the remote
+priority and severity as a string.
+
+    >>> print bugzilla.getRemoteImportance(1)
+    P1 normal
+
+    >>> print bugzilla.getRemoteImportance(2)
+    P1 high
+
 If a bug can't be found a BugNotFound error will be raised.
 
     >>> bugzilla.getRemoteStatus('no-such-bug')

=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla-oddities.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla-oddities.txt	2010-04-21 10:30:24 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla-oddities.txt	2010-08-12 20:06:35 +0000
@@ -9,8 +9,8 @@
 
 We support Issuezilla-style trackers. These trackers are essentially
 modified (ancient) versions of Bugzilla; their XML elements have
-slightly different names. We pretend Mozilla's Bugzilla is an Issuezilla
-instance here:
+slightly different names, and they lack the severity field. We pretend
+Mozilla's Bugzilla is an Issuezilla instance here:
 
     >>> from canonical.launchpad.interfaces import IBugTrackerSet
 
@@ -23,11 +23,12 @@
     >>> issuezilla._probe_version()
     (2, 11)
     >>> for bug_watch in mozilla_bugzilla.watches:
-    ...     print "%s: %s" % (bug_watch.remotebug, bug_watch.remotestatus)
-    2000:
-    123543:
-    42: FUBAR
-    42: FUBAR
+    ...     print "%s: %s %s" % (bug_watch.remotebug,
+    ...         bug_watch.remotestatus, bug_watch.remote_importance)
+    2000:  
+    123543:  
+    42: FUBAR BAZBAZ
+    42: FUBAR BAZBAZ
     >>> transaction.commit()
     >>> bug_watch_updater = CheckwatchesMaster(txn)
     >>> bug_watch_updater.updateBugWatches(
@@ -37,11 +38,12 @@
     (local bugs: 1, 2). (OOPS-...)
 
     >>> for bug_watch in mozilla_bugzilla.watches:
-    ...     print "%s: %s" % (bug_watch.remotebug, bug_watch.remotestatus)
-    2000: RESOLVED FIXED
-    123543: ASSIGNED
-    42: FUBAR
-    42: FUBAR
+    ...     print "%s: %s %s" % (bug_watch.remotebug,
+    ...         bug_watch.remotestatus, bug_watch.remote_importance)
+    2000: RESOLVED FIXED LOW
+    123543: ASSIGNED HIGH
+    42: FUBAR BAZBAZ
+    42: FUBAR BAZBAZ
 
 
 Bugzilla prior to 2.11
@@ -71,10 +73,12 @@
     >>> remote_bugs = ['42', '123543']
     >>> old_bugzilla.initializeRemoteBugDB(remote_bugs)
     >>> for remote_bug in remote_bugs:
-    ...     print "%s: %s" % (
-    ...         remote_bug, old_bugzilla.getRemoteStatus(remote_bug))
-    42: RESOLVED FIXED
-    123543: ASSIGNED
+    ...     print "%s: %s %s" % (
+    ...         remote_bug,
+    ...         old_bugzilla.getRemoteStatus(remote_bug),
+    ...         old_bugzilla.getRemoteImportance(remote_bug))
+    42: RESOLVED FIXED LOW BLOCKER
+    123543: ASSIGNED HIGH BLOCKER
 
 
 Bugzilla oddities
@@ -106,10 +110,12 @@
     >>> remote_bugs = ['2000', '123543']
     >>> weird_bugzilla.initializeRemoteBugDB(remote_bugs)
     >>> for remote_bug in remote_bugs:
-    ...     print "%s: %s" % (
-    ...         remote_bug, weird_bugzilla.getRemoteStatus(remote_bug))
-    2000: ASSIGNED
-    123543: RESOLVED FIXED
+    ...     print "%s: %s %s" % (
+    ...         remote_bug,
+    ...         weird_bugzilla.getRemoteStatus(remote_bug),
+    ...         weird_bugzilla.getRemoteImportance(remote_bug))
+    2000: ASSIGNED HIGH BLOCKER
+    123543: RESOLVED FIXED HIGH BLOCKER
 
 
 Broken Bugzillas

=== modified file 'lib/lp/bugs/doc/externalbugtracker-bugzilla.txt'
--- lib/lp/bugs/doc/externalbugtracker-bugzilla.txt	2010-04-21 10:30:24 +0000
+++ lib/lp/bugs/doc/externalbugtracker-bugzilla.txt	2010-08-12 20:06:35 +0000
@@ -1,11 +1,13 @@
-= ExternalBugTracker: Bugzilla =
+ExternalBugTracker: Bugzilla
+============================
 
 An ExternalBugtracker is used to talk to remote bug trackers and update bug
 watches. This document describes how the Bugzilla implementation of
 ExternalBugTracker works.
 
 
-== Basics ==
+Basics
+------
 
 The class that implements ExternalBugTracker is called Bugzilla.
 
@@ -58,14 +60,16 @@
 
     >>> from lp.bugs.tests.externalbugtracker import TestBugzilla
     >>> from canonical.launchpad.interfaces import IBugTrackerSet
-    >>> gnome_bugzilla = getUtility(IBugTrackerSet).getByName('gnome-bugzilla')
+    >>> gnome_bugzilla = \
+    ...     getUtility(IBugTrackerSet).getByName('gnome-bugzilla')
     >>> external_bugzilla = TestBugzilla(gnome_bugzilla.baseurl)
     >>> version = external_bugzilla._probe_version()
     >>> version
     (2, 20)
 
 
-== Launchpad plugin ==
+Launchpad plugin
+----------------
 
 Some Bugzillas offer the Bugzilla 3.4 XML-RPC API or have a Launchpad
 plugin installed. For these bugtrackers, we use the BugzillaAPI
@@ -258,7 +262,8 @@
     False
 
 
-== Status Conversion ==
+Status Conversion
+-----------------
 
 It contains a function for converting one of its own status to a Malone
 status. Bugzilla statuses consist of two parts, the status, and the
@@ -306,7 +311,75 @@
     UnknownRemoteStatusError: FOO
 
 
-== Updating Bug Watches ==
+Importance Conversion
+---------------------
+
+There is also a function for conversion of bugzilla importances to
+launchpad importances.  The Bugzilla importance is comprised of priority
+and severity, but we only use severity in mapping the value unless it
+isn't available in which case we map against priority values.
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT BLOCKER').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('LOW BLOCKER').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('BLOCKER').title
+    'Critical'
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT CRITICAL').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('LOW CRITICAL').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('CRITICAL').title
+    'Critical'
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT MAJOR').title
+    'High'
+    >>> external_bugzilla.convertRemoteImportance('LOW MAJOR').title
+    'High'
+    >>> external_bugzilla.convertRemoteImportance('MAJOR').title
+    'High'
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT NORMAL').title
+    'Medium'
+    >>> external_bugzilla.convertRemoteImportance('LOW NORMAL').title
+    'Medium'
+    >>> external_bugzilla.convertRemoteImportance('NORMAL').title
+    'Medium'
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT MINOR').title
+    'Low'
+    >>> external_bugzilla.convertRemoteImportance('LOW MINOR').title
+    'Low'
+    >>> external_bugzilla.convertRemoteImportance('MINOR').title
+    'Low'
+
+    >>> external_bugzilla.convertRemoteImportance('URGENT TRIVIAL').title
+    'Low'
+    >>> external_bugzilla.convertRemoteImportance('LOW TRIVIAL').title
+    'Low'
+    >>> external_bugzilla.convertRemoteImportance('TRIVIAL').title
+    'Low'
+
+    >>> external_bugzilla.convertRemoteImportance('LOW ENHANCEMENT').title
+    'Wishlist'
+    >>> external_bugzilla.convertRemoteImportance('ENHANCEMENT').title
+    'Wishlist'
+
+    >>> external_bugzilla.convertRemoteImportance('IMMEDIATE').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('URGENT').title
+    'Critical'
+    >>> external_bugzilla.convertRemoteImportance('HIGH').title
+    'High'
+    >>> external_bugzilla.convertRemoteImportance('MEDIUM').title
+    'Medium'
+    >>> external_bugzilla.convertRemoteImportance('LOW').title
+    'Low'
+
+
+Updating Bug Watches
+--------------------
 
 The main use of an ExternalBugtracker is to update bug watches. This is
 done through updateBugWatches(), which expects a list of bug watches to
@@ -315,9 +388,11 @@
     >>> from lp.bugs.scripts.checkwatches import CheckwatchesMaster
     >>> bug_watch_updater = CheckwatchesMaster(txn)
     >>> for bug_watch in gnome_bugzilla.watches:
-    ...     print "%s: %s" % (bug_watch.remotebug, bug_watch.remotestatus)
-    304070: None
-    3224:
+    ...     print "%s: %s %s" % (bug_watch.remotebug,
+    ...           bug_watch.remotestatus,
+    ...           bug_watch.remote_importance)
+    304070: None None
+    3224:  None
     >>> bug_watch_updater.updateBugWatches(
     ...     external_bugzilla, gnome_bugzilla.watches)
     INFO:...:Updating 2 watches for 2 bugs on http://bugzilla.gnome.org/bugs
@@ -325,28 +400,35 @@
     http://bugzilla.gnome.org/bugs (local bugs: 15). (OOPS-...)
 
     >>> for bug_watch in gnome_bugzilla.watches:
-    ...     print "%s: %s" % (bug_watch.remotebug, bug_watch.remotestatus)
-    304070: None
-    3224: RESOLVED FIXED
+    ...     print "%s: %s %s" % (bug_watch.remotebug,
+    ...           bug_watch.remotestatus,
+    ...           bug_watch.remote_importance)
+    304070: None None
+    3224: RESOLVED FIXED MINOR URGENT
 
 Let's add a handful of watches:
 
     >>> from canonical.launchpad.interfaces import (
     ...     IBugSet, IBugWatchSet, IPersonSet)
-    >>> sample_person = getUtility(IPersonSet).getByEmail('test@xxxxxxxxxxxxx')
+    >>> sample_person = getUtility(IPersonSet).getByEmail(
+    ...     'test@xxxxxxxxxxxxx')
     >>> bug_one = getUtility(IBugSet).get(1)
     >>> bug_watch_set = getUtility(IBugWatchSet)
 
     >>> expected_remote_statuses = dict(
     ...     [(int(bug_watch.remotebug), bug_watch.remotestatus)
     ...      for bug_watch in gnome_bugzilla.watches])
+    >>> expected_remote_importances = dict(
+    ...     [(int(bug_watch.remotebug), bug_watch.remote_importance)
+    ...      for bug_watch in gnome_bugzilla.watches])
     >>> for remote_bug_id in range(50,55):
     ...     bug_watch = bug_watch_set.createBugWatch(
     ...         bug=bug_one, owner=sample_person, bugtracker=gnome_bugzilla,
     ...         remotebug=str(remote_bug_id))
     ...     external_bugzilla.bugzilla_bugs[remote_bug_id] = (
-    ...         'RESOLVED', 'FIXED')
+    ...         'RESOLVED', 'FIXED', 'HIGH', 'ENHANCEMENT')
     ...     expected_remote_statuses[remote_bug_id] = 'RESOLVED FIXED'
+    ...     expected_remote_importances[remote_bug_id] = 'HIGH ENHANCEMENT'
     >>> from canonical.launchpad.ftests import sync
     >>> for bug_watch in gnome_bugzilla.watches:
     ...     sync(bug_watch)
@@ -377,6 +459,12 @@
     >>> remote_statuses == expected_remote_statuses
     True
 
+    >>> remote_importances = dict(
+    ...     [(int(bug_watch.remotebug), bug_watch.remote_importance)
+    ...      for bug_watch in gnome_bugzilla.watches])
+    >>> remote_importances == expected_remote_importances
+    True
+
     >>> external_bugzilla.trace_calls = False
 
 Let's add a few more watches:
@@ -384,13 +472,17 @@
     >>> expected_remote_statuses = dict(
     ...     [(int(bug_watch.remotebug), bug_watch.remotestatus)
     ...      for bug_watch in gnome_bugzilla.watches])
+    >>> expected_remote_importances = dict(
+    ...     [(int(bug_watch.remotebug), bug_watch.remote_importance)
+    ...      for bug_watch in gnome_bugzilla.watches])
     >>> for remote_bug_id in range(100,300):
     ...     bug_watch = bug_watch_set.createBugWatch(
     ...         bug=bug_one, owner=sample_person, bugtracker=gnome_bugzilla,
     ...         remotebug=str(remote_bug_id))
     ...     external_bugzilla.bugzilla_bugs[remote_bug_id] = (
-    ...         'ASSIGNED', '')
+    ...         'ASSIGNED', '', 'MEDIUM', 'URGENT')
     ...     expected_remote_statuses[remote_bug_id] = 'ASSIGNED'
+    ...     expected_remote_importances[remote_bug_id] = 'MEDIUM URGENT'
     >>> for bug_watch in gnome_bugzilla.watches:
     ...     sync(bug_watch)
 
@@ -417,6 +509,12 @@
     >>> remote_statuses == expected_remote_statuses
     True
 
+    >>> remote_importances = dict(
+    ...     [(int(bug_watch.remotebug), bug_watch.remote_importance)
+    ...      for bug_watch in gnome_bugzilla.watches])
+    >>> remote_importances == expected_remote_importances
+    True
+
     >>> external_bugzilla.trace_calls = False
 
 updateBugWatches() updates the lastchecked attribute on the watches, so
@@ -450,9 +548,11 @@
     Unknown
     >>> thunderbird_task.bugwatch.remotestatus is None
     True
+    >>> thunderbird_task.bugwatch.remote_importance is None
+    True
 
-We don't yet support updating the importance for Bugzilla bugs, so let's set it
-to some bogus value, to see that it gets set to UNKNOWN.
+Importance gets updated for Bugzilla bugs.  Let's set it to some bogus
+value, and see that it gets set to a proper value.
 
     >>> from canonical.launchpad.interfaces import BugTaskImportance
     >>> thunderbird_task.transitionToImportance(
@@ -464,7 +564,8 @@
     >>> mozilla_bugzilla = getUtility(IBugTrackerSet).getByName(
     ...     'mozilla.org')
     >>> external_bugzilla = TestBugzilla(mozilla_bugzilla.baseurl, '2.20')
-    >>> external_bugzilla.bugzilla_bugs = {1234: ('ASSIGNED', '')}
+    >>> external_bugzilla.bugzilla_bugs = {1234: (
+    ...     'ASSIGNED', '', 'MEDIUM', 'ENHANCEMENT')}
 
 Let's update the bug watch, and see that the linked bug watch got
 synced:
@@ -478,9 +579,11 @@
     >>> print thunderbird_task.status.title
     In Progress
     >>> print thunderbird_task.importance.title
-    Unknown
+    Wishlist
     >>> print thunderbird_task.bugwatch.remotestatus
     ASSIGNED
+    >>> print thunderbird_task.bugwatch.remote_importance
+    MEDIUM ENHANCEMENT
 
 If we change the bugtask status, it will be updated again even though
 the remote status hasn't changed. This can happen if we change the
@@ -498,13 +601,18 @@
     >>> thunderbird_task = bug_nine.bugtasks[0]
     >>> print thunderbird_task.status.title
     In Progress
+    >>> print thunderbird_task.importance.title
+    Wishlist
     >>> print thunderbird_task.bugwatch.remotestatus
     ASSIGNED
+    >>> print thunderbird_task.bugwatch.remote_importance
+    MEDIUM ENHANCEMENT
 
 If there are two bug watches, linked to different bugs, pointing to the
 same remote bug, both will of course be updated.
 
-    >>> external_bugzilla.bugzilla_bugs[42] = ('RESOLVED', 'FIXED')
+    >>> external_bugzilla.bugzilla_bugs[42] = (
+    ...     'RESOLVED', 'FIXED', 'LOW', 'BLOCKER')
     >>> bug_watch1 = bug_watch_set.createBugWatch(
     ...     bug=bug_one, owner=sample_person, bugtracker=mozilla_bugzilla,
     ...     remotebug='42')
@@ -521,9 +629,13 @@
     >>> bug_watch1 = getUtility(IBugWatchSet).get(bug_watch1_id)
     >>> print bug_watch1.remotestatus
     RESOLVED FIXED
+    >>> print bug_watch1.remote_importance
+    LOW BLOCKER
     >>> bug_watch2 = getUtility(IBugWatchSet).get(bug_watch2_id)
     >>> print bug_watch2.remotestatus
     RESOLVED FIXED
+    >>> print bug_watch2.remote_importance
+    LOW BLOCKER
 
 If updateBugWatches() can't parse the XML file returned from the remote
 bug tracker, an error is logged.
@@ -548,7 +660,8 @@
     'Unparsable Bug'
 
 
-== Getting Remote Product ==
+Getting Remote Product
+----------------------
 
 getRemoteProduct() returns the product a remote bug is associated with
 in Bugzilla. getRemoteProduct() has to be called after
@@ -556,7 +669,8 @@
 information to be fetched from the external Bugzilla instance.
 
     >>> external_bugzilla = TestBugzilla()
-    >>> external_bugzilla.bugzilla_bugs = {84: ('RESOLVED', 'FIXED')}
+    >>> external_bugzilla.bugzilla_bugs = {84: (
+    ...     'RESOLVED', 'FIXED', 'MEDIUM', 'NORMAL')}
     >>> external_bugzilla.initializeRemoteBugDB(['84'])
     >>> external_bugzilla.remote_bug_product['84']
     u'product-84'
@@ -567,7 +681,8 @@
 cases getRemoteProduct() returns None.
 
     >>> external_bugzilla = TestBugzilla()
-    >>> external_bugzilla.bugzilla_bugs = {84: ('RESOLVED', 'FIXED')}
+    >>> external_bugzilla.bugzilla_bugs = {84: (
+    ...     'RESOLVED', 'FIXED', 'MEDIUM', 'NORMAL')}
     >>> # Make the buglist XML not include the product tag.
     >>> external_bugzilla.bug_item_file = 'gnome_bug_li_item_noproduct.xml'
     >>> external_bugzilla.initializeRemoteBugDB(['84'])
@@ -577,7 +692,8 @@
 Requesting the product for a bug that doesn't exist raises BugNotFound.
 
     >>> external_bugzilla = TestBugzilla()
-    >>> external_bugzilla.bugzilla_bugs = {84: ('RESOLVED', 'FIXED')}
+    >>> external_bugzilla.bugzilla_bugs = {84: (
+    ...     'RESOLVED', 'FIXED', 'MEDIUM', 'NORMAL')}
     >>> external_bugzilla.initializeRemoteBugDB(['84'])
     >>> external_bugzilla.getRemoteProduct('42')
     Traceback (most recent call last):

=== modified file 'lib/lp/bugs/externalbugtracker/base.py'
--- lib/lp/bugs/externalbugtracker/base.py	2010-04-09 15:41:48 +0000
+++ lib/lp/bugs/externalbugtracker/base.py	2010-08-12 20:06:35 +0000
@@ -16,6 +16,7 @@
     'LookupTree',
     'PrivateRemoteBug',
     'UnknownBugTrackerTypeError',
+    'UnknownRemoteImportanceError',
     'UnknownRemoteStatusError',
     'UnparseableBugData',
     'UnparseableBugTrackerVersion',
@@ -48,7 +49,6 @@
 # Errors.
 #
 
-
 class BugWatchUpdateError(Exception):
     """Base exception for when we fail to update watches for a tracker."""
 
@@ -97,12 +97,12 @@
 # Warnings.
 #
 
-
 class BugWatchUpdateWarning(Exception):
     """An exception representing a warning.
 
     This is a flag exception for the benefit of the OOPS machinery.
     """
+
     def __init__(self, message, *args):
         # Require a message.
         Exception.__init__(self, message, *args)
@@ -120,8 +120,12 @@
     """The bug was not found in the external bug tracker."""
 
 
+class UnknownRemoteImportanceError(BugWatchUpdateWarning):
+    """The remote bug's importance isn't mapped to a `BugTaskImportance`."""
+
+
 class UnknownRemoteStatusError(BugWatchUpdateWarning):
-    """Raised when a remote bug's status isn't mapped to a `BugTaskStatus`."""
+    """The remote bug's status isn't mapped to a `BugTaskStatus`."""
 
 
 class PrivateRemoteBug(BugWatchUpdateWarning):
@@ -278,7 +282,7 @@
             self.result not in BugTaskStatus):
             raise TypeError(
                 'Result is not a member of BugTaskStatus: %r' % (
-                    self.result,))
+                    self.result))
         super(LookupBranch, self)._verify()
 
     def _describe_result(self, result):
@@ -305,7 +309,7 @@
                 raise ValueError(
                     "Table of %d columns needs %d titles, but %d given." % (
                         (max_depth + 1), (max_depth + 1), len(titles)))
-            yield line("'''%s'''" % (title,) for title in titles)
+            yield line("'''%s'''" % (title) for title in titles)
 
         def diff(last, now):
             """Yields elements from `now` when different to those in `last`.

=== modified file 'lib/lp/bugs/externalbugtracker/bugzilla.py'
--- lib/lp/bugs/externalbugtracker/bugzilla.py	2010-04-21 10:30:24 +0000
+++ lib/lp/bugs/externalbugtracker/bugzilla.py	2010-08-12 20:06:35 +0000
@@ -30,8 +30,8 @@
 from lp.bugs.externalbugtracker.base import (
     BugNotFound, BugTrackerAuthenticationError, BugTrackerConnectError,
     ExternalBugTracker, InvalidBugId, LookupTree,
-    UnknownRemoteStatusError, UnparseableBugData,
-    UnparseableBugTrackerVersion)
+    UnknownRemoteImportanceError, UnknownRemoteStatusError,
+    UnparseableBugData, UnparseableBugTrackerVersion)
 from lp.bugs.externalbugtracker.isolation import ensure_no_transaction
 from lp.bugs.externalbugtracker.xmlrpc import (
     UrlLib2Transport)
@@ -52,6 +52,7 @@
         self.version = self._parseVersion(version)
         self.is_issuezilla = False
         self.remote_bug_status = {}
+        self.remote_bug_importance = {}
         self.remote_bug_product = {}
 
     @ensure_no_transaction
@@ -209,13 +210,30 @@
 
         return tuple(int(number) for number in version_numbers)
 
+    _importance_lookup = {
+        'blocker':     BugTaskImportance.CRITICAL,
+        'critical':    BugTaskImportance.CRITICAL,
+        'immediate':   BugTaskImportance.CRITICAL,
+        'urgent':      BugTaskImportance.CRITICAL,
+        'major':       BugTaskImportance.HIGH,
+        'high':        BugTaskImportance.HIGH,
+        'normal':      BugTaskImportance.MEDIUM,
+        'medium':      BugTaskImportance.MEDIUM,
+        'minor':       BugTaskImportance.LOW,
+        'low':         BugTaskImportance.LOW,
+        'trivial':     BugTaskImportance.LOW,
+        'enhancement': BugTaskImportance.WISHLIST,
+        }
+
     def convertRemoteImportance(self, remote_importance):
-        """See `ExternalBugTracker`.
-
-        This method is implemented here as a stub to ensure that
-        existing functionality is preserved. As a result,
-        BugTaskImportance.UNKNOWN will always be returned.
-        """
+        """See `ExternalBugTracker`."""
+        try:
+            words = remote_importance.lower().split()
+            return self._importance_lookup[words.pop()]
+
+        except KeyError:
+            raise UnknownRemoteImportanceError(remote_importance)
+
         return BugTaskImportance.UNKNOWN
 
     _status_lookup_titles = 'Bugzilla status', 'Bugzilla resolution'
@@ -233,7 +251,7 @@
                  'PATCH_ALREADY_AVAILABLE', 'FIXED', 'RAWHIDE', 'UPSTREAM',
                  BugTaskStatus.FIXRELEASED),
                 ('WONTFIX', BugTaskStatus.WONTFIX),
-                (BugTaskStatus.INVALID,))),
+                (BugTaskStatus.INVALID, ))),
         ('REOPENED', 'NEW', 'UPSTREAM', 'DEFERRED', BugTaskStatus.CONFIRMED),
         ('UNCONFIRMED', BugTaskStatus.NEW),
         )
@@ -285,6 +303,8 @@
             id_tag = 'issue_id'
             status_tag = 'issue_status'
             resolution_tag = 'resolution'
+            priority_tag = 'priority'
+            severity_tag = None
         elif self.version < (2, 16):
             buglist_page = 'xml.cgi'
             data = {'id': ','.join(bug_ids)}
@@ -292,6 +312,8 @@
             id_tag = 'bug_id'
             status_tag = 'bug_status'
             resolution_tag = 'resolution'
+            priority_tag = 'priority'
+            severity_tag = 'bug_severity'
         else:
             buglist_page = 'buglist.cgi'
             data = {'form_name'   : 'buglist.cgi',
@@ -307,6 +329,8 @@
             id_tag = 'bz:id'
             status_tag = 'bz:bug_status'
             resolution_tag = 'bz:resolution'
+            priority_tag = 'bz:priority'
+            severity_tag = 'bz:bug_severity'
 
         buglist_xml = self._postPage(buglist_page, data)
         try:
@@ -365,6 +389,34 @@
                     status += ' %s' % resolution
             self.remote_bug_status[bug_id] = status
 
+            # Priority (for Importance)
+            priority = ''
+            priority_nodes = bug_node.getElementsByTagName(priority_tag)
+            assert len(priority_nodes) <= 1, (
+                "Should only be one priority node for bug %s" % bug_id)
+            if priority_nodes:
+                bug_priority_node = priority_nodes[0]
+                assert len(bug_priority_node.childNodes) == 1, (
+                    "priority node for bug %s should contain a non-empty "
+                    "text string." % bug_id)
+                priority = bug_priority_node.childNodes[0].data
+
+            # Severity (for Importance)
+            if severity_tag:
+                severity_nodes = bug_node.getElementsByTagName(severity_tag)
+                assert len(severity_nodes) <= 1, (
+                    "Should only be one severity node for bug %s." % bug_id)
+                if severity_nodes:
+                    assert len(severity_nodes[0].childNodes) <= 1, (
+                        "Severity for bug %s should just contain "
+                        "a string." % bug_id)
+                    if severity_nodes[0].childNodes:
+                        severity = severity_nodes[0].childNodes[0].data
+                        priority += ' %s' % severity
+            self.remote_bug_importance[bug_id] = priority
+            ##TODO: Refactor the above stanzas into a helper function
+
+            # Product
             product_nodes = bug_node.getElementsByTagName('bz:product')
             assert len(product_nodes) <= 1, (
                 "Should be at most one product node for bug %s." % bug_id)
@@ -375,14 +427,18 @@
                 self.remote_bug_product[bug_id] = (
                     product_node.childNodes[0].data)
 
+    def initializeRemoteImportance(self, bug_ids):
+        for bug_id in bug_ids:
+            self.remote_bug_importance[bug_id] = "NORMAL NORMAL"
+
     def getRemoteImportance(self, bug_id):
-        """See `ExternalBugTracker`.
-
-        This method is implemented here as a stub to ensure that
-        existing functionality is preserved. As a result,
-        UNKNOWN_REMOTE_IMPORTANCE will always be returned.
-        """
-        return UNKNOWN_REMOTE_IMPORTANCE
+        """See `ExternalBugTracker`."""
+        try:
+            if bug_id not in self.remote_bug_importance:
+                return "Bug %s is not in remote_bug_importance" %(bug_id)
+            return self.remote_bug_importance[bug_id]
+        except:
+            return UNKNOWN_REMOTE_IMPORTANCE
 
     def getRemoteStatus(self, bug_id):
         """See ExternalBugTracker."""
@@ -408,6 +464,7 @@
     If an `xmlrpclib.Fault` with error code 410 is raised by the
     function, we'll try to authenticate and call the function again.
     """
+
     def decorator(self, *args, **kwargs):
         try:
             return func(self, *args, **kwargs)
@@ -415,6 +472,7 @@
             # Catch authentication errors only.
             if fault.faultCode != 410:
                 raise
+
             self._authenticate()
             return func(self, *args, **kwargs)
     return decorator
@@ -586,6 +644,23 @@
         else:
             return status
 
+    def getRemoteImportance(self, bug_id):
+        """See `IExternalBugTracker`."""
+        actual_bug_id = self._getActualBugId(bug_id)
+
+        # Attempt to get the priority and severity from the bug.
+        # If we don't have the data for either, raise an error.
+        try:
+            priority = self._bugs[actual_bug_id]['priority']
+            severity = self._bugs[actual_bug_id]['severity']
+        except KeyError:
+            raise UnparseableBugData
+
+        if severity != '':
+            return "%s %s" % (priority, severity)
+        else:
+            return priority
+
     @ensure_no_transaction
     def getModifiedRemoteBugs(self, bug_ids, last_checked):
         """See `IExternalBugTracker`."""

=== modified file 'lib/lp/bugs/stories/webservice/xx-bug.txt'
--- lib/lp/bugs/stories/webservice/xx-bug.txt	2010-06-30 21:19:36 +0000
+++ lib/lp/bugs/stories/webservice/xx-bug.txt	2010-08-12 20:06:35 +0000
@@ -1031,7 +1031,7 @@
   last_error_type: None
   owner_link: u'http://.../~mark'
   remote_bug: u'2000'
-  remote_importance: None
+  remote_importance: u''
   remote_status: u''
   resource_type_link: u'http://.../#bug_watch'
   self_link: u'http://.../bugs/1/+watch/2'

=== modified file 'lib/lp/bugs/tests/externalbugtracker.py'
--- lib/lp/bugs/tests/externalbugtracker.py	2010-04-12 21:04:52 +0000
+++ lib/lp/bugs/tests/externalbugtracker.py	2010-08-12 20:06:35 +0000
@@ -60,13 +60,13 @@
     owner = getUtility(IPersonSet).getByEmail('no-priv@xxxxxxxxxxxxx')
     bugtracker_set = getUtility(IBugTrackerSet)
     index = 1
-    name = '%s-checkwatches' % (bugtracker_type.name.lower(),)
+    name = '%s-checkwatches' % (bugtracker_type.name.lower())
     while bugtracker_set.getByName("%s-%d" % (name, index)) is not None:
         index += 1
     name += '-%d' % index
     BugTracker(
         name=name,
-        title='%s *TESTING*' % (bugtracker_type.title,),
+        title='%s *TESTING*' % (bugtracker_type.title),
         bugtrackertype=bugtracker_type,
         baseurl=base_url,
         summary='-', contactdetails='-',
@@ -130,11 +130,12 @@
         'rejected': 8,
         'remind': 9,
         'wontfix': 10,
-        'worksforme': 11
-    }
+        'worksforme': 11,
+        }
 
     return "%s:%s" % (status_map[status], resolution_map[resolution])
 
+
 def set_bugwatch_error_type(bug_watch, error_type):
     """Set the last_error_type field of a bug watch to a given error type."""
     login('foo.bar@xxxxxxxxxxxxx')
@@ -244,9 +245,10 @@
         return self
 
     def _getBugsToTest(self):
-        """Return a dict with bugs in the form bug_id: (status, resolution)"""
-        return {3224: ('RESOLVED', 'FIXED'),
-                328430: ('UNCONFIRMED', '')}
+        """Return a dict with bugs in the form
+           bug_id: (status, resolution, priority, severity)"""
+        return {3224: ('RESOLVED', 'FIXED', 'MINOR', 'URGENT'),
+                328430: ('UNCONFIRMED', '', 'MEDIUM', 'NORMAL')}
 
     def _readBugItemFile(self):
         """Reads in the file for an individual bug item.
@@ -288,17 +290,20 @@
                 if bug_id not in self.bugzilla_bugs:
                     #Unknown bugs aren't included in the resulting xml.
                     continue
-                bug_status, bug_resolution = self.bugzilla_bugs[int(bug_id)]
+                bug_status, bug_resolution, bug_priority, bug_severity = \
+                            self.bugzilla_bugs[int(bug_id)]
                 bug_item = self._readBugItemFile() % {
                     'bug_id': bug_id,
                     'status': bug_status,
                     'resolution': bug_resolution,
+                    'priority': bug_priority,
+                    'severity': bug_severity,
                     }
                 bug_li_items.append(bug_item)
             return buglist_xml % {
                 'bug_li_items': '\n'.join(bug_li_items),
-                'page': page
-            }
+                'page': page,
+                }
         else:
             raise AssertionError('Unknown page: %s' % page)
 
@@ -312,8 +317,8 @@
     bug_item_file = 'weird_non_ascii_bug_li_item.xml'
 
     def _getBugsToTest(self):
-        return {2000: ('ASSIGNED', ''),
-                123543: ('RESOLVED', 'FIXED')}
+        return {2000: ('ASSIGNED', '', 'HIGH', 'BLOCKER'),
+                123543: ('RESOLVED', 'FIXED', 'HIGH', 'BLOCKER')}
 
 
 class TestBrokenBugzilla(TestBugzilla):
@@ -321,8 +326,8 @@
     bug_item_file = 'broken_bug_li_item.xml'
 
     def _getBugsToTest(self):
-        return {42: ('ASSIGNED', ''),
-                2000: ('RESOLVED', 'FIXED')}
+        return {42: ('ASSIGNED', '', 'HIGH', 'BLOCKER'),
+                2000: ('RESOLVED', 'FIXED', 'LOW', 'BLOCKER')}
 
 
 class TestIssuezilla(TestBugzilla):
@@ -335,8 +340,8 @@
     bug_id_form_element = 'id'
 
     def _getBugsToTest(self):
-        return {2000: ('RESOLVED', 'FIXED'),
-                123543: ('ASSIGNED', '')}
+        return {2000: ('RESOLVED', 'FIXED', 'LOW', 'BLOCKER'),
+                123543: ('ASSIGNED', '', 'HIGH', 'BLOCKER')}
 
 
 class TestOldBugzilla(TestBugzilla):
@@ -349,12 +354,13 @@
     bug_id_form_element = 'id'
 
     def _getBugsToTest(self):
-        return {42: ('RESOLVED', 'FIXED'),
-                123543: ('ASSIGNED', '')}
+        return {42: ('RESOLVED', 'FIXED', 'LOW', 'BLOCKER'),
+                123543: ('ASSIGNED', '', 'HIGH', 'BLOCKER')}
 
 
 class FakeHTTPConnection:
     """A fake HTTP connection."""
+
     def putheader(self, header, value):
         print "%s: %s" % (header, value)
 
@@ -452,7 +458,7 @@
             'time',
             'set_link',
             ],
-        'Test': ['login_required']
+        'Test': ['login_required'],
         }
 
     # Methods that require authentication.
@@ -1054,7 +1060,7 @@
 
     def _getPage(self, page):
         if self.trace_calls:
-            print "CALLED _getPage(%r)" % (page,)
+            print "CALLED _getPage(%r)" % (page)
         if page == "csv_export.php":
             return read_test_file('mantis_example_bug_export.csv')
         elif page.startswith('view.php?id='):
@@ -1065,7 +1071,7 @@
 
     def _postPage(self, page, form):
         if self.trace_calls:
-            print "CALLED _postPage(%r, ...)" % (page,)
+            print "CALLED _postPage(%r, ...)" % (page)
         return ''
 
     def cleanCache(self):
@@ -1105,7 +1111,7 @@
         file_path = os.path.join(os.path.dirname(__file__), 'testfiles')
 
         if self.trace_calls:
-            print "CALLED urlopen(%r)" % (url,)
+            print "CALLED urlopen(%r)" % (url)
 
         if self.csv_export_file is not None:
             csv_export_file = self.csv_export_file
@@ -1137,7 +1143,8 @@
         return {
             'id': self.id,
             'status': self.status,
-            'resolution': self.resolution,}
+            'resolution': self.resolution,
+            }
 
 
 class TestInternalXMLRPCTransport:
@@ -1442,7 +1449,7 @@
 
     def urlopen(self, url):
         if self.trace_calls:
-            print "CALLED urlopen(%r)" % (url,)
+            print "CALLED urlopen(%r)" % (url)
 
         file_path = os.path.join(os.path.dirname(__file__), 'testfiles')
 
@@ -1494,7 +1501,7 @@
 
     def _getPage(self, page):
         if self.trace_calls:
-            print "CALLED _getPage(%r)" % (page,)
+            print "CALLED _getPage(%r)" % (page)
 
         page_re = re.compile('support/tracker.php\?aid=([0-9]+)')
         bug_id = page_re.match(page).groups()[0]
@@ -1582,6 +1589,7 @@
     a hard-coded cookie header.
     """
     cookies = 'foo=bar'
+
     def getheaders(self, header):
         """Return the hard-coded cookie header."""
         if header.lower() in ('cookie', 'set-cookie', 'set-cookie2'):
@@ -1633,7 +1641,7 @@
                 'http', req, response, 302, 'Moved', headers)
         else:
             xmlrpc_response = xmlrpclib.dumps(
-                (req.get_full_url(),), methodresponse=True)
+                (req.get_full_url(), ), methodresponse=True)
             response = StringIO(xmlrpc_response)
             info = Urlib2TransportTestInfo()
             response.info = lambda: info
@@ -1643,6 +1651,7 @@
 
         return response
 
+
 def patch_transport_opener(transport):
     """Patch the transport's opener to use a test handler."""
     transport.opener.add_handler(Urlib2TransportTestHandler())

=== modified file 'lib/lp/bugs/tests/testfiles/broken_bug_li_item.xml'
--- lib/lp/bugs/tests/testfiles/broken_bug_li_item.xml	2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/testfiles/broken_bug_li_item.xml	2010-08-12 20:06:35 +0000
@@ -4,8 +4,8 @@
 
           <bz:id nc:parseType="Integer">%(bug_id)s</bz:id>
 
-          NOT USED</bz:bug_severity>
-          <bz:priority>NOT USED</bz:priority>
+          %(severity)s</bz:bug_severity>
+          <bz:priority>%(priority)s</bz:priority>
           <bz:op_sys>NOT USED</bz:op_sys>
           <bz:product>NOT USED</bz:product>
           <bz:bug_status>%(status)s</foobar>

=== modified file 'lib/lp/bugs/tests/testfiles/gnome_bug_li_item.xml'
--- lib/lp/bugs/tests/testfiles/gnome_bug_li_item.xml	2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/testfiles/gnome_bug_li_item.xml	2010-08-12 20:06:35 +0000
@@ -4,8 +4,8 @@
 
           <bz:id nc:parseType="Integer">%(bug_id)s</bz:id>
 
-          <bz:bug_severity>NOT USED</bz:bug_severity>
-          <bz:priority>NOT USED</bz:priority>
+          <bz:bug_severity>%(severity)s</bz:bug_severity>
+          <bz:priority>%(priority)s</bz:priority>
           <bz:op_sys>NOT USED</bz:op_sys>
           <bz:product>product-%(bug_id)s</bz:product>
           <bz:bug_status>%(status)s</bz:bug_status>

=== modified file 'lib/lp/bugs/tests/testfiles/issuezilla_item.xml'
--- lib/lp/bugs/tests/testfiles/issuezilla_item.xml	2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/testfiles/issuezilla_item.xml	2010-08-12 20:06:35 +0000
@@ -1,7 +1,7 @@
 <issue status_code="200" status_message="OK">
   <issue_id>%(bug_id)s</issue_id>
   <issue_status>%(status)s</issue_status>
-  <priority>NOT USED</priority>
+  <priority>%(priority)s</priority>
   <resolution>%(resolution)s</resolution>
   <component>NOT USED</component>
   <version>NOT USED</version>

=== modified file 'lib/lp/bugs/tests/testfiles/weird_non_ascii_bug_li_item.xml'
--- lib/lp/bugs/tests/testfiles/weird_non_ascii_bug_li_item.xml	2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/testfiles/weird_non_ascii_bug_li_item.xml	2010-08-12 20:06:35 +0000
@@ -4,8 +4,8 @@
 
           <bz:id nc:parseType="Integer">%(bug_id)s</bz:id>
 
-          <bz:bug_severity>NOT USED</bz:bug_severity>
-          <bz:priority>NOT USED</bz:priority>
+          <bz:bug_severity>%(severity)s</bz:bug_severity>
+          <bz:priority>%(priority)s</bz:priority>
           <bz:op_sys>NOT USED</bz:op_sys>
           <bz:product>NOT USED</bz:product>
           <bz:status>%(status)s</bz:status>

=== modified file 'lib/lp/bugs/tests/testfiles/ximian_bug_item.xml'
--- lib/lp/bugs/tests/testfiles/ximian_bug_item.xml	2009-06-12 16:36:02 +0000
+++ lib/lp/bugs/tests/testfiles/ximian_bug_item.xml	2010-08-12 20:06:35 +0000
@@ -2,14 +2,14 @@
   <bug_id>%(bug_id)s</bug_id>
   <bug_status>%(status)s</bug_status>
   <product>NOT USED</product>
-  <priority>NOT USED</priority>
+  <priority>%(priority)s</priority>
   <version>NOT USED</version>
   <assigned_to>NOT USED</assigned_to>
   <delta_ts>NOT USED</delta_ts>
   <component>NOT USED</component>
   <reporter>matt@xxxxxxxxxxxxx</reporter>
   <target_milestone>NOT USED</target_milestone>
-  <bug_severity>NOT USED</bug_severity>
+  <bug_severity>%(severity)s</bug_severity>
   <creation_ts>NOT USED</creation_ts>
   <qa_contact>NOT USED</qa_contact>
   <op_sys>NOT USED</op_sys>


Follow ups