Merge lp:~gary/launchpad/bug723999-2a into lp:launchpad

Proposed by Gary Poster
Status: Merged
Merged at revision: 12548
Proposed branch: lp:~gary/launchpad/bug723999-2a
Merge into: lp:launchpad
Diff against target: 472 lines (+106/-99)
3 files modified
lib/lp/bugs/interfaces/structuralsubscription.py (+0/-8)
lib/lp/bugs/model/structuralsubscription.py (+39/-27)
lib/lp/bugs/tests/test_structuralsubscriptiontarget.py (+67/-64)
To merge this branch: bzr merge lp:~gary/launchpad/bug723999-2a
Reviewer Review Type Date Requested Status
Benji York (community) code Approve
Review via email: mp+52427@code.launchpad.net

Description of the change

This MP is one of several I'll be making to clean up my work on bug723999. I'm dividing up the work to try and make it easier to review.

This branch is about removing the getSubscriptionsForBugTask method on bug targets. It only had existed after my previous work on bug723999 because of tests that I didn't change because of branch size issues earlier.

I replace it with the get_structural_subscribers function. The get_structural_subscribers_for_bugtasks function remains as a wrapper for get_structural_subscribers (again, because of branch review size limitations); it will disappear in subsequent branches, leaving only get_structural_subscribers. As you can tell from the wrapper function, we only use this functionality in LP by either passing a list of a single bugtask, or all of the bugtasks in a bug. I'll be changing the rest of LP to explicitly do that in a future branch.

I adapted the tests to use the new function. Unfortunately, they are in the wrong module, because this code no longer has anything to do with targets directly. I will move the tests to test_structuralsubscription.py in a subsequent branch.

make lint is happy.

Thank you

Gary

To post a comment you must log in.
Revision history for this message
Benji York (benji) wrote :

