Merge ~cjwatson/launchpad:stormify-bugnotification into launchpad:master

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 298c58e423172143e24be1d0e95be0ef33b8a958
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~cjwatson/launchpad:stormify-bugnotification
Merge into: launchpad:master
Diff against target: 1144 lines (+244/-148)
30 files modified
lib/lp/bugs/browser/tests/bug-views.txt (+5/-4)
lib/lp/bugs/doc/bug-change.txt (+7/-3)
lib/lp/bugs/doc/bug-set-status.txt (+3/-1)
lib/lp/bugs/doc/bugattachments.txt (+5/-4)
lib/lp/bugs/doc/bugnotification-sending.txt (+3/-1)
lib/lp/bugs/doc/bugnotification-threading.txt (+1/-2)
lib/lp/bugs/doc/bugnotifications.txt (+25/-12)
lib/lp/bugs/doc/bugsubscription.txt (+22/-18)
lib/lp/bugs/doc/bugwatch.txt (+5/-5)
lib/lp/bugs/doc/externalbugtracker-comment-imports.txt (+4/-4)
lib/lp/bugs/mail/bugnotificationrecipients.py (+2/-0)
lib/lp/bugs/mail/tests/test_bug_duplicate_notifications.py (+3/-1)
lib/lp/bugs/mail/tests/test_bug_task_assignment.py (+5/-2)
lib/lp/bugs/mail/tests/test_bug_task_deletion.py (+3/-1)
lib/lp/bugs/mail/tests/test_bug_task_modification.py (+3/-1)
lib/lp/bugs/mail/tests/test_handler.py (+4/-2)
lib/lp/bugs/model/bug.py (+5/-4)
lib/lp/bugs/model/bugnotification.py (+61/-30)
lib/lp/bugs/scripts/tests/test_bugimport.py (+3/-1)
lib/lp/bugs/scripts/tests/test_bugnotification.py (+9/-16)
lib/lp/bugs/stories/bugs/xx-bugs.txt (+1/-1)
lib/lp/bugs/stories/webservice/xx-bug.txt (+3/-1)
lib/lp/bugs/subscribers/tests/test_bug.py (+3/-3)
lib/lp/bugs/tests/bugs-emailinterface.txt (+20/-10)
lib/lp/bugs/tests/bugtarget-questiontarget.txt (+4/-1)
lib/lp/bugs/tests/test_bugchanges.py (+7/-6)
lib/lp/bugs/tests/test_bugnotification.py (+7/-3)
lib/lp/registry/doc/milestone.txt (+4/-3)
lib/lp/scripts/tests/test_garbo.py (+11/-5)
lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt (+6/-3)
Reviewer Review Type Date Requested Status
Ioana Lasc (community) Approve
Review via email: mp+385562@code.launchpad.net

Commit message

Convert BugNotification to Storm

