[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