[wwwsearch-commits] r17606 - wwwsearch/ClientForm/trunk
jjlee at codespeak.net
jjlee at codespeak.net
Fri Sep 16 22:57:05 CEST 2005
Author: jjlee
Date: Fri Sep 16 22:57:04 2005
New Revision: 17606
Modified:
wwwsearch/ClientForm/trunk/ClientForm.py
Log:
Apply another patch from Gary Poster to add docstrings and fix a problem with selected disabled controls should become deselected when; Fix a bug (I hope) in a list comprehension in ListControl.set_value_by_label() that would cause multiple matching, but non-ambiguous, labels to raise AmbiguityError
Modified: wwwsearch/ClientForm/trunk/ClientForm.py
==============================================================================
--- wwwsearch/ClientForm/trunk/ClientForm.py (original)
+++ wwwsearch/ClientForm/trunk/ClientForm.py Fri Sep 16 22:57:04 2005
@@ -1093,10 +1093,10 @@
attribute are defined by subclasses.
If the disabled attribute is true, this represents the state typically
- represented by browsers by `greying out' a control. If the disabled
+ represented by browsers by 'greying out' a control. If the disabled
attribute is true, the Control will raise AttributeError if an attempt is
made to change its value. In addition, the control will not be considered
- `successful' as defined by the W3C HTML 4 standard -- ie. it will
+ 'successful' as defined by the W3C HTML 4 standard -- ie. it will
contribute no data to the return value of the HTMLForm.click* methods. To
enable a control, set the disabled attribute to a false value.
@@ -1171,6 +1171,13 @@
raise NotImplementedError()
def get_labels(self):
+ """Return all labels (Label instances) for this control.
+
+ If the control was surrounded by a <label> tag, that will be the first
+ label; all other labels, connected by 'for' and 'id', are in the order
+ that appear in the HTML.
+
+ """
res = []
if self._label:
res.append(self._label)
@@ -1483,28 +1490,41 @@
def __init__(self, control, attrs):
label = _getLabel(attrs)
self.__dict__.update({
- 'name': attrs['value'],
- '_labels': label and [label] or [],
- 'attrs': attrs,
- 'control': control,
- '_disabled': attrs.has_key("disabled"),
- '_selected': False,
- 'id': attrs.get('id'),
+ "name": attrs["value"],
+ "_labels": label and [label] or [],
+ "attrs": attrs,
+ "control": control,
+ "disabled": attrs.has_key("disabled"),
+ "_selected": False,
+ "id": attrs.get("id"),
})
def get_labels(self):
+ """Return all labels (Label instances) for this item.
+
+ For items that represent radio buttons or checkboxes, if the item was
+ surrounded by a <label> tag, that will be the first label; all other
+ labels, connected by 'for' and 'id', are in the order that appear in
+ the HTML.
+
+ For items that represent select options, if the option had a label
+ attribute, that will be the first label. If the option has contents
+ (text within the option tags) and it is not the same as the label
+ attribute (if any), that will be a label. There is nothing in the
+ spec to my knowledge that makes an option with an id unable to be the
+ target of a label's for attribute, so those are included, if any, for
+ the sake of consistency and completeness.
+
+ """
res = []
res.extend(self._labels)
if self.id:
res.extend(self.control._form._id_to_labels.get(self.id, ()))
return res
- # selected and disabled properties
def __getattr__(self, name):
if name=='selected':
return self._selected
- elif name=='disabled':
- return self._disabled
raise AttributeError(name)
def __setattr__(self, name, value):
@@ -1512,8 +1532,7 @@
if bool(value) != bool(self._selected):
self.control._set_selected_state(self, value)
elif name == 'disabled':
- if bool(value) != bool(self._disabled):
- self.control._set_item_disabled(self, value)
+ self.__dict__['disabled'] = bool(value)
else:
raise AttributeError(name)
@@ -1663,13 +1682,14 @@
return False
def items_from_label(self, label, exclude_disabled=False):
+ """Return all items that have labels containing the given label text.
+
+ Optionally excludes disabled items.
+
+ """
if not isstringlike(label):
raise TypeError("item label must be string-like")
- # check all labels on the items, then if any of the values have
- # an id, go through all the collected labels on self._form._labels and
- # see if any of them match.
items = [] # order is important
- mapping = self._form._id_to_labels
for o in self.items:
if not exclude_disabled or not o.disabled:
for l in o.get_labels():
@@ -1679,12 +1699,32 @@
return items
def items_from_name(self, name, exclude_disabled=False):
+ """Return all items that have names matching the given name.
+
+ Optionally excludes disabled items.
+
+ """
if not isstringlike(name):
raise TypeError("item name must be string-like")
return [o for o in self.items if
o.name == name and (not exclude_disabled or not o.disabled)]
def get(self, name, by_label=False, nr=None, exclude_disabled=False):
+ """Return item by name or label, disambiguating if necessary with nr.
+
+ nr is an optional 0-based index of the items matching the query.
+
+ If nr is the default None value and more than item is found, raises
+ AmbiguityError.
+
+ If no item is found, raises ItemNotFoundError.
+
+ If items are found but nr is specified and not found, raises KeyError.
+
+ Optionally excludes disabled items.
+
+ """
+
if by_label:
method = self.items_from_label
else:
@@ -1692,23 +1732,40 @@
return disambiguate(method(name, exclude_disabled), nr, name)
def toggle(self, name, by_label=False, nr=None):
+ """Deprecated: given a name or label and optional disambiguating index
+ nr, toggle the matching item's selection.
+
+ Selecting items follows the behavior described in the docstring of the
+ 'get' method.
+
+ if the item is disabled, or this control is disabled or readonly,
+ raise AttributeError.
+
+ """
deprecation(
"item = control.get(...); item.selected = not item.selected")
o = self.get(name, by_label, nr)
self._set_selected_state(o, not o.selected)
def set(self, selected, name, by_label=False, nr=None):
+ """Deprecated: given a name or label and optional disambiguating index
+ nr, set the matching item's selection to the bool value of selected.
+
+ Selecting items follows the behavior described in the docstring of the
+ 'get' method.
+
+ if the item is disabled, or this control is disabled or readonly,
+ raise AttributeError.
+
+ """
deprecation(
"control.get(...).selected = <boolean>")
self._set_selected_state(self.get(name, by_label, nr), selected)
def _set_selected_state(self, item, action):
- """
- index: index of item
- action:
- bool False: off
- bool True: on
- """
+ # action:
+ # bool False: off
+ # bool True: on
if self.disabled:
raise AttributeError("control '%s' is disabled" % self.name)
if self.readonly:
@@ -1723,17 +1780,19 @@
if not action:
item.__dict__['_selected'] = action
else:
- selected = [o for o in self.items
- if o.selected and not o.disabled]
- # disabled items are not changeable but also not
- # 'successful': their names should not be sent to the
- # server, so they are effectively invisible, whether or not
- # the control considers itself to be selected
- for s in selected:
- s.__dict__['_selected'] = False
+ for o in self.items:
+ o.__dict__['_selected'] = False
item.__dict__['_selected'] = True
def toggle_single(self, by_label=None):
+ """Deprecated: toggle the selection of the single item in this control.
+
+ Raises ItemCountError if the control does not contain only one item.
+
+ by_label argument is ignored, and included only for backwards
+ compatibility.
+
+ """
deprecation(
"control.items[0].selected = not control.items[0].selected")
if len(self.items) != 1:
@@ -1743,6 +1802,14 @@
self._set_selected_state(item, not item.selected)
def set_single(self, selected, by_label=None):
+ """Deprecated: set the selection of the single item in this control.
+
+ Raises ItemCountError if the control does not contain only one item.
+
+ by_label argument is ignored, and included only for backwards
+ compatibility.
+
+ """
deprecation(
"control.items[0].selected = <boolean>")
if len(self.items) != 1:
@@ -1766,34 +1833,14 @@
"control.get(...).disabled = <boolean>")
self.get(name, by_label, nr).disabled = disabled
- def _set_item_disabled(self, item, disabled):
- if not self.multiple and item.selected and self.value:
- item.__dict__['_selected'] = False
- item.__dict__['_disabled'] = bool(disabled)
-
def set_all_items_disabled(self, disabled):
"""Set disabled state of all list items in a ListControl.
disabled: boolean disabled state
"""
- disabled = bool(disabled)
- if not self.multiple: # make sure that re-emerging items don't
- # make single-choice controls insane
- value = bool(self.value)
- for o in self.items:
- if not disabled and o.disabled:
- o.__dict__['_disabled'] = disabled
- if not self.multiple and o.selected:
- if value:
- o.selected = False
- else:
- value = True
- else:
- o.__dict__['_disabled'] = disabled
- else:
- for o in self.items:
- o.__dict__['_disabled'] = disabled
+ for o in self.items:
+ o.disabled = disabled
def get_item_attrs(self, name, by_label=False, nr=None):
"""Return dictionary of HTML attributes for a single ListControl item.
@@ -1806,6 +1853,7 @@
The returned dictionary maps HTML attribute names to values. The names
and values are taken from the original HTML.
+
"""
deprecation(
"control.get(...).attrs")
@@ -1946,23 +1994,31 @@
item.selected = True
def set_value_by_label(self, value):
+ """Set the value of control by item labels.
+
+ value is expected to be an iterable of strings that are substrings of
+ the item labels that should be selected. Ambiguous labels are accepted
+ as long as all ambiguous labels share the same item name.
+
+ """
if isstringlike(value):
raise TypeError(value)
items = []
for nn in value:
found = self.items_from_label(nn)
if len(found) > 1:
- # ambiguous labels are fine as long as values are same
+ # ambiguous labels are fine as long as item names (eg. OPTION
+ # values) are same
opt_name = found[0].name
- if [o for o in found[1:] if o != opt_name]:
+ if [o for o in found[1:] if o.name != opt_name]:
raise AmbiguityError(nn)
- for o in found: # for the multiple-item case, we could try to
- # be smarter, saving them up and trying to resolve, but that's
- # too much.
+ for o in found:
+ # For the multiple-item case, we could try to be smarter,
+ # saving them up and trying to resolve, but that's too much.
if o not in items:
items.append(o)
break
- else: # all of them are used
+ else: # all of them are used
raise ItemNotFoundError(nn)
# now we have all the items that should be on
# let's just turn everything off and then back on.
@@ -1971,6 +2027,7 @@
o.selected = True
def get_value_by_label(self):
+ """Return the value of the control as given by normalized labels."""
res = []
for o in self.items:
if not o.disabled and o.selected:
@@ -1983,6 +2040,11 @@
return res
def possible_items(self, by_label=False): # disabled are not possible
+ """Deprecated: return the names or labels of all possible items.
+
+ Includes disabled items, which may be misleading for some use cases.
+
+ """
deprecation(
"[item.name for item in self.items]")
if by_label:
@@ -2364,8 +2426,8 @@
Controls can be disabled or readonly. In either case, the control's value
cannot be changed until you clear those flags (see example below).
- Disabled is the state typically represented by browsers by `greying out' a
- control. Disabled controls are not `successful' -- they don't cause data
+ Disabled is the state typically represented by browsers by 'greying out' a
+ control. Disabled controls are not 'successful' -- they don't cause data
to get returned to the server. Readonly controls usually appear in
browsers as read-only text boxes. Readonly controls are successful. List
items can also be disabled. Attempts to select disabled items (with
More information about the wwwsearch-commits
mailing list