← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/launchpad/bugtasksearch-interfaces into lp:launchpad

 

William Grant has proposed merging lp:~wgrant/launchpad/bugtasksearch-interfaces into lp:launchpad.

Requested reviews:
  William Grant (wgrant)

For more details, see:
https://code.launchpad.net/~wgrant/launchpad/bugtasksearch-interfaces/+merge/118466

Months ago I split the core bugtask search model code out of lp.bugs.model.bugtask into lp.bugs.model.bugtasksearch. This branch begins the interface split, with BugTaskSearchParams being the first victim. Lots of imports needed changing in a lot of places.
-- 
https://code.launchpad.net/~wgrant/launchpad/bugtasksearch-interfaces/+merge/118466
Your team Launchpad code reviewers is subscribed to branch lp:launchpad.
=== modified file 'lib/lp/app/__init__.py'
--- lib/lp/app/__init__.py	2012-06-14 05:31:23 +0000
+++ lib/lp/app/__init__.py	2012-08-07 03:50:27 +0000
@@ -15,6 +15,8 @@
 # values, but they kindly left this global variable for you to monkey patch if
 # you want the old behavior, just like we do.
 from zope.app.form.browser import itemswidgets
+
+
 itemswidgets.EXPLICIT_EMPTY_SELECTION = False
 
 # Monkeypatch our embedded BeautifulSoup and the one in mechanize to

=== modified file 'lib/lp/app/browser/linkchecker.py'
--- lib/lp/app/browser/linkchecker.py	2012-01-01 02:58:52 +0000
+++ lib/lp/app/browser/linkchecker.py	2012-08-07 03:50:27 +0000
@@ -12,10 +12,8 @@
 from zope.component import getUtility
 
 from lp.app.errors import NotFoundError
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.code.errors import (
     CannotHaveLinkedBranch,
     InvalidNamespace,

=== modified file 'lib/lp/blueprints/model/specification.py'
--- lib/lp/blueprints/model/specification.py	2012-06-18 11:19:46 +0000
+++ lib/lp/blueprints/model/specification.py	2012-08-07 03:50:27 +0000
@@ -62,11 +62,9 @@
     )
 from lp.blueprints.model.specificationworkitem import SpecificationWorkItem
 from lp.bugs.interfaces.buglink import IBugLinkTarget
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
 from lp.bugs.interfaces.bugtaskfilter import filter_bugtasks_by_context
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.buglinktarget import BugLinkTargetMixin
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.distroseries import IDistroSeries

=== modified file 'lib/lp/bugs/browser/bug.py'
--- lib/lp/bugs/browser/bug.py	2012-08-03 01:42:13 +0000
+++ lib/lp/bugs/browser/bug.py	2012-08-07 03:50:27 +0000
@@ -79,11 +79,11 @@
     )
 from lp.bugs.interfaces.bugnomination import IBugNominationSet
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTask,
     IFrontPageBugTaskSearch,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.bugwatch import IBugWatchSet
 from lp.bugs.interfaces.cve import ICveSet
 from lp.bugs.mail.bugnotificationbuilder import format_rfc2822_date

=== modified file 'lib/lp/bugs/browser/buglinktarget.py'
--- lib/lp/bugs/browser/buglinktarget.py	2012-01-01 02:58:52 +0000
+++ lib/lp/bugs/browser/buglinktarget.py	2012-08-07 03:50:27 +0000
@@ -33,10 +33,8 @@
     IBugLinkForm,
     IUnlinkBugsForm,
     )
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.services.config import config
 from lp.services.propertycache import (
     cachedproperty,

=== modified file 'lib/lp/bugs/browser/bugtask.py'
--- lib/lp/bugs/browser/bugtask.py	2012-07-26 05:56:54 +0000
+++ lib/lp/bugs/browser/bugtask.py	2012-08-07 03:50:27 +0000
@@ -191,7 +191,6 @@
     BugBranchSearch,
     BugTagsSearchCombinator,
     BugTaskImportance,
-    BugTaskSearchParams,
     BugTaskStatus,
     BugTaskStatusSearch,
     BugTaskStatusSearchDisplay,
@@ -210,6 +209,7 @@
     UNRESOLVED_BUGTASK_STATUSES,
     UserCannotEditBugTaskStatus,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.bugtracker import (
     BugTrackerType,
     IHasExternalBugTracker,

=== modified file 'lib/lp/bugs/browser/cvereport.py'
--- lib/lp/bugs/browser/cvereport.py	2012-03-07 19:04:02 +0000
+++ lib/lp/bugs/browser/cvereport.py	2012-08-07 03:50:27 +0000
@@ -15,10 +15,10 @@
 from lp.app.browser.stringformatter import escape
 from lp.bugs.browser.bugtask import BugTaskListingItem
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     IBugTaskSet,
     RESOLVED_BUGTASK_STATUSES,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.cve import ICveSet
 from lp.registry.interfaces.person import IPersonSet
 from lp.services.helpers import shortlist

=== modified file 'lib/lp/bugs/browser/tests/bug-views.txt'
--- lib/lp/bugs/browser/tests/bug-views.txt	2012-08-03 02:43:20 +0000
+++ lib/lp/bugs/browser/tests/bug-views.txt	2012-08-07 03:50:27 +0000
@@ -35,10 +35,8 @@
     ...     )
     >>> from lp.services.webapp.servers import LaunchpadTestRequest
     >>> from lp.bugs.interfaces.bug import IBugSet
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskSearchParams,
-    ...     IBugTaskSet,
-    ...     )
+    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> from lp.registry.interfaces.distribution import IDistributionSet
     >>> from lp.registry.interfaces.person import IPersonSet
     >>> from lp.registry.interfaces.product import IProductSet

=== modified file 'lib/lp/bugs/configure.zcml'
--- lib/lp/bugs/configure.zcml	2012-07-27 01:15:04 +0000
+++ lib/lp/bugs/configure.zcml	2012-08-07 03:50:27 +0000
@@ -298,7 +298,7 @@
 
         <!-- BugTaskSearchParams -->
         <class
-            class="lp.bugs.interfaces.bugtask.BugTaskSearchParams">
+            class="lp.bugs.interfaces.bugtasksearch.BugTaskSearchParams">
             <allow
                 attributes="
                     setTarget

=== modified file 'lib/lp/bugs/doc/bug-nomination.txt'
--- lib/lp/bugs/doc/bug-nomination.txt	2012-05-22 12:05:51 +0000
+++ lib/lp/bugs/doc/bug-nomination.txt	2012-08-07 03:50:27 +0000
@@ -225,7 +225,7 @@
 For example, there are currently no bugtasks on the firefox_trunk
 productseries.
 
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 
     >>> params = BugTaskSearchParams(user=no_privs, bug=bug_one)
     >>> found_tasks = firefox_trunk.searchTasks(params)

