Merge lp:~lifeless/launchpad/batchnav into lp:launchpad

Proposed by Robert Collins
Status: Merged
Approved by: Robert Collins
Approved revision: no longer in the source branch.
Merged at revision: 13413
Proposed branch: lp:~lifeless/launchpad/batchnav
Merge into: lp:launchpad
Diff against target: 381 lines (+38/-117)
15 files modified
lib/canonical/launchpad/webapp/batching.py (+4/-6)
lib/lp/app/browser/root.py (+12/-20)
lib/lp/app/browser/tests/launchpad-search-pages.txt (+0/-2)
lib/lp/app/doc/batch-navigation.txt (+4/-74)
lib/lp/bugs/stories/webservice/xx-bug-tracker.txt (+1/-1)
lib/lp/bugs/stories/webservice/xx-bug.txt (+2/-2)
lib/lp/services/features/browser/tests/test_changelog.py (+1/-1)
lib/lp/soyuz/stories/ppa/xx-ppa-navigation.txt (+2/-2)
lib/lp/translations/browser/tests/pofile-views.txt (+1/-1)
lib/lp/translations/browser/translationmessage.py (+4/-1)
lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt (+1/-1)
lib/lp/translations/stories/standalone/xx-pofile-translate-empty-strings-without-validation.txt (+1/-1)
lib/lp/translations/stories/standalone/xx-pofile-translate-html-tags-escape.txt (+1/-1)
lib/lp/translations/stories/standalone/xx-pofile-translate-newlines-check.txt (+3/-3)
versions.cfg (+1/-1)
To merge this branch: bzr merge lp:~lifeless/launchpad/batchnav
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+67791@code.launchpad.net

Commit message

[r=lifeless][bug=809719] Update to lazr.batchnavigator 1.2.5.

Description of the change

