Permalink
Browse files

A better fix for #81: don't break with non-ascii strings as values.

  • Loading branch information...
dnouri committed Mar 31, 2012
1 parent 494db2b commit a22c0c416bb4044c5c0cfc1cacfda7ae5ae6c2d2
@@ -1,6 +1,6 @@
<input type="hidden" name="__start__" value="${field.name}:sequence"/>
<ul class="deformSet">
- <tal:loop tal:repeat="choice field.widget.values">
+ <tal:loop tal:repeat="choice values">
<tal:def tal:define="(value, title) choice">
<li class="deformSet-item">
<input tal:attributes="checked value in cstruct;
@@ -1,5 +1,5 @@
<div>
- <tal:loop tal:repeat="choice field.widget.values">
+ <tal:loop tal:repeat="choice values">
<tal:def tal:define="(value, description) choice">
<span>${description}</span>
<em id="${field.oid}-${repeat.choice.index}"
@@ -1,4 +1,4 @@
-<p tal:repeat="(value, description) field.widget.values" i18n:domain="deform">
+<p tal:repeat="(value, description) values" i18n:domain="deform">
<span>${description}</span>
<em tal:condition="value == cstruct" i18n:translate="">Selected</em>
<em tal:condition="value != cstruct" i18n:translate="">Not Selected</em>
@@ -2,8 +2,8 @@
id="${field.oid}"
tal:attributes="size field.widget.size"
tal:attributes="class field.widget.css_class">
- <option tal:repeat="(value, description) field.widget.values"
- tal:attributes="selected str(value) == cstruct and 'selected';
+ <option tal:repeat="(value, description) values"
+ tal:attributes="selected value == cstruct and 'selected';
class field.widget.css_class"
value="${value}">${description}</option>
</select>
@@ -588,6 +588,14 @@ def test_serialize_not_null_readonly(self):
self.assertEqual(renderer.kw['field'], field)
self.assertEqual(renderer.kw['cstruct'], cstruct)
+ def test_serialize_integer_values(self):
+ renderer = DummyRenderer()
+ schema = DummySchema()
+ field = DummyField(schema, renderer)
+ widget = self._makeOne(values=((1, 'one'),))
+ widget.serialize(field, None)
+ self.assertEqual(renderer.kw['values'], [('1', 'one')])
+
def test_deserialize_null(self):
from colander import null
widget = self._makeOne()
@@ -656,6 +664,14 @@ def test_serialize_not_null_readonly(self):
self.assertEqual(renderer.kw['field'], field)
self.assertEqual(renderer.kw['cstruct'], cstruct)
+ def test_serialize_integer_values(self):
+ renderer = DummyRenderer()
+ schema = DummySchema()
+ field = DummyField(schema, renderer)
+ widget = self._makeOne(values=((1, 'one'),))
+ widget.serialize(field, None)
+ self.assertEqual(renderer.kw['values'], [('1', 'one')])
+
def test_deserialize_null(self):
from colander import null
widget = self._makeOne()
@@ -1639,6 +1655,26 @@ def test___call___leaf_isnt_iterable(self):
result = reg([('abc', '123')])
self.assertEqual(result, {'js':['123'], 'css':['2']})
+class TestNormalizeChoices(unittest.TestCase):
+ def _call(self, values):
+ from deform.widget import _normalize_choices
+ return _normalize_choices(values)
+
+ def test_empty(self):
+ self.assertEqual(self._call(()), [])
+
+ def test_string(self):
+ self.assertEqual(self._call((('value', 'description'),)),
+ [('value', 'description')])
+
+ def test_text_type(self):
+ self.assertEqual(self._call(((text_type('value'), 'description'),)),
+ [('value', 'description')])
+
+ def test_integer(self):
+ self.assertEqual(self._call(((1, 'description'),)),
+ [('1', 'description')])
+
class DummyRenderer(object):
def __init__(self, result=''):
self.result = result
View
@@ -18,6 +18,14 @@
uppercase,
)
+def _normalize_choices(values):
+ result = []
+ for value, description in values:
+ if not isinstance(value, string_types):
+ value = str(value)
+ result.append((value, description))
+ return result
+
class Widget(object):
"""
A widget is the building block for rendering logic. The
@@ -613,7 +621,6 @@ class SelectWidget(Widget):
**Attributes/Arguments**
values
-
A sequence of two-tuples (the first value must be of type
string, unicode or integer, the second value must be string or
unicode) indicating allowable, displayed values, e.g. ``(
@@ -650,7 +657,8 @@ def serialize(self, field, cstruct, readonly=False):
if cstruct in (null, None):
cstruct = self.null_value
template = readonly and self.readonly_template or self.template
- return field.renderer(template, field=field, cstruct=cstruct)
+ return field.renderer(template, field=field, cstruct=cstruct,
+ values=_normalize_choices(self.values))
def deserialize(self, field, pstruct):
if pstruct in (null, self.null_value):
@@ -665,11 +673,12 @@ class RadioChoiceWidget(SelectWidget):
**Attributes/Arguments**
values
- A sequence of two-tuples (both values must be **string** or
- **unicode** values) indicating allowable, displayed values,
- e.g. ``( ('true', 'True'), ('false', 'False') )``. The first
- element in the tuple is the value that should be returned when
- the form is posted. The second is the display value.
+ A sequence of two-tuples (the first value must be of type
+ string, unicode or integer, the second value must be string or
+ unicode) indicating allowable, displayed values, e.g. ``(
+ ('true', 'True'), ('false', 'False') )``. The first element
+ in the tuple is the value that should be returned when the
+ form is posted. The second is the display value.
template
The template name used to render the widget. Default:
@@ -695,11 +704,12 @@ class CheckboxChoiceWidget(Widget):
**Attributes/Arguments**
values
- A sequence of two-tuples (both values must be **string** or
- **unicode** values) indicating allowable, displayed values,
- e.g. ``( ('true', 'True'), ('false', 'False') )``. The first
- element in the tuple is the value that should be returned when
- the form is posted. The second is the display value.
+ A sequence of two-tuples (the first value must be of type
+ string, unicode or integer, the second value must be string or
+ unicode) indicating allowable, displayed values, e.g. ``(
+ ('true', 'True'), ('false', 'False') )``. The first element
+ in the tuple is the value that should be returned when the
+ form is posted. The second is the display value.
template
The template name used to render the widget. Default:
@@ -722,7 +732,8 @@ def serialize(self, field, cstruct, readonly=False):
if cstruct in (null, None):
cstruct = ()
template = readonly and self.readonly_template or self.template
- return field.renderer(template, field=field, cstruct=cstruct)
+ return field.renderer(template, field=field, cstruct=cstruct,
+ values=_normalize_choices(self.values))
def deserialize(self, field, pstruct):
if pstruct is null:

0 comments on commit a22c0c4

Please sign in to comment.