[Checkins] SVN: zope.testbrowser/trunk/ LP #721252: AmbiguityError now shows all matching controls.

Marius Gedminas marius at pov.lt
Fri Feb 18 08:12:53 EST 2011


Log message for revision 120420:
  LP #721252: AmbiguityError now shows all matching controls.
  
  

Changed:
  U   zope.testbrowser/trunk/CHANGES.txt
  U   zope.testbrowser/trunk/src/zope/testbrowser/README.txt
  U   zope.testbrowser/trunk/src/zope/testbrowser/browser.py

-=-
Modified: zope.testbrowser/trunk/CHANGES.txt
===================================================================
--- zope.testbrowser/trunk/CHANGES.txt	2011-02-18 10:26:57 UTC (rev 120419)
+++ zope.testbrowser/trunk/CHANGES.txt	2011-02-18 13:12:52 UTC (rev 120420)
@@ -5,7 +5,7 @@
 3.11.2 (unreleased)
 -------------------
 
-- Nothing changed yet.
+- LP #721252: AmbiguityError now shows all matching controls.
 
 
 3.11.1 (2011-01-24)

Modified: zope.testbrowser/trunk/src/zope/testbrowser/README.txt
===================================================================
--- zope.testbrowser/trunk/src/zope/testbrowser/README.txt	2011-02-18 10:26:57 UTC (rev 120419)
+++ zope.testbrowser/trunk/src/zope/testbrowser/README.txt	2011-02-18 13:12:52 UTC (rev 120420)
@@ -463,7 +463,9 @@
     >>> browser.getControl('Ambiguous Control')
     Traceback (most recent call last):
     ...
-    AmbiguityError: label 'Ambiguous Control'
+    AmbiguityError: label 'Ambiguous Control' matches:
+      <TextControl(ambiguous-control-name=First)>
+      <TextControl(ambiguous-control-name=Second)>
 
 This is also true if an option in a control is ambiguous in relation to
 the control itself.
@@ -471,7 +473,9 @@
     >>> browser.getControl('Sub-control Ambiguity')
     Traceback (most recent call last):
     ...
-    AmbiguityError: label 'Sub-control Ambiguity'
+    AmbiguityError: label 'Sub-control Ambiguity' matches:
+      <SelectControl(ambiguous-subcontrol=[*, ambiguous])>
+      <Item name='ambiguous' id=None contents='Sub-control Ambiguity Exemplified' value='ambiguous' label='Sub-control Ambiguity Exemplified'>
 
 Ambiguous controls may be specified using an index value.  We use the control's
 value attribute to show the two controls; this attribute is properly introduced
@@ -536,7 +540,9 @@
     >>> browser.getControl(name='ambiguous-control-name')
     Traceback (most recent call last):
     ...
-    AmbiguityError: name 'ambiguous-control-name'
+    AmbiguityError: name 'ambiguous-control-name' matches:
+      <TextControl(ambiguous-control-name=First)>
+      <TextControl(ambiguous-control-name=Second)>
     >>> browser.getControl(name='does-not-exist')
     Traceback (most recent call last):
     ...
@@ -675,7 +681,11 @@
     >>> browser.getControl('Third') # ambiguous in the browser, so useful
     Traceback (most recent call last):
     ...
-    AmbiguityError: label 'Third'
+    AmbiguityError: label 'Third' matches:
+      <Item name='3' id=None contents='Tres' value='3' label='Third'>
+      <Item name='3' id=None contents='Trois' value='3' label='Third'>
+      <Item name='3' id='multi-checkbox-value-3' __label={'__text': 'Three\n        '} checked='checked' name='multi-checkbox-value' type='checkbox' id='multi-checkbox-value-3' value='3'>
+      <Item name='3' id='radio-value-3' __label={'__text': ' Drei'} type='radio' name='radio-value' value='3' id='radio-value-3'>
 
 Finally, submit controls provide ISubmitControl, and image controls provide
 IImageSubmitControl, which extents ISubmitControl.  These both simply add a
@@ -1185,11 +1195,17 @@
     >>> browser.getControl(name='text-value')
     Traceback (most recent call last):
     ...
-    AmbiguityError: name 'text-value'
+    AmbiguityError: name 'text-value' matches:
+      <TextControl(text-value=First Text)>
+      <TextControl(text-value=Second Text)>
+      <TextControl(text-value=Third Text)>
+      <TextControl(text-value=Fourth Text)>
     >>> browser.getControl('Text Control')
     Traceback (most recent call last):
     ...
-    AmbiguityError: label 'Text Control'
+    AmbiguityError: label 'Text Control' matches:
+      <TextControl(text-value=Third Text)>
+      <TextControl(text-value=Fourth Text)>
 
 I'll always get an ambiguous form field.  I can use the index argument, or
 with the `getForm` method I can disambiguate by searching only within a given

Modified: zope.testbrowser/trunk/src/zope/testbrowser/browser.py
===================================================================
--- zope.testbrowser/trunk/src/zope/testbrowser/browser.py	2011-02-18 10:26:57 UTC (rev 120419)
+++ zope.testbrowser/trunk/src/zope/testbrowser/browser.py	2011-02-18 13:12:52 UTC (rev 120420)
@@ -33,10 +33,14 @@
 _compress_re = re.compile(r"\s+")
 compressText = lambda text: _compress_re.sub(' ', text.strip())
 
-def disambiguate(intermediate, msg, index):
+def disambiguate(intermediate, msg, index, choice_repr=None):
     if intermediate:
         if index is None:
             if len(intermediate) > 1:
+                if choice_repr:
+                    msg += ' matches:' + ''.join([
+                                '\n  %s' % choice_repr(choice)
+                                for choice in intermediate])
                 raise mechanize.AmbiguityError(msg)
             else:
                 return intermediate[0]
@@ -47,6 +51,15 @@
                 msg = '%s index %d' % (msg, index)
     raise LookupError(msg)
 
+def control_form_tuple_repr((ctrl, form)):
+    if isinstance(ctrl, mechanize._form.Control):
+        # mechanize._form controls have a useful __str__ and a useless __repr__
+        return str(ctrl)
+    else:
+        # mechanize._form list control items have a useful __repr__ and a
+        # too-terse __str__.
+        return repr(ctrl)
+
 def controlFactory(control, form, browser):
     if isinstance(control, mechanize.Item):
         # it is a subcontrol
@@ -368,7 +381,8 @@
         """See zope.testbrowser.interfaces.IBrowser"""
         intermediate, msg = self._get_all_controls(
             label, name, self.mech_browser.forms(), include_subcontrols=True)
-        control, form = disambiguate(intermediate, msg, index)
+        control, form = disambiguate(intermediate, msg, index,
+                                     control_form_tuple_repr)
         return controlFactory(control, form, self)
 
     def _get_all_controls(self, label, name, forms, include_subcontrols=False):
@@ -624,7 +638,8 @@
             options = self.mech_control.get_items(name=value)
             msg = 'value %r' % value
         res = controlFactory(
-            disambiguate(options, msg, index), self.mech_form, self.browser)
+            disambiguate(options, msg, index, control_form_tuple_repr),
+            self.mech_form, self.browser)
         res.__dict__['control'] = self
         return res
 
@@ -753,7 +768,8 @@
                 intermediate = [
                     (control, form) for (control, form) in intermediate if
                     control.type in ('submit', 'submitbutton', 'image')]
-                control, form = disambiguate(intermediate, msg, index)
+                control, form = disambiguate(intermediate, msg, index,
+                                             control_form_tuple_repr)
                 self.browser._clickSubmit(form, control, coord)
             else: # JavaScript sort of submit
                 if index is not None or coord != (1,1):
@@ -778,5 +794,6 @@
             raise zope.testbrowser.interfaces.ExpiredError
         intermediate, msg = self.browser._get_all_controls(
             label, name, (self.mech_form,), include_subcontrols=True)
-        control, form = disambiguate(intermediate, msg, index)
+        control, form = disambiguate(intermediate, msg, index,
+                                     control_form_tuple_repr)
         return controlFactory(control, form, self.browser)



More information about the checkins mailing list