[Zope3-checkins] SVN: Zope3/branches/testbrowser-integration/src/zope/testbrowser/ - minor formatting: sort imports, add/remove whitespace, reorganize code

Benji York benji at zope.com
Tue Aug 23 11:06:56 EDT 2005


Log message for revision 38044:
  - minor formatting: sort imports, add/remove whitespace, reorganize code
  - add helpers for validating arguments
  - transmute .forms mapping into .getForm method
  - tests changes for above
  

Changed:
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt
  U   Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py

-=-
Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt	2005-08-23 14:06:13 UTC (rev 38043)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/README.txt	2005-08-23 15:06:56 UTC (rev 38044)
@@ -336,11 +336,11 @@
     >>> browser.getControl(label='Ambiguous Control', name='ambiguous-control-name')
     Traceback (most recent call last):
     ...
-    ValueError: Supply one and only one of 'label' and 'name' arguments
+    ValueError: Supply one and only one of "label" and "name" as arguments
     >>> browser.getControl()
     Traceback (most recent call last):
     ...
-    ValueError: Supply one and only one of 'label' and 'name' arguments
+    ValueError: Supply one and only one of "label" and "name" as arguments
 
 Radio and checkbox fields are unusual in that their labels and names may point
 to different objects: names point to logical collections of radio buttons or
@@ -869,7 +869,7 @@
 form has the same name or id, the first one will be returned.
 
     >>> browser.open('http://localhost/@@/testbrowser/forms.html')
-    >>> form = browser.forms['one']
+    >>> form = browser.getForm(name='one')
 
 The form exposes several attributes related to forms:
 
@@ -932,54 +932,36 @@
     AmbiguityError: label 'Text Control'
 
 I'll always get an ambiguous form field.  I can use the index argument, or
-with the `forms` mapping I can disambiguate by searching only within a given
+with the `getForm` method I can disambiguate by searching only within a given
 form:
 
-    >>> form = browser.forms['2']
+    >>> form = browser.getForm('2')
     >>> form.getControl(name='text-value').value
     'Second Text'
     >>> form.submit('Submit')
     >>> browser.contents
     '...<em>Second Text</em>...'
-    >>> form = browser.forms['2']
+    >>> form = browser.getForm('2')
     >>> form.getControl('Submit').click()
     >>> browser.contents
     '...<em>Second Text</em>...'
-    >>> browser.forms['3'].getControl('Text Control').value
+    >>> browser.getForm('3').getControl('Text Control').value
     'Third Text'
 
-The `forms` mapping also supports the check for containment
-
-    >>> 'three' in browser.forms
-    True
-
-and retrieval with optional default value:
-
-    >>> browser.forms.get('2')
-    <zope.testbrowser.browser.Form object at ...>
-    >>> browser.forms.get('invalid', 42)
-    42
-
 The last form on the page does not have a name, an id, or a submit button.
-Working with it is still easy, thanks to a values attribute that guarantees
+Working with it is still easy, thanks to a index attribute that guarantees
 order.  (Forms without submit buttons are sometimes useful for JavaScript.)
 
-    >>> form = browser.forms.values()[3]
+    >>> form = browser.getForm(index=3)
     >>> form.submit()
     >>> browser.contents
     '...<em>Fourth Text</em>...<em>Submitted without the submit button.</em>...'
 
-Other mapping attributes for the forms collection remain unimplemented.
-If useful, contributors implementing these would be welcome.
+If a form is requested that does not exists, an exception will be raised.
 
-    >>> browser.forms.items()
+    >>> form = browser.getForm('does-not-exist')
     Traceback (most recent call last):
-    ...
-    AttributeError: 'FormsMapping' object has no attribute 'items'
-    >>> browser.forms.keys()
-    Traceback (most recent call last):
-    ...
-    AttributeError: 'FormsMapping' object has no attribute 'keys'
+    LookupError
 
 Handling Errors
 ---------------

