quixote/form widget.py,1.40,1.41
Neil Schemenauer <nascheme-fVcApmY9cLvQ3/1i3zOLAti2O/[email protected]> Thu, 07 Nov 2002 17:29:19 -0500
| Newsgroups | gmane.comp.web.quixote.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /home/cvs/quixote/form
In directory hewson:/tmp/cvs-serv2742
Modified Files:
widget.py
Log Message:
Another stab at solving the "keys for selection options" problem. If
keys are not provided, try using the _p_oid of the allowed values. If
that doesn't work, check if the descriptions are unique and use them.
If that fails, raise a ValueError. Explicit keys will have to be
provided in that case.
Using _p_oid works well for us since most of our objects have OIDs. I
don't expect it to hurt other people either since the chance of someone
using _p_oid as an attribute is small.
Share code between SingleSelectWidget.parse and
MultipleSelectWidget.parse.
Index: widget.py
===================================================================
RCS file: /home/cvs/quixote/form/widget.py,v
retrieving revision 1.40
retrieving revision 1.41
diff -u -d -r1.40 -r1.41
--- widget.py 7 Nov 2002 18:00:36 -0000 1.40
+++ widget.py 7 Nov 2002 22:29:17 -0000 1.41
@@ -8,6 +8,7 @@
__revision__ = "$Id$"
+import struct
from types import FloatType, IntType, ListType, StringType, TupleType
from quixote import get_request
from quixote.html import htmltext, htmlescape, htmltag, ValuelessAttr
@@ -245,7 +246,7 @@
</select>
Instance attributes:
- options : [ (value:any, description:any, key:any) ]
+ options : [ (value:any, description:any, key:string) ]
value : any
The value is None or an element of dict(options.values()).
size : int
@@ -288,6 +289,34 @@
self.value = value
break
+ def _generate_keys (self, values, descriptions):
+ """Called if no keys were provided. Try to generate a set of keys
+ that will be consistent between rendering and parsing.
+ """
+ # try to use ZODB object IDs
+ keys = []
+ for value in values:
+ if value is None:
+ oid = ""
+ else:
+ oid = getattr(value, "_p_oid", None)
+ if not oid:
+ break
+ hi, lo = struct.unpack(">LL", oid)
+ oid = "%x" % ((hi << 32) | lo)
+ keys.append(oid)
+ else:
+ # found OID for every value
+ return keys
+ # can't use OIDs, try using descriptions
+ used_keys = {}
+ keys = map(str, descriptions)
+ for key in keys:
+ if used_keys.has_key(key):
+ raise ValueError, "duplicated descriptions (provide keys)"
+ used_keys[key] = 1
+ return keys
+
def set_options (self, options, sort=0):
"""(options: [objects:any], sort=0)
or
@@ -307,30 +336,29 @@
before others.
"""
if options:
- # provide default values for descriptions and keys
first = options[0]
+ values = []
+ descriptions = []
+ keys = []
if type(first) is TupleType:
if len(first) == 2:
- options = [ (object, description, description)
- for object, description in options ]
- elif len(first) != 3:
+ for value, description in options:
+ values.append(value)
+ descriptions.append(description)
+ elif len(first) == 3:
+ for value, description, key in options:
+ values.append(value)
+ descriptions.append(description)
+ keys.append(str(key))
+ else:
raise ValueError, 'invalid options %r' % options
else:
- options = zip(options, options, options)
+ values = descriptions = options
- # Look for duplicate keys. If any are found, replace them.
- found = {}
-
- def unique (key):
- count = 1
- while key in found:
- key = "%s__%d__" % (key, count)
- count += 1
- found[key]=1
- return key
+ if not keys:
+ keys = self._generate_keys(values, descriptions)
- options = [ (object, description, unique(key))
- for object, description, key in options ]
+ options = zip(values, descriptions, keys)
if sort:
def compare(a, b):
@@ -389,6 +417,13 @@
return htmltext("\n").join(tags)
+def _parse_single_selection(parsed_key, options):
+ for value, description, key in options:
+ if key == parsed_key:
+ return value
+ else:
+ raise FormValueError, "invalid value selected"
+
class SingleSelectWidget (SelectWidget):
"""Widget for single selection.
"""
@@ -396,15 +431,12 @@
widget_type = "single_select"
def parse (self, request):
- value = request.form.get(self.name)
+ parsed_key = request.form.get(self.name)
self.value = None
- if value:
- if type(value) is ListType:
+ if parsed_key:
+ if type(parsed_key) is ListType:
raise FormValueError, "cannot select multiple values"
- for object, description, key in self.options:
- if value == str(key): # str() not htmlescape()!
- self.value = object
- break
+ self.value = _parse_single_selection(parsed_key, self.options)
return self.value
@@ -479,15 +511,16 @@
return value in self.value
def parse (self, request):
- value = request.form.get(self.name)
- if value and type(value) is ListType:
- self.value = [ object
- for object, description, key in self.options
- if str(key) in value ] or None
- else:
- self.value = [ object
- for object, description, key in self.options
- if str(key) == value ] or None
+ parsed_keys = request.form.get(self.name)
+ self.value = None
+ if parsed_keys:
+ if type(parsed_keys) is ListType:
+ self.value = [ value
+ for value, description, key in self.options
+ if key in parsed_keys ] or None
+ else:
+ self.value = [ _parse_single_selection(parsed_keys,
+ self.options) ]
return self.value