To post a comment you must log in.
Revision history for this message
Ioana Lasc (ilasc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/lib/lp/bugs/browser/tests/bug-views.txt b/lib/lp/bugs/browser/tests/bug-views.txt
2index 2e89e54..2dccbf9 100644
3--- a/lib/lp/bugs/browser/tests/bug-views.txt
4+++ b/lib/lp/bugs/browser/tests/bug-views.txt
5@@ -648,7 +648,8 @@ Emails are sent out by adding entries to the bugnotification table. We
6 need to know how many messages are currently in that table.
7
8 >>> from lp.bugs.model.bugnotification import BugNotification
9- >>> bn_set = BugNotification.select(BugNotification.q.bugID == bug_one.id)
10+ >>> from lp.services.database.interfaces import IStore
11+ >>> bn_set = IStore(BugNotification).find(BugNotification, bug=bug_one)
12 >>> start_bugnotification_count = bn_set.count()
13
14 Add 'new-tag' multiple times so that we can verify that it will only be added
15@@ -666,11 +667,11 @@ once.
16 Since the 'new-tag' was added, a new entry in the bugnotification table
17 should exist.
18
19- >>> bn_set = BugNotification.select(BugNotification.q.bugID == bug_one.id,
20- ... orderBy = BugNotification.q.id)
21+ >>> bn_set = IStore(BugNotification).find(
22+ ... BugNotification, bug=bug_one).order_by(BugNotification.id)
23 >>> start_bugnotification_count == bn_set.count() - 1
24 True
25- >>> bn_set[-1].message.text_contents
26+ >>> bn_set.last().message.text_contents
27 u'** Tags added: new-tag'
28
29
30diff --git a/lib/lp/bugs/doc/bug-change.txt b/lib/lp/bugs/doc/bug-change.txt
31index 1d44ea1..881c389 100644
32--- a/lib/lp/bugs/doc/bug-change.txt
33+++ b/lib/lp/bugs/doc/bug-change.txt
34@@ -107,7 +107,9 @@ BugActivity entries are added when addChange() is called.
35 As are BugNotifications.
36
37 >>> from lp.bugs.model.bugnotification import BugNotification
38- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
39+ >>> from lp.services.database.interfaces import IStore
40+ >>> latest_notification = IStore(BugNotification).find(
41+ ... BugNotification).order_by(BugNotification.id).last()
42 >>> print(latest_notification.message.text_contents)
43 Some message text
44
45@@ -131,7 +133,8 @@ But if getBugActivity() returns None, no activity entries will be added.
46
47 And if getBugNotification() returns None, no notification will be added.
48
49- >>> new_latest_notification = BugNotification.selectFirst(orderBy='-id')
50+ >>> new_latest_notification = IStore(BugNotification).find(
51+ ... BugNotification).order_by(BugNotification.id).last()
52 >>> new_latest_notification.id == latest_notification.id
53 True
54
55@@ -158,7 +161,8 @@ bug's target for Meta data changes, but not for lifecycle changes.
56 ... filter.bug_notification_level = BugNotificationLevel.METADATA
57 >>> example_bug.addChange(
58 ... TestBugChange(when=nowish, person=example_person))
59- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
60+ >>> latest_notification = IStore(BugNotification).find(
61+ ... BugNotification).order_by(BugNotification.id).last()
62 >>> print(latest_notification.message.text_contents)
63 Some message text
64
65diff --git a/lib/lp/bugs/doc/bug-set-status.txt b/lib/lp/bugs/doc/bug-set-status.txt
66index cc9ccfe..0626c48 100644
67--- a/lib/lp/bugs/doc/bug-set-status.txt
68+++ b/lib/lp/bugs/doc/bug-set-status.txt
69@@ -41,7 +41,9 @@ It also emits an ObjectModifiedEvent so that BugNotification and
70 BugActivity records are created.
71
72 >>> from lp.bugs.model.bugnotification import BugNotification
73- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
74+ >>> from lp.services.database.interfaces import IStore
75+ >>> latest_notification = IStore(BugNotification).find(
76+ ... BugNotification).order_by(BugNotification.id).last()
77 >>> print(latest_notification.message.owner.displayname)
78 No Privileges Person
79 >>> print(latest_notification.message.text_contents)
80diff --git a/lib/lp/bugs/doc/bugattachments.txt b/lib/lp/bugs/doc/bugattachments.txt
81index 977c944..ac57c8f 100644
82--- a/lib/lp/bugs/doc/bugattachments.txt
83+++ b/lib/lp/bugs/doc/bugattachments.txt
84@@ -237,7 +237,9 @@ Since the ObjectCreatedEvent was generated, a notification about the
85 attachment was added.
86
87 >>> from lp.bugs.model.bugnotification import BugNotification
88- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
89+ >>> from lp.services.database.interfaces import IStore
90+ >>> latest_notification = IStore(BugNotification).find(
91+ ... BugNotification).order_by(BugNotification.id).last()
92 >>> print(latest_notification.message.text_contents)
93 ** Attachment added: "RA.txt"
94 http://.../RA.txt
95@@ -475,9 +477,8 @@ The libraryfile of this bug attachment is marked as "deleted".
96 Deleting an attachment causes a notification to be sent. It's worth
97 noting that the notification still includes the URL to the attachment.
98
99- >>> from lp.bugs.model.bugnotification import BugNotification
100- >>> latest_notification = BugNotification
101- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
102+ >>> latest_notification = IStore(BugNotification).find(
103+ ... BugNotification).order_by(BugNotification.id).last()
104 >>> latest_notification.is_comment
105 False
106 >>> print(latest_notification.message.text_contents)
107diff --git a/lib/lp/bugs/doc/bugnotification-sending.txt b/lib/lp/bugs/doc/bugnotification-sending.txt
108index 19cd3a8..92c265f 100644
109--- a/lib/lp/bugs/doc/bugnotification-sending.txt
110+++ b/lib/lp/bugs/doc/bugnotification-sending.txt
111@@ -619,7 +619,9 @@ more carefully at the notifications just to see that the status has
112 been set properly.
113
114 >>> from lp.bugs.model.bugnotification import BugNotification
115- >>> for notification in BugNotification.select(orderBy='id')[-8:]:
116+ >>> from lp.services.database.interfaces import IStore
117+ >>> for notification in list(IStore(BugNotification).find(
118+ ... BugNotification).order_by(BugNotification.id))[-8:]:
119 ... if notification.is_comment:
120 ... identifier = 'comment'
121 ... else:
122diff --git a/lib/lp/bugs/doc/bugnotification-threading.txt b/lib/lp/bugs/doc/bugnotification-threading.txt
123index 1864f0b..e73b4e3 100644
124--- a/lib/lp/bugs/doc/bugnotification-threading.txt
125+++ b/lib/lp/bugs/doc/bugnotification-threading.txt
126@@ -139,8 +139,7 @@ References header.
127 ... owner=sample_person, title="New bug", comment="New bug.",
128 ... target=bug_one.default_bugtask.target)
129 >>> bug = getUtility(IBugSet).createBug(params)
130- >>> notifications = IStore(BugNotification).find(
131- ... BugNotification, BugNotification.bug == bug)
132+ >>> notifications = IStore(BugNotification).find(BugNotification, bug=bug)
133 >>> messages = [emails for notifications, omitted, emails in
134 ... get_email_notifications(notifications)]
135 >>> len(messages)
136diff --git a/lib/lp/bugs/doc/bugnotifications.txt b/lib/lp/bugs/doc/bugnotifications.txt
137index b16b50a..1e364cc 100644
138--- a/lib/lp/bugs/doc/bugnotifications.txt
139+++ b/lib/lp/bugs/doc/bugnotifications.txt
140@@ -41,7 +41,9 @@ those notifications look like.
141 >>> firefox_crashes = firefox.createBug(params)
142
143 >>> from lp.bugs.model.bugnotification import BugNotification
144- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
145+ >>> from lp.services.database.interfaces import IStore
146+ >>> latest_notification = IStore(BugNotification).find(
147+ ... BugNotification).order_by(BugNotification.id).last()
148 >>> print(latest_notification.message.owner.displayname)
149 Sample Person
150
151@@ -68,7 +70,8 @@ bugactivity.txt, but for now here is a small demo.
152 >>> with notify_modified(firefox_crashes, ["description"]):
153 ... firefox_crashes.description = "a new description"
154
155- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
156+ >>> latest_notification = IStore(BugNotification).find(
157+ ... BugNotification).order_by(BugNotification.id).last()
158 >>> print(latest_notification.message.owner.displayname)
159 Sample Person
160
161@@ -107,7 +110,8 @@ bug. Let's take a look at each type.
162 >>> notify(ObjectCreatedEvent(
163 ... firefox_crashes_in_debian, firefox_crashes_in_debian.owner))
164
165- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
166+ >>> latest_notification = IStore(BugNotification).find(
167+ ... BugNotification).order_by(BugNotification.id).last()
168 >>> print(latest_notification.message.owner.displayname)
169 Sample Person
170
171@@ -133,7 +137,8 @@ bug. Let's take a look at each type.
172 >>> notify(ObjectCreatedEvent(
173 ... firefox_crashes_in_sid, firefox_crashes_in_sid.owner))
174
175- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
176+ >>> latest_notification = IStore(BugNotification).find(
177+ ... BugNotification).order_by(BugNotification.id).last()
178 >>> print(latest_notification.message.owner.displayname)
179 Sample Person
180
181@@ -161,7 +166,8 @@ bug. Let's take a look at each type.
182 >>> notify(ObjectCreatedEvent(
183 ... evolution_crashes_too, evolution_crashes_too.owner))
184
185- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
186+ >>> latest_notification = IStore(BugNotification).find(
187+ ... BugNotification).order_by(BugNotification.id).last()
188 >>> print(latest_notification.message.owner.displayname)
189 Sample Person
190
191@@ -183,7 +189,8 @@ bug. Let's take a look at each type.
192 >>> notify(ObjectCreatedEvent(
193 ... firefox_crashes_in_trunk, firefox_crashes_in_trunk.owner))
194
195- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
196+ >>> latest_notification = IStore(BugNotification).find(
197+ ... BugNotification).order_by(BugNotification.id).last()
198 >>> print(latest_notification.message.owner.displayname)
199 Sample Person
200
201@@ -205,7 +212,8 @@ bug. Let's take a look at each type.
202 ... bug=firefox_crashes, owner=current_user)
203 >>> notify(ObjectCreatedEvent(comment_on_firefox_crashes_in_debian))
204
205- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
206+ >>> latest_notification = IStore(BugNotification).find(
207+ ... BugNotification).order_by(BugNotification.id).last()
208 >>> print(latest_notification.message.owner.displayname)
209 Sample Person
210
211@@ -228,7 +236,8 @@ task Fixed, and assigns themselves to it.
212 ... BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
213 ... firefox_crashes_in_debian.transitionToAssignee(bug_submitter)
214
215- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
216+ >>> latest_notification = IStore(BugNotification).find(
217+ ... BugNotification).order_by(BugNotification.id).last()
218 >>> print(latest_notification.message.owner.displayname)
219 Sample Person
220
221@@ -244,7 +253,8 @@ task Fixed, and assigns themselves to it.
222 ... BugTaskStatus.FIXRELEASED, getUtility(ILaunchBag).user)
223 ... firefox_crashes_in_trunk.transitionToAssignee(bug_submitter)
224
225- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
226+ >>> latest_notification = IStore(BugNotification).find(
227+ ... BugNotification).order_by(BugNotification.id).last()
228 >>> print(latest_notification.message.owner.displayname)
229 Sample Person
230
231@@ -269,7 +279,8 @@ this document:
232 >>> bug = Bug.get(1)
233 >>> bugcve = cve.linkBug(bug) # note this creates the event and notifies
234
235- >>> latest_notification = BugNotification.selectFirst(orderBy='-id')
236+ >>> latest_notification = IStore(BugNotification).find(
237+ ... BugNotification).order_by(BugNotification.id).last()
238 >>> print(latest_notification.message.owner.displayname)
239 Sample Person
240
241@@ -285,7 +296,8 @@ During bulk imports or changes of bugs, we often want to suppress
242 email notifications. Due to the previous operation, there is a
243 pending bug notification for bug 1:
244
245- >>> notifications = BugNotification.selectBy(bugID=1, date_emailed=None)
246+ >>> notifications = IStore(BugNotification).find(
247+ ... BugNotification, bug_id=1, date_emailed=None)
248 >>> notifications.count()
249 1
250
251@@ -293,6 +305,7 @@ This notification can be expired using the expireNotifications()
252 method:
253
254 >>> bug.expireNotifications()
255- >>> notifications = BugNotification.selectBy(bugID=1, date_emailed=None)
256+ >>> notifications = IStore(BugNotification).find(
257+ ... BugNotification, bug_id=1, date_emailed=None)
258 >>> notifications.count()
259 0
260diff --git a/lib/lp/bugs/doc/bugsubscription.txt b/lib/lp/bugs/doc/bugsubscription.txt
261index fdae4e0..052dee6 100644
262--- a/lib/lp/bugs/doc/bugsubscription.txt
263+++ b/lib/lp/bugs/doc/bugsubscription.txt
264@@ -365,11 +365,12 @@ INotificationRecipientSet instance for us:
265 You can query for the addresses and reasons:
266
267 >>> addresses = recipients.getEmails()
268- >>> [(address, recipients.getReason(address)[1]) for address in addresses]
269- [('foo.bar@canonical.com', 'Subscriber'),
270- ('mark@example.com', 'Subscriber'),
271- ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
272- ('test@canonical.com', 'Assignee')]
273+ >>> for address in addresses:
274+ ... print('%s: %s' % (address, recipients.getReason(address)[1]))
275+ foo.bar@canonical.com: Subscriber
276+ mark@example.com: Subscriber
277+ no-priv@canonical.com: Subscriber (linux-source-2.6.15 in Ubuntu)
278+ test@canonical.com: Assignee
279
280 If IBug.getBugNotificationRecipients() is passed a BugNotificationLevel
281 in its `level` parameter, only structural subscribers with that
282@@ -378,10 +379,11 @@ notification level or higher will be returned.
283 >>> recipients = linux_source_bug.getBugNotificationRecipients(
284 ... level=BugNotificationLevel.COMMENTS)
285 >>> addresses = recipients.getEmails()
286- >>> [(address, recipients.getReason(address)[1]) for address in addresses]
287- [('foo.bar@canonical.com', 'Subscriber'),
288- ('mark@example.com', 'Subscriber'),
289- ('test@canonical.com', 'Assignee')]
290+ >>> for address in addresses:
291+ ... print('%s: %s' % (address, recipients.getReason(address)[1]))
292+ foo.bar@canonical.com: Subscriber
293+ mark@example.com: Subscriber
294+ test@canonical.com: Assignee
295
296 When Sample Person is unsubscribed from linux_source_bug, they are no
297 longer included in the result of getBugNotificationRecipients() for
298@@ -391,10 +393,11 @@ the COMMENTS level...
299 >>> recipients = linux_source_bug.getBugNotificationRecipients(
300 ... level=BugNotificationLevel.COMMENTS)
301 >>> addresses = recipients.getEmails()
302- >>> [(address, recipients.getReason(address)[1]) for address in addresses]
303- [('foo.bar@canonical.com', 'Subscriber'),
304- ('mark@example.com', 'Subscriber'),
305- ('test@canonical.com', 'Assignee')]
306+ >>> for address in addresses:
307+ ... print('%s: %s' % (address, recipients.getReason(address)[1]))
308+ foo.bar@canonical.com: Subscriber
309+ mark@example.com: Subscriber
310+ test@canonical.com: Assignee
311
312 ...but remains included for the level LIFECYCLE.
313
314@@ -402,11 +405,12 @@ the COMMENTS level...
315 >>> recipients = linux_source_bug.getBugNotificationRecipients(
316 ... level=BugNotificationLevel.LIFECYCLE)
317 >>> addresses = recipients.getEmails()
318- >>> [(address, recipients.getReason(address)[1]) for address in addresses]
319- [('foo.bar@canonical.com', 'Subscriber'),
320- ('mark@example.com', 'Subscriber'),
321- ('no-priv@canonical.com', u'Subscriber (linux-source-2.6.15 in Ubuntu)'),
322- ('test@canonical.com', 'Assignee')]
323+ >>> for address in addresses:
324+ ... print('%s: %s' % (address, recipients.getReason(address)[1]))
325+ foo.bar@canonical.com: Subscriber
326+ mark@example.com: Subscriber
327+ no-priv@canonical.com: Subscriber (linux-source-2.6.15 in Ubuntu)
328+ test@canonical.com: Assignee
329
330 To find out if someone is already directly subscribed to a bug, call
331 IBug.isSubscribed, passing in an IPerson:
332diff --git a/lib/lp/bugs/doc/bugwatch.txt b/lib/lp/bugs/doc/bugwatch.txt
333index c280375..0431c68 100644
334--- a/lib/lp/bugs/doc/bugwatch.txt
335+++ b/lib/lp/bugs/doc/bugwatch.txt
336@@ -317,14 +317,14 @@ tasks, because it's not a valid person and only valid persons can get karma.
337
338 Finally, let's make sure that bug notifications were added:
339
340- >>> from lp.bugs.model.bugnotification import (
341- ... BugNotification)
342- >>> unsent_notifications = (
343- ... BugNotification.selectBy(date_emailed=None, orderBy='id'))
344+ >>> from lp.bugs.model.bugnotification import BugNotification
345+ >>> from lp.services.database.interfaces import IStore
346+ >>> unsent_notifications = IStore(BugNotification).find(
347+ ... BugNotification, date_emailed=None).order_by(BugNotification.id)
348
349 >>> for bug_notification in unsent_notifications:
350 ... print("Bug %s changed by %s:" % (
351- ... bug_notification.bug.id,
352+ ... bug_notification.bug_id,
353 ... bug_notification.message.owner.displayname))
354 ... print(bug_notification.message.text_contents)
355 Bug 1 changed by Bug Watch Updater:
356diff --git a/lib/lp/bugs/doc/externalbugtracker-comment-imports.txt b/lib/lp/bugs/doc/externalbugtracker-comment-imports.txt
357index 4f0aa00..7c7a5b0 100644
358--- a/lib/lp/bugs/doc/externalbugtracker-comment-imports.txt
359+++ b/lib/lp/bugs/doc/externalbugtracker-comment-imports.txt
360@@ -431,13 +431,13 @@ watch, there can be a lot of comments. To avoid causing a lot of email
361 notifications to be sent, only one notification is sent for all the
362 comments.
363
364- >>> from lp.bugs.model.bugnotification import (
365- ... BugNotification)
366+ >>> from lp.bugs.model.bugnotification import BugNotification
367+ >>> from lp.services.database.interfaces import IStore
368 >>> old_notifications = set()
369 >>> def get_new_notifications(bug):
370 ... new_notifications = [
371- ... notification for notification in (
372- ... BugNotification.selectBy(bug=bug, orderBy='id'))
373+ ... notification for notification in IStore(BugNotification).find(
374+ ... BugNotification, bug=bug).order_by(BugNotification.id)
375 ... if notification not in old_notifications]
376 ... old_notifications.update(new_notifications)
377 ... return new_notifications
378diff --git a/lib/lp/bugs/mail/bugnotificationrecipients.py b/lib/lp/bugs/mail/bugnotificationrecipients.py
379index bcec38d..ff1cf8b 100644
380--- a/lib/lp/bugs/mail/bugnotificationrecipients.py
381+++ b/lib/lp/bugs/mail/bugnotificationrecipients.py
382@@ -3,6 +3,8 @@
383
384 """Code for handling bug notification recipients in bug mail."""
385
386+from __future__ import absolute_import, print_function, unicode_literals
387+
388 __metaclass__ = type
389 __all__ = [
390 'BugNotificationRecipients',
391diff --git a/lib/lp/bugs/mail/tests/test_bug_duplicate_notifications.py b/lib/lp/bugs/mail/tests/test_bug_duplicate_notifications.py
392index 61ad6ca..431ad45 100644
393--- a/lib/lp/bugs/mail/tests/test_bug_duplicate_notifications.py
394+++ b/lib/lp/bugs/mail/tests/test_bug_duplicate_notifications.py
395@@ -9,6 +9,7 @@ from zope.component import getUtility
396 from lp.bugs.interfaces.bugtask import BugTaskStatus
397 from lp.bugs.model.bugnotification import BugNotification
398 from lp.bugs.scripts.bugnotification import construct_email_notifications
399+from lp.services.database.interfaces import IStore
400 from lp.services.webapp.interfaces import ILaunchBag
401 from lp.services.webapp.snapshot import notify_modified
402 from lp.testing import TestCaseWithFactory
403@@ -46,7 +47,8 @@ class TestAssignmentNotification(TestCaseWithFactory):
404 self.master_bug_task.transitionToStatus(
405 BugTaskStatus.CONFIRMED, self.user)
406 transaction.commit()
407- latest_notification = BugNotification.selectFirst(orderBy='-id')
408+ latest_notification = IStore(BugNotification).find(
409+ BugNotification).order_by(BugNotification.id).last()
410 notifications, omitted, messages = construct_email_notifications(
411 [latest_notification])
412 self.assertEqual(
413diff --git a/lib/lp/bugs/mail/tests/test_bug_task_assignment.py b/lib/lp/bugs/mail/tests/test_bug_task_assignment.py
414index 031bb14..3e34cdd 100644
415--- a/lib/lp/bugs/mail/tests/test_bug_task_assignment.py
416+++ b/lib/lp/bugs/mail/tests/test_bug_task_assignment.py
417@@ -8,6 +8,7 @@ from zope.component import getUtility
418
419 from lp.bugs.model.bugnotification import BugNotification
420 from lp.bugs.scripts.bugnotification import construct_email_notifications
421+from lp.services.database.interfaces import IStore
422 from lp.services.mail import stub
423 from lp.services.webapp.interfaces import ILaunchBag
424 from lp.services.webapp.snapshot import notify_modified
425@@ -91,7 +92,8 @@ class TestAssignmentNotification(TestCaseWithFactory):
426 task changes and ensure the assignee is not one."""
427 with notify_modified(self.bug_task, ['assignee'], user=self.user):
428 self.bug_task.transitionToAssignee(self.person_assigned)
429- latest_notification = BugNotification.selectFirst(orderBy='-id')
430+ latest_notification = IStore(BugNotification).find(
431+ BugNotification).order_by(BugNotification.id).last()
432 notifications, omitted, messages = construct_email_notifications(
433 [latest_notification])
434 self.assertEqual(len(notifications), 1,
435@@ -106,7 +108,8 @@ class TestAssignmentNotification(TestCaseWithFactory):
436 task changes."""
437 with notify_modified(self.bug_task, ['assignee'], user=self.user):
438 self.bug_task.transitionToAssignee(self.team_assigned)
439- latest_notification = BugNotification.selectFirst(orderBy='-id')
440+ latest_notification = IStore(BugNotification).find(
441+ BugNotification).order_by(BugNotification.id).last()
442 notifications, omitted, messages = construct_email_notifications(
443 [latest_notification])
444 self.assertEqual(len(notifications), 1,
445diff --git a/lib/lp/bugs/mail/tests/test_bug_task_deletion.py b/lib/lp/bugs/mail/tests/test_bug_task_deletion.py
446index 4811568..0cbb63f 100644
447--- a/lib/lp/bugs/mail/tests/test_bug_task_deletion.py
448+++ b/lib/lp/bugs/mail/tests/test_bug_task_deletion.py
449@@ -8,6 +8,7 @@ from zope.component import getUtility
450
451 from lp.bugs.model.bugnotification import BugNotification
452 from lp.bugs.scripts.bugnotification import construct_email_notifications
453+from lp.services.database.interfaces import IStore
454 from lp.services.webapp.interfaces import ILaunchBag
455 from lp.testing import TestCaseWithFactory
456 from lp.testing.layers import DatabaseFunctionalLayer
457@@ -30,7 +31,8 @@ class TestDeletionNotification(TestCaseWithFactory):
458 """Test X-Launchpad-Bug-Modifier appears when a bugtask is deleted."""
459 self.bug_task.delete(self.user)
460 transaction.commit()
461- latest_notification = BugNotification.selectFirst(orderBy='-id')
462+ latest_notification = IStore(BugNotification).find(
463+ BugNotification).order_by(BugNotification.id).last()
464 notifications, omitted, messages = construct_email_notifications(
465 [latest_notification])
466 self.assertEqual(len(notifications), 1,
467diff --git a/lib/lp/bugs/mail/tests/test_bug_task_modification.py b/lib/lp/bugs/mail/tests/test_bug_task_modification.py
468index 6587370..c181a1b 100644
469--- a/lib/lp/bugs/mail/tests/test_bug_task_modification.py
470+++ b/lib/lp/bugs/mail/tests/test_bug_task_modification.py
471@@ -9,6 +9,7 @@ from zope.component import getUtility
472 from lp.bugs.interfaces.bugtask import BugTaskStatus
473 from lp.bugs.model.bugnotification import BugNotification
474 from lp.bugs.scripts.bugnotification import construct_email_notifications
475+from lp.services.database.interfaces import IStore
476 from lp.services.webapp.interfaces import ILaunchBag
477 from lp.services.webapp.snapshot import notify_modified
478 from lp.testing import TestCaseWithFactory
479@@ -35,7 +36,8 @@ class TestModificationNotification(TestCaseWithFactory):
480 self.bug_task.transitionToStatus(
481 BugTaskStatus.CONFIRMED, self.user)
482 transaction.commit()
483- latest_notification = BugNotification.selectFirst(orderBy='-id')
484+ latest_notification = IStore(BugNotification).find(
485+ BugNotification).order_by(BugNotification.id).last()
486 notifications, omitted, messages = construct_email_notifications(
487 [latest_notification])
488 self.assertEqual(len(notifications), 1,
489diff --git a/lib/lp/bugs/mail/tests/test_handler.py b/lib/lp/bugs/mail/tests/test_handler.py
490index e89c8fb..c5af232 100644
491--- a/lib/lp/bugs/mail/tests/test_handler.py
492+++ b/lib/lp/bugs/mail/tests/test_handler.py
493@@ -30,6 +30,7 @@ from lp.bugs.mail.handler import (
494 from lp.bugs.model.bugnotification import BugNotification
495 from lp.registry.enums import BugSharingPolicy
496 from lp.services.config import config
497+from lp.services.database.interfaces import IStore
498 from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
499 from lp.services.webapp.authorization import LaunchpadSecurityPolicy
500 from lp.testing import (
501@@ -220,7 +221,8 @@ class MaloneHandlerProcessTestCase(TestCaseWithFactory):
502
503 @staticmethod
504 def getLatestBugNotification():
505- return BugNotification.selectFirst(orderBy='-id')
506+ return IStore(BugNotification).find(
507+ BugNotification).order_by(BugNotification.id).last()
508
509 def test_new_bug(self):
510 project = self.factory.makeProduct(name='fnord')
511@@ -322,7 +324,7 @@ class MaloneHandlerProcessTestCase(TestCaseWithFactory):
512 self.assertEqual(1, len(bug.bugtasks))
513 self.assertEqual(project, bug.bugtasks[0].target)
514 recipients = set()
515- for notification in BugNotification.select():
516+ for notification in IStore(BugNotification).find(BugNotification):
517 for recipient in notification.recipients:
518 recipients.add(recipient.person)
519 self.assertContentEqual([maintainer], recipients)
520diff --git a/lib/lp/bugs/model/bug.py b/lib/lp/bugs/model/bug.py
521index 7ea2576..98169c6 100644
522--- a/lib/lp/bugs/model/bug.py
523+++ b/lib/lp/bugs/model/bug.py
524@@ -1216,10 +1216,11 @@ class Bug(SQLBase, InformationTypeMixin):
525
526 def expireNotifications(self):
527 """See `IBug`."""
528- for notification in BugNotification.selectBy(
529- bug=self, date_emailed=None):
530- notification.date_emailed = UTC_NOW
531- notification.syncUpdate()
532+ store = IStore(BugNotification)
533+ notifications = store.find(
534+ BugNotification, bug=self, date_emailed=None)
535+ notifications.set(date_emailed=UTC_NOW)
536+ store.flush()
537
538 def newMessage(self, owner=None, subject=None,
539 content=None, parent=None, bugwatch=None,
540diff --git a/lib/lp/bugs/model/bugnotification.py b/lib/lp/bugs/model/bugnotification.py
541index 77786c9..dc7e089 100644
542--- a/lib/lp/bugs/model/bugnotification.py
543+++ b/lib/lp/bugs/model/bugnotification.py
544@@ -17,19 +17,17 @@ from datetime import (
545 )
546
547 import pytz
548-from sqlobject import (
549- BoolCol,
550- ForeignKey,
551- StringCol,
552- )
553 from storm.expr import (
554 In,
555 Join,
556 LeftJoin,
557 )
558 from storm.locals import (
559+ Bool,
560+ DateTime,
561 Int,
562 Reference,
563+ Unicode,
564 )
565 from storm.store import Store
566 from zope.component import getUtility
567@@ -51,34 +49,52 @@ from lp.bugs.model.structuralsubscription import StructuralSubscription
568 from lp.registry.interfaces.person import IPersonSet
569 from lp.services.config import config
570 from lp.services.database import bulk
571-from lp.services.database.datetimecol import UtcDateTimeCol
572-from lp.services.database.enumcol import EnumCol
573+from lp.services.database.enumcol import DBEnum
574 from lp.services.database.interfaces import IStore
575-from lp.services.database.sqlbase import SQLBase
576 from lp.services.database.stormbase import StormBase
577 from lp.services.messages.model.message import Message
578
579
580 @implementer(IBugNotification)
581-class BugNotification(SQLBase):
582+class BugNotification(StormBase):
583 """A textual representation about a bug change."""
584
585- message = ForeignKey(dbName='message', notNull=True, foreignKey='Message')
586- activity = ForeignKey(
587- dbName='activity', notNull=False, foreignKey='BugActivity')
588- bug = ForeignKey(dbName='bug', notNull=True, foreignKey='Bug')
589- is_comment = BoolCol(notNull=True)
590- date_emailed = UtcDateTimeCol(notNull=False)
591- status = EnumCol(
592- dbName='status',
593- schema=BugNotificationStatus, default=BugNotificationStatus.PENDING,
594- notNull=True)
595+ __storm_table__ = 'BugNotification'
596+
597+ id = Int(primary=True)
598+
599+ message_id = Int(name='message', allow_none=False)
600+ message = Reference(message_id, 'Message.id')
601+
602+ activity_id = Int('activity', allow_none=True)
603+ activity = Reference(activity_id, 'BugActivity.id')
604+
605+ bug_id = Int(name='bug', allow_none=False)
606+ bug = Reference(bug_id, 'Bug.id')
607+
608+ is_comment = Bool(allow_none=False)
609+ date_emailed = DateTime(tzinfo=pytz.UTC, allow_none=True)
610+ status = DBEnum(
611+ name='status',
612+ enum=BugNotificationStatus, default=BugNotificationStatus.PENDING,
613+ allow_none=False)
614+
615+ def __init__(self, bug, is_comment, message, date_emailed=None,
616+ activity=None, status=BugNotificationStatus.PENDING):
617+ self.bug = bug
618+ self.is_comment = is_comment
619+ self.message = message
620+ self.date_emailed = date_emailed
621+ self.activity = activity
622+ self.status = status
623
624 @property
625 def recipients(self):
626 """See `IBugNotification`."""
627- return BugNotificationRecipient.selectBy(
628- bug_notification=self, orderBy='id')
629+ return IStore(BugNotificationRecipient).find(
630+ BugNotificationRecipient,
631+ BugNotificationRecipient.bug_notification == self).order_by(
632+ BugNotificationRecipient.id)
633
634 @property
635 def bug_filters(self):
636@@ -89,6 +105,9 @@ class BugNotification(SQLBase):
637 BugNotificationFilter.bug_subscription_filter_id),
638 BugNotificationFilter.bug_notification == self)
639
640+ def destroySelf(self):
641+ Store.of(self).remove(self)
642+
643
644 @implementer(IBugNotificationSet)
645 class BugNotificationSet:
646@@ -129,7 +148,7 @@ class BugNotificationSet:
647 elif (last_omitted_notification is not None and
648 notification.message.ownerID ==
649 last_omitted_notification.message.ownerID and
650- notification.bugID == last_omitted_notification.bugID and
651+ notification.bug_id == last_omitted_notification.bug_id and
652 last_omitted_notification.message.datecreated -
653 notification.message.datecreated < interval):
654 last_omitted_notification = notification
655@@ -137,7 +156,7 @@ class BugNotificationSet:
656 last_omitted_notification = None
657 pending_notifications.append(notification)
658 people_ids.add(notification.message.ownerID)
659- bug_ids.add(notification.bugID)
660+ bug_ids.add(notification.bug_id)
661 # Now we do some calls that are purely for caching.
662 # Converting these into lists forces the queries to execute.
663 if pending_notifications:
664@@ -308,15 +327,27 @@ class BugNotificationSet:
665
666
667 @implementer(IBugNotificationRecipient)
668-class BugNotificationRecipient(SQLBase):
669+class BugNotificationRecipient(StormBase):
670 """A recipient of a bug notification."""
671
672- bug_notification = ForeignKey(
673- dbName='bug_notification', notNull=True, foreignKey='BugNotification')
674- person = ForeignKey(
675- dbName='person', notNull=True, foreignKey='Person')
676- reason_header = StringCol(dbName='reason_header', notNull=True)
677- reason_body = StringCol(dbName='reason_body', notNull=True)
678+ __storm_table__ = 'BugNotificationRecipient'
679+
680+ id = Int(primary=True)
681+
682+ bug_notification_id = Int(name='bug_notification', allow_none=False)
683+ bug_notification = Reference(bug_notification_id, 'BugNotification.id')
684+
685+ person_id = Int(name='person', allow_none=False)
686+ person = Reference(person_id, 'Person.id')
687+
688+ reason_header = Unicode(name='reason_header', allow_none=False)
689+ reason_body = Unicode(name='reason_body', allow_none=False)
690+
691+ def __init__(self, bug_notification, person, reason_header, reason_body):
692+ self.bug_notification = bug_notification
693+ self.person = person
694+ self.reason_header = reason_header
695+ self.reason_body = reason_body
696
697
698 @implementer(IBugNotificationFilter)
699diff --git a/lib/lp/bugs/scripts/tests/test_bugimport.py b/lib/lp/bugs/scripts/tests/test_bugimport.py
700index e706052..2e5d7e5 100644
701--- a/lib/lp/bugs/scripts/tests/test_bugimport.py
702+++ b/lib/lp/bugs/scripts/tests/test_bugimport.py
703@@ -40,6 +40,7 @@ from lp.registry.interfaces.person import (
704 )
705 from lp.registry.interfaces.product import IProductSet
706 from lp.services.config import config
707+from lp.services.database.interfaces import IStore
708 from lp.services.database.sqlbase import cursor
709 from lp.services.identity.interfaces.account import AccountStatus
710 from lp.services.identity.interfaces.emailaddress import IEmailAddressSet
711@@ -453,7 +454,8 @@ class ImportBugTestCase(TestCase):
712 logout()
713
714 def assertNoPendingNotifications(self, bug):
715- notifications = BugNotification.selectBy(bug=bug, date_emailed=None)
716+ notifications = IStore(BugNotification).find(
717+ BugNotification, bug=bug, date_emailed=None)
718 count = notifications.count()
719 self.assertEqual(count, 0,
720 'Found %d pending notifications for bug %d'
721diff --git a/lib/lp/bugs/scripts/tests/test_bugnotification.py b/lib/lp/bugs/scripts/tests/test_bugnotification.py
722index 734b68f..99b59c6 100644
723--- a/lib/lp/bugs/scripts/tests/test_bugnotification.py
724+++ b/lib/lp/bugs/scripts/tests/test_bugnotification.py
725@@ -1,6 +1,8 @@
726 # Copyright 2009-2018 Canonical Ltd. This software is licensed under the
727 # GNU Affero General Public License version 3 (see the file LICENSE).
728-"""Tests for construction bug notification emails for sending."""
729+"""Tests for constructing bug notification emails for sending."""
730+
731+from __future__ import absolute_import, print_function, unicode_literals
732
733 __metaclass__ = type
734
735@@ -15,7 +17,6 @@ import StringIO
736 import unittest
737
738 import pytz
739-from storm.store import Store
740 from testtools.matchers import (
741 MatchesRegex,
742 Not,
743@@ -75,10 +76,7 @@ from lp.registry.interfaces.person import IPersonSet
744 from lp.registry.interfaces.product import IProductSet
745 from lp.services.config import config
746 from lp.services.database.interfaces import IStore
747-from lp.services.database.sqlbase import (
748- flush_database_updates,
749- sqlvalues,
750- )
751+from lp.services.database.sqlbase import flush_database_updates
752 from lp.services.mail.helpers import (
753 get_contact_email_addresses,
754 get_email_template,
755@@ -1008,14 +1006,9 @@ class TestEmailNotificationsWithFilters(TestCaseWithFactory):
756 def addNotificationRecipient(self, notification, person):
757 # Manually insert BugNotificationRecipient for
758 # construct_email_notifications to work.
759- # Not sure why using SQLObject constructor doesn't work (it
760- # tries to insert a row with only the ID which fails).
761- Store.of(notification).execute("""
762- INSERT INTO BugNotificationRecipient
763- (bug_notification, person, reason_header, reason_body)
764- VALUES (%s, %s, %s, %s)""" % sqlvalues(
765- notification, person,
766- u'reason header', u'reason body'))
767+ BugNotificationRecipient(
768+ bug_notification=notification, person=person,
769+ reason_header='reason header', reason_body='reason body')
770
771 def addNotification(self, person):
772 # Add a notification along with recipient data.
773@@ -1176,8 +1169,8 @@ class TestEmailNotificationsWithFilters(TestCaseWithFactory):
774 def fetch_notifications(subscriber, bug):
775 return IStore(BugNotification).find(
776 BugNotification,
777- BugNotification.id == BugNotificationRecipient.bug_notificationID,
778- BugNotificationRecipient.personID == subscriber.id,
779+ BugNotification.id == BugNotificationRecipient.bug_notification_id,
780+ BugNotificationRecipient.person == subscriber,
781 BugNotification.bug == bug)
782
783
784diff --git a/lib/lp/bugs/stories/bugs/xx-bugs.txt b/lib/lp/bugs/stories/bugs/xx-bugs.txt
785index 05f2622..0dd58c7 100644
786--- a/lib/lp/bugs/stories/bugs/xx-bugs.txt
787+++ b/lib/lp/bugs/stories/bugs/xx-bugs.txt
788@@ -40,5 +40,5 @@ Bar. First, let's clear out the notification table:
789
790 After the comment has been submitted, a notification is added:
791
792- >>> BugNotification.select().count()
793+ >>> IStore(BugNotification).find(BugNotification).count()
794 1
795diff --git a/lib/lp/bugs/stories/webservice/xx-bug.txt b/lib/lp/bugs/stories/webservice/xx-bug.txt
796index 119fb43..e36d172 100644
797--- a/lib/lp/bugs/stories/webservice/xx-bug.txt
798+++ b/lib/lp/bugs/stories/webservice/xx-bug.txt
799@@ -113,6 +113,7 @@ bugs.
800
801 >>> from lp.bugs.interfaces.bug import IBugSet
802 >>> from lp.bugs.model.bugnotification import BugNotification
803+ >>> from lp.services.database.interfaces import IStore
804 >>> from lp.testing import ANONYMOUS, login, logout
805 >>> from zope.component import getUtility
806
807@@ -125,7 +126,8 @@ bugs.
808 ... activity.person.name))
809 bug, added bug, salgado
810
811- >>> for notification in BugNotification.selectBy(bug=bug, orderBy='id'):
812+ >>> for notification in IStore(BugNotification).find(
813+ ... BugNotification, bug=bug).order_by(BugNotification.id):
814 ... print('%s, %s, %s' % (
815 ... notification.message.owner.name, notification.is_comment,
816 ... notification.message.text_contents))
817diff --git a/lib/lp/bugs/subscribers/tests/test_bug.py b/lib/lp/bugs/subscribers/tests/test_bug.py
818index 28130c1..19658d1 100644
819--- a/lib/lp/bugs/subscribers/tests/test_bug.py
820+++ b/lib/lp/bugs/subscribers/tests/test_bug.py
821@@ -61,9 +61,9 @@ class BugSubscriberTestCase(TestCaseWithFactory):
822 def getNotifiedPersons(self, include_all=False):
823 notified_persons = Store.of(self.bug).find(
824 Person,
825- BugNotification.id == BugNotificationRecipient.bug_notificationID,
826- BugNotificationRecipient.personID == Person.id,
827- BugNotification.bugID == self.bug.id)
828+ BugNotification.id == BugNotificationRecipient.bug_notification_id,
829+ BugNotificationRecipient.person_id == Person.id,
830+ BugNotification.bug == self.bug)
831 if include_all:
832 return list(notified_persons)
833 else:
834diff --git a/lib/lp/bugs/tests/bugs-emailinterface.txt b/lib/lp/bugs/tests/bugs-emailinterface.txt
835index 2bc5460..ccb90bc 100644
836--- a/lib/lp/bugs/tests/bugs-emailinterface.txt
837+++ b/lib/lp/bugs/tests/bugs-emailinterface.txt
838@@ -90,8 +90,10 @@ bug got submitted correctly:
839 >>> from lp.services.mail import stub
840 >>> bugset = getUtility(IBugSet)
841 >>> from lp.bugs.model.bugnotification import BugNotification
842+ >>> from lp.services.database.interfaces import IStore
843 >>> def get_latest_added_bug():
844- ... latest_notification = BugNotification.selectFirst(orderBy='-id')
845+ ... latest_notification = IStore(BugNotification).find(
846+ ... BugNotification).order_by(BugNotification.id).last()
847 ... return latest_notification.bug
848 >>> bug = get_latest_added_bug()
849
850@@ -129,7 +131,8 @@ The owner of the bug was set to the submitter:
851
852 A notification was added:
853
854- >>> bug_notification = BugNotification.selectFirst(orderBy='-id')
855+ >>> bug_notification = IStore(BugNotification).find(
856+ ... BugNotification).order_by(BugNotification.id).last()
857 >>> print(bug_notification.message.owner.displayname)
858 Foo Bar
859
860@@ -174,7 +177,8 @@ this:
861
862 A notification was added:
863
864- >>> bug_notification = BugNotification.selectFirst(orderBy='-id')
865+ >>> bug_notification = IStore(BugNotification).find(
866+ ... BugNotification).order_by(BugNotification.id).last()
867 >>> print(bug_notification.message.owner.displayname)
868 Sample Person
869
870@@ -1084,7 +1088,8 @@ created:
871
872 A notification was added:
873
874- >>> bug_notification = BugNotification.selectFirst(orderBy='-id')
875+ >>> bug_notification = IStore(BugNotification).find(
876+ ... BugNotification).order_by(BugNotification.id).last()
877 >>> print(bug_notification.message.text_contents)
878 ** Also affects: debian
879 ...
880@@ -1660,7 +1665,8 @@ edited:
881 >>> print(linux_task.status.name)
882 CONFIRMED
883
884- >>> bug_notification = BugNotification.selectFirst(orderBy='-id')
885+ >>> bug_notification = IStore(BugNotification).find(
886+ ... BugNotification).order_by(BugNotification.id).last()
887 >>> print(bug_notification.bug.id)
888 10
889 >>> print(bug_notification.message.text_contents)
890@@ -1686,8 +1692,9 @@ The user is a bug supervisors of the upstream product
891 mozilla-firefox (Ubuntu): New, assigned to no one
892 mozilla-firefox (Debian): Confirmed, assigned to no one
893
894- >>> pending_notifications = BugNotification.select(
895- ... orderBy='-id', limit=2)
896+ >>> from storm.locals import Desc
897+ >>> pending_notifications = IStore(BugNotification).find(
898+ ... BugNotification).order_by(Desc(BugNotification.id))[:2]
899 >>> for bug_notification in pending_notifications:
900 ... print(bug_notification.bug.id)
901 ... print(bug_notification.message.text_contents)
902@@ -1727,7 +1734,8 @@ The user is a package bug supervisor
903 mozilla-firefox (Ubuntu): Confirmed, assigned to Helge Kreutzmann
904 mozilla-firefox (Debian): Confirmed, assigned to no one
905
906- >>> pending_notifications = BugNotification.select(orderBy='-id', limit=2)
907+ >>> pending_notifications = IStore(BugNotification).find(
908+ ... BugNotification).order_by(Desc(BugNotification.id))[:2]
909 >>> for bug_notification in pending_notifications:
910 ... print(bug_notification.bug.id)
911 ... print(bug_notification.message.text_contents)
912@@ -1758,7 +1766,8 @@ The user is a distribution member
913 mozilla-firefox (Ubuntu): New, assigned to Sample Person
914 mozilla-firefox (Debian): Confirmed, assigned to no one
915
916- >>> pending_notifications = BugNotification.select(orderBy='-id', limit=2)
917+ >>> pending_notifications = IStore(BugNotification).find(
918+ ... BugNotification).order_by(Desc(BugNotification.id))[:2]
919 >>> for bug_notification in pending_notifications:
920 ... print(bug_notification.bug.id)
921 ... print(bug_notification.message.text_contents)
922@@ -2452,7 +2461,8 @@ An email may contain more than one attachment; all of them are stored.
923
924 A bugnotification is sent for each attached file.
925
926- >>> bug_notifications = BugNotification.select(orderBy='-id', limit=3)
927+ >>> bug_notifications = IStore(BugNotification).find(
928+ ... BugNotification).order_by(Desc(BugNotification.id))[:3]
929 >>> for bug_notification in bug_notifications:
930 ... print('-------------------')
931 ... print(bug_notification.message.chunks[0].content)
932diff --git a/lib/lp/bugs/tests/bugtarget-questiontarget.txt b/lib/lp/bugs/tests/bugtarget-questiontarget.txt
933index cd2c7e0..2bf90ca 100644
934--- a/lib/lp/bugs/tests/bugtarget-questiontarget.txt
935+++ b/lib/lp/bugs/tests/bugtarget-questiontarget.txt
936@@ -128,8 +128,11 @@ question and that the bugtasks are Invalid.
937 >>> 'test@canonical.com' in recipients.getEmails()
938 True
939
940+ >>> from storm.locals import Desc
941 >>> from lp.bugs.model.bugnotification import BugNotification
942- >>> bug_notifications = BugNotification.select(orderBy='-id')
943+ >>> from lp.services.database.interfaces import IStore
944+ >>> bug_notifications = IStore(BugNotification).find(
945+ ... BugNotification).order_by(Desc(BugNotification.id))
946 >>> for notification in bug_notifications:
947 ... print(notification.message.text_contents)
948 ** Converted to question:
949diff --git a/lib/lp/bugs/tests/test_bugchanges.py b/lib/lp/bugs/tests/test_bugchanges.py
950index 4f32051..48c74b0 100644
951--- a/lib/lp/bugs/tests/test_bugchanges.py
952+++ b/lib/lp/bugs/tests/test_bugchanges.py
953@@ -20,6 +20,7 @@ from lp.bugs.interfaces.bugtask import (
954 from lp.bugs.interfaces.cve import ICveSet
955 from lp.bugs.model.bugnotification import BugNotification
956 from lp.bugs.scripts.bugnotification import construct_email_notifications
957+from lp.services.database.interfaces import IStore
958 from lp.services.librarian.browser import ProxiedLibraryFileAlias
959 from lp.services.webapp.publisher import canonical_url
960 from lp.services.webapp.snapshot import notify_modified
961@@ -80,8 +81,8 @@ class TestBugChanges(TestCaseWithFactory):
962 bug = self.bug
963 old_activities = set(bug.activity)
964 old_notification_ids = set(
965- notification.id for notification in (
966- BugNotification.selectBy(bug=bug)))
967+ notification.id for notification in IStore(BugNotification).find(
968+ BugNotification, bug=bug))
969
970 if append:
971 self.old_activities.update(old_activities)
972@@ -107,8 +108,8 @@ class TestBugChanges(TestCaseWithFactory):
973 def getNewNotifications(self, bug=None):
974 if bug is None:
975 bug = self.bug
976- bug_notifications = BugNotification.selectBy(
977- bug=bug, orderBy='id')
978+ bug_notifications = IStore(BugNotification).find(
979+ BugNotification, bug=bug).order_by(BugNotification.id)
980 new_notifications = [
981 notification for notification in bug_notifications
982 if notification.id not in self.old_notification_ids]
983@@ -1506,8 +1507,8 @@ class TestBugChanges(TestCaseWithFactory):
984
985 # Ensure that only the people subscribed to the bug that
986 # gets marked as a duplicate are notified.
987- master_notifications = BugNotification.selectBy(
988- bug=self.bug, orderBy='id')
989+ master_notifications = IStore(BugNotification).find(
990+ BugNotification, bug=self.bug).order_by(BugNotification.id)
991 new_notifications = [
992 notification for notification in master_notifications
993 if notification.id not in self.old_notification_ids]
994diff --git a/lib/lp/bugs/tests/test_bugnotification.py b/lib/lp/bugs/tests/test_bugnotification.py
995index b0ecfc3..6672082 100644
996--- a/lib/lp/bugs/tests/test_bugnotification.py
997+++ b/lib/lp/bugs/tests/test_bugnotification.py
998@@ -23,6 +23,7 @@ from lp.bugs.model.bugnotification import (
999 )
1000 from lp.bugs.model.bugsubscriptionfilter import BugSubscriptionFilterMute
1001 from lp.services.config import config
1002+from lp.services.database.interfaces import IStore
1003 from lp.services.messages.interfaces.message import IMessageSet
1004 from lp.services.messages.model.message import MessageSet
1005 from lp.services.webapp.snapshot import notify_modified
1006@@ -372,7 +373,8 @@ class TestNotificationsForDuplicates(TestCaseWithFactory):
1007 # bug, not to subscribers of the master bug.
1008 self.dupe_bug.newMessage(
1009 self.dupe_bug.owner, subject='subject', content='content')
1010- latest_notification = BugNotification.selectFirst(orderBy='-id')
1011+ latest_notification = IStore(BugNotification).find(
1012+ BugNotification).order_by(BugNotification.id).last()
1013 recipients = set(
1014 recipient.person
1015 for recipient in latest_notification.recipients)
1016@@ -383,7 +385,8 @@ class TestNotificationsForDuplicates(TestCaseWithFactory):
1017 with notify_modified(
1018 self.dupe_bug, ['description'], user=self.dupe_bug.owner):
1019 self.dupe_bug.description = 'A changed description'
1020- latest_notification = BugNotification.selectFirst(orderBy='-id')
1021+ latest_notification = IStore(BugNotification).find(
1022+ BugNotification).order_by(BugNotification.id).last()
1023 recipients = set(
1024 recipient.person
1025 for recipient in latest_notification.recipients)
1026@@ -397,7 +400,8 @@ class TestNotificationsForDuplicates(TestCaseWithFactory):
1027 # provided by the Bug.addChange mechanism.
1028 branch = self.factory.makeBranch(owner=self.dupe_bug.owner)
1029 self.dupe_bug.linkBranch(branch, self.dupe_bug.owner)
1030- latest_notification = BugNotification.selectFirst(orderBy='-id')
1031+ latest_notification = IStore(BugNotification).find(
1032+ BugNotification).order_by(BugNotification.id).last()
1033 recipients = set(
1034 recipient.person
1035 for recipient in latest_notification.recipients)
1036diff --git a/lib/lp/registry/doc/milestone.txt b/lib/lp/registry/doc/milestone.txt
1037index 2ad094c..5e4b086 100644
1038--- a/lib/lp/registry/doc/milestone.txt
1039+++ b/lib/lp/registry/doc/milestone.txt
1040@@ -317,8 +317,7 @@ Target change notifications
1041 When we change the milestone for a bug task, subscribers to both the old
1042 milestone and the new one are notified.
1043
1044- >>> from lp.bugs.model.bugnotification import (
1045- ... BugNotification)
1046+ >>> from lp.bugs.model.bugnotification import BugNotification
1047 >>> from lp.bugs.interfaces.bug import IBugSet
1048 >>> from lp.registry.interfaces.person import IPersonSet
1049 >>> from lp.registry.interfaces.product import IProductSet
1050@@ -353,7 +352,9 @@ change event.
1051 A new bug notification is created, and both Celso and David are in the
1052 list of recipients.
1053
1054- >>> notification = BugNotification.select("date_emailed IS NULL")[-1]
1055+ >>> from lp.services.database.interfaces import IStore
1056+ >>> notification = IStore(BugNotification).find(
1057+ ... BugNotification, date_emailed=None).last()
1058 >>> print notification.message.chunks[0].content
1059 ** Changed in: firefox
1060 Milestone: 1.0 => 2.0
1061diff --git a/lib/lp/scripts/tests/test_garbo.py b/lib/lp/scripts/tests/test_garbo.py
1062index 14ba31f..1de59db 100644
1063--- a/lib/lp/scripts/tests/test_garbo.py
1064+++ b/lib/lp/scripts/tests/test_garbo.py
1065@@ -46,6 +46,7 @@ from zope.security.proxy import removeSecurityProxy
1066
1067 from lp.answers.model.answercontact import AnswerContact
1068 from lp.app.enums import InformationType
1069+from lp.bugs.interfaces.bug import IBugSet
1070 from lp.bugs.model.bugnotification import (
1071 BugNotification,
1072 BugNotificationRecipient,
1073@@ -109,6 +110,7 @@ from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
1074 from lp.services.job.interfaces.job import JobStatus
1075 from lp.services.job.model.job import Job
1076 from lp.services.librarian.model import TimeLimitedToken
1077+from lp.services.messages.interfaces.message import IMessageSet
1078 from lp.services.messages.model.message import Message
1079 from lp.services.openid.model.openidconsumer import OpenIDConsumerNonce
1080 from lp.services.scripts.tests import run_script
1081@@ -790,14 +792,18 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
1082 def test_BugNotificationPruner(self):
1083 # Create some sample data
1084 switch_dbuser('testadmin')
1085+ bug = getUtility(IBugSet).get(1)
1086+ message = getUtility(IMessageSet).get(
1087+ 'foo@example.com-332342--1231')[0]
1088+ person = self.factory.makePerson()
1089 notification = BugNotification(
1090- messageID=1,
1091- bugID=1,
1092+ message=message,
1093+ bug=bug,
1094 is_comment=True,
1095 date_emailed=None)
1096 BugNotificationRecipient(
1097 bug_notification=notification,
1098- personID=1,
1099+ person=person,
1100 reason_header='Whatever',
1101 reason_body='Whatever')
1102 # We don't create an entry exactly 30 days old to avoid
1103@@ -806,12 +812,12 @@ class TestGarbo(FakeAdapterMixin, TestCaseWithFactory):
1104 message = Message(rfc822msgid=str(delta))
1105 notification = BugNotification(
1106 message=message,
1107- bugID=1,
1108+ bug=bug,
1109 is_comment=True,
1110 date_emailed=UTC_NOW + SQL("interval '%d days'" % delta))
1111 BugNotificationRecipient(
1112 bug_notification=notification,
1113- personID=1,
1114+ person=person,
1115 reason_header='Whatever',
1116 reason_body='Whatever')
1117
1118diff --git a/lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt b/lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt
1119index d4c42cc..75f99ff 100644
1120--- a/lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt
1121+++ b/lib/lp/soyuz/doc/closing-bugs-from-changelogs.txt
1122@@ -146,8 +146,10 @@ comment addition. The both notifications will be batched together into a
1123 single email later.
1124
1125 >>> from lp.bugs.model.bugnotification import BugNotification
1126- >>> notifications = BugNotification.select(orderBy='id')
1127- >>> for notification in notifications[-2:]:
1128+ >>> from lp.services.database.interfaces import IStore
1129+ >>> notifications = IStore(BugNotification).find(
1130+ ... BugNotification).order_by(BugNotification.id)
1131+ >>> for notification in list(notifications)[-2:]:
1132 ... print("From %s:\n%s\n" % (
1133 ... notification.message.owner.displayname,
1134 ... notification.message.text_contents))
1135@@ -178,7 +180,8 @@ packages are synced from Debian.
1136
1137 >>> close_bugs_for_queue_item(queue_item)
1138
1139- >>> notifications = BugNotification.select(orderBy='id')
1140+ >>> notifications = IStore(BugNotification).find(
1141+ ... BugNotification).order_by(BugNotification.id)
1142 >>> new_notifications = notifications[number_of_old_notifications:]
1143 >>> [notification.message.text_contents
1144 ... for notification in new_notifications]

Subscribers

People subscribed via source and target branches

to status/vote changes: