[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