=== modified file 'lib/lp/bugs/doc/bug-tags.txt'
--- lib/lp/bugs/doc/bug-tags.txt	2012-08-03 01:42:13 +0000
+++ lib/lp/bugs/doc/bug-tags.txt	2012-08-07 03:50:27 +0000
@@ -227,7 +227,7 @@
 We can search for bugs with some specific tag.
 
     >>> from lp.services.searchbuilder import all
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> from lp.registry.interfaces.distribution import IDistributionSet
     >>> ubuntu = getUtility(IDistributionSet).getByName('ubuntu')
     >>> svg_tasks = ubuntu.searchTasks(

=== modified file 'lib/lp/bugs/doc/bug.txt'
--- lib/lp/bugs/doc/bug.txt	2012-08-03 15:04:12 +0000
+++ lib/lp/bugs/doc/bug.txt	2012-08-07 03:50:27 +0000
@@ -254,8 +254,8 @@
 Note that a search will return all public bugs, omitting bug 14 which is
 private:
 
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     IBugTaskSet, BugTaskSearchParams)
+    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> from lp.bugs.model.bug import Bug
     >>> from lp.services.database.lpstorm import IStore
 

=== modified file 'lib/lp/bugs/doc/bugattachments.txt'
--- lib/lp/bugs/doc/bugattachments.txt	2012-05-02 05:25:11 +0000
+++ lib/lp/bugs/doc/bugattachments.txt	2012-08-07 03:50:27 +0000
@@ -385,10 +385,8 @@
 We can search for attachment of a specific types:
 
     >>> from lp.bugs.interfaces.bugattachment import BugAttachmentType
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskSearchParams,
-    ...     IBugTaskSet,
-    ...     )
+    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> bugtaskset = getUtility(IBugTaskSet)
     >>> attachmenttype = BugAttachmentType.UNSPECIFIED
     >>> params = BugTaskSearchParams(attachmenttype=attachmenttype, user=None)

=== modified file 'lib/lp/bugs/doc/bugtask-search.txt'
--- lib/lp/bugs/doc/bugtask-search.txt	2012-07-27 13:12:41 +0000
+++ lib/lp/bugs/doc/bugtask-search.txt	2012-08-07 03:50:27 +0000
@@ -4,10 +4,8 @@
 method, but they all delegate the search to IBugTaskSet.search(). That
 method accepts a single parameter; an BugTaskSearchParams instance.
 
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskSearchParams,
-    ...     IBugTaskSet,
-    ...     )
+    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> bugtask_set = getUtility(IBugTaskSet)
     >>> all_public = BugTaskSearchParams(user=None)
     >>> found_bugtasks = bugtask_set.search(all_public)

=== modified file 'lib/lp/bugs/doc/cve.txt'
--- lib/lp/bugs/doc/cve.txt	2012-01-20 17:12:18 +0000
+++ lib/lp/bugs/doc/cve.txt	2012-08-07 03:50:27 +0000
@@ -106,7 +106,7 @@
 distribution. The method that drives this report is
 ICveSet.getBugCvesForBugTasks:
 
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> from lp.registry.model.distribution import Distribution
     >>> params = BugTaskSearchParams(None)
     >>> ubuntu = Distribution.selectOneBy(name="ubuntu")

=== modified file 'lib/lp/bugs/interfaces/bugtask.py'
--- lib/lp/bugs/interfaces/bugtask.py	2012-07-11 01:43:30 +0000
+++ lib/lp/bugs/interfaces/bugtask.py	2012-08-07 03:50:27 +0000
@@ -13,7 +13,6 @@
     'BugBranchSearch',
     'BugTagsSearchCombinator',
     'BugTaskImportance',
-    'BugTaskSearchParams',
     'BugTaskStatus',
     'BugTaskStatusSearch',
     'BugTaskStatusSearchDisplay',
@@ -47,7 +46,6 @@
     'valid_remote_bug_url',
     ]
 
-import collections
 import httplib
 
 from lazr.enum import (
@@ -98,7 +96,6 @@
     SimpleVocabulary,
     )
 from zope.security.interfaces import Unauthorized
-from zope.security.proxy import isinstance as zope_isinstance
 
 from lp import _
 from lp.app.interfaces.launchpad import IHasDateCreated
@@ -120,11 +117,6 @@
     StrippedTextLine,
     Summary,
     )
-from lp.services.searchbuilder import (
-    all,
-    any,
-    NULL,
-    )
 from lp.services.webapp.interfaces import ITableBatchNavigator
 from lp.soyuz.interfaces.component import IComponent
 
@@ -1123,354 +1115,6 @@
     milestone = Attribute("The milestone for which this task is scheduled.")
 
 
