Merge lp:~jtv/lazr.batchnavigator/bug-574159 into lp:lazr.batchnavigator

Proposed by Jeroen T. Vermeulen on 2010-05-03
Status: Merged
Approved by: Jeroen T. Vermeulen on 2010-05-07
Approved revision: 30
Merged at revision: 28
Proposed branch: lp:~jtv/lazr.batchnavigator/bug-574159
Merge into: lp:lazr.batchnavigator
Diff against target: 101 lines (+55/-14)
2 files modified
src/lazr/batchnavigator/README.txt (+21/-0)
src/lazr/batchnavigator/_batchnavigator.py (+34/-14)
To merge this branch: bzr merge lp:~jtv/lazr.batchnavigator/bug-574159
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve on 2010-05-07
Barry Warsaw code 2010-05-03 Pending
Review via email: mp+24577@code.launchpad.net

Commit Message

Ignore negative batch sizes.

Description of the Change

= Bug 574159 =

The batch navigator happily accepts negative batch sizes, which as far as I can tell have no meaning and cause oopses in Launchpad.

Here's a fix to make it ignore negative batch sizes. If we ever do decide to assign a useful meaning to negative batch sizes, at least this makes the choice explicit and tests it.

At least, that's the theory. The fact is that I haven't figured out how to run the test yet.

To post a comment you must log in.
Jeroen T. Vermeulen (jtv) wrote :

Had to patch up the test a bit, but it's passing now.

Barry Warsaw (barry) wrote :

> Had to patch up the test a bit, but it's passing now.

Well the branch diff /still/ isn't available on the page, but I managed to
trick Launchpad into giving it to me.

=== modified file 'src/lazr/batchnavigator/README.txt'
--- src/lazr/batchnavigator/README.txt 2009-03-23 16:14:28 +0000
+++ src/lazr/batchnavigator/README.txt 2010-05-04 03:10:46 +0000
> @@ -191,6 +191,20 @@
> >>> navigator.nextBatchURL()
> 'http://www.example.com/foo?start=3&batch=1'
>
> +The batch argument must be positive. Negative numbers or zero are ignored.
> +
> + >>> from cgi import parse_qs
> + >>> BatchNavigator(reindeer, request=build_request([('batch', '0')]))
> + >>> next_batch = reindeer_batch_navigator_post_with_qs.nextBatchURL()
> + >>> print parse_qs(next_batch)['batch']
> + 50
> +
> + >>> BatchNavigator(reindeer, request=build_request([('batch', '-1')]))
> + >>> next_batch = reindeer_batch_navigator_post_with_qs.nextBatchURL()
> + >>> print parse_qs(next_batch)['batch']
> + 50

I'm not sure how this shows that the batch is ignored. Without looking at the
rest of the test, what does '50' mean? Maybe the docs before this explain
that this is the default batch size, but if not, could you provide a little
more context?

> +
> +
> =============
> Empty Batches
> =============

=== modified file 'src/lazr/batchnavigator/_batchnavigator.py'
--- src/lazr/batchnavigator/_batchnavigator.py 2009-03-23 16:14:28 +0000
+++ src/lazr/batchnavigator/_batchnavigator.py 2010-05-04 03:10:46 +0000
> @@ -108,16 +108,19 @@
> self.default_size = size
>
> request_size = batch_params_source.get(self.batch_variable_name, None)
> - if request_size:
> + if request_size is not None:
> try:
> - size = int(request_size)
> + request_size = int(request_size)

I don't love the fact that you're changing the type of the local variable
`request_size` within the conditional. Are you sure request_size isn't used
or referenced outside of this block?

> except (ValueError, TypeError):
> - pass
> - if size > self.max_batch_size:
> + request_size = 0
> +
> + if request_size > self.max_batch_size:
> raise InvalidBatchSizeError(
> 'Maximum for "%s" parameter is %d.' %
> (self.batch_variable_name,
> self.max_batch_size))
> + if request_size > 0:
> + size = request_size

No InvalidBatchSizeError for when the request is < 0? Do you think an error
makes more sense?

>
> if size is None:
> size = self.default_batch_size

30. By Jeroen T. Vermeulen on 2010-05-05

Extracted method.

Jeroen T. Vermeulen (jtv) wrote :
Download full text (3.5 KiB)

Hi Barry,

Thanks for looking at it despite the difficulties.

> Well the branch diff /still/ isn't available on the page, but I managed to
> trick Launchpad into giving it to me.

Unfortunately you still got an outdated diff. Meanwhile I've updated it again; it's probably best to do this using bzr.

> === modified file 'src/lazr/batchnavigator/README.txt'
> --- src/lazr/batchnavigator/README.txt 2009-03-23 16:14:28 +0000
> +++ src/lazr/batchnavigator/README.txt 2010-05-04 03:10:46 +0000
> > @@ -191,6 +191,20 @@
> > >>> navigator.nextBatchURL()
> > 'http://www.example.com/foo?start=3&batch=1'
> >
> > +The batch argument must be positive. Negative numbers or zero are ignored.
> > +
> > + >>> from cgi import parse_qs
> > + >>> BatchNavigator(reindeer, request=build_request([('batch', '0')]))
> > + >>> next_batch = reindeer_batch_navigator_post_with_qs.nextBatchURL()
> > + >>> print parse_qs(next_batch)['batch']
> > + 50
> > +
> > + >>> BatchNavigator(reindeer, request=build_request([('batch', '-1')]))
> > + >>> next_batch = reindeer_batch_navigator_post_with_qs.nextBatchURL()
> > + >>> print parse_qs(next_batch)['batch']
> > + 50
>
> I'm not sure how this shows that the batch is ignored. Without looking at the
> rest of the test, what does '50' mean? Maybe the docs before this explain
> that this is the default batch size, but if not, could you provide a little
> more context?

