Merge lp:~sinzui/launchpad/noneable-bug-475433 into lp:launchpad/db-devel

Proposed by Curtis Hovey
Status: Merged
Merged at revision: not available
Proposed branch: lp:~sinzui/launchpad/noneable-bug-475433
Merge into: lp:launchpad/db-devel
Diff against target: 68 lines (+32/-6)
2 files modified
lib/canonical/launchpad/doc/stripped-text-widget.txt (+29/-4)
lib/canonical/launchpad/fields/__init__.py (+3/-2)
To merge this branch: bzr merge lp:~sinzui/launchpad/noneable-bug-475433
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) release-critical Approve
Barry Warsaw (community) code Approve
Review via email: mp+14487@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

This is my branch to fix the StrippedTextLine field to handle None for
non-required attributes.

    lp:~sinzui/launchpad/noneable-bug-475433
    Diff size: 69
    Launchpad bug: https://bugs.launchpad.net/bugs/475433
    Test command: ./bin/test -vvt "stripped-text-widget"
    Pre-implementation: no one
    Target release: 3.1.10

= Fix the StrippedTextLine field from oopsing =

The OOPS-1405ED465 oops shows the StrippedTextLine is working with None, but
it assumes it has a string.

    * Module canonical.launchpad.fields, line 206, in set
      super(StrippedTextLine, self).set(object, value.strip())
    AttributeError: 'NoneType' object has no attribute 'strip'

The milestone code_name is optional. but is effectively required to avoid
the oops.

The StrippedTextLine.set() method was added to by Tim's 2009-10-2
bmp-inline-commit-message branch to support API operations, but unlike
its counterpart StrippableText.set(), it does not check if the value is None.

== Rules ==

    * StrippedTextLine should test for None before calling strip().

== QA ==

    * Visit a milestone you can edit
    * Set the code name field to empty and submit
    * Verify there is no oops and that the value is not set on the page.

== Lint ==

Linting changed files:
  lib/canonical/launchpad/doc/stripped-text-widget.txt
  lib/canonical/launchpad/fields/__init__.py

== Test ==

    * lib/canonical/launchpad/doc/stripped-text-widget.txt
      * Added a test to verify that the StrippedTextLine strips text and
        can handle None.

== Implementation ==

    * lib/canonical/launchpad/fields/__init__.py
      * Added a guard before calling strip() on the supposed string.
        This is the same approach used by StrippableText for large text.

Revision history for this message
Barry Warsaw (barry) wrote :

Looks good to me.

review: Approve (code)
Revision history for this message
Curtis Hovey (sinzui) wrote :

It has been more than an hour and still no diff.

=== modified file 'lib/canonical/launchpad/doc/stripped-text-widget.txt'
--- lib/canonical/launchpad/doc/stripped-text-widget.txt 2009-08-13 19:36:01 +0000
+++ lib/canonical/launchpad/doc/stripped-text-widget.txt 2009-11-05 17:12:19 +0000
@@ -1,4 +1,32 @@
-= StrippedTextLine Widget =
+StrippedTextLine field
+======================
+
+The StrippedTextLine field strips the leading and trailing text from the
+set value.
+
+ >>> from canonical.launchpad.fields import StrippedTextLine
+
+ >>> non_required_field = StrippedTextLine(
+ ... __name__='field', title=u'Title', required=False)
+
+ >>> class Thing:
+ ... def __init__(self, field):
+ ... self.field = field
+ >>> thing = Thing('abc')
+
+ >>> non_required_field.set(thing, ' egf ')
+ >>> non_required_field.get(thing)
+ 'egf'
+
+None is an accepted field value.
+
+ >>> non_required_field.set(thing, None)
+ >>> print non_required_field.get(thing)
+ None
+
+
+StrippedTextLine Widget
+-----------------------

 This custom widget is used to strip leading and trailing whitespaces.

@@ -21,9 +49,6 @@
 If only whitespace is provided, the widget acts like no input was
 provided.

- >>> from canonical.launchpad.fields import StrippedTextLine
- >>> non_required_field = StrippedTextLine(
- ... __name__='field', title=u'Title', required=False)
   >>> non_required_field.missing_value is None
   True
   >>> request = LaunchpadTestRequest(form={'field.field':' \n '})

=== modified file 'lib/canonical/launchpad/fields/__init__.py'
--- lib/canonical/launchpad/fields/__init__.py 2009-10-23 00:48:47 +0000
+++ lib/canonical/launchpad/fields/__init__.py 2009-11-05 16:52:54 +0000
@@ -203,13 +203,14 @@

     def set(self, object, value):
         """Strip the value and pass up."""
- super(StrippedTextLine, self).set(object, value.strip())
+ if value is not None:
+ value = value.strip()
+ super(StrippedTextLine, self).set(object, value)

 class NoneableTextLine(StrippedTextLine):
     implements(INoneableTextLine)

-
 # Title
 # A field to capture a launchpad object title
 class Title(StrippedTextLine):

Revision history for this message
Francis J. Lacoste (flacoste) :
review: Approve (release-critical)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/doc/stripped-text-widget.txt'
2--- lib/canonical/launchpad/doc/stripped-text-widget.txt 2009-08-13 19:36:01 +0000
3+++ lib/canonical/launchpad/doc/stripped-text-widget.txt 2009-11-05 20:10:23 +0000
4@@ -1,4 +1,32 @@
5-= StrippedTextLine Widget =
6+StrippedTextLine field
7+======================
8+
9+The StrippedTextLine field strips the leading and trailing text from the
10+set value.
11+
12+ >>> from canonical.launchpad.fields import StrippedTextLine
13+
14+ >>> non_required_field = StrippedTextLine(
15+ ... __name__='field', title=u'Title', required=False)
16+
17+ >>> class Thing:
18+ ... def __init__(self, field):
19+ ... self.field = field
20+ >>> thing = Thing('abc')
21+
22+ >>> non_required_field.set(thing, ' egf ')
23+ >>> non_required_field.get(thing)
24+ 'egf'
25+
26+None is an accepted field value.
27+
28+ >>> non_required_field.set(thing, None)
29+ >>> print non_required_field.get(thing)
30+ None
31+
32+
33+StrippedTextLine Widget
34+-----------------------
35
36 This custom widget is used to strip leading and trailing whitespaces.
37
38@@ -21,9 +49,6 @@
39 If only whitespace is provided, the widget acts like no input was
40 provided.
41
42- >>> from canonical.launchpad.fields import StrippedTextLine
43- >>> non_required_field = StrippedTextLine(
44- ... __name__='field', title=u'Title', required=False)
45 >>> non_required_field.missing_value is None
46 True
47 >>> request = LaunchpadTestRequest(form={'field.field':' \n '})
48
49=== modified file 'lib/canonical/launchpad/fields/__init__.py'
50--- lib/canonical/launchpad/fields/__init__.py 2009-10-23 00:48:47 +0000
51+++ lib/canonical/launchpad/fields/__init__.py 2009-11-05 20:10:23 +0000
52@@ -203,13 +203,14 @@
53
54 def set(self, object, value):
55 """Strip the value and pass up."""
56- super(StrippedTextLine, self).set(object, value.strip())
57+ if value is not None:
58+ value = value.strip()
59+ super(StrippedTextLine, self).set(object, value)
60
61
62 class NoneableTextLine(StrippedTextLine):
63 implements(INoneableTextLine)
64
65-
66 # Title
67 # A field to capture a launchpad object title
68 class Title(StrippedTextLine):

Subscribers

People subscribed via source and target branches

to status/vote changes: