Merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel into lp:launchpad
- wire-up-filter-subs-bug-655567-devel
- Merge into devel
Proposed by
Gavin Panella
on 2010-10-15
| Status: | Merged |
|---|---|
| Approved by: | Gavin Panella on 2010-10-15 |
| Approved revision: | no longer in the source branch. |
| Merged at revision: | 11721 |
| Proposed branch: | lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel |
| Merge into: | lp:launchpad |
| Diff against target: |
881 lines (+239/-250) 12 files modified
database/schema/security.cfg (+7/-0) lib/lp/bugs/configure.zcml (+1/-0) lib/lp/bugs/interfaces/bug.py (+8/-2) lib/lp/bugs/model/bug.py (+61/-36) lib/lp/bugs/model/tests/test_bug.py (+91/-9) lib/lp/registry/doc/structural-subscriptions.txt (+0/-55) lib/lp/registry/interfaces/person.py (+0/-11) lib/lp/registry/interfaces/structuralsubscription.py (+2/-2) lib/lp/registry/model/person.py (+0/-53) lib/lp/registry/model/structuralsubscription.py (+5/-19) lib/lp/registry/tests/test_structuralsubscriptiontarget.py (+63/-62) utilities/format-new-and-modified-imports (+1/-1) |
| To merge this branch: | bzr merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567-devel |
| Related bugs: |
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Abel Deuring (community) | code | 2010-10-15 | Approve on 2010-10-15 |
|
Review via email:
|
|||
Commit Message
Merge wire-up-
Description of the Change
Merge lp:~allenap/launchpad/wire-up-filter-subs-bug-655567 into devel. It's already in db-devel.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'database/schema/security.cfg' |
| 2 | --- database/schema/security.cfg 2010-10-07 22:46:08 +0000 |
| 3 | +++ database/schema/security.cfg 2010-10-15 16:17:07 +0000 |
| 4 | @@ -549,6 +549,7 @@ |
| 5 | public.bugsubscriptionfilterstatus = SELECT |
| 6 | public.bugsubscriptionfilterimportance = SELECT |
| 7 | public.bugsubscriptionfiltertag = SELECT |
| 8 | +public.bugtag = SELECT |
| 9 | public.bugtask = SELECT, INSERT, UPDATE |
| 10 | public.bugtracker = SELECT, INSERT |
| 11 | public.bugtrackercomponent = SELECT, INSERT, UPDATE, DELETE |
| 12 | @@ -638,6 +639,7 @@ |
| 13 | public.bugsubscriptionfiltertag = SELECT |
| 14 | public.bugnotification = SELECT, INSERT |
| 15 | public.bugnotificationrecipient = SELECT, INSERT |
| 16 | +public.bugtag = SELECT |
| 17 | public.structuralsubscription = SELECT |
| 18 | public.message = SELECT, INSERT |
| 19 | public.messagechunk = SELECT, INSERT |
| 20 | @@ -833,6 +835,7 @@ |
| 21 | public.bugnotification = SELECT, INSERT |
| 22 | public.bugnotificationrecipient = SELECT, INSERT |
| 23 | public.bugnomination = SELECT |
| 24 | +public.bugtag = SELECT |
| 25 | public.bugtask = SELECT, UPDATE |
| 26 | public.product = SELECT |
| 27 | public.project = SELECT |
| 28 | @@ -1194,6 +1197,7 @@ |
| 29 | public.bugnotification = SELECT, INSERT |
| 30 | public.bugnotificationrecipient = SELECT, INSERT |
| 31 | public.bugnomination = SELECT |
| 32 | +public.bugtag = SELECT |
| 33 | public.bugtask = SELECT, UPDATE |
| 34 | public.product = SELECT, UPDATE |
| 35 | public.project = SELECT, UPDATE |
| 36 | @@ -1300,6 +1304,7 @@ |
| 37 | public.bugnotification = SELECT, INSERT |
| 38 | public.bugnotificationrecipient = SELECT, INSERT |
| 39 | public.bugnomination = SELECT |
| 40 | +public.bugtag = SELECT |
| 41 | public.bugtask = SELECT, UPDATE |
| 42 | public.product = SELECT, UPDATE |
| 43 | public.project = SELECT, UPDATE |
| 44 | @@ -1855,6 +1860,7 @@ |
| 45 | public.bug = SELECT, INSERT, UPDATE |
| 46 | public.bugjob = SELECT, INSERT |
| 47 | public.bugaffectsperson = SELECT, INSERT, UPDATE, DELETE |
| 48 | +public.bugtag = SELECT |
| 49 | public.bugtask = SELECT, INSERT, UPDATE |
| 50 | public.accountpassword = SELECT, INSERT |
| 51 | public.teamparticipation = SELECT, INSERT |
| 52 | @@ -1917,6 +1923,7 @@ |
| 53 | public.bugaffectsperson = SELECT |
| 54 | public.bugnotification = SELECT, DELETE |
| 55 | public.bugnotificationrecipientarchive = SELECT |
| 56 | +public.bugtag = SELECT |
| 57 | public.bugwatch = SELECT, UPDATE |
| 58 | public.bugwatchactivity = SELECT, DELETE |
| 59 | public.codeimportresult = SELECT, DELETE |
| 60 | |
| 61 | === modified file 'lib/lp/bugs/configure.zcml' |
| 62 | --- lib/lp/bugs/configure.zcml 2010-10-06 18:53:53 +0000 |
| 63 | +++ lib/lp/bugs/configure.zcml 2010-10-15 16:17:07 +0000 |
| 64 | @@ -706,6 +706,7 @@ |
| 65 | getSubscribersForPerson |
| 66 | indexed_messages |
| 67 | getAlsoNotifiedSubscribers |
| 68 | + getStructuralSubscribers |
| 69 | getBugWatch |
| 70 | canBeNominatedFor |
| 71 | getNominationFor |
| 72 | |
| 73 | === modified file 'lib/lp/bugs/interfaces/bug.py' |
| 74 | --- lib/lp/bugs/interfaces/bug.py 2010-10-12 14:56:31 +0000 |
| 75 | +++ lib/lp/bugs/interfaces/bug.py 2010-10-15 16:17:07 +0000 |
| 76 | @@ -493,6 +493,12 @@ |
| 77 | from duplicates. |
| 78 | """ |
| 79 | |
| 80 | + def getStructuralSubscribers(recipients=None, level=None): |
| 81 | + """Return `IPerson`s subscribed to this bug's targets. |
| 82 | + |
| 83 | + This takes into account bug subscription filters. |
| 84 | + """ |
| 85 | + |
| 86 | def getSubscriptionsFromDuplicates(): |
| 87 | """Return IBugSubscriptions subscribed from dupes of this bug.""" |
| 88 | |
| 89 | @@ -501,9 +507,9 @@ |
| 90 | |
| 91 | def getSubscribersForPerson(person): |
| 92 | """Find the persons or teams by which person is subscribed. |
| 93 | - |
| 94 | + |
| 95 | This call should be quite cheap to make and performs a single query. |
| 96 | - |
| 97 | + |
| 98 | :return: An IResultSet. |
| 99 | """ |
| 100 | |
| 101 | |
| 102 | === modified file 'lib/lp/bugs/model/bug.py' |
| 103 | --- lib/lp/bugs/model/bug.py 2010-10-14 11:05:05 +0000 |
| 104 | +++ lib/lp/bugs/model/bug.py 2010-10-15 16:17:07 +0000 |
| 105 | @@ -51,7 +51,6 @@ |
| 106 | In, |
| 107 | LeftJoin, |
| 108 | Max, |
| 109 | - Min, |
| 110 | Not, |
| 111 | Or, |
| 112 | Select, |
| 113 | @@ -156,14 +155,13 @@ |
| 114 | from lp.bugs.model.bugnomination import BugNomination |
| 115 | from lp.bugs.model.bugnotification import BugNotification |
| 116 | from lp.bugs.model.bugsubscription import BugSubscription |
| 117 | +from lp.bugs.model.bugtarget import OfficialBugTag |
| 118 | from lp.bugs.model.bugtask import ( |
| 119 | BugTask, |
| 120 | bugtask_sort_key, |
| 121 | - BugTaskSet, |
| 122 | get_bug_privacy_filter, |
| 123 | NullBugTask, |
| 124 | ) |
| 125 | -from lp.bugs.model.bugtarget import OfficialBugTag |
| 126 | from lp.bugs.model.bugwatch import BugWatch |
| 127 | from lp.hardwaredb.interfaces.hwdb import IHWSubmissionBugSet |
| 128 | from lp.registry.enum import BugNotificationLevel |
| 129 | @@ -172,10 +170,7 @@ |
| 130 | IDistributionSourcePackage, |
| 131 | ) |
| 132 | from lp.registry.interfaces.distroseries import IDistroSeries |
| 133 | -from lp.registry.interfaces.person import ( |
| 134 | - IPersonSet, |
| 135 | - validate_public_person, |
| 136 | - ) |
| 137 | +from lp.registry.interfaces.person import validate_public_person |
| 138 | from lp.registry.interfaces.product import IProduct |
| 139 | from lp.registry.interfaces.productseries import IProductSeries |
| 140 | from lp.registry.interfaces.series import SeriesStatus |
| 141 | @@ -458,11 +453,9 @@ |
| 142 | store = Store.of(self) |
| 143 | message_by_id = {} |
| 144 | if include_parents: |
| 145 | - def to_messages(rows): |
| 146 | - return [row[0] for row in rows] |
| 147 | + to_messages = lambda rows: [row[0] for row in rows] |
| 148 | else: |
| 149 | - def to_messages(rows): |
| 150 | - return rows |
| 151 | + to_messages = lambda rows: rows |
| 152 | def eager_load_owners(messages): |
| 153 | # Because we may have multiple owners, we spend less time in storm |
| 154 | # with very large bugs by not joining and instead querying a second |
| 155 | @@ -976,31 +969,12 @@ |
| 156 | |
| 157 | also_notified_subscribers = set() |
| 158 | |
| 159 | - structural_subscription_targets = set() |
| 160 | - |
| 161 | for bugtask in self.bugtasks: |
| 162 | if bugtask.assignee: |
| 163 | also_notified_subscribers.add(bugtask.assignee) |
| 164 | if recipients is not None: |
| 165 | recipients.addAssignee(bugtask.assignee) |
| 166 | |
| 167 | - if IStructuralSubscriptionTarget.providedBy(bugtask.target): |
| 168 | - structural_subscription_targets.add(bugtask.target) |
| 169 | - if bugtask.target.parent_subscription_target is not None: |
| 170 | - structural_subscription_targets.add( |
| 171 | - bugtask.target.parent_subscription_target) |
| 172 | - |
| 173 | - if ISourcePackage.providedBy(bugtask.target): |
| 174 | - # Distribution series bug tasks with a package have the |
| 175 | - # source package set as their target, so we add the |
| 176 | - # distroseries explicitly to the set of subscription |
| 177 | - # targets. |
| 178 | - structural_subscription_targets.add( |
| 179 | - bugtask.distroseries) |
| 180 | - |
| 181 | - if bugtask.milestone is not None: |
| 182 | - structural_subscription_targets.add(bugtask.milestone) |
| 183 | - |
| 184 | # If the target's bug supervisor isn't set, |
| 185 | # we add the owner as a subscriber. |
| 186 | pillar = bugtask.pillar |
| 187 | @@ -1009,22 +983,73 @@ |
| 188 | if recipients is not None: |
| 189 | recipients.addRegistrant(pillar.owner, pillar) |
| 190 | |
| 191 | - person_set = getUtility(IPersonSet) |
| 192 | - target_subscribers = person_set.getSubscribersForTargets( |
| 193 | - structural_subscription_targets, recipients=recipients, |
| 194 | - level=level) |
| 195 | - |
| 196 | - also_notified_subscribers.update(target_subscribers) |
| 197 | + # Structural subscribers. |
| 198 | + also_notified_subscribers.update( |
| 199 | + self.getStructuralSubscribers( |
| 200 | + recipients=recipients, level=level)) |
| 201 | |
| 202 | # Direct subscriptions always take precedence over indirect |
| 203 | # subscriptions. |
| 204 | direct_subscribers = set(self.getDirectSubscribers()) |
| 205 | + |
| 206 | # Remove security proxy for the sort key, but return |
| 207 | # the regular proxied object. |
| 208 | return sorted( |
| 209 | (also_notified_subscribers - direct_subscribers), |
| 210 | key=lambda x: removeSecurityProxy(x).displayname) |
| 211 | |
| 212 | + def getStructuralSubscribers(self, recipients=None, level=None): |
| 213 | + """See `IBug`. """ |
| 214 | + query_arguments = [] |
| 215 | + for bugtask in self.bugtasks: |
| 216 | + if IStructuralSubscriptionTarget.providedBy(bugtask.target): |
| 217 | + query_arguments.append((bugtask.target, bugtask)) |
| 218 | + if bugtask.target.parent_subscription_target is not None: |
| 219 | + query_arguments.append( |
| 220 | + (bugtask.target.parent_subscription_target, bugtask)) |
| 221 | + if ISourcePackage.providedBy(bugtask.target): |
| 222 | + # Distribution series bug tasks with a package have the source |
| 223 | + # package set as their target, so we add the distroseries |
| 224 | + # explicitly to the set of subscription targets. |
| 225 | + query_arguments.append((bugtask.distroseries, bugtask)) |
| 226 | + if bugtask.milestone is not None: |
| 227 | + query_arguments.append((bugtask.milestone, bugtask)) |
| 228 | + |
| 229 | + if len(query_arguments) == 0: |
| 230 | + return EmptyResultSet() |
| 231 | + |
| 232 | + if level is None: |
| 233 | + # If level is not specified, default to NOTHING so that all |
| 234 | + # subscriptions are found. XXX: Perhaps this should go in |
| 235 | + # getSubscriptionsForBugTask()? |
| 236 | + level = BugNotificationLevel.NOTHING |
| 237 | + |
| 238 | + # Build the query. |
| 239 | + union = lambda left, right: left.union(right) |
| 240 | + queries = ( |
| 241 | + target.getSubscriptionsForBugTask(bugtask, level) |
| 242 | + for target, bugtask in query_arguments) |
| 243 | + subscriptions = reduce(union, queries) |
| 244 | + |
| 245 | + # Pull all the subscriptions in. |
| 246 | + subscriptions = list(subscriptions) |
| 247 | + |
| 248 | + # Prepare a query for the subscribers. |
| 249 | + subscribers = Store.of(self).find( |
| 250 | + Person, Person.id.is_in( |
| 251 | + subscription.subscriberID |
| 252 | + for subscription in subscriptions)) |
| 253 | + |
| 254 | + if recipients is not None: |
| 255 | + # We need to process subscriptions, so pull all the subscribes |
| 256 | + # into the cache, then update recipients with the subscriptions. |
| 257 | + subscribers = list(subscribers) |
| 258 | + for subscription in subscriptions: |
| 259 | + recipients.addStructuralSubscriber( |
| 260 | + subscription.subscriber, subscription.target) |
| 261 | + |
| 262 | + return subscribers |
| 263 | + |
| 264 | def getBugNotificationRecipients(self, duplicateof=None, old_bug=None, |
| 265 | level=None, |
| 266 | include_master_dupe_subscribers=False): |
| 267 | |
| 268 | === renamed file 'lib/lp/bugs/tests/test_bug.py' => 'lib/lp/bugs/model/tests/test_bug.py' |
| 269 | --- lib/lp/bugs/tests/test_bug.py 2010-10-14 13:47:47 +0000 |
| 270 | +++ lib/lp/bugs/model/tests/test_bug.py 2010-10-15 16:17:07 +0000 |
| 271 | @@ -5,7 +5,10 @@ |
| 272 | |
| 273 | __metaclass__ = type |
| 274 | |
| 275 | +from storm.store import ResultSet |
| 276 | + |
| 277 | from canonical.testing.layers import DatabaseFunctionalLayer |
| 278 | +from lp.bugs.mail.bugnotificationrecipients import BugNotificationRecipients |
| 279 | from lp.registry.enum import BugNotificationLevel |
| 280 | from lp.registry.interfaces.person import PersonVisibility |
| 281 | from lp.registry.model.structuralsubscription import StructuralSubscription |
| 282 | @@ -14,6 +17,7 @@ |
| 283 | person_logged_in, |
| 284 | TestCaseWithFactory, |
| 285 | ) |
| 286 | +from lp.testing.matchers import StartsWith |
| 287 | |
| 288 | |
| 289 | class TestBug(TestCaseWithFactory): |
| 290 | @@ -36,7 +40,7 @@ |
| 291 | bug = self.factory.makeBug() |
| 292 | person = self.factory.makePerson() |
| 293 | team1 = self.factory.makeTeam(members=[person]) |
| 294 | - team2 = self.factory.makeTeam(members=[person]) |
| 295 | + self.factory.makeTeam(members=[person]) |
| 296 | with person_logged_in(person): |
| 297 | bug.subscribe(team1, person) |
| 298 | self.assertEqual([team1], list(bug.getSubscribersForPerson(person))) |
| 299 | @@ -157,8 +161,7 @@ |
| 300 | subscriber = self.factory.makePerson() |
| 301 | subscribers.append(subscriber) |
| 302 | with person_logged_in(subscriber): |
| 303 | - subscription = bug.subscribe( |
| 304 | - subscriber, subscriber, level=level) |
| 305 | + bug.subscribe(subscriber, subscriber, level=level) |
| 306 | direct_subscribers = bug.getDirectSubscribers(level=level) |
| 307 | |
| 308 | # All the previous subscribers will be included because |
| 309 | @@ -181,8 +184,7 @@ |
| 310 | subscriber = self.factory.makePerson() |
| 311 | subscribers.append(subscriber) |
| 312 | with person_logged_in(subscriber): |
| 313 | - subscription = bug.subscribe( |
| 314 | - subscriber, subscriber, level=level) |
| 315 | + bug.subscribe(subscriber, subscriber, level=level) |
| 316 | |
| 317 | # All the subscribers should be returned by |
| 318 | # getDirectSubscribers() because it defaults to returning |
| 319 | @@ -211,8 +213,7 @@ |
| 320 | subscriber = self.factory.makePerson() |
| 321 | subscribers.append(subscriber) |
| 322 | with person_logged_in(subscriber): |
| 323 | - subscription = duplicate_bug.subscribe( |
| 324 | - subscriber, subscriber, level=level) |
| 325 | + duplicate_bug.subscribe(subscriber, subscriber, level=level) |
| 326 | duplicate_subscribers = ( |
| 327 | bug.getSubscribersFromDuplicates(level=level)) |
| 328 | # All the previous subscribers will be included because |
| 329 | @@ -237,11 +238,92 @@ |
| 330 | duplicate_bug.owner, duplicate_bug.owner) |
| 331 | subscriber = self.factory.makePerson() |
| 332 | with person_logged_in(subscriber): |
| 333 | - direct_subscription = bug.subscribe( |
| 334 | + bug.subscribe( |
| 335 | subscriber, subscriber, level=BugNotificationLevel.NOTHING) |
| 336 | - dupe_subscription = duplicate_bug.subscribe( |
| 337 | + duplicate_bug.subscribe( |
| 338 | subscriber, subscriber, level=BugNotificationLevel.METADATA) |
| 339 | duplicate_subscribers = bug.getSubscribersFromDuplicates() |
| 340 | self.assertTrue( |
| 341 | subscriber not in duplicate_subscribers, |
| 342 | "Subscriber should not be in duplicate_subscribers.") |
| 343 | + |
| 344 | + |
| 345 | +class TestBugStructuralSubscribers(TestCaseWithFactory): |
| 346 | + |
| 347 | + layer = DatabaseFunctionalLayer |
| 348 | + |
| 349 | + def test_getStructuralSubscribers_no_subscribers(self): |
| 350 | + # If there are no subscribers for any of the bug's targets then no |
| 351 | + # subscribers will be returned by getStructuralSubscribers(). |
| 352 | + product = self.factory.makeProduct() |
| 353 | + bug = self.factory.makeBug(product=product) |
| 354 | + subscribers = bug.getStructuralSubscribers() |
| 355 | + self.assertIsInstance(subscribers, ResultSet) |
| 356 | + self.assertEqual([], list(subscribers)) |
| 357 | + |
| 358 | + def test_getStructuralSubscribers_single_target(self): |
| 359 | + # Subscribers for any of the bug's targets are returned. |
| 360 | + subscriber = self.factory.makePerson() |
| 361 | + login_person(subscriber) |
| 362 | + product = self.factory.makeProduct() |
| 363 | + product.addBugSubscription(subscriber, subscriber) |
| 364 | + bug = self.factory.makeBug(product=product) |
| 365 | + self.assertEqual([subscriber], list(bug.getStructuralSubscribers())) |
| 366 | + |
| 367 | + def test_getStructuralSubscribers_multiple_targets(self): |
| 368 | + # Subscribers for any of the bug's targets are returned. |
| 369 | + actor = self.factory.makePerson() |
| 370 | + login_person(actor) |
| 371 | + |
| 372 | + subscriber1 = self.factory.makePerson() |
| 373 | + subscriber2 = self.factory.makePerson() |
| 374 | + |
| 375 | + product1 = self.factory.makeProduct(owner=actor) |
| 376 | + product1.addBugSubscription(subscriber1, subscriber1) |
| 377 | + product2 = self.factory.makeProduct(owner=actor) |
| 378 | + product2.addBugSubscription(subscriber2, subscriber2) |
| 379 | + |
| 380 | + bug = self.factory.makeBug(product=product1) |
| 381 | + bug.addTask(actor, product2) |
| 382 | + |
| 383 | + subscribers = bug.getStructuralSubscribers() |
| 384 | + self.assertIsInstance(subscribers, ResultSet) |
| 385 | + self.assertEqual(set([subscriber1, subscriber2]), set(subscribers)) |
| 386 | + |
| 387 | + def test_getStructuralSubscribers_recipients(self): |
| 388 | + # If provided, getStructuralSubscribers() calls the appropriate |
| 389 | + # methods on a BugNotificationRecipients object. |
| 390 | + subscriber = self.factory.makePerson() |
| 391 | + login_person(subscriber) |
| 392 | + product = self.factory.makeProduct() |
| 393 | + product.addBugSubscription(subscriber, subscriber) |
| 394 | + bug = self.factory.makeBug(product=product) |
| 395 | + recipients = BugNotificationRecipients() |
| 396 | + subscribers = bug.getStructuralSubscribers(recipients=recipients) |
| 397 | + # The return value is a list only when populating recipients. |
| 398 | + self.assertIsInstance(subscribers, list) |
| 399 | + self.assertEqual([subscriber], recipients.getRecipients()) |
| 400 | + reason, header = recipients.getReason(subscriber) |
| 401 | + self.assertThat( |
| 402 | + reason, StartsWith( |
| 403 | + u"You received this bug notification because " |
| 404 | + u"you are subscribed to ")) |
| 405 | + self.assertThat(header, StartsWith(u"Subscriber ")) |
| 406 | + |
| 407 | + def test_getStructuralSubscribers_level(self): |
| 408 | + # getStructuralSubscribers() respects the given level. |
| 409 | + subscriber = self.factory.makePerson() |
| 410 | + login_person(subscriber) |
| 411 | + product = self.factory.makeProduct() |
| 412 | + subscription = product.addBugSubscription(subscriber, subscriber) |
| 413 | + subscription.bug_notification_level = BugNotificationLevel.METADATA |
| 414 | + bug = self.factory.makeBug(product=product) |
| 415 | + self.assertEqual( |
| 416 | + [subscriber], list( |
| 417 | + bug.getStructuralSubscribers( |
| 418 | + level=BugNotificationLevel.METADATA))) |
| 419 | + subscription.bug_notification_level = BugNotificationLevel.METADATA |
| 420 | + self.assertEqual( |
| 421 | + [], list( |
| 422 | + bug.getStructuralSubscribers( |
| 423 | + level=BugNotificationLevel.COMMENTS))) |
| 424 | |
| 425 | === modified file 'lib/lp/registry/doc/structural-subscriptions.txt' |
| 426 | --- lib/lp/registry/doc/structural-subscriptions.txt 2010-10-06 18:53:53 +0000 |
| 427 | +++ lib/lp/registry/doc/structural-subscriptions.txt 2010-10-15 16:17:07 +0000 |
| 428 | @@ -198,61 +198,6 @@ |
| 429 | name16 |
| 430 | |
| 431 | |
| 432 | -Retrieving structural subscribers of targets |
| 433 | -============================================ |
| 434 | - |
| 435 | -Subscribers of one or more targets are retrieved by |
| 436 | -PersonSet.getSubscribersForTargets. |
| 437 | - |
| 438 | -XXX Abel Deuring 2008-07-11 We must remove the security proxy, because |
| 439 | -PersonSet.getSubscribersForTargets() accesses the private attribute |
| 440 | -firefox._targets_args. This attribute should be renamed. Bug #247525. |
| 441 | - |
| 442 | - >>> from zope.security.proxy import removeSecurityProxy |
| 443 | - >>> firefox_no_proxy = removeSecurityProxy(firefox) |
| 444 | - >>> from lp.registry.interfaces.person import IPersonSet |
| 445 | - >>> person_set = getUtility(IPersonSet) |
| 446 | - >>> firefox_subscribers = person_set.getSubscribersForTargets( |
| 447 | - ... [firefox_no_proxy]) |
| 448 | - >>> print_bug_subscribers(firefox_subscribers) |
| 449 | - name12 |
| 450 | - |
| 451 | -If PersonSet.getSubscribersForTargets() is passed a |
| 452 | -BugNotificationLevel in its `level` parameter, only structural |
| 453 | -subscribers with that notification level or higher will be returned. |
| 454 | -The subscription level of ff_sub, the only structural subscription |
| 455 | -to firefox, is NOTHING, hence we get an empty list if we pass any |
| 456 | -larger bug notification level. |
| 457 | - |
| 458 | - >>> firefox_subscribers = person_set.getSubscribersForTargets( |
| 459 | - ... [firefox_no_proxy], level=BugNotificationLevel.LIFECYCLE) |
| 460 | - >>> print len(firefox_subscribers) |
| 461 | - 0 |
| 462 | - |
| 463 | -If the bug notification level of ff_sub is increased, the subscription |
| 464 | -is included in the result of PersonSet.getSubscribersForTarget(). |
| 465 | - |
| 466 | - >>> ff_sub.level = BugNotificationLevel.LIFECYCLE |
| 467 | - >>> firefox_subscribers = person_set.getSubscribersForTargets( |
| 468 | - ... [firefox_no_proxy]) |
| 469 | - >>> print_bug_subscribers(firefox_subscribers) |
| 470 | - name12 |
| 471 | - >>> ff_sub.level = BugNotificationLevel.METADATA |
| 472 | - >>> firefox_subscribers = person_set.getSubscribersForTargets( |
| 473 | - ... [firefox_no_proxy]) |
| 474 | - >>> print_bug_subscribers(firefox_subscribers) |
| 475 | - name12 |
| 476 | - |
| 477 | -More than one target can be passed to PersonSet.getSubscribersForTargets(). |
| 478 | - |
| 479 | - >>> ubuntu_no_proxy = removeSecurityProxy(ubuntu) |
| 480 | - >>> ubuntu_or_firefox_subscribers = person_set.getSubscribersForTargets( |
| 481 | - ... [firefox_no_proxy, ubuntu_no_proxy]) |
| 482 | - >>> print_bug_subscribers(ubuntu_or_firefox_subscribers) |
| 483 | - name12 |
| 484 | - name16 |
| 485 | - |
| 486 | - |
| 487 | Target type display |
| 488 | =================== |
| 489 | |
| 490 | |
| 491 | === modified file 'lib/lp/registry/interfaces/person.py' |
| 492 | --- lib/lp/registry/interfaces/person.py 2010-09-29 20:05:17 +0000 |
| 493 | +++ lib/lp/registry/interfaces/person.py 2010-10-15 16:17:07 +0000 |
| 494 | @@ -2006,17 +2006,6 @@ |
| 495 | specified product are returned. |
| 496 | """ |
| 497 | |
| 498 | - def getSubscribersForTargets(targets, recipients=None): |
| 499 | - """Return the set of subscribers for `targets`. |
| 500 | - |
| 501 | - :param targets: The sequence of targets for which to get the |
| 502 | - subscribers. |
| 503 | - :param recipients: An optional instance of |
| 504 | - `BugNotificationRecipients`. |
| 505 | - If present, all found subscribers will be |
| 506 | - added to it. |
| 507 | - """ |
| 508 | - |
| 509 | def updatePersonalStandings(): |
| 510 | """Update the personal standings of some people. |
| 511 | |
| 512 | |
| 513 | === modified file 'lib/lp/registry/interfaces/structuralsubscription.py' |
| 514 | --- lib/lp/registry/interfaces/structuralsubscription.py 2010-10-05 09:23:22 +0000 |
| 515 | +++ lib/lp/registry/interfaces/structuralsubscription.py 2010-10-15 16:17:07 +0000 |
| 516 | @@ -200,8 +200,8 @@ |
| 517 | def userHasBugSubscriptions(user): |
| 518 | """Is `user` subscribed, directly or via a team, to bug mail?""" |
| 519 | |
| 520 | - def getSubscriptionsForBug(bug, level): |
| 521 | - """Return subscriptions for a given `IBug` at `level`.""" |
| 522 | + def getSubscriptionsForBugTask(bug, level): |
| 523 | + """Return subscriptions for a given `IBugTask` at `level`.""" |
| 524 | |
| 525 | |
| 526 | class IStructuralSubscriptionTargetWrite(Interface): |
| 527 | |
| 528 | === modified file 'lib/lp/registry/model/person.py' |
| 529 | --- lib/lp/registry/model/person.py 2010-09-29 14:38:30 +0000 |
| 530 | +++ lib/lp/registry/model/person.py 2010-10-15 16:17:07 +0000 |
| 531 | @@ -4060,59 +4060,6 @@ |
| 532 | Person.id in (%s) |
| 533 | ''' % branch_clause) |
| 534 | |
| 535 | - def getSubscribersForTargets(self, targets, recipients=None, level=None): |
| 536 | - """See `IPersonSet`. """ |
| 537 | - if len(targets) == 0: |
| 538 | - return set() |
| 539 | - target_criteria = [] |
| 540 | - for target in targets: |
| 541 | - # target_args is a mapping from query arguments |
| 542 | - # to query values. |
| 543 | - target_args = target._target_args |
| 544 | - target_criteria_clauses = [] |
| 545 | - for key, value in target_args.items(): |
| 546 | - if value is not None: |
| 547 | - target_criteria_clauses.append( |
| 548 | - '%s = %s' % (key, quote(value))) |
| 549 | - else: |
| 550 | - target_criteria_clauses.append( |
| 551 | - '%s IS NULL' % key) |
| 552 | - if level is not None: |
| 553 | - target_criteria_clauses.append('bug_notification_level >= %s' |
| 554 | - % quote(level.value)) |
| 555 | - |
| 556 | - target_criteria.append( |
| 557 | - '(%s)' % ' AND '.join(target_criteria_clauses)) |
| 558 | - |
| 559 | - # Build a UNION query, since using OR slows down the query a lot. |
| 560 | - subscriptions = StructuralSubscription.select(target_criteria[0]) |
| 561 | - for target_criterion in target_criteria[1:]: |
| 562 | - subscriptions = subscriptions.union( |
| 563 | - StructuralSubscription.select(target_criterion)) |
| 564 | - |
| 565 | - # Listify the result, since we want to loop over it multiple times. |
| 566 | - subscriptions = list(subscriptions) |
| 567 | - |
| 568 | - # We can't use prejoins in UNION queries, so populate the cache |
| 569 | - # by getting all the subscribers. |
| 570 | - subscriber_ids = [ |
| 571 | - subscription.subscriberID for subscription in subscriptions] |
| 572 | - if len(subscriber_ids) > 0: |
| 573 | - # Pull in ValidPersonCache records in addition to Person |
| 574 | - # records to warm up the cache. |
| 575 | - list(IStore(Person).find( |
| 576 | - (Person, ValidPersonCache), |
| 577 | - In(Person.id, subscriber_ids), |
| 578 | - ValidPersonCache.id == Person.id)) |
| 579 | - |
| 580 | - subscribers = set() |
| 581 | - for subscription in subscriptions: |
| 582 | - subscribers.add(subscription.subscriber) |
| 583 | - if recipients is not None: |
| 584 | - recipients.addStructuralSubscriber( |
| 585 | - subscription.subscriber, subscription.target) |
| 586 | - return subscribers |
| 587 | - |
| 588 | def updatePersonalStandings(self): |
| 589 | """See `IPersonSet`.""" |
| 590 | cur = cursor() |
| 591 | |
| 592 | === modified file 'lib/lp/registry/model/structuralsubscription.py' |
| 593 | --- lib/lp/registry/model/structuralsubscription.py 2010-10-05 16:52:02 +0000 |
| 594 | +++ lib/lp/registry/model/structuralsubscription.py 2010-10-15 16:17:07 +0000 |
| 595 | @@ -484,21 +484,8 @@ |
| 596 | return True |
| 597 | return False |
| 598 | |
| 599 | - def getSubscriptionsForBug(self, bug, level): |
| 600 | + def getSubscriptionsForBugTask(self, bugtask, level): |
| 601 | """See `IStructuralSubscriptionTarget`.""" |
| 602 | - if IProjectGroup.providedBy(self): |
| 603 | - targets = set(self.products) |
| 604 | - elif IMilestone.providedBy(self): |
| 605 | - targets = [self.series_target] |
| 606 | - else: |
| 607 | - targets = [self] |
| 608 | - |
| 609 | - bugtasks = [ |
| 610 | - bugtask for bugtask in bug.bugtasks |
| 611 | - if bugtask.target in targets] |
| 612 | - |
| 613 | - assert len(bugtasks) != 0, repr(self) |
| 614 | - |
| 615 | origin = [ |
| 616 | StructuralSubscription, |
| 617 | LeftJoin( |
| 618 | @@ -515,7 +502,7 @@ |
| 619 | BugSubscriptionFilter.id)), |
| 620 | ] |
| 621 | |
| 622 | - if len(bug.tags) == 0: |
| 623 | + if len(bugtask.bug.tags) == 0: |
| 624 | tag_conditions = [ |
| 625 | BugSubscriptionFilter.include_any_tags == False, |
| 626 | ] |
| 627 | @@ -534,13 +521,12 @@ |
| 628 | # There's no status filter, or there is a status filter |
| 629 | # and and it matches. |
| 630 | Or(BugSubscriptionFilterStatus.id == None, |
| 631 | - BugSubscriptionFilterStatus.status.is_in( |
| 632 | - bugtask.status for bugtask in bugtasks)), |
| 633 | + BugSubscriptionFilterStatus.status == bugtask.status), |
| 634 | # There's no importance filter, or there is an importance |
| 635 | # filter and it matches. |
| 636 | Or(BugSubscriptionFilterImportance.id == None, |
| 637 | - BugSubscriptionFilterImportance.importance.is_in( |
| 638 | - bugtask.importance for bugtask in bugtasks)), |
| 639 | + BugSubscriptionFilterImportance.importance == ( |
| 640 | + bugtask.importance)), |
| 641 | # Any number of conditions relating to tags. |
| 642 | *tag_conditions)), |
| 643 | ] |
| 644 | |
| 645 | === modified file 'lib/lp/registry/tests/test_structuralsubscriptiontarget.py' |
| 646 | --- lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-06 18:53:53 +0000 |
| 647 | +++ lib/lp/registry/tests/test_structuralsubscriptiontarget.py 2010-10-15 16:17:07 +0000 |
| 648 | @@ -173,19 +173,20 @@ |
| 649 | def makeBugTask(self): |
| 650 | return self.factory.makeBugTask(target=self.target) |
| 651 | |
| 652 | - def test_getSubscriptionsForBug(self): |
| 653 | + def test_getSubscriptionsForBugTask(self): |
| 654 | # If no one has a filtered subscription for the given bug, the result |
| 655 | - # of getSubscriptionsForBug() is the same as for getSubscriptions(). |
| 656 | + # of getSubscriptionsForBugTask() is the same as for |
| 657 | + # getSubscriptions(). |
| 658 | bugtask = self.makeBugTask() |
| 659 | subscriptions = self.target.getSubscriptions( |
| 660 | min_bug_notification_level=BugNotificationLevel.NOTHING) |
| 661 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 662 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 663 | - self.assertEqual(list(subscriptions), list(subscriptions_for_bug)) |
| 664 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 665 | + bugtask, BugNotificationLevel.NOTHING) |
| 666 | + self.assertEqual(list(subscriptions), list(subscriptions_for_bugtask)) |
| 667 | |
| 668 | - def test_getSubscriptionsForBug_with_filter_on_status(self): |
| 669 | + def test_getSubscriptionsForBugTask_with_filter_on_status(self): |
| 670 | # If a status filter exists for a subscription, the result of |
| 671 | - # getSubscriptionsForBug() may be a subset of getSubscriptions(). |
| 672 | + # getSubscriptionsForBugTask() may be a subset of getSubscriptions(). |
| 673 | bugtask = self.makeBugTask() |
| 674 | |
| 675 | # Create a new subscription on self.target. |
| 676 | @@ -195,9 +196,9 @@ |
| 677 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS |
| 678 | |
| 679 | # Without any filters the subscription is found. |
| 680 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 681 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 682 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 683 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 684 | + bugtask, BugNotificationLevel.NOTHING) |
| 685 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 686 | |
| 687 | # Filter the subscription to bugs in the CONFIRMED state. |
| 688 | subscription_filter = BugSubscriptionFilter() |
| 689 | @@ -205,19 +206,19 @@ |
| 690 | subscription_filter.statuses = [BugTaskStatus.CONFIRMED] |
| 691 | |
| 692 | # With the filter the subscription is not found. |
| 693 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 694 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 695 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 696 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 697 | + bugtask, BugNotificationLevel.NOTHING) |
| 698 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 699 | |
| 700 | # If the filter is adjusted, the subscription is found again. |
| 701 | subscription_filter.statuses = [bugtask.status] |
| 702 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 703 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 704 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 705 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 706 | + bugtask, BugNotificationLevel.NOTHING) |
| 707 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 708 | |
| 709 | - def test_getSubscriptionsForBug_with_filter_on_importance(self): |
| 710 | + def test_getSubscriptionsForBugTask_with_filter_on_importance(self): |
| 711 | # If an importance filter exists for a subscription, the result of |
| 712 | - # getSubscriptionsForBug() may be a subset of getSubscriptions(). |
| 713 | + # getSubscriptionsForBugTask() may be a subset of getSubscriptions(). |
| 714 | bugtask = self.makeBugTask() |
| 715 | |
| 716 | # Create a new subscription on self.target. |
| 717 | @@ -227,9 +228,9 @@ |
| 718 | subscription.bug_notification_level = BugNotificationLevel.COMMENTS |
| 719 | |
| 720 | # Without any filters the subscription is found. |
| 721 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 722 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 723 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 724 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 725 | + bugtask, BugNotificationLevel.NOTHING) |
| 726 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 727 | |
| 728 | # Filter the subscription to bugs in the CRITICAL state. |
| 729 | subscription_filter = BugSubscriptionFilter() |
| 730 | @@ -237,19 +238,19 @@ |
| 731 | subscription_filter.importances = [BugTaskImportance.CRITICAL] |
| 732 | |
| 733 | # With the filter the subscription is not found. |
| 734 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 735 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 736 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 737 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 738 | + bugtask, BugNotificationLevel.NOTHING) |
| 739 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 740 | |
| 741 | # If the filter is adjusted, the subscription is found again. |
| 742 | subscription_filter.importances = [bugtask.importance] |
| 743 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 744 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 745 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 746 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 747 | + bugtask, BugNotificationLevel.NOTHING) |
| 748 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 749 | |
| 750 | - def test_getSubscriptionsForBug_with_filter_on_level(self): |
| 751 | + def test_getSubscriptionsForBugTask_with_filter_on_level(self): |
| 752 | # All structural subscriptions have a level for bug notifications |
| 753 | - # which getSubscriptionsForBug() observes. |
| 754 | + # which getSubscriptionsForBugTask() observes. |
| 755 | bugtask = self.makeBugTask() |
| 756 | |
| 757 | # Create a new METADATA level subscription on self.target. |
| 758 | @@ -259,19 +260,19 @@ |
| 759 | subscription.bug_notification_level = BugNotificationLevel.METADATA |
| 760 | |
| 761 | # The subscription is found when looking for NOTHING or above. |
| 762 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 763 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 764 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 765 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 766 | + bugtask, BugNotificationLevel.NOTHING) |
| 767 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 768 | # The subscription is found when looking for METADATA or above. |
| 769 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 770 | - bugtask.bug, BugNotificationLevel.METADATA) |
| 771 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 772 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 773 | + bugtask, BugNotificationLevel.METADATA) |
| 774 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 775 | # The subscription is not found when looking for COMMENTS or above. |
| 776 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 777 | - bugtask.bug, BugNotificationLevel.COMMENTS) |
| 778 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 779 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 780 | + bugtask, BugNotificationLevel.COMMENTS) |
| 781 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 782 | |
| 783 | - def test_getSubscriptionsForBug_with_filter_include_any_tags(self): |
| 784 | + def test_getSubscriptionsForBugTask_with_filter_include_any_tags(self): |
| 785 | # If a subscription filter has include_any_tags, a bug with one or |
| 786 | # more tags is matched. |
| 787 | bugtask = self.makeBugTask() |
| 788 | @@ -285,17 +286,17 @@ |
| 789 | subscription_filter.include_any_tags = True |
| 790 | |
| 791 | # Without any tags the subscription is not found. |
| 792 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 793 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 794 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 795 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 796 | + bugtask, BugNotificationLevel.NOTHING) |
| 797 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 798 | |
| 799 | # With any tag the subscription is found. |
| 800 | bugtask.bug.tags = ["foo"] |
| 801 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 802 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 803 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 804 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 805 | + bugtask, BugNotificationLevel.NOTHING) |
| 806 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 807 | |
| 808 | - def test_getSubscriptionsForBug_with_filter_exclude_any_tags(self): |
| 809 | + def test_getSubscriptionsForBugTask_with_filter_exclude_any_tags(self): |
| 810 | # If a subscription filter has exclude_any_tags, only bugs with no |
| 811 | # tags are matched. |
| 812 | bugtask = self.makeBugTask() |
| 813 | @@ -309,17 +310,17 @@ |
| 814 | subscription_filter.exclude_any_tags = True |
| 815 | |
| 816 | # Without any tags the subscription is found. |
| 817 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 818 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 819 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 820 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 821 | + bugtask, BugNotificationLevel.NOTHING) |
| 822 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 823 | |
| 824 | # With any tag the subscription is not found. |
| 825 | bugtask.bug.tags = ["foo"] |
| 826 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 827 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 828 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 829 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 830 | + bugtask, BugNotificationLevel.NOTHING) |
| 831 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 832 | |
| 833 | - def test_getSubscriptionsForBug_with_multiple_filters(self): |
| 834 | + def test_getSubscriptionsForBugTask_with_multiple_filters(self): |
| 835 | # If multiple filters exist for a subscription, all filters must |
| 836 | # match. |
| 837 | bugtask = self.makeBugTask() |
| 838 | @@ -337,23 +338,23 @@ |
| 839 | subscription_filter.importances = [BugTaskImportance.CRITICAL] |
| 840 | |
| 841 | # With the filter the subscription is not found. |
| 842 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 843 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 844 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 845 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 846 | + bugtask, BugNotificationLevel.NOTHING) |
| 847 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 848 | |
| 849 | # If the filter is adjusted to match status but not importance, the |
| 850 | # subscription is still not found. |
| 851 | subscription_filter.statuses = [bugtask.status] |
| 852 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 853 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 854 | - self.assertEqual([], list(subscriptions_for_bug)) |
| 855 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 856 | + bugtask, BugNotificationLevel.NOTHING) |
| 857 | + self.assertEqual([], list(subscriptions_for_bugtask)) |
| 858 | |
| 859 | # If the filter is adjusted to also match importance, the subscription |
| 860 | # is found again. |
| 861 | subscription_filter.importances = [bugtask.importance] |
| 862 | - subscriptions_for_bug = self.target.getSubscriptionsForBug( |
| 863 | - bugtask.bug, BugNotificationLevel.NOTHING) |
| 864 | - self.assertEqual([subscription], list(subscriptions_for_bug)) |
| 865 | + subscriptions_for_bugtask = self.target.getSubscriptionsForBugTask( |
| 866 | + bugtask, BugNotificationLevel.NOTHING) |
| 867 | + self.assertEqual([subscription], list(subscriptions_for_bugtask)) |
| 868 | |
| 869 | |
| 870 | class TestStructuralSubscriptionForDistro( |
| 871 | |
| 872 | === modified file 'utilities/format-new-and-modified-imports' |
| 873 | --- utilities/format-new-and-modified-imports 2010-09-28 09:50:49 +0000 |
| 874 | +++ utilities/format-new-and-modified-imports 2010-10-15 16:17:07 +0000 |
| 875 | @@ -9,5 +9,5 @@ |
| 876 | # |
| 877 | |
| 878 | bzr status --short "$@" | \ |
| 879 | - awk '/^.[MN] .*[.]py$/ { print $2 }' | \ |
| 880 | + awk '/^.[MN] .*[.]py$/ { print $NF }' | \ |
| 881 | xargs -r "$(dirname "$0")/format-imports" |

(18:18:58) allenap: adeuring: It's already reviewed and landed in db-devel, so I just need a +1 to land on devel.
(18:20:00) adeuring: allenap: so, rs=me
(18:20:10) allenap: adeuring: Thanks.