Modified: Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py
===================================================================
--- Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py	2005-08-23 14:06:13 UTC (rev 38043)
+++ Zope3/branches/testbrowser-integration/src/zope/testbrowser/browser.py	2005-08-23 15:06:56 UTC (rev 38044)
@@ -16,16 +16,16 @@
 $Id$
 """
 __docformat__ = "reStructuredText"
+from zope.testbrowser import interfaces
+import ClientForm
+import mechanize
+import operator
+import pullparser
 import re
 import StringIO
 import urllib2
-import mechanize
-import pullparser
-import ClientForm
 import zope.interface
 
-from zope.testbrowser import interfaces
-
 RegexType = type(re.compile(''))
 _compress_re = re.compile(r"\s+")
 compressText = lambda text: _compress_re.sub(' ', text.strip())
@@ -44,6 +44,33 @@
                 msg = '%s index %d' % (msg, index)
     raise LookupError(msg)
 
+def controlFactory(control, form, browser):
+    if isinstance(control, ClientForm.Item):
+        # it is a subcontrol
+        return ItemControl(control, form, browser)
+    else:
+        t = control.type
+        if t in ('checkbox', 'select', 'radio'):
+            return ListControl(control, form, browser)
+        elif t in ('submit', 'submitbutton'):
+            return SubmitControl(control, form, browser)
+        elif t=='image':
+            return ImageControl(control, form, browser)
+        else:
+            return Control(control, form, browser)
+
+def onlyOne(items, description):
+    total = sum([bool(i) for i in items])
+    if total == 0 or total > 1:
+        raise ValueError(
+            "Supply one and only one of %s as arguments" % description)
+
+def zeroOrOne(items, description):
+    if sum([bool(i) for i in items]) > 1:
+        raise ValueError(
+            "Supply no more than one of %s as arguments" % description)
+
+
 class Browser(object):
     """A web user agent."""
     zope.interface.implements(interfaces.IBrowser)
@@ -72,11 +99,6 @@
         return self.mech_browser.title()
 
     @property
-    def forms(self):
-        """See zope.testbrowser.interfaces.IBrowser"""
-        return FormsMapping(self)
-
-    @property
     def contents(self):
         """See zope.testbrowser.interfaces.IBrowser"""
         response = self.mech_browser.response()
@@ -193,9 +215,8 @@
         return controlFactory(control, form, self)
 
     def _get_all_controls(self, label, name, forms, include_subcontrols=False):
-        if not ((label is not None) ^ (name is not None)):
-            raise ValueError(
-                "Supply one and only one of 'label' and 'name' arguments")
+        onlyOne([label, name], '"label" and "name"')
+
         if label is not None:
             res = self._findByLabel(label, forms, include_subcontrols)
             msg = 'label %r' % label
@@ -204,15 +225,20 @@
             msg = 'name %r' % name
         return res, msg
         
-    def _findForm(self, id, name, action):
+    def getForm(self, id=None, name=None, action=None, index=None):
+        zeroOrOne([id, name, action], '"id", "name", and "action"')
+
+        matching_forms = []
         for form in self.mech_browser.forms():
             if ((id is not None and form.attrs.get('id') == id)
             or (name is not None and form.name == name)
-            or (action is not None and re.search(action, str(form.action)))):
-                self.mech_browser.form = form
-                return form
+            or (action is not None and re.search(action, str(form.action)))
+            or id == name == action == None):
+                matching_forms.append(form)
 
-        return None
+        form = disambiguate(matching_forms, '', index)
+        self.mech_browser.form = form
+        return Form(self, form)
         
     def _clickSubmit(self, form, control, coord):
         self.mech_browser.open(form.click(
@@ -221,6 +247,7 @@
     def _changed(self):
         self._counter += 1
 
+
 class Link(object):
     zope.interface.implements(interfaces.ILink)
 
@@ -255,6 +282,7 @@
         return "<%s text=%r url=%r>" % (
             self.__class__.__name__, self.text, self.url)
 
+
 class Control(object):
     """A control of a form."""
     zope.interface.implements(interfaces.IControl)
@@ -317,6 +345,7 @@
         return "<%s name=%r type=%r>" % (
             self.__class__.__name__, self.name, self.type)
 
+
 class ListControl(Control):
     zope.interface.implements(interfaces.IListControl)
 
@@ -372,9 +401,9 @@
     def getControl(self, label=None, value=None, index=None):
         if self._browser_counter != self.browser._counter:
             raise interfaces.ExpiredError
-        if not ((label is not None) ^ (value is not None)):
-            raise ValueError(
-                "Supply one and only one of 'label' and 'value' arguments")
+
+        onlyOne([label, value], '"label" and "value"')
+
         if label is not None:
             options = self.mech_control.items_from_label(label)
             msg = 'label %r' % label
@@ -386,6 +415,7 @@
         res.__dict__['control'] = self
         return res
 
+
 class SubmitControl(Control):
     zope.interface.implements(interfaces.ISubmitControl)
 
@@ -395,6 +425,7 @@
         self.browser._clickSubmit(self.mech_form, self.mech_control, (1,1))
         self.browser._changed()
 
+
 class ImageControl(Control):
     zope.interface.implements(interfaces.IImageSubmitControl)
 
@@ -404,6 +435,7 @@
         self.browser._clickSubmit(self.mech_form, self.mech_control, coord)
         self.browser._changed()
 
+
 class ItemControl(object):
     zope.interface.implements(interfaces.IItemControl)
 
@@ -454,58 +486,7 @@
             self.__class__.__name__, self.mech_item.control.name,
             self.mech_item.control.type, self.optionValue)
 
-def controlFactory(control, form, browser):
-    if isinstance(control, ClientForm.Item):
-        # it is a subcontrol
-        return ItemControl(control, form, browser)
-    else:
-        t = control.type
-        if t in ('checkbox', 'select', 'radio'):
-            return ListControl(control, form, browser)
-        elif t in ('submit', 'submitbutton'):
-            return SubmitControl(control, form, browser)
-        elif t=='image':
-            return ImageControl(control, form, browser)
-        else:
-            return Control(control, form, browser)
 
-class FormsMapping(object):
-    """All forms on the page of the browser."""
-    zope.interface.implements(interfaces.IFormsMapping)
-    
-    def __init__(self, browser):
-        self.browser = browser
-        self._browser_counter = self.browser._counter
-
-    def __getitem__(self, key):
-        """See zope.interface.common.mapping.IItemMapping"""
-        if self._browser_counter != self.browser._counter:
-            raise interfaces.ExpiredError
-        form = self.browser._findForm(key, key, None)
-        if form is None:
-            raise KeyError(key)
-        return Form(self.browser, form)
-
-    def get(self, key, default=None):
-        """See zope.interface.common.mapping.IReadMapping"""
-        try:
-            return self[key]
-        except KeyError:
-            return default
-
-    def __contains__(self, key):
-        """See zope.interface.common.mapping.IReadMapping"""
-        if self._browser_counter != self.browser._counter:
-            raise interfaces.ExpiredError
-        return self.browser._findForm(key, key, None) is not None
-
-    def values(self):
-        if self._browser_counter != self.browser._counter:
-            raise interfaces.ExpiredError
-        return [Form(self.browser, form) for form in
-                self.browser.mech_browser.forms()]
-
-
 class Form(object):
     """HTML Form"""
     zope.interface.implements(interfaces.IForm)



More information about the Zope3-Checkins mailing list