This is https://code.launchpad.net/~stub/launchpad/batch-navigator/+merge/67233 updated to grab 1.2.5 and fix the regression we found in it (discussed on that bug). The upstream change is trivial so I'm just self-reviewing this and shooting to ec2. I've made a placeholder bug to permit a QA step.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/webapp/batching.py'
2--- lib/canonical/launchpad/webapp/batching.py 2010-10-14 23:03:41 +0000
3+++ lib/canonical/launchpad/webapp/batching.py 2011-07-13 06:27:29 +0000
4@@ -98,19 +98,17 @@
5 class ActiveBatchNavigator(BatchNavigator):
6 """A paginator for active items.
7
8- Used when a view needs to display more than one BatchNavigator of items.
9+ Used when a view needs to display two BatchNavigators.
10 """
11- start_variable_name = 'active_start'
12- batch_variable_name = 'active_batch'
13+ variable_name_prefix = 'active'
14
15
16 class InactiveBatchNavigator(BatchNavigator):
17 """A paginator for inactive items.
18
19- Used when a view needs to display more than one BatchNavigator of items.
20+ Used when a view needs to display two Batchavigators.
21 """
22- start_variable_name = 'inactive_start'
23- batch_variable_name = 'inactive_batch'
24+ variable_name_prefix = 'inactive'
25
26
27 class TableBatchNavigator(BatchNavigator):
28
29=== modified file 'lib/lp/app/browser/root.py'
30--- lib/lp/app/browser/root.py 2011-07-12 01:42:11 +0000
31+++ lib/lp/app/browser/root.py 2011-07-13 06:27:29 +0000
32@@ -13,6 +13,7 @@
33 import time
34
35 import feedparser
36+from lazr.batchnavigator import ListRangeFactory
37 from lazr.batchnavigator.z3batching import batch
38 from zope.component import getUtility
39 from zope.interface import Interface
40@@ -566,6 +567,7 @@
41 class GoogleBatchNavigator(BatchNavigator):
42 """A batch navigator with a fixed size of 20 items per batch."""
43
44+ _batch_factory = WindowedListBatch
45 # Searches generally don't show the 'Last' link when there is a
46 # good chance of getting over 100,000 results.
47 show_last_link = False
48@@ -573,7 +575,9 @@
49 singular_heading = 'page'
50 plural_heading = 'pages'
51
52- def __init__(self, results, request, start=0, size=20, callback=None):
53+ def __init__(self, results, request, start=0, size=20, callback=None,
54+ transient_parameters=None, force_start=False,
55+ range_factory=None):
56 """See `BatchNavigator`.
57
58 :param results: A `PageMatches` object that contains the matching
59@@ -584,25 +588,13 @@
60 :param size: The batch size is fixed to 20, The param is not used.
61 :param callback: Not used.
62 """
63- # We do not want to call super() because it will use the batch
64- # size from the URL.
65- # pylint: disable-msg=W0231
66 results = WindowedList(results, start, results.total)
67- self.request = request
68- request_start = request.get(self.start_variable_name, None)
69- if request_start is None:
70- self.start = start
71- else:
72- try:
73- self.start = int(request_start)
74- except (ValueError, TypeError):
75- self.start = start
76+ super(GoogleBatchNavigator, self).__init__(results, request,
77+ start=start, size=size, callback=callback,
78+ transient_parameters=transient_parameters, force_start=force_start,
79+ range_factory=range_factory)
80
81+ def determineSize(self, size, batch_params_source):
82+ # Force the default and users requested sizes to 20.
83 self.default_size = 20
84-
85- self.transient_parameters = [self.start_variable_name]
86-
87- self.batch = WindowedListBatch(
88- results, start=self.start, size=self.default_size)
89- self.setHeadings(
90- self.default_singular_heading, self.default_plural_heading)
91+ return 20
92
93=== modified file 'lib/lp/app/browser/tests/launchpad-search-pages.txt'
94--- lib/lp/app/browser/tests/launchpad-search-pages.txt 2011-07-12 01:42:11 +0000
95+++ lib/lp/app/browser/tests/launchpad-search-pages.txt 2011-07-13 06:27:29 +0000
96@@ -444,8 +444,6 @@
97 provides a link to the next batch, which also happens to be the last
98 batch.
99
100- >>> len(search_view.pages.getBatches())
101- 2
102 >>> search_view.pages.nextBatchURL()
103 '...start=20'
104 >>> search_view.pages.lastBatchURL()
105
106=== modified file 'lib/lp/app/doc/batch-navigation.txt'
107--- lib/lp/app/doc/batch-navigation.txt 2011-07-12 01:42:11 +0000
108+++ lib/lp/app/doc/batch-navigation.txt 2011-07-13 06:27:29 +0000
109@@ -47,88 +47,18 @@
110 ... 'Cupid', 'Donner', 'Blitzen', 'Rudolph']
111
112
113-Performance with SQLObject
114-==========================
115-
116-This section demonstrates that batching generates sensible SQL queries when
117-used with SQLObject, i.e. that it puts appropriate LIMIT clauses on queries.
118-
119-Imports and initialization:
120-
121- >>> from lp.testing.pgsql import CursorWrapper
122- >>> from canonical.launchpad.database.emailaddress import EmailAddress
123- >>> from canonical.launchpad.interfaces.lpstorm import IStore
124- >>> ignore = IStore(EmailAddress) # Prime the database connection.
125- ... # (Priming is important if this test is run in isolation).
126- >>> CursorWrapper.record_sql = True
127-
128-Prepare a query, and create a batch of the results:
129-
130- >>> select_results = EmailAddress.select(orderBy='id')
131- >>> batch_nav = BatchNavigator(select_results, build_request(), size=10)
132- >>> email_batch = batch_nav.currentBatch()
133- >>> batch_items = list(email_batch)
134-
135-Because we're only looking at the first batch, the database is only
136-asked for the first 11 rows. (lazr.batchnavigator asks for 11 instead
137-of 10 so that it can reliably detect the end of the dataset).
138-
139- >>> len(CursorWrapper.last_executed_sql)
140- 1
141- >>> print CursorWrapper.last_executed_sql[0]
142- SELECT ... FROM EmailAddress ... LIMIT 11...
143-
144-Get the next 10. The database is only asked for the next 11 rows:
145-
146- >>> CursorWrapper.last_executed_sql = []
147- >>> email_batch2 = email_batch.nextBatch()
148- >>> batch_items = list(email_batch2)
149- >>> len(CursorWrapper.last_executed_sql)
150- 1
151- >>> CursorWrapper.last_executed_sql[0].endswith('LIMIT 11 OFFSET 10')
152- True
153-
154-As seen above, simply accessing the batch doesn't trigger a SQL query
155-asking for the length of the entire resultset. But explicitly asking
156-for the length will trigger a SQL query in most circumstances.
157-
158- >>> CursorWrapper.last_executed_sql = []
159- >>> ignored = email_batch.total()
160- >>> print CursorWrapper.last_executed_sql[0]
161- SELECT COUNT(*) FROM EmailAddress
162-
163-There are exceptions. When the current batch is the last one in the
164-list, it's possible to get the length of the entire resultset without
165-triggering a COUNT query.
166-
167- >>> CursorWrapper.last_executed_sql = []
168- >>> batch_nav = BatchNavigator(select_results, build_request(), size=50)
169- >>> final_batch = batch_nav.currentBatch().nextBatch()
170- >>> batch_items = list(final_batch)
171- >>> ignored = final_batch.total()
172- >>> print "\n".join(CursorWrapper.last_executed_sql)
173- SELECT ... FROM EmailAddress ... OFFSET 0
174- SELECT ... FROM EmailAddress ... OFFSET 50
175-
176-When the current batch contains the entire resultset, it's possible to
177-get the length of the resultset without triggering a COUNT query.
178-
179- >>> CursorWrapper.last_executed_sql = []
180- >>> one_page_nav = BatchNavigator(select_results, build_request(), size=200)
181- >>> only_batch = one_page_nav.currentBatch()
182- >>> batch_items = list(only_batch)
183- >>> ignored = only_batch.total()
184- >>> print "\n".join(CursorWrapper.last_executed_sql)
185- SELECT ... FROM EmailAddress ... OFFSET 0
186-
187 Multiple pages
188 ==============
189
190 The batch navigator tells us whether multiple pages will be used.
191
192+ >>> from canonical.launchpad.database.emailaddress import EmailAddress
193+ >>> select_results = EmailAddress.select(orderBy='id')
194+ >>> batch_nav = BatchNavigator(select_results, build_request(), size=50)
195 >>> batch_nav.has_multiple_pages
196 True
197
198+ >>> one_page_nav = BatchNavigator(select_results, build_request(), size=200)
199 >>> one_page_nav.has_multiple_pages
200 False
201
202
203=== modified file 'lib/lp/bugs/stories/webservice/xx-bug-tracker.txt'
204--- lib/lp/bugs/stories/webservice/xx-bug-tracker.txt 2011-07-12 01:42:11 +0000
205+++ lib/lp/bugs/stories/webservice/xx-bug-tracker.txt 2011-07-13 06:27:29 +0000
206@@ -10,7 +10,7 @@
207 >>> bug_tracker_collection = anon_webservice.get(
208 ... '/bugs/bugtrackers').jsonBody()
209 >>> pprint_collection(bug_tracker_collection)
210- next_collection_link: u'http://.../bugs/bugtrackers?ws.start=5&ws.size=5'
211+ next_collection_link: u'http://.../bugs/bugtrackers?ws.size=5&memo=5&ws.start=5'
212 resource_type_link: u'http://.../#bug_trackers'
213 start: 0
214 total_size: 8
215
216=== modified file 'lib/lp/bugs/stories/webservice/xx-bug.txt'
217--- lib/lp/bugs/stories/webservice/xx-bug.txt 2011-07-12 01:42:11 +0000
218+++ lib/lp/bugs/stories/webservice/xx-bug.txt 2011-07-13 06:27:29 +0000
219@@ -1841,7 +1841,7 @@
220
221 >>> cves = webservice.get("/bugs/cve").jsonBody()
222 >>> pprint_collection(cves)
223- next_collection_link: u'http://.../bugs/cve?ws.start=5&ws.size=5'
224+ next_collection_link: u'http://.../bugs/cve?ws.size=5&memo=5&ws.start=5'
225 resource_type_link: u'http://.../#cves'
226 start: 0
227 total_size: 10
228@@ -2130,7 +2130,7 @@
229 >>> activity = webservice.get(
230 ... bug_one['activity_collection_link']).jsonBody()
231 >>> pprint_collection(activity)
232- next_collection_link: u'http://.../bugs/1/activity?ws.start=5&ws.size=5'
233+ next_collection_link: u'http://.../bugs/1/activity?ws.size=5&memo=5&ws.start=5'
234 resource_type_link: u'http://.../#bug_activity-page-resource'
235 start: 0
236 total_size: 25
237
238=== modified file 'lib/lp/services/features/browser/tests/test_changelog.py'
239--- lib/lp/services/features/browser/tests/test_changelog.py 2011-07-12 01:42:11 +0000
240+++ lib/lp/services/features/browser/tests/test_changelog.py 2011-07-13 06:27:29 +0000
241@@ -80,7 +80,7 @@
242 self.assertEqual('change', batch._singular_heading)
243 self.assertEqual('changes', batch._plural_heading)
244 self.assertEqual(10, batch.default_size)
245- self.assertEqual(2, len(batch.getBatches()))
246+ self.assertEqual(None, batch.currentBatch().nextBatch().nextBatch())
247
248 def test_page_batched_changes(self):
249 self.makeFeatureFlagChanges()
250
251=== modified file 'lib/lp/soyuz/stories/ppa/xx-ppa-navigation.txt'
252--- lib/lp/soyuz/stories/ppa/xx-ppa-navigation.txt 2011-07-12 01:42:11 +0000
253+++ lib/lp/soyuz/stories/ppa/xx-ppa-navigation.txt 2011-07-13 06:27:29 +0000
254@@ -179,8 +179,8 @@
255 The 'First' and 'Previous' links, however, are now active.
256
257 >>> anon_browser.getLink('First').url
258- 'http://launchpad.dev/%7Ecprov/+archive/ppa/+index?start=0&batch=1'
259+ 'http://launchpad.dev/%7Ecprov/+archive/ppa/+index?batch=1'
260
261 >>> anon_browser.getLink('Previous').url
262- 'http://launchpad.dev/%7Ecprov/+archive/ppa/+index?start=1&batch=1'
263+ 'http://launchpad.dev/%7Ecprov/+archive/ppa/+index?batch=1&direction=backwards&memo=2&start=1'
264
265
266=== modified file 'lib/lp/translations/browser/tests/pofile-views.txt'
267--- lib/lp/translations/browser/tests/pofile-views.txt 2011-07-12 01:42:11 +0000
268+++ lib/lp/translations/browser/tests/pofile-views.txt 2011-07-13 06:27:29 +0000
269@@ -241,7 +241,7 @@
270 Also, we get redirected to the next batch.
271
272 >>> pofile_view.request.response.getHeader('Location')
273- 'http://127.0.0.1?start=10'
274+ 'http://127.0.0.1?memo=10&start=10'
275
276 The messsage's sequence is the position of that message in latest imported
277 template. We are going to test now what happens when we submit a potmsgset
278
279=== modified file 'lib/lp/translations/browser/translationmessage.py'
280--- lib/lp/translations/browser/translationmessage.py 2011-07-12 01:42:11 +0000
281+++ lib/lp/translations/browser/translationmessage.py 2011-07-13 06:27:29 +0000
282@@ -128,6 +128,9 @@
283 results is an iterable of results. request is the web request
284 being processed. size is a default batch size which the callsite
285 can choose to provide.
286+
287+ Why a custom BatchNavigator is required is a great mystery and
288+ should be documented here.
289 """
290 schema, netloc, path, parameters, query, fragment = (
291 urlparse(str(request.URL)))
292@@ -164,7 +167,7 @@
293
294 BatchNavigator.__init__(self, results, request, start_value, size)
295
296- def generateBatchURL(self, batch):
297+ def generateBatchURL(self, batch, backwards=False):
298 """Return a custom batch URL for `ITranslationMessage`'s views."""
299 url = ""
300 if batch is None:
301
302=== modified file 'lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt'
303--- lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt 2011-07-12 01:42:11 +0000
304+++ lib/lp/translations/stories/importqueue/xx-translation-import-queue-filtering.txt 2011-07-13 06:27:29 +0000
305@@ -56,7 +56,7 @@
306 >>> browser.getLink('Next')
307 <Link
308 text='Next'
309- url='http://.../+imports/+index?start=5&batch=5'>
310+ url='http://.../+imports/+index?batch=5&memo=5&start=5'>
311
312
313 == Target filter ==
314
315=== modified file 'lib/lp/translations/stories/standalone/xx-pofile-translate-empty-strings-without-validation.txt'
316--- lib/lp/translations/stories/standalone/xx-pofile-translate-empty-strings-without-validation.txt 2011-07-12 01:42:11 +0000
317+++ lib/lp/translations/stories/standalone/xx-pofile-translate-empty-strings-without-validation.txt 2011-07-13 06:27:29 +0000
318@@ -27,5 +27,5 @@
319 it as an error.
320
321 >>> print browser.url
322- http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es/+translate?batch=1&start=13
323+ http://translations.launchpad.dev/ubuntu/hoary/+source/evolution/+pots/evolution-2.2/es/+translate?batch=1&memo=13&start=13
324
325
326=== modified file 'lib/lp/translations/stories/standalone/xx-pofile-translate-html-tags-escape.txt'
327--- lib/lp/translations/stories/standalone/xx-pofile-translate-html-tags-escape.txt 2011-07-12 01:42:11 +0000
328+++ lib/lp/translations/stories/standalone/xx-pofile-translate-html-tags-escape.txt 2011-07-13 06:27:29 +0000
329@@ -20,7 +20,7 @@
330 We are in next form page.
331
332 >>> print user_browser.url
333- http://translations.launchpad.dev/ubuntu/hoary/+source/pmount/+pots/pmount/hr/+translate?start=10
334+ http://translations.launchpad.dev/ubuntu/hoary/+source/pmount/+pots/pmount/hr/+translate?memo=10&start=10
335
336 Let's go back to the modified message.
337
338
339=== modified file 'lib/lp/translations/stories/standalone/xx-pofile-translate-newlines-check.txt'
340--- lib/lp/translations/stories/standalone/xx-pofile-translate-newlines-check.txt 2011-07-12 01:42:11 +0000
341+++ lib/lp/translations/stories/standalone/xx-pofile-translate-newlines-check.txt 2011-07-13 06:27:29 +0000
342@@ -82,7 +82,7 @@
343 We were redirected to the next form, the translation was accepted.
344
345 >>> print browser.url
346- http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1&start=0
347+ http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1
348
349 Get previous page to check that the save translation is the right one.
350
351@@ -112,7 +112,7 @@
352 We were redirected to the next form, the translation was accepted.
353
354 >>> print browser.url
355- http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1&start=0
356+ http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1
357
358 Get previous page to check that the save translation is the right one.
359
360@@ -142,7 +142,7 @@
361 We were redirected to the next form, the translation was accepted.
362
363 >>> print browser.url
364- http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1&start=0
365+ http://translations.launchpad.dev/evolution/trunk/+pots/evolution-2.2/es/+translate?batch=1
366
367 Get previous page to check that the save translation is the right one.
368
369
370=== modified file 'versions.cfg'
371--- versions.cfg 2011-07-13 01:37:43 +0000
372+++ versions.cfg 2011-07-13 06:27:29 +0000
373@@ -30,7 +30,7 @@
374 launchpadlib = 1.9.3
375 lazr.amqp = 0.1
376 lazr.authentication = 0.1.1
377-lazr.batchnavigator = 1.2.2
378+lazr.batchnavigator = 1.2.5
379 lazr.config = 1.1.3
380 lazr.delegates = 1.2.0
381 lazr.enum = 1.1.3