← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/destroy-bugtask-markers into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/destroy-bugtask-markers into lp:launchpad with lp:~wgrant/launchpad/unuse-bugtask-markers as a prerequisite.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #55089 in Launchpad itself: "IUpstreamBugTask should be renamed to IProjectBugTask"
  https://bugs.launchpad.net/launchpad/+bug/55089
  Bug #80902 in Launchpad itself: "Can't target bug report from project to distribution, or vice versa"
  https://bugs.launchpad.net/launchpad/+bug/80902

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/destroy-bugtask-markers/+merge/68637

This branch destroys the I*BugTask marker interfaces.

Users are stripped from lp.bugs.model.bugtask, _init is no longer overridden to add them, tonnes of tests have been updated to use IBugTask instead, and the interfaces themselves have been removed.
-- 
https://code.launchpad.net/~wgrant/launchpad/destroy-bugtask-markers/+merge/68637
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/destroy-bugtask-markers into lp:launchpad.
=== modified file 'lib/canonical/launchpad/mail/commands.py'
--- lib/canonical/launchpad/mail/commands.py	2011-05-12 21:33:10 +0000
+++ lib/canonical/launchpad/mail/commands.py	2011-07-21 07:27:39 +0000
@@ -57,7 +57,7 @@
 from lp.bugs.interfaces.bugtask import (
     BugTaskImportance,
     BugTaskStatus,
-    IDistroBugTask,
+    IBugTask,
     )
 from lp.bugs.interfaces.cve import ICveSet
 from lp.registry.interfaces.distribution import IDistribution
@@ -642,7 +642,7 @@
             bugtask = bug.getBugTask(bug_target.distribution)
             if bugtask is not None:
                 bugtask_before_edit = Snapshot(
-                    bugtask, providing=IDistroBugTask)
+                    bugtask, providing=IBugTask)
                 bugtask.sourcepackagename = bug_target.sourcepackagename
                 event = ObjectModifiedEvent(
                     bugtask, bugtask_before_edit, ['sourcepackagename'])

=== modified file 'lib/lp/bugs/doc/bug.txt'
--- lib/lp/bugs/doc/bug.txt	2011-06-29 09:04:14 +0000
+++ lib/lp/bugs/doc/bug.txt	2011-07-21 07:27:39 +0000
@@ -601,7 +601,7 @@
 Modifying a bugtask will update IBug.date_last_updated.
 
     >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskImportance, BugTaskStatus, IUpstreamBugTask)
+    ...     BugTaskImportance, BugTaskStatus, IBugTask)
 
     >>> firefox_task = firefox_bug.bugtasks[0]
 
@@ -614,7 +614,7 @@
     New
 
     >>> bugtask_before_modification = Snapshot(
-    ...     firefox_task, providing=IUpstreamBugTask)
+    ...     firefox_task, providing=IBugTask)
 
     >>> firefox_task.transitionToImportance(
     ...     BugTaskImportance.CRITICAL, current_user())

=== modified file 'lib/lp/bugs/doc/bugactivity.txt'
--- lib/lp/bugs/doc/bugactivity.txt	2011-02-17 17:23:06 +0000
+++ lib/lp/bugs/doc/bugactivity.txt	2011-07-21 07:27:39 +0000
@@ -25,9 +25,8 @@
     >>> from lazr.lifecycle.event import ObjectModifiedEvent
     >>> from lazr.lifecycle.snapshot import Snapshot
     >>> from lp.bugs.interfaces.bugtask import (
+    ...     IBugTask,
     ...     IBugTaskSet,
-    ...     IDistroBugTask,
-    ...     IUpstreamBugTask,
     ...     )
     >>> from lp.registry.interfaces.product import IProductSet
     >>> user = getUtility(ILaunchBag).user
@@ -87,7 +86,7 @@
     ...     "distribution", "sourcepackagename", "milestone", "status",
     ...     "importance", "assignee", "bugwatch"]
     >>> old_source_package_assignment = Snapshot(
-    ...   source_package_assignment, providing=IDistroBugTask)
+    ...   source_package_assignment, providing=IBugTask)
     >>> source_package_assignment.transitionToStatus(
     ...     BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
     >>> source_package_assignment_edited = ObjectModifiedEvent(
@@ -135,7 +134,7 @@
     ...     "product", "milestone", "status", "assignee", "bugwatch",
     ...     "importance"]
     >>> old_product_assignment = Snapshot(
-    ...     product_assignment, providing=IUpstreamBugTask)
+    ...     product_assignment, providing=IBugTask)
     >>> product_assignment.transitionToStatus(
     ...     BugTaskStatus.INVALID, getUtility(ILaunchBag).user)
     >>> product_assignment_edited = ObjectModifiedEvent(

=== modified file 'lib/lp/bugs/doc/bugnotifications.txt'
--- lib/lp/bugs/doc/bugnotifications.txt	2011-02-11 22:04:25 +0000
+++ lib/lp/bugs/doc/bugnotifications.txt	2011-07-21 07:27:39 +0000
@@ -229,11 +229,11 @@
     >>> from lazr.lifecycle.snapshot import Snapshot
     >>> from lp.bugs.interfaces.bugtask import (
     ...     BugTaskStatus,
-    ...     IDistroBugTask,
+    ...     IBugTask,
     ...     )
 
     >>> bugtask_before_modification = Snapshot(
-    ...     firefox_crashes_in_debian, providing=IDistroBugTask)
+    ...     firefox_crashes_in_debian, providing=IBugTask)
     >>> firefox_crashes_in_debian.transitionToStatus(
     ...     BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
     >>> firefox_crashes_in_debian.transitionToAssignee(bug_submitter)
@@ -252,9 +252,8 @@
     ** Changed in: mozilla-firefox (Debian)
     ...
 
-    >>> from lp.bugs.interfaces.bugtask import IProductSeriesBugTask
     >>> bugtask_before_modification = Snapshot(
-    ...     firefox_crashes_in_trunk, providing=IProductSeriesBugTask)
+    ...     firefox_crashes_in_trunk, providing=IBugTask)
     >>> firefox_crashes_in_trunk.transitionToStatus(
     ...     BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
     >>> firefox_crashes_in_trunk.transitionToAssignee(bug_submitter)

=== modified file 'lib/lp/bugs/doc/bugtask.txt'
--- lib/lp/bugs/doc/bugtask.txt	2011-07-21 07:27:38 +0000
+++ lib/lp/bugs/doc/bugtask.txt	2011-07-21 07:27:39 +0000
@@ -103,15 +103,12 @@
 
   * a product series
 
-    >>> from lp.bugs.interfaces.bugtask import IProductSeriesBugTask
 
     >>> firefox = productset['firefox']
     >>> firefox_1_0 = firefox.getSeries("1.0")
 
     >>> productseries_task = bugtaskset.createTask(
     ...     owner=mark, bug=bug_one, productseries=firefox_1_0)
-    >>> IProductSeriesBugTask.providedBy(productseries_task)
-    True
 
     >>> productseries_task.target == firefox_1_0
     True

=== modified file 'lib/lp/bugs/doc/initial-bug-contacts.txt'
--- lib/lp/bugs/doc/initial-bug-contacts.txt	2011-03-23 16:28:51 +0000
+++ lib/lp/bugs/doc/initial-bug-contacts.txt	2011-07-21 07:27:39 +0000
@@ -120,7 +120,7 @@
     >>> import transaction
     >>> from lazr.lifecycle.event import ObjectModifiedEvent
     >>> from lazr.lifecycle.snapshot import Snapshot
-    >>> from lp.bugs.interfaces.bugtask import IDistroBugTask
+    >>> from lp.bugs.interfaces.bugtask import IBugTask
     >>> from lp.services.mail import stub
 
     >>> daf = personset.getByName("daf")
@@ -130,7 +130,7 @@
     <...StructuralSubscription object at ...>
 
     >>> old_state = Snapshot(
-    ...     bug_one_in_ubuntu_firefox, providing=IDistroBugTask)
+    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
     >>> bug_one_in_ubuntu_firefox.sourcepackagename = (
     ...     ubuntu_pmount.sourcepackagename)
@@ -223,7 +223,7 @@
 package to None.
 
     >>> old_state = Snapshot(
-    ...     bug_one_in_ubuntu_firefox, providing=IDistroBugTask)
+    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
     >>> bug_one_in_ubuntu_firefox.sourcepackagename = None
 
@@ -250,7 +250,7 @@
     <...StructuralSubscription object at ...>
 
     >>> old_state = Snapshot(
-    ...     bug_one_in_ubuntu_firefox, providing=IDistroBugTask)
+    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
     >>> bug_one_in_ubuntu_firefox.sourcepackagename = (
     ...     ubuntu_pmount.sourcepackagename)
@@ -284,7 +284,7 @@
 and then the bug gets reassigned to mozilla firefox:
 
     >>> old_state = Snapshot(
-    ...     bug_one_in_ubuntu_firefox, providing=IDistroBugTask)
+    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
     >>> bug_one_in_ubuntu_firefox.sourcepackagename = (
     ...     ubuntu_firefox.sourcepackagename)
@@ -322,8 +322,6 @@
 Then we'll reassign bug #2 in Ubuntu to be in Firefox, noting that Foo
 Bar gets subscribed to the bug in the process:
 
-    >>> from lp.bugs.interfaces.bugtask import IUpstreamBugTask
-
     >>> bug_two_in_ubuntu = getUtility(IBugTaskSet).get(3)
     >>> print bug_two_in_ubuntu.bug.id
     2
@@ -335,8 +333,7 @@
     ...      bug_two_in_ubuntu.bug.subscriptions])
     [u'Steve Alexander']
 