This is where the outdated diff hurts us. I had changed the test to state that the default batch size was used instead, and show the default batch size (which is 50) before showing that the actual batch sizes for these two batch navigators are also 50.

> === modified file 'src/lazr/batchnavigator/_batchnavigator.py'
> --- src/lazr/batchnavigator/_batchnavigator.py 2009-03-23 16:14:28 +0000
> +++ src/lazr/batchnavigator/_batchnavigator.py 2010-05-04 03:10:46 +0000
> > @@ -108,16 +108,19 @@
> > self.default_size = size
> >
> > request_size = batch_params_source.get(self.batch_variable_name,
> None)
> > - if request_size:
> > + if request_size is not None:
> > try:
> > - size = int(request_size)
> > + request_size = int(request_size)
>
> I don't love the fact that you're changing the type of the local variable
> `request_size` within the conditional. Are you sure request_size isn't used
> or referenced outside of this block?

Quite. I've now done the right thing though: extracted the method and used separate names for the variables. It also makes the logic a bit easier to follow, because the new method can just "return None" whenever things don't work out.

> > except (ValueError, TypeError):
> > - pass
> > - if size > self.max_batch_size:
> > + request_size = 0
> > +
> > + if request_size > self.max_batch_size:
> > raise InvalidBatchSizeError(
> > 'Maximum for "%s" parameter is %d.' %
> > (self.batch_variable_name,
> > self.max_batch_size))
> > + if request_size > 0:
> > + siz...

Read more...

Jeroen T. Vermeulen (jtv) wrote :

The diff updated promptly this time.

Abel Deuring (adeuring) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/batchnavigator/README.txt'
2--- src/lazr/batchnavigator/README.txt 2009-03-23 16:14:28 +0000
3+++ src/lazr/batchnavigator/README.txt 2010-05-05 03:40:45 +0000
4@@ -191,6 +191,27 @@
5 >>> navigator.nextBatchURL()
6 'http://www.example.com/foo?start=3&batch=1'
7
8+The batch argument must be positive. Other numbers are ignored, and the
9+default batch size is used instead.
10+
11+ >>> from cgi import parse_qs
12+ >>> request = build_request({'batch': '0'})
13+ >>> navigator = BatchNavigator(range(99), request=request)
14+ >>> print navigator.default_batch_size
15+ 50
16+ >>> for value in parse_qs(navigator.nextBatchURL())['batch']:
17+ ... print value
18+ 50
19+
20+ >>> request = build_request({'batch': '-1'})
21+ >>> navigator = BatchNavigator(range(99), request=request)
22+ >>> print navigator.default_batch_size
23+ 50
24+ >>> for value in parse_qs(navigator.nextBatchURL())['batch']:
25+ ... print value
26+ 50
27+
28+
29 =============
30 Empty Batches
31 =============
32
33=== modified file 'src/lazr/batchnavigator/_batchnavigator.py'
34--- src/lazr/batchnavigator/_batchnavigator.py 2009-03-23 16:14:28 +0000
35+++ src/lazr/batchnavigator/_batchnavigator.py 2010-05-05 03:40:45 +0000
36@@ -1,4 +1,4 @@
37-# Copyright 2004-2009 Canonical Ltd. All rights reserved.
38+# Copyright 2004-2010 Canonical Ltd. All rights reserved.
39 #
40 # This file is part of lazr.batchnavigator
41 #
42@@ -106,19 +106,9 @@
43 self.start = start
44
45 self.default_size = size
46-
47- request_size = batch_params_source.get(self.batch_variable_name, None)
48- if request_size:
49- try:
50- size = int(request_size)
51- except (ValueError, TypeError):
52- pass
53- if size > self.max_batch_size:
54- raise InvalidBatchSizeError(
55- 'Maximum for "%s" parameter is %d.' %
56- (self.batch_variable_name,
57- self.max_batch_size))
58-
59+ request_size = self._getRequestedSize(batch_params_source)
60+ if request_size is not None:
61+ size = request_size
62 if size is None:
63 size = self.default_batch_size
64
65@@ -128,6 +118,36 @@
66 self.setHeadings(
67 self.default_singular_heading, self.default_plural_heading)
68
69+ def _getRequestedSize(self, batch_params_source):
70+ """Figure out what batch size the user requested, if any.
71+
72+ Sizes that are not positive numbers are ignored.
73+
74+ :return: An acceptable batch size requested by the user, or
75+ None.
76+ :raise: `InvalidBatchSizeError` if the requested size exceeds
77+ `max_batch_size`.
78+ """
79+ size_string = batch_params_source.get(self.batch_variable_name, None)
80+ if size_string is None:
81+ return None
82+
83+ try:
84+ request_size = int(size_string)
85+ except (ValueError, TypeError):
86+ return None
87+
88+ if request_size <= 0:
89+ return None
90+
91+ if request_size > self.max_batch_size:
92+ raise InvalidBatchSizeError(
93+ 'Maximum for "%s" parameter is %d.' %
94+ (self.batch_variable_name,
95+ self.max_batch_size))
96+
97+ return request_size
98+
99 @property
100 def heading(self):
101 """See `IBatchNavigator`"""

Subscribers

People subscribed via source and target branches