-class BugTaskSearchParams:
-    """Encapsulates search parameters for BugTask.search()
-
-    Details:
-
-      user is an object that provides IPerson, and represents the
-      person performing the query (which is important to know for, for
-      example, privacy-aware results.) If user is None, the search
-      will be filtered to only consider public bugs.
-
-      product, distribution and distroseries (IBugTargets) should /not/
-      be supplied to BugTaskSearchParams; instead, IBugTarget's
-      searchTasks() method should be invoked with a single search_params
-      argument.
-
-      Keyword arguments should always be used. The argument passing
-      semantics are as follows:
-
-        * BugTaskSearchParams(arg='foo', user=bar): Match all IBugTasks
-          where IBugTask.arg == 'foo' for user bar.
-
-        * BugTaskSearchParams(arg=any('foo', 'bar')): Match all
-          IBugTasks where IBugTask.arg == 'foo' or IBugTask.arg ==
-          'bar'. In this case, no user was passed, so all private bugs
-          are excluded from the search results.
-
-        * BugTaskSearchParams(arg1='foo', arg2='bar'): Match all
-          IBugTasks where IBugTask.arg1 == 'foo' and IBugTask.arg2 ==
-          'bar'
-
-    The set will be ordered primarily by the column specified in orderby,
-    and then by bugtask id.
-
-    For a more thorough treatment, check out:
-
-        lib/lp/bugs/doc/bugtask-search.txt
-    """
-
-    product = None
-    project = None
-    distribution = None
-    distroseries = None
-    productseries = None
-
-    def __init__(self, user, bug=None, searchtext=None, fast_searchtext=None,
-                 status=None, importance=None, milestone=None,
-                 milestone_tag=None, assignee=None, sourcepackagename=None,
-                 owner=None, attachmenttype=None, orderby=None,
-                 omit_dupes=False, subscriber=None, component=None,
-                 pending_bugwatch_elsewhere=False, resolved_upstream=False,
-                 open_upstream=False, has_no_upstream_bugtask=False, tag=None,
-                 has_cve=False, bug_supervisor=None, bug_reporter=None,
-                 nominated_for=None, bug_commenter=None, omit_targeted=False,
-                 date_closed=None, affected_user=None, affects_me=False,
-                 hardware_bus=None, hardware_vendor_id=None,
-                 hardware_product_id=None, hardware_driver_name=None,
-                 hardware_driver_package_name=None,
-                 hardware_owner_is_bug_reporter=None,
-                 hardware_owner_is_affected_by_bug=False,
-                 hardware_owner_is_subscribed_to_bug=False,
-                 hardware_is_linked_to_bug=False,
-                 linked_branches=None, linked_blueprints=None,
-                 structural_subscriber=None, modified_since=None,
-                 created_since=None, exclude_conjoined_tasks=False, cve=None,
-                 upstream_target=None, milestone_dateexpected_before=None,
-                 milestone_dateexpected_after=None, created_before=None,
-                 information_type=None):
-
-        self.bug = bug
-        self.searchtext = searchtext
-        self.fast_searchtext = fast_searchtext
-        self.status = status
-        self.importance = importance
-        self.milestone = milestone
-        self.milestone_tag = milestone_tag
-        self.assignee = assignee
-        self.sourcepackagename = sourcepackagename
-        self.owner = owner
-        self.attachmenttype = attachmenttype
-        self.user = user
-        self.orderby = orderby
-        self.omit_dupes = omit_dupes
-        self.omit_targeted = omit_targeted
-        self.subscriber = subscriber
-        self.component = component
-        self.pending_bugwatch_elsewhere = pending_bugwatch_elsewhere
-        self.resolved_upstream = resolved_upstream
-        self.open_upstream = open_upstream
-        self.has_no_upstream_bugtask = has_no_upstream_bugtask
-        self.tag = tag
-        self.has_cve = has_cve
-        self.bug_supervisor = bug_supervisor
-        self.bug_reporter = bug_reporter
-        self.nominated_for = nominated_for
-        self.bug_commenter = bug_commenter
-        self.date_closed = date_closed
-        self.affected_user = affected_user
-        self.affects_me = affects_me
-        self.hardware_bus = hardware_bus
-        self.hardware_vendor_id = hardware_vendor_id
-        self.hardware_product_id = hardware_product_id
-        self.hardware_driver_name = hardware_driver_name
-        self.hardware_driver_package_name = hardware_driver_package_name
-        self.hardware_owner_is_bug_reporter = hardware_owner_is_bug_reporter
-        self.hardware_owner_is_affected_by_bug = (
-            hardware_owner_is_affected_by_bug)
-        self.hardware_owner_is_subscribed_to_bug = (
-            hardware_owner_is_subscribed_to_bug)
-        self.hardware_is_linked_to_bug = hardware_is_linked_to_bug
-        self.linked_branches = linked_branches
-        self.linked_blueprints = linked_blueprints
-        self.structural_subscriber = structural_subscriber
-        self.modified_since = modified_since
-        self.created_since = created_since
-        self.created_before = created_before
-        self.exclude_conjoined_tasks = exclude_conjoined_tasks
-        self.cve = cve
-        self.upstream_target = upstream_target
-        self.milestone_dateexpected_before = milestone_dateexpected_before
-        self.milestone_dateexpected_after = milestone_dateexpected_after
-        if isinstance(information_type, collections.Iterable):
-            self.information_type = set(information_type)
-        elif information_type:
-            self.information_type = set((information_type,))
-        else:
-            self.information_type = None
-
-    def setProduct(self, product):
-        """Set the upstream context on which to filter the search."""
-        self.product = product
-
-    def setProject(self, project):
-        """Set the upstream context on which to filter the search."""
-        self.project = project
-
-    def setDistribution(self, distribution):
-        """Set the distribution context on which to filter the search."""
-        self.distribution = distribution
-
-    def setDistroSeries(self, distroseries):
-        """Set the distroseries context on which to filter the search."""
-        self.distroseries = distroseries
-
-    def setProductSeries(self, productseries):
-        """Set the productseries context on which to filter the search."""
-        self.productseries = productseries
-
-    def setSourcePackage(self, sourcepackage):
-        """Set the sourcepackage context on which to filter the search."""
-        # Import this here to avoid circular dependencies
-        from lp.registry.interfaces.sourcepackage import (
-            ISourcePackage)
-        if isinstance(sourcepackage, any):
-            # Unwrap the source package.
-            self.sourcepackagename = any(*[
-                pkg.sourcepackagename for pkg in sourcepackage.query_values])
-            distroseries = any(*[pkg.distroseries for pkg in
-                sourcepackage.query_values if ISourcePackage.providedBy(pkg)])
-            distributions = any(*[pkg.distribution for pkg in
-                sourcepackage.query_values
-                if not ISourcePackage.providedBy(pkg)])
-            if distroseries.query_values and not distributions.query_values:
-                self.distroseries = distroseries
-            elif not distroseries.query_values and distributions.query_values:
-                self.distributions = distributions
-            else:
-                # At this point we have determined that either we have both
-                # distroseries and distributions, or we have neither of them.
-                # We will set both.  Doing so will give us the cross-product,
-                # because searching source packages is
-                # sourcepackagename-specific rather than actually
-                # context-specific. This is not ideal but is tolerable given
-                # no actual use of mixed-type any() exists today.
-                self.distroseries = distroseries
-                self.distributions = distributions
-            return
-        if ISourcePackage.providedBy(sourcepackage):
-            # This is a sourcepackage in a distro series.
-            self.distroseries = sourcepackage.distroseries
-        else:
-            # This is a sourcepackage in a distribution.
-            self.distribution = sourcepackage.distribution
-        self.sourcepackagename = sourcepackage.sourcepackagename
-
-    def setTarget(self, target):
-        """Constrain the search to only return items in target.
-
-        This is equivalent to calling setProduct etc but the type of target
-        does not need to be known to the caller.
-
-        :param target: A `IHasBug`, or some search term like all/any/none on
-            `IHasBug`. If using all/any all the targets must be of the
-            same type due to implementation limitations. Currently only
-            distroseries and productseries `IHasBug` implementations are
-            supported.
-        """
-        # Yay circular deps.
-        from lp.registry.interfaces.distribution import IDistribution
-        from lp.registry.interfaces.distroseries import IDistroSeries
-        from lp.registry.interfaces.product import IProduct
-        from lp.registry.interfaces.productseries import IProductSeries
-        from lp.registry.interfaces.milestone import IMilestone
-        from lp.registry.interfaces.projectgroup import IProjectGroup
-        from lp.registry.interfaces.sourcepackage import ISourcePackage
-        from lp.registry.interfaces.distributionsourcepackage import \
-            IDistributionSourcePackage
-        if isinstance(target, (any, all)):
-            assert len(target.query_values), \
-                'cannot determine target with no targets'
-            instance = target.query_values[0]
-        else:
-            instance = target
-        if IDistribution.providedBy(instance):
-            self.setDistribution(target)
-        elif IDistroSeries.providedBy(instance):
-            self.setDistroSeries(target)
-        elif IProduct.providedBy(instance):
-            self.setProduct(target)
-        elif IProductSeries.providedBy(instance):
-            self.setProductSeries(target)
-        elif IMilestone.providedBy(instance):
-            self.milestone = target
-        elif ISourcePackage.providedBy(instance):
-            self.setSourcePackage(target)
-        elif IDistributionSourcePackage.providedBy(instance):
-            self.setSourcePackage(target)
-        elif IProjectGroup.providedBy(instance):
-            self.setProject(target)
-        else:
-            raise AssertionError("unknown target type %r" % target)
-
-    @classmethod
-    def _anyfy(cls, value):
-        """If value is a sequence, wrap its items with the `any` combinator.
-
-        Otherwise, return value as is, or None if it's a zero-length sequence.
-        """
-        if zope_isinstance(value, (list, tuple)):
-            if len(value) > 1:
-                return any(*value)
-            elif len(value) == 1:
-                return value[0]
-            else:
-                return None
-        else:
-            return value
-
-    @classmethod
-    def fromSearchForm(cls, user,
-                       order_by=('-importance', ), search_text=None,
-                       status=list(UNRESOLVED_BUGTASK_STATUSES),
-                       importance=None,
-                       assignee=None, bug_reporter=None, bug_supervisor=None,
-                       bug_commenter=None, bug_subscriber=None, owner=None,
-                       affected_user=None, affects_me=False,
-                       has_patch=None, has_cve=None,
-                       distribution=None, tags=None,
-                       tags_combinator=BugTagsSearchCombinator.ALL,
-                       omit_duplicates=True, omit_targeted=None,
-                       status_upstream=None, milestone_assignment=None,
-                       milestone=None, component=None, nominated_for=None,
-                       sourcepackagename=None, has_no_package=None,
-                       hardware_bus=None, hardware_vendor_id=None,
-                       hardware_product_id=None, hardware_driver_name=None,
-                       hardware_driver_package_name=None,
-                       hardware_owner_is_bug_reporter=None,
-                       hardware_owner_is_affected_by_bug=False,
-                       hardware_owner_is_subscribed_to_bug=False,
-                       hardware_is_linked_to_bug=False, linked_branches=None,
-                       linked_blueprints=None, structural_subscriber=None,
-                       modified_since=None, created_since=None,
-                       created_before=None, information_type=None):
-        """Create and return a new instance using the parameter list."""
-        search_params = cls(user=user, orderby=order_by)
-
-        search_params.searchtext = search_text
-        search_params.status = cls._anyfy(status)
-        search_params.importance = cls._anyfy(importance)
-        search_params.assignee = assignee
-        search_params.bug_reporter = bug_reporter
-        search_params.bug_supervisor = bug_supervisor
-        search_params.bug_commenter = bug_commenter
-        search_params.subscriber = bug_subscriber
-        search_params.owner = owner
-        search_params.affected_user = affected_user
-        search_params.distribution = distribution
-        if has_patch:
-            # Import this here to avoid circular imports
-            from lp.bugs.interfaces.bugattachment import (
-                BugAttachmentType)
-            search_params.attachmenttype = BugAttachmentType.PATCH
-        search_params.has_cve = has_cve
-        if zope_isinstance(tags, (list, tuple)):
-            if len(tags) > 0:
-                if tags_combinator == BugTagsSearchCombinator.ALL:
-                    search_params.tag = all(*tags)
-                else:
-                    search_params.tag = any(*tags)
-        elif zope_isinstance(tags, str):
-            search_params.tag = tags
-        elif tags is None:
-            pass  # tags not supplied
-        else:
-            raise AssertionError(
-                'Tags can only be supplied as a list or a string.')
-        search_params.omit_dupes = omit_duplicates
-        search_params.omit_targeted = omit_targeted
-        if status_upstream is not None:
-            if 'pending_bugwatch' in status_upstream:
-                search_params.pending_bugwatch_elsewhere = True
-            if 'resolved_upstream' in status_upstream:
-                search_params.resolved_upstream = True
-            if 'open_upstream' in status_upstream:
-                search_params.open_upstream = True
-            if 'hide_upstream' in status_upstream:
-                search_params.has_no_upstream_bugtask = True
-        search_params.milestone = cls._anyfy(milestone)
-        search_params.component = cls._anyfy(component)
-        search_params.sourcepackagename = sourcepackagename
-        if has_no_package:
-            search_params.sourcepackagename = NULL
-        search_params.nominated_for = nominated_for
-
-        search_params.hardware_bus = hardware_bus
-        search_params.hardware_vendor_id = hardware_vendor_id
-        search_params.hardware_product_id = hardware_product_id
-        search_params.hardware_driver_name = hardware_driver_name
-        search_params.hardware_driver_package_name = (
-            hardware_driver_package_name)
-        search_params.hardware_owner_is_bug_reporter = (
-            hardware_owner_is_bug_reporter)
-        search_params.hardware_owner_is_affected_by_bug = (
-            hardware_owner_is_affected_by_bug)
-        search_params.hardware_owner_is_subscribed_to_bug = (
-            hardware_owner_is_subscribed_to_bug)
-        search_params.hardware_is_linked_to_bug = (
-            hardware_is_linked_to_bug)
-        search_params.linked_branches = linked_branches
-        search_params.linked_blueprints = linked_blueprints
-        search_params.structural_subscriber = structural_subscriber
-        search_params.modified_since = modified_since
-        search_params.created_since = created_since
-        search_params.created_before = created_before
-        search_params.information_type = information_type
-
-        return search_params
-
-
 class IBugTaskSet(Interface):
     """A utility to retrieving BugTasks."""
     title = Attribute('Title')

=== added file 'lib/lp/bugs/interfaces/bugtasksearch.py'
--- lib/lp/bugs/interfaces/bugtasksearch.py	1970-01-01 00:00:00 +0000
+++ lib/lp/bugs/interfaces/bugtasksearch.py	2012-08-07 03:50:27 +0000
@@ -0,0 +1,374 @@
+# Copyright 2009-2012 Canonical Ltd.  This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Interfaces for searching bug tasks. Mostly used with IBugTaskSet."""
+
+__metaclass__ = type
+
+__all__ = [
+    'BugTaskSearchParams',
+    ]
+
+import collections
+
+from zope.security.proxy import isinstance as zope_isinstance
+
+from lp.bugs.interfaces.bugtask import (
+    BugTagsSearchCombinator,
+    UNRESOLVED_BUGTASK_STATUSES,
+    )
+from lp.services.searchbuilder import (
+    all,
+    any,
+    NULL,
+    )
+
+
+class BugTaskSearchParams:
+    """Encapsulates search parameters for BugTask.search()
+
+    Details:
+
+      user is an object that provides IPerson, and represents the
+      person performing the query (which is important to know for, for
+      example, privacy-aware results.) If user is None, the search
+      will be filtered to only consider public bugs.
+
+      product, distribution and distroseries (IBugTargets) should /not/
+      be supplied to BugTaskSearchParams; instead, IBugTarget's
+      searchTasks() method should be invoked with a single search_params
+      argument.
+
+      Keyword arguments should always be used. The argument passing
+      semantics are as follows:
+
+        * BugTaskSearchParams(arg='foo', user=bar): Match all IBugTasks
+          where IBugTask.arg == 'foo' for user bar.
+
+        * BugTaskSearchParams(arg=any('foo', 'bar')): Match all
+          IBugTasks where IBugTask.arg == 'foo' or IBugTask.arg ==
+          'bar'. In this case, no user was passed, so all private bugs
+          are excluded from the search results.
+
+        * BugTaskSearchParams(arg1='foo', arg2='bar'): Match all
+          IBugTasks where IBugTask.arg1 == 'foo' and IBugTask.arg2 ==
+          'bar'
+
+    The set will be ordered primarily by the column specified in orderby,
+    and then by bugtask id.
+
+    For a more thorough treatment, check out:
+
+        lib/lp/bugs/doc/bugtask-search.txt
+    """
+
+    product = None
+    project = None
+    distribution = None
+    distroseries = None
+    productseries = None
+
+    def __init__(self, user, bug=None, searchtext=None, fast_searchtext=None,
+                 status=None, importance=None, milestone=None,
+                 milestone_tag=None, assignee=None, sourcepackagename=None,
+                 owner=None, attachmenttype=None, orderby=None,
+                 omit_dupes=False, subscriber=None, component=None,
+                 pending_bugwatch_elsewhere=False, resolved_upstream=False,
+                 open_upstream=False, has_no_upstream_bugtask=False, tag=None,
+                 has_cve=False, bug_supervisor=None, bug_reporter=None,
+                 nominated_for=None, bug_commenter=None, omit_targeted=False,
+                 date_closed=None, affected_user=None, affects_me=False,
+                 hardware_bus=None, hardware_vendor_id=None,
+                 hardware_product_id=None, hardware_driver_name=None,
+                 hardware_driver_package_name=None,
+                 hardware_owner_is_bug_reporter=None,
+                 hardware_owner_is_affected_by_bug=False,
+                 hardware_owner_is_subscribed_to_bug=False,
+                 hardware_is_linked_to_bug=False,
+                 linked_branches=None, linked_blueprints=None,
+                 structural_subscriber=None, modified_since=None,
+                 created_since=None, exclude_conjoined_tasks=False, cve=None,
+                 upstream_target=None, milestone_dateexpected_before=None,
+                 milestone_dateexpected_after=None, created_before=None,
+                 information_type=None):
+
+        self.bug = bug
+        self.searchtext = searchtext
+        self.fast_searchtext = fast_searchtext
+        self.status = status
+        self.importance = importance
+        self.milestone = milestone
+        self.milestone_tag = milestone_tag
+        self.assignee = assignee
+        self.sourcepackagename = sourcepackagename
+        self.owner = owner
+        self.attachmenttype = attachmenttype
+        self.user = user
+        self.orderby = orderby
+        self.omit_dupes = omit_dupes
+        self.omit_targeted = omit_targeted
+        self.subscriber = subscriber
+        self.component = component
+        self.pending_bugwatch_elsewhere = pending_bugwatch_elsewhere
+        self.resolved_upstream = resolved_upstream
+        self.open_upstream = open_upstream
+        self.has_no_upstream_bugtask = has_no_upstream_bugtask
+        self.tag = tag
+        self.has_cve = has_cve
+        self.bug_supervisor = bug_supervisor
+        self.bug_reporter = bug_reporter
+        self.nominated_for = nominated_for
+        self.bug_commenter = bug_commenter
+        self.date_closed = date_closed
+        self.affected_user = affected_user
+        self.affects_me = affects_me
+        self.hardware_bus = hardware_bus
+        self.hardware_vendor_id = hardware_vendor_id
+        self.hardware_product_id = hardware_product_id
+        self.hardware_driver_name = hardware_driver_name
+        self.hardware_driver_package_name = hardware_driver_package_name
+        self.hardware_owner_is_bug_reporter = hardware_owner_is_bug_reporter
+        self.hardware_owner_is_affected_by_bug = (
+            hardware_owner_is_affected_by_bug)
+        self.hardware_owner_is_subscribed_to_bug = (
+            hardware_owner_is_subscribed_to_bug)
+        self.hardware_is_linked_to_bug = hardware_is_linked_to_bug
+        self.linked_branches = linked_branches
+        self.linked_blueprints = linked_blueprints
+        self.structural_subscriber = structural_subscriber
+        self.modified_since = modified_since
+        self.created_since = created_since
+        self.created_before = created_before
+        self.exclude_conjoined_tasks = exclude_conjoined_tasks
+        self.cve = cve
+        self.upstream_target = upstream_target
+        self.milestone_dateexpected_before = milestone_dateexpected_before
+        self.milestone_dateexpected_after = milestone_dateexpected_after
+        if isinstance(information_type, collections.Iterable):
+            self.information_type = set(information_type)
+        elif information_type:
+            self.information_type = set((information_type,))
+        else:
+            self.information_type = None
+
+    def setProduct(self, product):
+        """Set the upstream context on which to filter the search."""
+        self.product = product
+
+    def setProject(self, project):
+        """Set the upstream context on which to filter the search."""
+        self.project = project
+
+    def setDistribution(self, distribution):
+        """Set the distribution context on which to filter the search."""
+        self.distribution = distribution
+
+    def setDistroSeries(self, distroseries):
+        """Set the distroseries context on which to filter the search."""
+        self.distroseries = distroseries
+
+    def setProductSeries(self, productseries):
+        """Set the productseries context on which to filter the search."""
+        self.productseries = productseries
+
+    def setSourcePackage(self, sourcepackage):
+        """Set the sourcepackage context on which to filter the search."""
+        # Import this here to avoid circular dependencies
+        from lp.registry.interfaces.sourcepackage import (
+            ISourcePackage)
+        if isinstance(sourcepackage, any):
+            # Unwrap the source package.
+            self.sourcepackagename = any(*[
+                pkg.sourcepackagename for pkg in sourcepackage.query_values])
+            distroseries = any(*[pkg.distroseries for pkg in
+                sourcepackage.query_values if ISourcePackage.providedBy(pkg)])
+            distributions = any(*[pkg.distribution for pkg in
+                sourcepackage.query_values
+                if not ISourcePackage.providedBy(pkg)])
+            if distroseries.query_values and not distributions.query_values:
+                self.distroseries = distroseries
+            elif not distroseries.query_values and distributions.query_values:
+                self.distributions = distributions
+            else:
+                # At this point we have determined that either we have both
+                # distroseries and distributions, or we have neither of them.
+                # We will set both.  Doing so will give us the cross-product,
+                # because searching source packages is
+                # sourcepackagename-specific rather than actually
+                # context-specific. This is not ideal but is tolerable given
+                # no actual use of mixed-type any() exists today.
+                self.distroseries = distroseries
+                self.distributions = distributions
+            return
+        if ISourcePackage.providedBy(sourcepackage):
+            # This is a sourcepackage in a distro series.
+            self.distroseries = sourcepackage.distroseries
+        else:
+            # This is a sourcepackage in a distribution.
+            self.distribution = sourcepackage.distribution
+        self.sourcepackagename = sourcepackage.sourcepackagename
+
+    def setTarget(self, target):
+        """Constrain the search to only return items in target.
+
+        This is equivalent to calling setProduct etc but the type of target
+        does not need to be known to the caller.
+
+        :param target: A `IHasBug`, or some search term like all/any/none on
+            `IHasBug`. If using all/any all the targets must be of the
+            same type due to implementation limitations. Currently only
+            distroseries and productseries `IHasBug` implementations are
+            supported.
+        """
+        # Yay circular deps.
+        from lp.registry.interfaces.distribution import IDistribution
+        from lp.registry.interfaces.distroseries import IDistroSeries
+        from lp.registry.interfaces.product import IProduct
+        from lp.registry.interfaces.productseries import IProductSeries
+        from lp.registry.interfaces.milestone import IMilestone
+        from lp.registry.interfaces.projectgroup import IProjectGroup
+        from lp.registry.interfaces.sourcepackage import ISourcePackage
+        from lp.registry.interfaces.distributionsourcepackage import \
+            IDistributionSourcePackage
+        if isinstance(target, (any, all)):
+            assert len(target.query_values), \
+                'cannot determine target with no targets'
+            instance = target.query_values[0]
+        else:
+            instance = target
+        if IDistribution.providedBy(instance):
+            self.setDistribution(target)
+        elif IDistroSeries.providedBy(instance):
+            self.setDistroSeries(target)
+        elif IProduct.providedBy(instance):
+            self.setProduct(target)
+        elif IProductSeries.providedBy(instance):
+            self.setProductSeries(target)
+        elif IMilestone.providedBy(instance):
+            self.milestone = target
+        elif ISourcePackage.providedBy(instance):
+            self.setSourcePackage(target)
+        elif IDistributionSourcePackage.providedBy(instance):
+            self.setSourcePackage(target)
+        elif IProjectGroup.providedBy(instance):
+            self.setProject(target)
+        else:
+            raise AssertionError("unknown target type %r" % target)
+
+    @classmethod
+    def _anyfy(cls, value):
+        """If value is a sequence, wrap its items with the `any` combinator.
+
+        Otherwise, return value as is, or None if it's a zero-length sequence.
+        """
+        if zope_isinstance(value, (list, tuple)):
+            if len(value) > 1:
+                return any(*value)
+            elif len(value) == 1:
+                return value[0]
+            else:
+                return None
+        else:
+            return value
+
+    @classmethod
+    def fromSearchForm(cls, user,
+                       order_by=('-importance', ), search_text=None,
+                       status=list(UNRESOLVED_BUGTASK_STATUSES),
+                       importance=None,
+                       assignee=None, bug_reporter=None, bug_supervisor=None,
+                       bug_commenter=None, bug_subscriber=None, owner=None,
+                       affected_user=None, affects_me=False,
+                       has_patch=None, has_cve=None,
+                       distribution=None, tags=None,
+                       tags_combinator=BugTagsSearchCombinator.ALL,
+                       omit_duplicates=True, omit_targeted=None,
+                       status_upstream=None, milestone_assignment=None,
+                       milestone=None, component=None, nominated_for=None,
+                       sourcepackagename=None, has_no_package=None,
+                       hardware_bus=None, hardware_vendor_id=None,
+                       hardware_product_id=None, hardware_driver_name=None,
+                       hardware_driver_package_name=None,
+                       hardware_owner_is_bug_reporter=None,
+                       hardware_owner_is_affected_by_bug=False,
+                       hardware_owner_is_subscribed_to_bug=False,
+                       hardware_is_linked_to_bug=False, linked_branches=None,
+                       linked_blueprints=None, structural_subscriber=None,
+                       modified_since=None, created_since=None,
+                       created_before=None, information_type=None):
+        """Create and return a new instance using the parameter list."""
+        search_params = cls(user=user, orderby=order_by)
+
+        search_params.searchtext = search_text
+        search_params.status = cls._anyfy(status)
+        search_params.importance = cls._anyfy(importance)
+        search_params.assignee = assignee
+        search_params.bug_reporter = bug_reporter
+        search_params.bug_supervisor = bug_supervisor
+        search_params.bug_commenter = bug_commenter
+        search_params.subscriber = bug_subscriber
+        search_params.owner = owner
+        search_params.affected_user = affected_user
+        search_params.distribution = distribution
+        if has_patch:
+            # Import this here to avoid circular imports
+            from lp.bugs.interfaces.bugattachment import (
+                BugAttachmentType)
+            search_params.attachmenttype = BugAttachmentType.PATCH
+        search_params.has_cve = has_cve
+        if zope_isinstance(tags, (list, tuple)):
+            if len(tags) > 0:
+                if tags_combinator == BugTagsSearchCombinator.ALL:
+                    search_params.tag = all(*tags)
+                else:
+                    search_params.tag = any(*tags)
+        elif zope_isinstance(tags, str):
+            search_params.tag = tags
+        elif tags is None:
+            pass  # tags not supplied
+        else:
+            raise AssertionError(
+                'Tags can only be supplied as a list or a string.')
+        search_params.omit_dupes = omit_duplicates
+        search_params.omit_targeted = omit_targeted
+        if status_upstream is not None:
+            if 'pending_bugwatch' in status_upstream:
+                search_params.pending_bugwatch_elsewhere = True
+            if 'resolved_upstream' in status_upstream:
+                search_params.resolved_upstream = True
+            if 'open_upstream' in status_upstream:
+                search_params.open_upstream = True
+            if 'hide_upstream' in status_upstream:
+                search_params.has_no_upstream_bugtask = True
+        search_params.milestone = cls._anyfy(milestone)
+        search_params.component = cls._anyfy(component)
+        search_params.sourcepackagename = sourcepackagename
+        if has_no_package:
+            search_params.sourcepackagename = NULL
+        search_params.nominated_for = nominated_for
+
+        search_params.hardware_bus = hardware_bus
+        search_params.hardware_vendor_id = hardware_vendor_id
+        search_params.hardware_product_id = hardware_product_id
+        search_params.hardware_driver_name = hardware_driver_name
+        search_params.hardware_driver_package_name = (
+            hardware_driver_package_name)
+        search_params.hardware_owner_is_bug_reporter = (
+            hardware_owner_is_bug_reporter)
+        search_params.hardware_owner_is_affected_by_bug = (
+            hardware_owner_is_affected_by_bug)
+        search_params.hardware_owner_is_subscribed_to_bug = (
+            hardware_owner_is_subscribed_to_bug)
+        search_params.hardware_is_linked_to_bug = (
+            hardware_is_linked_to_bug)
+        search_params.linked_branches = linked_branches
+        search_params.linked_blueprints = linked_blueprints
+        search_params.structural_subscriber = structural_subscriber
+        search_params.modified_since = modified_since
+        search_params.created_since = created_since
+        search_params.created_before = created_before
+        search_params.information_type = information_type
+
+        return search_params
+
+

=== modified file 'lib/lp/bugs/model/bug.py'
--- lib/lp/bugs/model/bug.py	2012-08-03 17:04:51 +0000
+++ lib/lp/bugs/model/bug.py	2012-08-07 03:50:27 +0000
@@ -2023,7 +2023,7 @@
         to be made to the queries which screen for privacy.  See
         bugtasksearch's get_bug_privacy_filter.
         """
-        from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+        from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 
         if not self.private:
             # This is a public bug.

=== modified file 'lib/lp/bugs/model/bugtarget.py'
--- lib/lp/bugs/model/bugtarget.py	2012-08-07 00:01:04 +0000
+++ lib/lp/bugs/model/bugtarget.py	2012-08-07 03:50:27 +0000
@@ -24,10 +24,10 @@
 from lp.bugs.interfaces.bugtarget import IOfficialBugTag
 from lp.bugs.interfaces.bugtask import (
     BugTagsSearchCombinator,
-    BugTaskSearchParams,
     UNRESOLVED_BUGTASK_STATUSES,
     )
 from lp.bugs.interfaces.bugtaskfilter import simple_weight_calculator
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugtask import BugTaskSet
 from lp.registry.interfaces.distribution import IDistribution
 from lp.registry.interfaces.product import IProduct

=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py	2012-07-25 05:43:37 +0000
+++ lib/lp/bugs/model/bugtask.py	2012-08-07 03:50:27 +0000
@@ -78,7 +78,6 @@
 from lp.bugs.interfaces.bugtask import (
     BUG_SUPERVISOR_BUGTASK_STATUSES,
     BugTaskImportance,
-    BugTaskSearchParams,
     BugTaskStatus,
     BugTaskStatusSearch,
     CannotDeleteBugtask,
@@ -97,6 +96,7 @@
     UserCannotEditBugTaskMilestone,
     UserCannotEditBugTaskStatus,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.enums import (
     InformationType,
     PUBLIC_INFORMATION_TYPES,

=== modified file 'lib/lp/bugs/model/bugtasksearch.py'
--- lib/lp/bugs/model/bugtasksearch.py	2012-07-27 13:12:41 +0000
+++ lib/lp/bugs/model/bugtasksearch.py	2012-08-07 03:50:27 +0000
@@ -44,11 +44,11 @@
 from lp.bugs.interfaces.bugtask import (
     BugBlueprintSearch,
     BugBranchSearch,
-    BugTaskSearchParams,
     BugTaskStatus,
     BugTaskStatusSearch,
     DB_INCOMPLETE_BUGTASK_STATUSES,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bug import (
     Bug,
     BugAffectsPerson,

=== modified file 'lib/lp/bugs/model/tests/test_bug.py'
--- lib/lp/bugs/model/tests/test_bug.py	2012-08-06 22:03:02 +0000
+++ lib/lp/bugs/model/tests/test_bug.py	2012-08-07 03:50:27 +0000
@@ -14,6 +14,7 @@
 from testtools.testcase import ExpectedException
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
+
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.bugs.adapters.bugchange import BugTitleChange
 from lp.bugs.enums import (

=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py	2012-07-24 05:18:23 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py	2012-08-07 03:50:27 +0000
@@ -32,7 +32,6 @@
     )
 from lp.bugs.interfaces.bugtask import (
     BugTaskImportance,
-    BugTaskSearchParams,
     BugTaskStatus,
     BugTaskStatusSearch,
     CannotDeleteBugtask,
@@ -42,6 +41,7 @@
     UNRESOLVED_BUGTASK_STATUSES,
     UserCannotEditBugTaskMilestone,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.bugwatch import IBugWatchSet
 from lp.bugs.model.bugtask import (
     bug_target_from_key,

=== modified file 'lib/lp/bugs/model/tests/test_bugtasksearch.py'
--- lib/lp/bugs/model/tests/test_bugtasksearch.py	2012-07-27 13:12:41 +0000
+++ lib/lp/bugs/model/tests/test_bugtasksearch.py	2012-08-07 03:50:27 +0000
@@ -21,10 +21,10 @@
     BugBlueprintSearch,
     BugBranchSearch,
     BugTaskImportance,
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTaskSet,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugsummary import BugSummary
 from lp.bugs.model.bugtask import BugTask
 from lp.bugs.model.bugtasksearch import (

=== modified file 'lib/lp/bugs/scripts/bugexport.py'
--- lib/lp/bugs/scripts/bugexport.py	2012-03-22 23:21:24 +0000
+++ lib/lp/bugs/scripts/bugexport.py	2012-08-07 03:50:27 +0000
@@ -18,10 +18,8 @@
 from zope.component import getUtility
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.services.librarian.browser import ProxiedLibraryFileAlias
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.browser.bugtask import get_comments_for_bugtask
 
 BUGS_XMLNS = 'https://launchpad.net/xmlns/2006/bugs'

=== modified file 'lib/lp/bugs/stories/bug-privacy/xx-bug-privacy.txt'
--- lib/lp/bugs/stories/bug-privacy/xx-bug-privacy.txt	2012-07-17 14:29:17 +0000
+++ lib/lp/bugs/stories/bug-privacy/xx-bug-privacy.txt	2012-08-07 03:50:27 +0000
@@ -144,7 +144,7 @@
 
     >>> from zope.component import getUtility
     >>> from lp.services.webapp.interfaces import ILaunchBag
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> from lp.registry.interfaces.distribution import IDistributionSet
     >>> from lp.registry.interfaces.sourcepackagename import (
     ...     ISourcePackageNameSet,

=== modified file 'lib/lp/bugs/tests/test_bugsearch_conjoined.py'
--- lib/lp/bugs/tests/test_bugsearch_conjoined.py	2012-04-26 06:38:34 +0000
+++ lib/lp/bugs/tests/test_bugsearch_conjoined.py	2012-08-07 03:50:27 +0000
@@ -13,10 +13,10 @@
 
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTaskSet,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.interfaces.series import SeriesStatus
 from lp.testing import (
     person_logged_in,

=== modified file 'lib/lp/bugs/tests/test_cve.py'
--- lib/lp/bugs/tests/test_cve.py	2012-01-18 16:15:37 +0000
+++ lib/lp/bugs/tests/test_cve.py	2012-08-07 03:50:27 +0000
@@ -5,7 +5,7 @@
 
 from zope.component import getUtility
 
-from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.cve import ICveSet
 from lp.services.webapp.testing import verifyObject
 from lp.testing import (

=== modified file 'lib/lp/code/browser/branch.py'
--- lib/lp/code/browser/branch.py	2012-07-27 03:50:11 +0000
+++ lib/lp/code/browser/branch.py	2012-08-07 03:50:27 +0000
@@ -90,10 +90,10 @@
 from lp.bugs.interfaces.bug import IBugSet
 from lp.bugs.interfaces.bugbranch import IBugBranch
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     IBugTaskSet,
     UNRESOLVED_BUGTASK_STATUSES,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.code.browser.branchmergeproposal import (
     latest_proposals_for_each_branch,
     )

=== modified file 'lib/lp/code/model/branch.py'
--- lib/lp/code/model/branch.py	2012-07-17 21:58:06 +0000
+++ lib/lp/code/model/branch.py	2012-08-07 03:50:27 +0000
@@ -62,11 +62,9 @@
     IPrivacy,
     )
 from lp.app.interfaces.services import IService
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
 from lp.bugs.interfaces.bugtaskfilter import filter_bugtasks_by_context
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.buildmaster.model.buildqueue import BuildQueue
 from lp.code.bzr import (
     BranchFormat,

=== modified file 'lib/lp/code/model/branchcollection.py'
--- lib/lp/code/model/branchcollection.py	2012-07-17 21:58:06 +0000
+++ lib/lp/code/model/branchcollection.py	2012-08-07 03:50:27 +0000
@@ -31,11 +31,9 @@
 from zope.component import getUtility
 from zope.interface import implements
 
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
 from lp.bugs.interfaces.bugtaskfilter import filter_bugtasks_by_context
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugbranch import BugBranch
 from lp.bugs.model.bugtask import BugTask
 from lp.code.enums import BranchMergeProposalStatus

=== modified file 'lib/lp/hardwaredb/doc/hwdb-device-tables.txt'
--- lib/lp/hardwaredb/doc/hwdb-device-tables.txt	2012-02-03 09:25:20 +0000
+++ lib/lp/hardwaredb/doc/hwdb-device-tables.txt	2012-08-07 03:50:27 +0000
@@ -2351,10 +2351,8 @@
 more bug tags.
 
     >>> from lp.services.searchbuilder import any
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskSearchParams,
-    ...     IBugTaskSet,
-    ...     )
+    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 
     >>> bugtask_set = getUtility(IBugTaskSet)
     >>> bugtasks = bugtask_set.search(

=== modified file 'lib/lp/registry/browser/__init__.py'
--- lib/lp/registry/browser/__init__.py	2012-07-07 14:00:30 +0000
+++ lib/lp/registry/browser/__init__.py	2012-08-07 03:50:27 +0000
@@ -29,10 +29,8 @@
     LaunchpadEditFormView,
     )
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.interfaces.productseries import IProductSeries
 from lp.registry.interfaces.series import SeriesStatus
 from lp.services.webapp.publisher import (

=== modified file 'lib/lp/registry/browser/distributionsourcepackage.py'
--- lib/lp/registry/browser/distributionsourcepackage.py	2012-08-07 00:01:04 +0000
+++ lib/lp/registry/browser/distributionsourcepackage.py	2012-08-07 03:50:27 +0000
@@ -55,10 +55,8 @@
     StructuralSubscriptionTargetTraversalMixin,
     )
 from lp.bugs.interfaces.bug import IBugSet
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    BugTaskStatus,
-    )
+from lp.bugs.interfaces.bugtask import BugTaskStatus
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.browser import add_subscribe_link
 from lp.registry.browser.pillar import PillarBugsMenu
 from lp.registry.interfaces.distributionsourcepackage import (

=== modified file 'lib/lp/registry/browser/person.py'
--- lib/lp/registry/browser/person.py	2012-08-06 23:29:31 +0000
+++ lib/lp/registry/browser/person.py	2012-08-07 03:50:27 +0000
@@ -143,10 +143,10 @@
     LaunchpadRadioWidgetWithDescription,
     )
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTaskSet,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugtask import BugTaskSet
 from lp.buildmaster.enums import BuildStatus
 from lp.code.browser.sourcepackagerecipelisting import HasRecipesMenuMixin

=== modified file 'lib/lp/registry/browser/tests/test_milestone.py'
--- lib/lp/registry/browser/tests/test_milestone.py	2012-08-07 00:01:04 +0000
+++ lib/lp/registry/browser/tests/test_milestone.py	2012-08-07 03:50:27 +0000
@@ -11,10 +11,8 @@
 from zope.component import getUtility
 
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.enums import InformationType
 from lp.registry.interfaces.person import TeamSubscriptionPolicy
 from lp.registry.model.milestonetag import ProjectGroupMilestoneTag

=== modified file 'lib/lp/registry/doc/person-account.txt'
--- lib/lp/registry/doc/person-account.txt	2012-01-15 11:52:24 +0000
+++ lib/lp/registry/doc/person-account.txt	2012-08-07 03:50:27 +0000
@@ -95,7 +95,7 @@
     >>> [coc.active for coc in foobar.signedcocs]
     [True]
 
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> params = BugTaskSearchParams(foobar, assignee=foobar)
     >>> foobar.searchTasks(params).count() > 0
     True

=== modified file 'lib/lp/registry/doc/person.txt'
--- lib/lp/registry/doc/person.txt	2012-07-06 19:36:03 +0000
+++ lib/lp/registry/doc/person.txt	2012-08-07 03:50:27 +0000
@@ -1309,7 +1309,7 @@
 A person with bugs assigned to them in a context is considered a 'Bug
 Contributor'.
 
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 
     >>> cprov.searchTasks(
     ...     BugTaskSearchParams(user=foobar, assignee=cprov)).count()

=== modified file 'lib/lp/registry/doc/sourcepackage.txt'
--- lib/lp/registry/doc/sourcepackage.txt	2011-12-30 06:14:56 +0000
+++ lib/lp/registry/doc/sourcepackage.txt	2012-08-07 03:50:27 +0000
@@ -252,8 +252,8 @@
 You can search for bugs in an IDistroSourcePackage using the
 .searchTasks method:
 
-    >>> from lp.bugs.interfaces.bugtask import (
-    ...     BugTaskSearchParams, BugTaskStatus)
+    >>> from lp.bugs.interfaces.bugtask import BugTaskStatus
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> params = BugTaskSearchParams(
     ...     status=BugTaskStatus.NEW, user=None)
     >>> tasks = ubuntu_firefox.searchTasks(params)

=== modified file 'lib/lp/registry/model/milestone.py'
--- lib/lp/registry/model/milestone.py	2012-08-06 23:29:31 +0000
+++ lib/lp/registry/model/milestone.py	2012-08-07 03:50:27 +0000
@@ -43,10 +43,10 @@
 from lp.bugs.interfaces.bugsummary import IBugSummaryDimension
 from lp.bugs.interfaces.bugtarget import IHasBugs
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTaskSet,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugtarget import HasBugsBase
 from lp.bugs.model.bugtask import BugTaskSet
 from lp.bugs.model.structuralsubscription import (

=== modified file 'lib/lp/registry/model/person.py'
--- lib/lp/registry/model/person.py	2012-07-30 18:50:41 +0000
+++ lib/lp/registry/model/person.py	2012-08-07 03:50:27 +0000
@@ -134,10 +134,8 @@
     )
 from lp.blueprints.model.specificationworkitem import SpecificationWorkItem
 from lp.bugs.interfaces.bugtarget import IBugTarget
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.model.bugtarget import HasBugsBase
 from lp.bugs.model.bugtask import get_related_bugtasks_search_params
 from lp.bugs.model.structuralsubscription import StructuralSubscription

=== modified file 'lib/lp/registry/services/sharingservice.py'
--- lib/lp/registry/services/sharingservice.py	2012-07-24 06:39:54 +0000
+++ lib/lp/registry/services/sharingservice.py	2012-08-07 03:50:27 +0000
@@ -26,10 +26,8 @@
 from zope.traversing.browser.absoluteurl import absoluteURL
 
 from lp.app.browser.tales import ObjectImageDisplayAPI
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.code.interfaces.branchcollection import IAllBranches
 from lp.registry.enums import (
     InformationType,

=== modified file 'lib/lp/registry/tests/test_project_milestone.py'
--- lib/lp/registry/tests/test_project_milestone.py	2012-06-29 08:40:05 +0000
+++ lib/lp/registry/tests/test_project_milestone.py	2012-08-07 03:50:27 +0000
@@ -20,10 +20,10 @@
 from lp.blueprints.interfaces.specification import ISpecificationSet
 from lp.bugs.interfaces.bug import CreateBugParams
 from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
     BugTaskStatus,
     IBugTaskSet,
     )
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.registry.interfaces.person import IPersonSet
 from lp.registry.interfaces.product import IProductSet
 from lp.registry.interfaces.projectgroup import IProjectGroupSet

=== modified file 'lib/lp/services/webapp/doc/webapp-authorization.txt'
--- lib/lp/services/webapp/doc/webapp-authorization.txt	2011-12-24 17:49:30 +0000
+++ lib/lp/services/webapp/doc/webapp-authorization.txt	2012-08-07 03:50:27 +0000
@@ -177,7 +177,7 @@
 
     >>> principal.scope = mozilla
     >>> setupInteraction(principal)
-    >>> from lp.bugs.interfaces.bugtask import BugTaskSearchParams
+    >>> from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
     >>> bug_task = firefox.searchTasks(
     ...     BugTaskSearchParams(user=personset.getByName('name16')))[0]
     >>> check_permission('launchpad.Edit', bug_task)

=== modified file 'lib/lp/systemhomes.py'
--- lib/lp/systemhomes.py	2012-07-27 08:01:54 +0000
+++ lib/lp/systemhomes.py	2012-08-07 03:50:27 +0000
@@ -31,10 +31,8 @@
     CreateBugParams,
     IBugSet,
     )
-from lp.bugs.interfaces.bugtask import (
-    BugTaskSearchParams,
-    IBugTaskSet,
-    )
+from lp.bugs.interfaces.bugtask import IBugTaskSet
+from lp.bugs.interfaces.bugtasksearch import BugTaskSearchParams
 from lp.bugs.interfaces.bugtracker import IBugTrackerSet
 from lp.bugs.interfaces.bugwatch import IBugWatchSet
 from lp.bugs.interfaces.malone import (


Follow ups