-    >>> old_state = Snapshot(
-    ...     bug_two_in_ubuntu, providing=IUpstreamBugTask)
+    >>> old_state = Snapshot(bug_two_in_ubuntu, providing=IBugTask)
 
     >>> bug_two_in_ubuntu.product = mozilla_firefox
 

=== modified file 'lib/lp/bugs/doc/malone-karma.txt'
--- lib/lp/bugs/doc/malone-karma.txt	2010-12-02 16:13:51 +0000
+++ lib/lp/bugs/doc/malone-karma.txt	2011-07-21 07:27:39 +0000
@@ -74,10 +74,10 @@
 
     >>> from lp.bugs.interfaces.bugtask import (
     ...     BugTaskStatus,
-    ...     IDistroBugTask,
+    ...     IBugTask,
     ...     )
     >>> bugtask = bug.bugtasks[0]
-    >>> old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
+    >>> old_bugtask = Snapshot(bugtask, providing=IBugTask)
     >>> bugtask.transitionToStatus(
     ...     BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(bugtask, old_bugtask, ['status']))
@@ -85,13 +85,11 @@
 
 Mark a bug task as fixed when it is assigned awards the karma to the assignee:
 
-    >>> from lp.bugs.interfaces.bugtask import IUpstreamBugTask
-
     >>> ufo_product = factory.makeProduct(name='ufo')
     >>> assignee = factory.makePerson(name='assignee')
     >>> assigned_bugtask = factory.makeBugTask(bug=bug, target=ufo_product)
     >>> assigned_bugtask.transitionToAssignee(assignee)
-    >>> old_bugtask = Snapshot(assigned_bugtask, providing=IUpstreamBugTask)
+    >>> old_bugtask = Snapshot(assigned_bugtask, providing=IBugTask)
     >>> assigned_bugtask.transitionToStatus(
     ...     BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(assigned_bugtask, old_bugtask, ['status']))
@@ -103,7 +101,7 @@
 
 Reject a bug task:
 
-    >>> old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
+    >>> old_bugtask = Snapshot(bugtask, providing=IBugTask)
     >>> bugtask.transitionToStatus(
     ...     BugTaskStatus.INVALID, bugtask.target.owner)
     >>> notify(ObjectModifiedEvent(bugtask, old_bugtask, ['status']))
@@ -111,7 +109,7 @@
 
 User accept a bug task:
 
-    >>> old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
+    >>> old_bugtask = Snapshot(bugtask, providing=IBugTask)
     >>> bugtask.transitionToStatus(
     ...     BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(bugtask, old_bugtask, ['status']))
@@ -120,7 +118,7 @@
 Driver accept a bug task:
 
     >>> login_person(bugtask.target.owner)
-    >>> old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
+    >>> old_bugtask = Snapshot(bugtask, providing=IBugTask)
     >>> bugtask.transitionToStatus(
     ...     BugTaskStatus.TRIAGED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(bugtask, old_bugtask, ['status']))
@@ -134,7 +132,7 @@
     >>> bugtask.transitionToImportance(
     ...     BugTaskImportance.HIGH, getUtility(ILaunchBag).user)
     >>> for importance in BugTaskImportance.items:
-    ...     old_bugtask = Snapshot(bugtask, providing=IDistroBugTask)
+    ...     old_bugtask = Snapshot(bugtask, providing=IBugTask)
     ...     bugtask.transitionToImportance(
     ...         importance, getUtility(ILaunchBag).user)
     ...     print importance.name
@@ -184,9 +182,8 @@
 
     >>> debian_woody_task.transitionToStatus(
     ...     BugTaskStatus.NEW, getUtility(ILaunchBag).user)
-    >>> from lp.bugs.interfaces.bugtask import IDistroSeriesBugTask
     >>> old_bugtask = Snapshot(
-    ...     debian_woody_task, providing=IDistroSeriesBugTask)
+    ...     debian_woody_task, providing=IBugTask)
     >>> debian_woody_task.transitionToStatus(
     ...     BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(debian_woody_task, old_bugtask, ['status']))
@@ -196,9 +193,8 @@
 
     >>> evolution_trunk_task.transitionToStatus(
     ...     BugTaskStatus.NEW, getUtility(ILaunchBag).user)
-    >>> from lp.bugs.interfaces.bugtask import IProductSeriesBugTask
     >>> old_bugtask = Snapshot(
-    ...     evolution_trunk_task, providing=IProductSeriesBugTask)
+    ...     evolution_trunk_task, providing=IBugTask)
     >>> evolution_trunk_task.transitionToStatus(
     ...     BugTaskStatus.CONFIRMED, getUtility(ILaunchBag).user)
     >>> notify(ObjectModifiedEvent(

=== modified file 'lib/lp/bugs/doc/security-teams.txt'
--- lib/lp/bugs/doc/security-teams.txt	2011-03-17 03:03:33 +0000
+++ lib/lp/bugs/doc/security-teams.txt	2011-07-21 07:27:39 +0000
@@ -227,9 +227,9 @@
     >>> from zope.event import notify
     >>> from lazr.lifecycle.event import ObjectModifiedEvent
     >>> from lazr.lifecycle.snapshot import Snapshot
-    >>> from lp.bugs.interfaces.bugtask import IUpstreamBugTask
+    >>> from lp.bugs.interfaces.bugtask import IBugTask
 
-    >>> old_state = Snapshot(bug_in_evolution, providing=IUpstreamBugTask)
+    >>> old_state = Snapshot(bug_in_evolution, providing=IBugTask)
     >>> bug_in_evolution.product = thunderbird
     >>> bug_product_changed = ObjectModifiedEvent(
     ...     bug_in_evolution, old_state, ["product"])

=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py	2011-06-21 01:34:08 +0000
+++ lib/lp/bugs/interfaces/bugtask.py	2011-07-21 07:27:39 +0000
@@ -25,14 +25,10 @@
     'IBugTaskSearch',
     'IBugTaskSet',
     'ICreateQuestionFromBugTaskForm',
-    'IDistroBugTask',
-    'IDistroSeriesBugTask',
     'IFrontPageBugTaskSearch',
     'INominationsReviewTableBatchNavigator',
     'IPersonBugTaskSearch',
-    'IProductSeriesBugTask',
     'IRemoveQuestionFromBugTaskForm',
-    'IUpstreamBugTask',
     'IUpstreamProductBugTaskSearch',
     'IllegalRelatedBugTasksParams',
     'IllegalTarget',
@@ -831,9 +827,6 @@
     def getDelta(old_task):
         """Compute the delta from old_task to this task.
 
-        old_task and this task are either both IDistroBugTask's or both
-        IUpstreamBugTask's, otherwise a TypeError is raised.
-
         Returns an IBugTaskDelta or None if there were no changes between
         old_task and this task.
         """
@@ -1077,41 +1070,6 @@
     milestone = Attribute("The milestone for which this task is scheduled.")
 
 
-class IUpstreamBugTask(IBugTask):
-    """A bug needing fixing in a product."""
-    # XXX Brad Bollenbach 2006-08-03 bugs=55089:
-    # This interface should be renamed.
-    product = Choice(title=_('Project'), required=True, vocabulary='Product')
-
-
-class IDistroBugTask(IBugTask):
-    """A bug needing fixing in a distribution, possibly a specific package."""
-    sourcepackagename = Choice(
-        title=_("Source Package Name"), required=False,
-        description=_("The source package in which the bug occurs. "
-        "Leave blank if you are not sure."),
-        vocabulary='SourcePackageName')
-    distribution = Choice(
-        title=_("Distribution"), required=True, vocabulary='Distribution')
-
-
-class IDistroSeriesBugTask(IBugTask):
-    """A bug needing fixing in a distrorelease, or a specific package."""
-    sourcepackagename = Choice(
-        title=_("Source Package Name"), required=True,
-        vocabulary='SourcePackageName')
-    distroseries = Choice(
-        title=_("Series"), required=True,
-        vocabulary='DistroSeries')
-
-
-class IProductSeriesBugTask(IBugTask):
-    """A bug needing fixing a productseries."""
-    productseries = Choice(
-        title=_("Series"), required=True,
-        vocabulary='ProductSeries')
-
-
 class BugTaskSearchParams:
     """Encapsulates search parameters for BugTask.search()
 

=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py	2011-07-19 20:31:43 +0000
+++ lib/lp/bugs/model/bugtask.py	2011-07-21 07:27:39 +0000
@@ -58,7 +58,6 @@
 from zope.component import getUtility
 from zope.event import notify
 from zope.interface import (
-    alsoProvides,
     implements,
     providedBy,
     )
@@ -120,12 +119,8 @@
     IBugTask,
     IBugTaskDelta,
     IBugTaskSet,
-    IDistroBugTask,
-    IDistroSeriesBugTask,
     IllegalRelatedBugTasksParams,
     IllegalTarget,
-    IProductSeriesBugTask,
-    IUpstreamBugTask,
     RESOLVED_BUGTASK_STATUSES,
     UNRESOLVED_BUGTASK_STATUSES,
     UserCannotEditBugTaskAssignee,
@@ -337,9 +332,6 @@
     @property
     def target(self):
         """See `IBugTask`."""
-        # We explicitly reference attributes here (rather than, say,
-        # IDistroBugTask.providedBy(self)), because we can't assume this
-        # task has yet been marked with the correct interface.
         return determine_target(
             self.product, self.productseries, self.distribution,
             self.distroseries, self.sourcepackagename)
@@ -680,7 +672,7 @@
     def getConjoinedMaster(self, bugtasks, bugtasks_by_package=None):
         """See `IBugTask`."""
         conjoined_master = None
-        if IDistroBugTask.providedBy(self):
+        if self.distribution:
             if bugtasks_by_package is None:
                 bugtasks_by_package = (
                     self.bug.getBugTasksByPackageName(bugtasks))
@@ -698,7 +690,7 @@
                 if bugtask.distroseries == current_series:
                     conjoined_master = bugtask
                     break
-        elif IUpstreamBugTask.providedBy(self):
+        elif self.product:
             assert self.product.development_focusID is not None, (
                 'A product should always have a development series.')
             devel_focusID = self.product.development_focusID
@@ -724,7 +716,7 @@
     def conjoined_slave(self):
         """See `IBugTask`."""
         conjoined_slave = None
-        if IDistroSeriesBugTask.providedBy(self):
+        if self.distroseries:
             distribution = self.distroseries.distribution
             if self.distroseries != distribution.currentseries:
                 # Only current series tasks are conjoined.
@@ -734,7 +726,7 @@
                     bugtask.sourcepackagename == self.sourcepackagename):
                     conjoined_slave = bugtask
                     break
-        elif IProductSeriesBugTask.providedBy(self):
+        elif self.productseries:
             product = self.productseries.product
             if self.productseries != product.development_focus:
                 # Only development focus tasks are conjoined.
@@ -765,27 +757,6 @@
             # setter methods directly.
             setattr(self, synched_attr, PassthroughValue(slave_attr_value))
 
-    def _init(self, *args, **kw):
-        """Marks the task when it's created or fetched from the database."""
-        SQLBase._init(self, *args, **kw)
-
-        # We check both the foreign key column and the reference so we
-        # can detect unflushed references.  The reference check will
-        # only be made if the FK is None, so no additional queries
-        # will be executed.
-        if self.productID is not None or self.product is not None:
-            alsoProvides(self, IUpstreamBugTask)
-        elif (self.productseriesID is not None or
-              self.productseries is not None):
-            alsoProvides(self, IProductSeriesBugTask)
-        elif self.distroseriesID is not None or self.distroseries is not None:
-            alsoProvides(self, IDistroSeriesBugTask)
-        elif self.distributionID is not None or self.distribution is not None:
-            # If nothing else, this is a distro task.
-            alsoProvides(self, IDistroBugTask)
-        else:
-            raise AssertionError("Task %d is floating." % self.id)
-
     @property
     def target_uses_malone(self):
         """See `IBugTask`"""
@@ -1107,7 +1078,7 @@
             # current target, or reset it to None
             self.milestone = None
 
-        if IUpstreamBugTask.providedBy(self):
+        if self.product:
             if IProduct.providedBy(target):
                 self.product = target
             else:
@@ -1187,12 +1158,12 @@
         else:
             component_name = component.name
 
-        if IUpstreamBugTask.providedBy(self):
+        if self.product:
             header_value = 'product=%s;' % self.target.name
-        elif IProductSeriesBugTask.providedBy(self):
+        elif self.productseries:
             header_value = 'product=%s; productseries=%s;' % (
                 self.productseries.product.name, self.productseries.name)
-        elif IDistroBugTask.providedBy(self):
+        elif self.distribution:
             header_value = ((
                 'distribution=%(distroname)s; '
                 'sourcepackage=%(sourcepackagename)s; '
@@ -1200,7 +1171,7 @@
                 {'distroname': self.distribution.name,
                  'sourcepackagename': sourcepackagename_value,
                  'componentname': component_name})
-        elif IDistroSeriesBugTask.providedBy(self):
+        elif self.distroseries:
             header_value = ((
                 'distribution=%(distroname)s; '
                 'distroseries=%(distroseriesname)s; '
@@ -1229,25 +1200,6 @@
 
     def getDelta(self, old_task):
         """See `IBugTask`."""
-        valid_interfaces = [
-            IUpstreamBugTask,
-            IProductSeriesBugTask,
-            IDistroBugTask,
-            IDistroSeriesBugTask,
-            ]
-
-        # This tries to find a matching pair of bug tasks, i.e. where
-        # both provide IUpstreamBugTask, or both IDistroBugTask.
-        # Failing that, it drops off the bottom of the loop and raises
-        # the TypeError.
-        for interface in valid_interfaces:
-            if interface.providedBy(self) and interface.providedBy(old_task):
-                break
-        else:
-            raise TypeError(
-                "Can't calculate delta on bug tasks of incompatible types: "
-                "[%s, %s]." % (repr(old_task), repr(self)))
-
         # calculate the differences in the fields that both types of tasks
         # have in common
         changes = {}
@@ -1270,14 +1222,7 @@
         """Can the user edit this tasks's pillar?"""
         if user is None:
             return False
-        if IUpstreamBugTask.providedBy(self):
-            pillar = self.product
-        elif IProductSeriesBugTask.providedBy(self):
-            pillar = self.productseries.product
-        elif IDistroBugTask.providedBy(self):
-            pillar = self.distribution
-        else:
-            pillar = self.distroseries.distribution
+        pillar = self.pillar
         return ((pillar.bug_supervisor is not None and
                  user.inTeam(pillar.bug_supervisor)) or
                 pillar.userCanEdit(user))

=== modified file 'lib/lp/bugs/tests/test_bugnotification.py'
--- lib/lp/bugs/tests/test_bugnotification.py	2011-05-23 09:13:32 +0000
+++ lib/lp/bugs/tests/test_bugnotification.py	2011-07-21 07:27:39 +0000
@@ -29,7 +29,7 @@
 from lp.answers.tests.test_question_notifications import pop_questionemailjobs
 from lp.bugs.interfaces.bugtask import (
     BugTaskStatus,
-    IUpstreamBugTask,
+    IBugTask,
     )
 from lp.bugs.model.bugnotification import (
     BugNotification,
@@ -134,8 +134,7 @@
         # Ensure that notifications are sent to subscribers of a
         # question linked to the expired bug.
         bugtask = self.bug.default_bugtask
-        bugtask_before_modification = Snapshot(
-            bugtask, providing=IUpstreamBugTask)
+        bugtask_before_modification = Snapshot(bugtask, providing=IBugTask)
         bugtask.transitionToStatus(BugTaskStatus.EXPIRED, self.product.owner)
         bug_modified = ObjectModifiedEvent(
             bugtask, bugtask_before_modification, ["status"])