launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #03212
[Merge] lp:~lifeless/launchpad/bug-752153 into lp:launchpad
Robert Collins has proposed merging lp:~lifeless/launchpad/bug-752153 into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #752153 in Launchpad itself: " batch navigation uses high OFFSET rather than db constraints"
https://bugs.launchpad.net/launchpad/+bug/752153
For more details, see:
https://code.launchpad.net/~lifeless/launchpad/bug-752153/+merge/56505
Update our batchnavigator dependency to 1.2.3 which supports database friendly batching (including stable batchs that don't skip/repeat things when folk remove or add items).
The FUGLY bit in the google class that subclasses BatchNavigator is because its not calling the constructor - A small future iteration in batchnavigator will allow that to be cleaned up, but I noticed that very late in the piece, and its not really related to the thrust of this work.
--
https://code.launchpad.net/~lifeless/launchpad/bug-752153/+merge/56505
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/launchpad/bug-752153 into lp:launchpad.
=== modified file 'lib/lp/app/browser/root.py'
--- lib/lp/app/browser/root.py 2011-03-07 16:32:12 +0000
+++ lib/lp/app/browser/root.py 2011-04-06 05:04:27 +0000
@@ -13,6 +13,7 @@
import time
import feedparser
+from lazr.batchnavigator import ListRangeFactory
from lazr.batchnavigator.z3batching import batch
from zope.component import getUtility
from zope.schema.interfaces import TooLong
@@ -560,6 +561,7 @@
class GoogleBatchNavigator(BatchNavigator):
"""A batch navigator with a fixed size of 20 items per batch."""
+ _batch_factory = WindowedListBatch
# Searches generally don't show the 'Last' link when there is a
# good chance of getting over 100,000 results.
show_last_link = False
@@ -567,7 +569,9 @@
singular_heading = 'page'
plural_heading = 'pages'
- def __init__(self, results, request, start=0, size=20, callback=None):
+ def __init__(self, results, request, start=0, size=20, callback=None,
+ transient_parameters=None, force_start=False,
+ range_factory=None):
"""See `BatchNavigator`.
:param results: A `PageMatches` object that contains the matching
@@ -583,20 +587,68 @@
# pylint: disable-msg=W0231
results = WindowedList(results, start, results.total)
self.request = request
- request_start = request.get(self.start_variable_name, None)
- if request_start is None:
+ local = (self.batch_variable_name, self.start_variable_name,
+ self.memo_variable_name, self.direction_variable_name)
+ self.transient_parameters = set(local)
+ if transient_parameters is not None:
+ self.transient_parameters.update(transient_parameters)
+
+ # For backwards compatibility (as in the past a work-around has been
+ # to include the url batch params in hidden fields within posted
+ # forms), if the request is a POST request, and either the 'start'
+ # or 'batch' params are included then revert to the default behaviour
+ # of using the request (which automatically gets the params from the
+ # request.form dict).
+ if request.method == 'POST' and (
+ self.start_variable_name in request.form or
+ self.batch_variable_name in request.form):
+ batch_params_source = request
+ else:
+ # We grab the request variables directly from the requests
+ # query_string_parameters so that they will be recognized
+ # even during post operations.
+ batch_params_source = dict(
+ (k, v[0]) for k, v
+ in self.query_string_parameters.items() if k in local)
+
+ # In this code we ignore invalid request variables since it
+ # probably means the user finger-fumbled it in the request. We
+ # could raise UnexpectedFormData, but is there a good reason?
+ def param_var(name):
+ return batch_params_source.get(name, None)
+ # -- start
+ request_start = param_var(self.start_variable_name)
+ if force_start or request_start is None:
self.start = start
else:
try:
self.start = int(request_start)
except (ValueError, TypeError):
self.start = start
-
+ # -- size
self.default_size = 20
-
- self.transient_parameters = [self.start_variable_name]
-
- self.batch = WindowedListBatch(
- results, start=self.start, size=self.default_size)
+ size = self.default_size
+ # -- direction
+ direction = param_var(self.direction_variable_name)
+ if direction == 'backwards':
+ direction = False
+ else:
+ direction = None
+ # -- memo
+ memo = param_var(self.memo_variable_name)
+ if direction is not None and memo is None:
+ # Walking backwards from the end - the only case where we generate
+ # a url with no memo but a direction (and the only case where we
+ # need it: from the start with no memo is equivalent to a simple
+ # list slice anyway).
+ memo = ''
+
+ if range_factory is None:
+ range_factory = ListRangeFactory(results)
+ self.batch = self._batch_factory(results, range_factory,
+ start=self.start, size=size, range_forwards=direction,
+ range_memo=memo)
+ if callback is not None:
+ callback(self, self.batch)
self.setHeadings(
self.default_singular_heading, self.default_plural_heading)
=== modified file 'lib/lp/app/browser/tests/launchpad-search-pages.txt'
--- lib/lp/app/browser/tests/launchpad-search-pages.txt 2011-03-07 16:32:12 +0000
+++ lib/lp/app/browser/tests/launchpad-search-pages.txt 2011-04-06 05:04:27 +0000
@@ -444,8 +444,6 @@
provides a link to the next batch, which also happens to be the last
batch.
- >>> len(search_view.pages.getBatches())
- 2
>>> search_view.pages.nextBatchURL()
'...start=20'
>>> search_view.pages.lastBatchURL()
=== modified file 'lib/lp/services/features/browser/tests/test_changelog.py'
--- lib/lp/services/features/browser/tests/test_changelog.py 2011-02-18 21:51:56 +0000
+++ lib/lp/services/features/browser/tests/test_changelog.py 2011-04-06 05:04:27 +0000
@@ -80,7 +80,7 @@
self.assertEqual('change', batch._singular_heading)
self.assertEqual('changes', batch._plural_heading)
self.assertEqual(10, batch.default_size)
- self.assertEqual(2, len(batch.getBatches()))
+ self.assertEqual(None, batch.currentBatch().nextBatch().nextBatch())
def test_page_batched_changes(self):
self.makeFeatureFlagChanges()
=== modified file 'versions.cfg'
--- versions.cfg 2011-04-05 12:10:01 +0000
+++ versions.cfg 2011-04-06 05:04:27 +0000
@@ -29,7 +29,7 @@
keyring = 0.5.1
launchpadlib = 1.9.3
lazr.authentication = 0.1.1
-lazr.batchnavigator = 1.2.2
+lazr.batchnavigator = 1.2.3
lazr.config = 1.1.3
lazr.delegates = 1.2.0
lazr.enum = 1.1.2