This branch looks fine, being primarily a mechanical transformation from one perspective to another.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/interfaces/structuralsubscription.py'
2--- lib/lp/bugs/interfaces/structuralsubscription.py 2011-02-04 06:30:13 +0000
3+++ lib/lp/bugs/interfaces/structuralsubscription.py 2011-03-07 15:46:18 +0000
4@@ -14,10 +14,6 @@
5 'IStructuralSubscriptionTargetHelper',
6 ]
7
8-from lazr.enum import (
9- DBEnumeratedType,
10- DBItem,
11- )
12 from lazr.restful.declarations import (
13 call_with,
14 export_as_webservice_entry,
15@@ -41,7 +37,6 @@
16 )
17 from zope.schema import (
18 Bool,
19- Choice,
20 Datetime,
21 Int,
22 )
23@@ -149,9 +144,6 @@
24 def userHasBugSubscriptions(user):
25 """Is `user` subscribed, directly or via a team, to bug mail?"""
26
27- def getSubscriptionsForBugTask(bug, level):
28- """Return subscriptions for a given `IBugTask` at `level`."""
29-
30
31 class IStructuralSubscriptionTargetWrite(Interface):
32 """A Launchpad Structure allowing users to subscribe to it.
33
34=== modified file 'lib/lp/bugs/model/structuralsubscription.py'
35--- lib/lp/bugs/model/structuralsubscription.py 2011-03-04 02:29:09 +0000
36+++ lib/lp/bugs/model/structuralsubscription.py 2011-03-07 15:46:18 +0000
37@@ -4,6 +4,7 @@
38 __metaclass__ = type
39 __all__ = [
40 'get_all_structural_subscriptions',
41+ 'get_structural_subscribers',
42 'get_structural_subscribers_for_bugtasks',
43 'get_structural_subscription_targets',
44 'StructuralSubscription',
45@@ -47,6 +48,8 @@
46 from canonical.database.sqlbase import quote
47 from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities
48 from canonical.launchpad.interfaces.lpstorm import IStore
49+from lp.bugs.interfaces.bug import IBug
50+from lp.bugs.interfaces.bugtask import IBugTask
51 from lp.bugs.interfaces.structuralsubscription import (
52 IStructuralSubscription,
53 IStructuralSubscriptionTarget,
54@@ -476,24 +479,6 @@
55 return True
56 return False
57
58- def getSubscriptionsForBugTask(self, bugtask, level):
59- """See `IStructuralSubscriptionTarget`."""
60- # Note that this method does not take into account
61- # structural subscriptions without filters. Since it is only
62- # used for tests at this point, that's not a problem; moreover,
63- # we intend all structural subscriptions to have filters.
64- candidates, filter_id_query = (
65- _get_structural_subscription_filter_id_query(
66- bugtask.bug, [bugtask], level))
67- if not candidates:
68- return EmptyResultSet()
69- return IStore(StructuralSubscription).find(
70- StructuralSubscription,
71- BugSubscriptionFilter.structural_subscription_id ==
72- StructuralSubscription.id,
73- In(BugSubscriptionFilter.id,
74- filter_id_query)).config(distinct=True)
75-
76
77 def get_structural_subscription_targets(bugtasks):
78 """Return (bugtask, target) pairs for each target of the bugtasks.
79@@ -551,7 +536,30 @@
80 *conditions)
81
82
83-def _get_structural_subscribers(candidates, filter_id_query, recipients):
84+def get_structural_subscribers(bug_or_bugtask, recipients, level):
85+ """Return subscribers for bug or bugtask at level.
86+
87+ :param bug: a bug.
88+ :param recipients: a BugNotificationRecipients object or None.
89+ Populates if given.
90+ :param level: a level from lp.bugs.enum.BugNotificationLevel.
91+
92+ Excludes structural subscriptions for people who are directly subscribed
93+ to the bug."""
94+ if IBug.providedBy(bug_or_bugtask):
95+ bug = bug_or_bugtask
96+ bugtasks = bug.bugtasks
97+ elif IBugTask.providedBy(bug_or_bugtask):
98+ bug = bug_or_bugtask.bug
99+ bugtasks = [bug_or_bugtask]
100+ else:
101+ raise ValueError('First argument must be bug or bugtask')
102+ # XXX gary 2011-03-03 bug 728818
103+ # Once we no longer have structural subscriptions without filters in
104+ # qastaging and production, _get_structural_subscription_filter_id_query
105+ # can just return the query, and leave the candidates out of it.
106+ candidates, filter_id_query = (
107+ _get_structural_subscription_filter_id_query(bug, bugtasks, level))
108 if not candidates:
109 return EmptyResultSet()
110 # This is here because of a circular import.
111@@ -601,22 +609,26 @@
112 level=None):
113 """Return subscribers for structural filters for the bugtasks at "level".
114
115- :param bugtasks: an iterable of bugtasks. All must be for the same bug.
116+ :param bugtasks: an iterable of bugtasks. Should be a single bugtask, or
117+ all of the bugtasks from one bug.
118 :param recipients: a BugNotificationRecipients object or None.
119 Populates if given.
120 :param level: a level from lp.bugs.enum.BugNotificationLevel.
121
122 Excludes structural subscriptions for people who are directly subscribed
123 to the bug."""
124+ bugtasks = list(bugtasks)
125 if not bugtasks:
126 return EmptyResultSet()
127- bugs = set(bugtask.bug for bugtask in bugtasks)
128- if len(bugs) > 1:
129- raise NotImplementedError('Each bugtask must be from the same bug.')
130- bug = bugs.pop()
131- candidates, query = _get_structural_subscription_filter_id_query(
132- bug, bugtasks, level)
133- return _get_structural_subscribers(candidates, query, recipients)
134+ if len(bugtasks) == 1:
135+ target = bugtasks[0]
136+ else:
137+ target = bugtasks[0].bug
138+ if target.bugtasks != bugtasks:
139+ raise NotImplementedError(
140+ 'bugtasks must be one, or the full set of bugtasks from one '
141+ 'bug')
142+ return get_structural_subscribers(target, recipients, level)
143
144
145 class ArrayAgg(NamedFunc):
146
147=== modified file 'lib/lp/bugs/tests/test_structuralsubscriptiontarget.py'
148--- lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-03-01 18:58:40 +0000
149+++ lib/lp/bugs/tests/test_structuralsubscriptiontarget.py 2011-03-07 15:46:18 +0000
150@@ -37,7 +37,10 @@
151 IStructuralSubscriptionTarget,
152 IStructuralSubscriptionTargetHelper,
153 )
154-from lp.bugs.model.structuralsubscription import StructuralSubscription
155+from lp.bugs.model.structuralsubscription import (
156+ get_structural_subscribers,
157+ StructuralSubscription,
158+ )
159 from lp.bugs.tests.test_bugtarget import bugtarget_filebug
160 from lp.registry.errors import (
161 DeleteSubscriptionError,
162@@ -194,98 +197,98 @@
163 self.ordinary_subscriber, self.ordinary_subscriber)
164 self.initial_filter = self.subscription.bug_filters[0]
165
166- def assertSubscriptions(
167- self, expected_subscriptions, level=BugNotificationLevel.NOTHING):
168- observed_subscriptions = list(
169- self.target.getSubscriptionsForBugTask(self.bugtask, level))
170- self.assertEqual(expected_subscriptions, observed_subscriptions)
171+ def assertSubscribers(
172+ self, expected_subscribers, level=BugNotificationLevel.NOTHING):
173+ observed_subscribers = list(
174+ get_structural_subscribers(self.bugtask, None, level))
175+ self.assertEqual(expected_subscribers, observed_subscribers)
176
177- def test_getSubscriptionsForBugTask(self):
178+ def test_getStructuralSubscribers(self):
179 # If no one has a filtered subscription for the given bug, the result
180- # of getSubscriptionsForBugTask() is the same as for
181- # getSubscriptions().
182+ # of get_structural_subscribers() is the same as for
183+ # the set of people from each subscription in getSubscriptions().
184 subscriptions = self.target.getSubscriptions()
185- self.assertSubscriptions(list(subscriptions))
186+ self.assertSubscribers([sub.subscriber for sub in subscriptions])
187
188- def test_getSubscriptionsForBugTask_with_filter_on_status(self):
189+ def test_getStructuralSubscribers_with_filter_on_status(self):
190 # If a status filter exists for a subscription, the result of
191- # getSubscriptionsForBugTask() may be a subset of getSubscriptions().
192+ # get_structural_subscribers() may be a subset of getSubscriptions().
193
194 # Without any filters the subscription is found.
195- self.assertSubscriptions([self.subscription])
196+ self.assertSubscribers([self.ordinary_subscriber])
197
198 # Filter the subscription to bugs in the CONFIRMED state.
199 self.initial_filter.statuses = [BugTaskStatus.CONFIRMED]
200
201 # With the filter the subscription is not found.
202- self.assertSubscriptions([])
203+ self.assertSubscribers([])
204
205 # If the filter is adjusted, the subscription is found again.
206 self.initial_filter.statuses = [self.bugtask.status]
207- self.assertSubscriptions([self.subscription])
208+ self.assertSubscribers([self.ordinary_subscriber])
209
210- def test_getSubscriptionsForBugTask_with_filter_on_importance(self):
211+ def test_getStructuralSubscribers_with_filter_on_importance(self):
212 # If an importance filter exists for a subscription, the result of
213- # getSubscriptionsForBugTask() may be a subset of getSubscriptions().
214+ # get_structural_subscribers() may be a subset of getSubscriptions().
215
216 # Without any filters the subscription is found.
217- self.assertSubscriptions([self.subscription])
218+ self.assertSubscribers([self.ordinary_subscriber])
219
220 # Filter the subscription to bugs in the CRITICAL state.
221 self.initial_filter.importances = [BugTaskImportance.CRITICAL]
222
223 # With the filter the subscription is not found.
224- self.assertSubscriptions([])
225+ self.assertSubscribers([])
226
227 # If the filter is adjusted, the subscription is found again.
228 self.initial_filter.importances = [self.bugtask.importance]
229- self.assertSubscriptions([self.subscription])
230+ self.assertSubscribers([self.ordinary_subscriber])
231
232- def test_getSubscriptionsForBugTask_with_filter_on_level(self):
233+ def test_getStructuralSubscribers_with_filter_on_level(self):
234 # All structural subscriptions have a level for bug notifications
235- # which getSubscriptionsForBugTask() observes.
236+ # which get_structural_subscribers() observes.
237
238 # Adjust the subscription level to METADATA.
239 self.initial_filter.bug_notification_level = (
240 BugNotificationLevel.METADATA)
241
242 # The subscription is found when looking for NOTHING or above.
243- self.assertSubscriptions(
244- [self.subscription], BugNotificationLevel.NOTHING)
245+ self.assertSubscribers(
246+ [self.ordinary_subscriber], BugNotificationLevel.NOTHING)
247 # The subscription is found when looking for METADATA or above.
248- self.assertSubscriptions(
249- [self.subscription], BugNotificationLevel.METADATA)
250+ self.assertSubscribers(
251+ [self.ordinary_subscriber], BugNotificationLevel.METADATA)
252 # The subscription is not found when looking for COMMENTS or above.
253- self.assertSubscriptions(
254+ self.assertSubscribers(
255 [], BugNotificationLevel.COMMENTS)
256
257- def test_getSubscriptionsForBugTask_with_filter_include_any_tags(self):
258+ def test_getStructuralSubscribers_with_filter_include_any_tags(self):
259 # If a subscription filter has include_any_tags, a bug with one or
260 # more tags is matched.
261
262 self.initial_filter.include_any_tags = True
263
264 # Without any tags the subscription is not found.
265- self.assertSubscriptions([])
266+ self.assertSubscribers([])
267
268 # With any tag the subscription is found.
269 self.bug.tags = ["foo"]
270- self.assertSubscriptions([self.subscription])
271+ self.assertSubscribers([self.ordinary_subscriber])
272
273- def test_getSubscriptionsForBugTask_with_filter_exclude_any_tags(self):
274+ def test_getStructuralSubscribers_with_filter_exclude_any_tags(self):
275 # If a subscription filter has exclude_any_tags, only bugs with no
276 # tags are matched.
277
278 self.initial_filter.exclude_any_tags = True
279
280 # Without any tags the subscription is found.
281- self.assertSubscriptions([self.subscription])
282+ self.assertSubscribers([self.ordinary_subscriber])
283
284 # With any tag the subscription is not found.
285 self.bug.tags = ["foo"]
286- self.assertSubscriptions([])
287+ self.assertSubscribers([])
288
289- def test_getSubscriptionsForBugTask_with_filter_for_any_tag(self):
290+ def test_getStructuralSubscribers_with_filter_for_any_tag(self):
291 # If a subscription filter specifies that any of one or more specific
292 # tags must be present, bugs with any of those tags are matched.
293
294@@ -294,13 +297,13 @@
295 self.initial_filter.find_all_tags = False
296
297 # Without either tag the subscription is not found.
298- self.assertSubscriptions([])
299+ self.assertSubscribers([])
300
301 # With either tag the subscription is found.
302 self.bug.tags = ["bar", "baz"]
303- self.assertSubscriptions([self.subscription])
304+ self.assertSubscribers([self.ordinary_subscriber])
305
306- def test_getSubscriptionsForBugTask_with_filter_for_all_tags(self):
307+ def test_getStructuralSubscribers_with_filter_for_all_tags(self):
308 # If a subscription filter specifies that all of one or more specific
309 # tags must be present, bugs with all of those tags are matched.
310
311@@ -309,17 +312,17 @@
312 self.initial_filter.find_all_tags = True
313
314 # Without either tag the subscription is not found.
315- self.assertSubscriptions([])
316+ self.assertSubscribers([])
317
318 # Without only one of the required tags the subscription is not found.
319 self.bug.tags = ["foo"]
320- self.assertSubscriptions([])
321+ self.assertSubscribers([])
322
323 # With both required tags the subscription is found.
324 self.bug.tags = ["foo", "bar"]
325- self.assertSubscriptions([self.subscription])
326+ self.assertSubscribers([self.ordinary_subscriber])
327
328- def test_getSubscriptionsForBugTask_with_filter_for_not_any_tag(self):
329+ def test_getStructuralSubscribers_with_filter_for_not_any_tag(self):
330 # If a subscription filter specifies that any of one or more specific
331 # tags must not be present, bugs without any of those tags are
332 # matched.
333@@ -329,26 +332,26 @@
334 self.initial_filter.find_all_tags = False
335
336 # Without either tag the subscription is found.
337- self.assertSubscriptions([self.subscription])
338+ self.assertSubscribers([self.ordinary_subscriber])
339
340 # With both tags, the subscription is omitted.
341 self.bug.tags = ["foo", "bar"]
342- self.assertSubscriptions([])
343+ self.assertSubscribers([])
344
345 # With only one tag, the subscription is found again.
346 self.bug.tags = ["foo"]
347- self.assertSubscriptions([self.subscription])
348+ self.assertSubscribers([self.ordinary_subscriber])
349
350 # However, if find_all_tags is True, even a single excluded tag
351 # causes the subscription to be skipped.
352 self.initial_filter.find_all_tags = True
353- self.assertSubscriptions([])
354+ self.assertSubscribers([])
355
356 # This is also true, of course, if the bug has both tags.
357 self.bug.tags = ["foo", "bar"]
358- self.assertSubscriptions([])
359+ self.assertSubscribers([])
360
361- def test_getSubscriptionsForBugTask_with_filter_for_not_all_tags(self):
362+ def test_getStructuralSubscribers_with_filter_for_not_all_tags(self):
363 # If a subscription filter specifies that all of one or more specific
364 # tags must not be present, bugs without all of those tags are
365 # matched.
366@@ -358,64 +361,64 @@
367 self.initial_filter.find_all_tags = True
368
369 # Without either tag the subscription is found.
370- self.assertSubscriptions([self.subscription])
371+ self.assertSubscribers([self.ordinary_subscriber])
372
373 # With only one of the excluded tags the subscription is not
374 # found--we are saying that we want to find both an absence of foo
375 # and an absence of bar, and yet foo exists.
376 self.bug.tags = ["foo"]
377- self.assertSubscriptions([])
378+ self.assertSubscribers([])
379
380 # With both tags the subscription is also not found.
381 self.bug.tags = ["foo", "bar"]
382- self.assertSubscriptions([])
383+ self.assertSubscribers([])
384
385- def test_getSubscriptionsForBugTask_with_multiple_filters(self):
386+ def test_getStructuralSubscribers_with_multiple_filters(self):
387 # If multiple filters exist for a subscription, all filters must
388 # match.
389
390 # Add the "foo" tag to the bug.
391 self.bug.tags = ["foo"]
392- self.assertSubscriptions([self.subscription])
393+ self.assertSubscribers([self.ordinary_subscriber])
394
395 # Filter the subscription to bugs in the CRITICAL state.
396 self.initial_filter.statuses = [BugTaskStatus.CONFIRMED]
397 self.initial_filter.importances = [BugTaskImportance.CRITICAL]
398
399 # With the filter the subscription is not found.
400- self.assertSubscriptions([])
401+ self.assertSubscribers([])
402
403 # If the filter is adjusted to match status but not importance, the
404 # subscription is still not found.
405 self.initial_filter.statuses = [self.bugtask.status]
406- self.assertSubscriptions([])
407+ self.assertSubscribers([])
408
409 # If the filter is adjusted to also match importance, the subscription
410 # is found again.
411 self.initial_filter.importances = [self.bugtask.importance]
412- self.assertSubscriptions([self.subscription])
413+ self.assertSubscribers([self.ordinary_subscriber])
414
415 # If the filter is given some tag criteria, the subscription is not
416 # found.
417 self.initial_filter.tags = [u"-foo", u"bar", u"baz"]
418 self.initial_filter.find_all_tags = False
419- self.assertSubscriptions([])
420+ self.assertSubscribers([])
421
422 # After removing the "foo" tag and adding the "bar" tag, the
423 # subscription is found.
424 self.bug.tags = ["bar"]
425- self.assertSubscriptions([self.subscription])
426+ self.assertSubscribers([self.ordinary_subscriber])
427
428 # Requiring that all tag criteria are fulfilled causes the
429 # subscription to no longer be found.
430 self.initial_filter.find_all_tags = True
431- self.assertSubscriptions([])
432+ self.assertSubscribers([])
433
434 # After adding the "baz" tag, the subscription is found again.
435 self.bug.tags = ["bar", "baz"]
436- self.assertSubscriptions([self.subscription])
437+ self.assertSubscribers([self.ordinary_subscriber])
438
439- def test_getSubscriptionsForBugTask_any_filter_is_a_match(self):
440+ def test_getStructuralSubscribers_any_filter_is_a_match(self):
441 # If a subscription has multiple filters, the subscription is selected
442 # when any filter is found to match. Put another way, the filters are
443 # ORed together.
444@@ -425,24 +428,24 @@
445 subscription_filter2.tags = [u"foo"]
446
447 # With the filter the subscription is not found.
448- self.assertSubscriptions([])
449+ self.assertSubscribers([])
450
451 # If the bugtask is adjusted to match the criteria of the first filter
452 # but not those of the second, the subscription is found.
453 self.bugtask.transitionToStatus(
454 BugTaskStatus.CONFIRMED, self.ordinary_subscriber)
455- self.assertSubscriptions([self.subscription])
456+ self.assertSubscribers([self.ordinary_subscriber])
457
458 # If the filter is adjusted to also match the criteria of the second
459 # filter, the subscription is still found.
460 self.bugtask.bug.tags = [u"foo"]
461- self.assertSubscriptions([self.subscription])
462+ self.assertSubscribers([self.ordinary_subscriber])
463
464 # If the bugtask is adjusted to no longer match the criteria of the
465 # first filter, the subscription is still found.
466 self.bugtask.transitionToStatus(
467 BugTaskStatus.INPROGRESS, self.ordinary_subscriber)
468- self.assertSubscriptions([self.subscription])
469+ self.assertSubscribers([self.ordinary_subscriber])
470
471
472 class TestStructuralSubscriptionForDistro(