~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
= Zope Widgets use IBrowserFormNG =

Regular Zope widgets have the problem of failing with low-level
exceptions (TypeError, AttributeError, ...) when the request contains
a non-expected number of values.

Launchpad monkey patch the base Zope widgets so that they use
the IBrowserFormNG interface (see webapp-publication.txt) to obtain
the form value.

The monkey patch is installed by default:

    >>> from lp.services.webapp.servers import (
    ...     Zope3WidgetsUseIBrowserFormNGMonkeyPatch)
    >>> Zope3WidgetsUseIBrowserFormNGMonkeyPatch.installed
    True

Without the patch, the regular Zope3 widgets fail with a low-level
exception:

    >>> import zope.schema as schema
    >>> from zope.app.form.browser import IntWidget, TextWidget
    >>> from lp.services.webapp.servers import LaunchpadTestRequest

    >>> Zope3WidgetsUseIBrowserFormNGMonkeyPatch.uninstall()

    >>> int_field = schema.Int(__name__='int')
    >>> request = LaunchpadTestRequest(
    ...     form={'field.int': [1, 2]})
    >>> int_widget = IntWidget(int_field, request)
    >>> int_widget.getInputValue()
    Traceback (most recent call last):
      ...
    TypeError: ...

With the monkey patch in place, instead of failing with a low-level
exception, the widget will raise an UnexpectedFormData when the request
contains more than one argument.

    >>> Zope3WidgetsUseIBrowserFormNGMonkeyPatch.install()

    >>> int_widget.getInputValue()
    Traceback (most recent call last):
      ...
    UnexpectedFormData: ...

    >>> text_field = schema.TextLine(__name__='text')
    >>> request = LaunchpadTestRequest(
    ...     form={'field.text': ['two', 'strings']})
    >>> text_widget = TextWidget(text_field, request)
    >>> text_widget.getInputValue()
    Traceback (most recent call last):
      ...
    UnexpectedFormData: ...

Since the SimpleInputWidget._getFormValue is overriden, it also works
with the Launchpad widgets extending it:

    >>> from lp.app.widgets.textwidgets import StrippedTextWidget

    >>> stripped_text_widget = StrippedTextWidget(text_field, request)
    >>> stripped_text_widget.getInputValue()
    Traceback (most recent call last):
      ...
    UnexpectedFormData: ...

Widgets expecting a variable number of values continue to work
with this monkey patch:

    >>> from zope.schema import Choice, List
    >>> from zope.app.form.browser import MultiSelectWidget

    >>> request = LaunchpadTestRequest(form={'field.list': ['1', '2']})
    >>> list_field = List(
    ...     __name__='list', value_type=Choice(values=[1, 2, 3]))

    # MultiSelectWidget needs a bounded field.
    >>> list_field = list_field.bind(object())
    >>> list_widget = MultiSelectWidget(
    ...     list_field, list_field.value_type.vocabulary, request)
    >>> list_widget.getInputValue()
    [1, 2]