[Checkins] SVN: zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/ Attempt to avoid subversion bailing ungraciously on multiple tree conflicts when I try merge.

Brian Sutherland jinty at web.de
Sun Jan 30 06:36:35 EST 2011


Log message for revision 120000:
  Attempt to avoid subversion bailing ungraciously on multiple tree conflicts when I try merge.

Changed:
  D   zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests.py
  A   zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests_old.py
  A   zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/webtest.py
  D   zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/wsgi.py

-=-
Deleted: zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests.py
===================================================================
--- zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests.py	2011-01-30 11:22:24 UTC (rev 119999)
+++ zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests.py	2011-01-30 11:36:35 UTC (rev 120000)
@@ -1,531 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2004 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""Real test for file-upload and beginning of a better internal test framework
-"""
-import unittest
-import cStringIO
-import doctest
-import httplib
-import mechanize
-import os
-import re
-import socket
-import sys
-
-from webtest import TestApp
-from zope.app.testing.functional import FunctionalDocFileSuite
-import zope.app.testing.functional
-import zope.testing.renormalizing
-
-import zope.testbrowser.browser
-from zope.testbrowser.testing import Browser as TestingBrowser
-from zope.testbrowser.wsgi import Browser as WSGIBrowser
-from zope.testbrowser.ftests.wsgitestapp import WSGITestApplication
-
-def set_next_response(body, headers=None, status='200', reason='OK'):
-    global next_response_body
-    global next_response_headers
-    global next_response_status
-    global next_response_reason
-    if headers is None:
-        headers = (
-            'Content-Type: text/html\r\n'
-            'Content-Length: %s\r\n'
-            % len(body))
-    next_response_body = body
-    next_response_headers = headers
-    next_response_status = status
-    next_response_reason = reason
-
-
-class FauxConnection(object):
-    """A ``mechanize`` compatible connection object."""
-
-    def __init__(self, host, timeout=None):
-        pass
-
-    def set_debuglevel(self, level):
-        pass
-
-    def _quote(self, url):
-        # the publisher expects to be able to split on whitespace, so we have
-        # to make sure there is none in the URL
-        return url.replace(' ', '%20')
-
-    def request(self, method, url, body=None, headers=None):
-        if body is None:
-            body = ''
-
-        if url == '':
-            url = '/'
-
-        url = self._quote(url)
-
-        # Construct the headers.
-        header_chunks = []
-        if headers is not None:
-            for header in headers.items():
-                header_chunks.append('%s: %s' % header)
-            headers = '\n'.join(header_chunks) + '\n'
-        else:
-            headers = ''
-
-        # Construct the full HTTP request string, since that is what the
-        # ``HTTPCaller`` wants.
-        request_string = (method + ' ' + url + ' HTTP/1.1\n'
-                          + headers + '\n' + body)
-
-        print request_string.replace('\r', '')
-
-    def getresponse(self):
-        """Return a ``mechanize`` compatible response.
-
-        The goal of this method is to convert the Zope Publisher's response to
-        a ``mechanize`` compatible response, which is also understood by
-        mechanize.
-        """
-        return FauxResponse(next_response_body,
-                            next_response_headers,
-                            next_response_status,
-                            next_response_reason,
-                            )
-
-
-class FauxResponse(object):
-
-    def __init__(self, content, headers, status, reason):
-        self.content = content
-        self.status = status
-        self.reason = reason
-        self.msg = httplib.HTTPMessage(cStringIO.StringIO(headers), 0)
-        self.content_as_file = cStringIO.StringIO(self.content)
-
-    def read(self, amt=None):
-        return self.content_as_file.read(amt)
-
-    def close(self):
-        """To overcome changes in mechanize and socket in python2.5"""
-        pass
-
-
-class FauxHTTPHandler(mechanize.HTTPHandler):
-
-    http_request = mechanize.HTTPHandler.do_request_
-
-    def http_open(self, req):
-        """Open an HTTP connection having a ``mechanize`` request."""
-        # Here we connect to the publisher.
-
-        if sys.version_info > (2, 6) and not hasattr(req, 'timeout'):
-            # Workaround mechanize incompatibility with Python
-            # 2.6. See: LP #280334
-            req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
-        return self.do_open(FauxConnection, req)
-
-
-class FauxMechanizeBrowser(mechanize.Browser):
-
-    handler_classes = {
-        # scheme handlers
-        "http": FauxHTTPHandler,
-
-        "_http_error": mechanize.HTTPErrorProcessor,
-        "_http_default_error": mechanize.HTTPDefaultErrorHandler,
-
-        # feature handlers
-        "_authen": mechanize.HTTPBasicAuthHandler,
-        "_redirect": mechanize.HTTPRedirectHandler,
-        "_cookies": mechanize.HTTPCookieProcessor,
-        "_refresh": mechanize.HTTPRefreshProcessor,
-        "_referer": mechanize.Browser.handler_classes['_referer'],
-        "_equiv": mechanize.HTTPEquivProcessor,
-        }
-
-    default_schemes = ["http"]
-    default_others = ["_http_error", "_http_default_error"]
-    default_features = ["_authen", "_redirect", "_cookies"]
-
-
-class Browser(zope.testbrowser.browser.Browser):
-
-    def __init__(self, url=None):
-        mech_browser = FauxMechanizeBrowser()
-        super(Browser, self).__init__(url=url, mech_browser=mech_browser)
-
-    def open(self, body, headers=None, status=200, reason='OK',
-             url='http://localhost/'):
-        set_next_response(body, headers, status, reason)
-        zope.testbrowser.browser.Browser.open(self, url)
-
-
-def test_submit_duplicate_name():
-    """
-    This test was inspired by bug #723 as testbrowser would pick up the wrong
-    button when having the same name twice in a form.
-
-    >>> browser = Browser()
-
-
-    When given a form with two submit buttons that have the same name:
-
-    >>> browser.open('''\
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <input type="submit" name="submit_me" value="GOOD" />
-    ...      <input type="submit" name="submit_me" value="BAD" />
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-
-    We can specify the second button through it's label/value:
-
-    >>> browser.getControl('BAD')
-    <SubmitControl name='submit_me' type='submit'>
-    >>> browser.getControl('BAD').value
-    'BAD'
-    >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF +ELLIPSIS
-    POST / HTTP/1.1
-    ...
-    Content-type: multipart/form-data; ...
-    Content-disposition: form-data; name="submit_me"
-    <BLANKLINE>
-    BAD
-    ...
-
-
-    This also works if the labels have whitespace around them (this tests a
-    regression caused by the original fix for the above):
-
-    >>> browser.open('''\
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <input type="submit" name="submit_me" value=" GOOD " />
-    ...      <input type="submit" name="submit_me" value=" BAD " />
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-    >>> browser.getControl('BAD')
-    <SubmitControl name='submit_me' type='submit'>
-    >>> browser.getControl('BAD').value
-    ' BAD '
-    >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF +ELLIPSIS
-    POST / HTTP/1.1
-    ...
-    Content-type: multipart/form-data; ...
-    Content-disposition: form-data; name="submit_me"
-    <BLANKLINE>
-     BAD 
-    ...
-"""
-
-
-def test_file_upload():
-    """
-
-    >>> browser = Browser()
-
-
-    When given a form with a file-upload
-
-    >>> browser.open('''\
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <input name="foo" type="file" />
-    ...      <input type="submit" value="OK" />
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-
-    Fill in the form value using add_file:
-
-    >>> browser.getControl(name='foo').add_file(
-    ...     cStringIO.StringIO('sample_data'), 'text/foo', 'x.foo')
-    >>> browser.getControl('OK').click() # doctest: +REPORT_NDIFF +ELLIPSIS
-    POST / HTTP/1.1
-    ...
-    Content-type: multipart/form-data; ...
-    Content-disposition: form-data; name="foo"; filename="x.foo"
-    Content-type: text/foo
-    <BLANKLINE>
-    sample_data
-    ...
-
-
-    You can pass a string to add_file:
-
-    >>> browser.getControl(name='foo').add_file(
-    ...     'blah blah blah', 'text/blah', 'x.blah')
-    >>> browser.getControl('OK').click() # doctest: +REPORT_NDIFF +ELLIPSIS
-    POST / HTTP/1.1
-    ...
-    Content-type: multipart/form-data; ...
-    Content-disposition: form-data; name="foo"; filename="x.blah"
-    Content-type: text/blah
-    <BLANKLINE>
-    blah blah blah
-    ...
-    """
-
-def test_submit_gets_referrer():
-    """
-    Test for bug #98437: No HTTP_REFERER was sent when submitting a form.
-
-    >>> browser = Browser()
-
-
-    A simple form for testing, like abobe.
-
-    >>> browser.open('''\
-    ... <html><body>
-    ...   <form id="form" action="." method="post"
-    ...                   enctype="multipart/form-data">
-    ...      <input type="submit" name="submit_me" value="GOOD" />
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-
-    Now submit the form, and see that we get an referrer along:
-
-    >>> form = browser.getForm(id='form')
-    >>> form.submit(name='submit_me') # doctest: +ELLIPSIS
-    POST / HTTP/1.1
-    ...
-    Referer: http://localhost/
-    ...
-"""
-
-
-def test_new_instance_no_contents_should_not_fail(self):
-    """
-    When first instantiated, the browser has no contents.
-    (Regression test for <http://bugs.launchpad.net/zope3/+bug/419119>)
-
-    >>> browser = Browser()
-    >>> print browser.contents
-    None
-    """
-
-
-def test_strip_linebreaks_from_textarea(self):
-    """
-    >>> browser = Browser()
-
-    According to http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 line
-    break immediately after start tags or immediately before end tags must be
-    ignored, but real browsers only ignore a line break after a start tag.
-    So if we give the following form:
-
-    >>> browser.open('''
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <textarea name="textarea">
-    ... Foo
-    ... </textarea>
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-
-    The value of the textarea won't contain the first line break:
-
-    >>> browser.getControl(name='textarea').value
-    'Foo\\n'
-
-
-    Of course, if we add line breaks, so that there are now two line breaks
-    after the start tag, the textarea value will start and end with a line
-    break.
-
-    >>> browser.open('''
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <textarea name="textarea">
-    ...
-    ... Foo
-    ... </textarea>
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-    >>> browser.getControl(name='textarea').value
-    '\\nFoo\\n'
-
-
-    Also, if there is some other whitespace after the start tag, it will be
-    preserved.
-
-    >>> browser.open('''
-    ... <html><body>
-    ...   <form action="." method="post" enctype="multipart/form-data">
-    ...      <textarea name="textarea">  Foo  </textarea>
-    ...   </form></body></html>
-    ... ''') # doctest: +ELLIPSIS
-    GET / HTTP/1.1
-    ...
-
-    >>> browser.getControl(name='textarea').value
-    '  Foo  '
-    """
-
-
-def test_relative_link():
-    """
-    RFC 1808 specifies how relative URLs should be resolved, let's see
-    that we conform to it. Let's start with a simple example.
-
-    >>> browser = Browser()
-    >>> browser.open('''\
-    ... <html><body>
-    ...     <a href="foo">link</a>
-    ... </body></html>
-    ... ''', url='http://localhost/bar') # doctest: +ELLIPSIS
-    GET /bar HTTP/1.1
-    ...
-
-    >>> link = browser.getLink('link')
-    >>> link.url
-    'http://localhost/foo'
-
-
-    It's possible to have a relative URL consisting of only a query part. In
-    that case it should simply be appended to the base URL.
-
-    >>> browser.open('''\
-    ... <html><body>
-    ...     <a href="?key=value">link</a>
-    ... </body></html>
-    ... ''', url='http://localhost/bar') # doctest: +ELLIPSIS
-    GET /bar HTTP/1.1
-    ...
-
-    >>> link = browser.getLink('link')
-    >>> link.url
-    'http://localhost/bar?key=value'
-
-
-    In the example above, the base URL was the page URL, but we can also
-    specify a base URL using a <base> tag.
-
-    >>> browser.open('''\
-    ... <html><head><base href="http://localhost/base" /></head><body>
-    ...     <a href="?key=value">link</a>
-    ... </body></html>
-    ... ''', url='http://localhost/base/bar') # doctest: +ELLIPSIS
-    GET /base/bar HTTP/1.1
-    ...
-
-    >>> link = browser.getLink('link')
-    >>> link.url
-    'http://localhost/base?key=value'
-    """
-
-
-class win32CRLFtransformer(object):
-    def sub(self, replacement, text):
-        return text.replace(r'\r', '')
-
-checker = zope.testing.renormalizing.RENormalizing([
-    (re.compile(r'^--\S+\.\S+\.\S+', re.M), '-' * 30),
-    (re.compile(r'boundary=\S+\.\S+\.\S+'), 'boundary=' + '-' * 30),
-    (re.compile(r'^---{10}.*', re.M), '-' * 30),
-    (re.compile(r'boundary=-{10}.*'), 'boundary=' + '-' * 30),
-    (re.compile(r'User-agent:\s+\S+'), 'User-agent: Python-urllib/2.4'),
-    (re.compile(r'HTTP_USER_AGENT:\s+\S+'),
-     'HTTP_USER_AGENT: Python-urllib/2.4'),
-    (re.compile(r'Content-[Ll]ength:.*'), 'Content-Length: 123'),
-    (re.compile(r'Status: 200.*'), 'Status: 200 OK'),
-    (win32CRLFtransformer(), None),
-    (re.compile(r'User-Agent: Python-urllib/2.5'),
-     'User-agent: Python-urllib/2.4'),
-    (re.compile(r'User-Agent: Python-urllib/2.6'),
-     'User-agent: Python-urllib/2.4'),
-    (re.compile(r'Host: localhost'), 'Connection: close'),
-    (re.compile(r'Content-Type: '), 'Content-type: '),
-    (re.compile(r'Content-Disposition: '), 'Content-disposition: '),
-    (re.compile(r'; charset=UTF-8'), ';charset=utf-8'),
-    # webtest quotes cookies differently to zope.publisher
-    (re.compile(r'\'comment\': \'"silly billy"\','), "'comment': 'silly%20billy',"),
-    # webtest seems to expire cookies one second before the date set in set_cookie
-    (re.compile(r"'expires': datetime.datetime\(2029, 12, 31, 23, 59, 59, tzinfo=<UTC>\),"), "'expires': datetime.datetime(2030, 1, 1, 0, 0, tzinfo=<UTC>),"),
-    (re.compile(r"Object: <WSGI application>,"), "Object: <zope.site.folder.Folder object at ...>,"),
-    ])
-
-TestBrowserLayer = zope.app.testing.functional.ZCMLLayer(
-    os.path.join(os.path.split(__file__)[0], 'ftests/ftesting.zcml'),
-    __name__, 'TestBrowserLayer', allow_teardown=True)
-
-
-def test_suite():
-    flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
-
-    this_file = doctest.DocTestSuite(checker=checker)
-    wire = doctest.DocFileSuite('over_the_wire.txt', optionflags=flags)
-    wire.level = 2
-
-    tests = [this_file, wire]
-
-    # Zope Publisher Tests
-    zope_publisher = FunctionalDocFileSuite('zope-publisher.txt', optionflags=flags,
-        checker=checker)
-    zope_publisher.layer = TestBrowserLayer
-
-    tests.append(zope_publisher)
-
-    # WSGI Browser tests
-    def make_browser(*args, **kw):
-        app = WSGITestApplication()
-        test_app = TestApp(app)
-        return WSGIBrowser(test_app, *args, **kw)
-    globals = dict(Browser=make_browser)
-
-    readme = doctest.DocFileSuite('README.txt', optionflags=flags,
-        checker=checker, globs=globals)
-
-    cookies = doctest.DocFileSuite('cookies.txt', optionflags=flags,
-        checker=checker, globs=globals)
-
-    fixed_bugs = doctest.DocFileSuite('fixed-bugs.txt', optionflags=flags,
-        globs=globals)
-
-    wsgi = doctest.DocFileSuite('wsgi.txt', optionflags=flags,
-        checker=checker, globs=globals)
-
-    tests.extend([readme, cookies, fixed_bugs, wsgi])
-
-    return unittest.TestSuite(tests)
-
-
-def run_suite(suite):
-    runner = unittest.TextTestRunner(sys.stdout, verbosity=1)
-    result = runner.run(suite)
-    if not result.wasSuccessful():
-        if len(result.errors) == 1 and not result.failures:
-            err = result.errors[0][1]
-        elif len(result.failures) == 1 and not result.errors:
-            err = result.failures[0][1]
-        else:
-            err = "errors occurred; run in verbose mode for details"
-        print err
-
-if __name__ == "__main__":
-    run_suite(test_suite())

Copied: zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests_old.py (from rev 119678, zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests.py)
===================================================================
--- zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests_old.py	                        (rev 0)
+++ zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/tests_old.py	2011-01-30 11:36:35 UTC (rev 120000)
@@ -0,0 +1,531 @@
+##############################################################################
+#
+# Copyright (c) 2004 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Real test for file-upload and beginning of a better internal test framework
+"""
+import unittest
+import cStringIO
+import doctest
+import httplib
+import mechanize
+import os
+import re
+import socket
+import sys
+
+from webtest import TestApp
+from zope.app.testing.functional import FunctionalDocFileSuite
+import zope.app.testing.functional
+import zope.testing.renormalizing
+
+import zope.testbrowser.browser
+from zope.testbrowser.testing import Browser as TestingBrowser
+from zope.testbrowser.wsgi import Browser as WSGIBrowser
+from zope.testbrowser.ftests.wsgitestapp import WSGITestApplication
+
+def set_next_response(body, headers=None, status='200', reason='OK'):
+    global next_response_body
+    global next_response_headers
+    global next_response_status
+    global next_response_reason
+    if headers is None:
+        headers = (
+            'Content-Type: text/html\r\n'
+            'Content-Length: %s\r\n'
+            % len(body))
+    next_response_body = body
+    next_response_headers = headers
+    next_response_status = status
+    next_response_reason = reason
+
+
+class FauxConnection(object):
+    """A ``mechanize`` compatible connection object."""
+
+    def __init__(self, host, timeout=None):
+        pass
+
+    def set_debuglevel(self, level):
+        pass
+
+    def _quote(self, url):
+        # the publisher expects to be able to split on whitespace, so we have
+        # to make sure there is none in the URL
+        return url.replace(' ', '%20')
+
+    def request(self, method, url, body=None, headers=None):
+        if body is None:
+            body = ''
+
+        if url == '':
+            url = '/'
+
+        url = self._quote(url)
+
+        # Construct the headers.
+        header_chunks = []
+        if headers is not None:
+            for header in headers.items():
+                header_chunks.append('%s: %s' % header)
+            headers = '\n'.join(header_chunks) + '\n'
+        else:
+            headers = ''
+
+        # Construct the full HTTP request string, since that is what the
+        # ``HTTPCaller`` wants.
+        request_string = (method + ' ' + url + ' HTTP/1.1\n'
+                          + headers + '\n' + body)
+
+        print request_string.replace('\r', '')
+
+    def getresponse(self):
+        """Return a ``mechanize`` compatible response.
+
+        The goal of this method is to convert the Zope Publisher's response to
+        a ``mechanize`` compatible response, which is also understood by
+        mechanize.
+        """
+        return FauxResponse(next_response_body,
+                            next_response_headers,
+                            next_response_status,
+                            next_response_reason,
+                            )
+
+
+class FauxResponse(object):
+
+    def __init__(self, content, headers, status, reason):
+        self.content = content
+        self.status = status
+        self.reason = reason
+        self.msg = httplib.HTTPMessage(cStringIO.StringIO(headers), 0)
+        self.content_as_file = cStringIO.StringIO(self.content)
+
+    def read(self, amt=None):
+        return self.content_as_file.read(amt)
+
+    def close(self):
+        """To overcome changes in mechanize and socket in python2.5"""
+        pass
+
+
+class FauxHTTPHandler(mechanize.HTTPHandler):
+
+    http_request = mechanize.HTTPHandler.do_request_
+
+    def http_open(self, req):
+        """Open an HTTP connection having a ``mechanize`` request."""
+        # Here we connect to the publisher.
+
+        if sys.version_info > (2, 6) and not hasattr(req, 'timeout'):
+            # Workaround mechanize incompatibility with Python
+            # 2.6. See: LP #280334
+            req.timeout = socket._GLOBAL_DEFAULT_TIMEOUT
+        return self.do_open(FauxConnection, req)
+
+
+class FauxMechanizeBrowser(mechanize.Browser):
+
+    handler_classes = {
+        # scheme handlers
+        "http": FauxHTTPHandler,
+
+        "_http_error": mechanize.HTTPErrorProcessor,
+        "_http_default_error": mechanize.HTTPDefaultErrorHandler,
+
+        # feature handlers
+        "_authen": mechanize.HTTPBasicAuthHandler,
+        "_redirect": mechanize.HTTPRedirectHandler,
+        "_cookies": mechanize.HTTPCookieProcessor,
+        "_refresh": mechanize.HTTPRefreshProcessor,
+        "_referer": mechanize.Browser.handler_classes['_referer'],
+        "_equiv": mechanize.HTTPEquivProcessor,
+        }
+
+    default_schemes = ["http"]
+    default_others = ["_http_error", "_http_default_error"]
+    default_features = ["_authen", "_redirect", "_cookies"]
+
+
+class Browser(zope.testbrowser.browser.Browser):
+
+    def __init__(self, url=None):
+        mech_browser = FauxMechanizeBrowser()
+        super(Browser, self).__init__(url=url, mech_browser=mech_browser)
+
+    def open(self, body, headers=None, status=200, reason='OK',
+             url='http://localhost/'):
+        set_next_response(body, headers, status, reason)
+        zope.testbrowser.browser.Browser.open(self, url)
+
+
+def test_submit_duplicate_name():
+    """
+    This test was inspired by bug #723 as testbrowser would pick up the wrong
+    button when having the same name twice in a form.
+
+    >>> browser = Browser()
+
+
+    When given a form with two submit buttons that have the same name:
+
+    >>> browser.open('''\
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <input type="submit" name="submit_me" value="GOOD" />
+    ...      <input type="submit" name="submit_me" value="BAD" />
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+
+    We can specify the second button through it's label/value:
+
+    >>> browser.getControl('BAD')
+    <SubmitControl name='submit_me' type='submit'>
+    >>> browser.getControl('BAD').value
+    'BAD'
+    >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF +ELLIPSIS
+    POST / HTTP/1.1
+    ...
+    Content-type: multipart/form-data; ...
+    Content-disposition: form-data; name="submit_me"
+    <BLANKLINE>
+    BAD
+    ...
+
+
+    This also works if the labels have whitespace around them (this tests a
+    regression caused by the original fix for the above):
+
+    >>> browser.open('''\
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <input type="submit" name="submit_me" value=" GOOD " />
+    ...      <input type="submit" name="submit_me" value=" BAD " />
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+    >>> browser.getControl('BAD')
+    <SubmitControl name='submit_me' type='submit'>
+    >>> browser.getControl('BAD').value
+    ' BAD '
+    >>> browser.getControl('BAD').click() # doctest: +REPORT_NDIFF +ELLIPSIS
+    POST / HTTP/1.1
+    ...
+    Content-type: multipart/form-data; ...
+    Content-disposition: form-data; name="submit_me"
+    <BLANKLINE>
+     BAD 
+    ...
+"""
+
+
+def test_file_upload():
+    """
+
+    >>> browser = Browser()
+
+
+    When given a form with a file-upload
+
+    >>> browser.open('''\
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <input name="foo" type="file" />
+    ...      <input type="submit" value="OK" />
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+
+    Fill in the form value using add_file:
+
+    >>> browser.getControl(name='foo').add_file(
+    ...     cStringIO.StringIO('sample_data'), 'text/foo', 'x.foo')
+    >>> browser.getControl('OK').click() # doctest: +REPORT_NDIFF +ELLIPSIS
+    POST / HTTP/1.1
+    ...
+    Content-type: multipart/form-data; ...
+    Content-disposition: form-data; name="foo"; filename="x.foo"
+    Content-type: text/foo
+    <BLANKLINE>
+    sample_data
+    ...
+
+
+    You can pass a string to add_file:
+
+    >>> browser.getControl(name='foo').add_file(
+    ...     'blah blah blah', 'text/blah', 'x.blah')
+    >>> browser.getControl('OK').click() # doctest: +REPORT_NDIFF +ELLIPSIS
+    POST / HTTP/1.1
+    ...
+    Content-type: multipart/form-data; ...
+    Content-disposition: form-data; name="foo"; filename="x.blah"
+    Content-type: text/blah
+    <BLANKLINE>
+    blah blah blah
+    ...
+    """
+
+def test_submit_gets_referrer():
+    """
+    Test for bug #98437: No HTTP_REFERER was sent when submitting a form.
+
+    >>> browser = Browser()
+
+
+    A simple form for testing, like abobe.
+
+    >>> browser.open('''\
+    ... <html><body>
+    ...   <form id="form" action="." method="post"
+    ...                   enctype="multipart/form-data">
+    ...      <input type="submit" name="submit_me" value="GOOD" />
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+
+    Now submit the form, and see that we get an referrer along:
+
+    >>> form = browser.getForm(id='form')
+    >>> form.submit(name='submit_me') # doctest: +ELLIPSIS
+    POST / HTTP/1.1
+    ...
+    Referer: http://localhost/
+    ...
+"""
+
+
+def test_new_instance_no_contents_should_not_fail(self):
+    """
+    When first instantiated, the browser has no contents.
+    (Regression test for <http://bugs.launchpad.net/zope3/+bug/419119>)
+
+    >>> browser = Browser()
+    >>> print browser.contents
+    None
+    """
+
+
+def test_strip_linebreaks_from_textarea(self):
+    """
+    >>> browser = Browser()
+
+    According to http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1 line
+    break immediately after start tags or immediately before end tags must be
+    ignored, but real browsers only ignore a line break after a start tag.
+    So if we give the following form:
+
+    >>> browser.open('''
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <textarea name="textarea">
+    ... Foo
+    ... </textarea>
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+
+    The value of the textarea won't contain the first line break:
+
+    >>> browser.getControl(name='textarea').value
+    'Foo\\n'
+
+
+    Of course, if we add line breaks, so that there are now two line breaks
+    after the start tag, the textarea value will start and end with a line
+    break.
+
+    >>> browser.open('''
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <textarea name="textarea">
+    ...
+    ... Foo
+    ... </textarea>
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+    >>> browser.getControl(name='textarea').value
+    '\\nFoo\\n'
+
+
+    Also, if there is some other whitespace after the start tag, it will be
+    preserved.
+
+    >>> browser.open('''
+    ... <html><body>
+    ...   <form action="." method="post" enctype="multipart/form-data">
+    ...      <textarea name="textarea">  Foo  </textarea>
+    ...   </form></body></html>
+    ... ''') # doctest: +ELLIPSIS
+    GET / HTTP/1.1
+    ...
+
+    >>> browser.getControl(name='textarea').value
+    '  Foo  '
+    """
+
+
+def test_relative_link():
+    """
+    RFC 1808 specifies how relative URLs should be resolved, let's see
+    that we conform to it. Let's start with a simple example.
+
+    >>> browser = Browser()
+    >>> browser.open('''\
+    ... <html><body>
+    ...     <a href="foo">link</a>
+    ... </body></html>
+    ... ''', url='http://localhost/bar') # doctest: +ELLIPSIS
+    GET /bar HTTP/1.1
+    ...
+
+    >>> link = browser.getLink('link')
+    >>> link.url
+    'http://localhost/foo'
+
+
+    It's possible to have a relative URL consisting of only a query part. In
+    that case it should simply be appended to the base URL.
+
+    >>> browser.open('''\
+    ... <html><body>
+    ...     <a href="?key=value">link</a>
+    ... </body></html>
+    ... ''', url='http://localhost/bar') # doctest: +ELLIPSIS
+    GET /bar HTTP/1.1
+    ...
+
+    >>> link = browser.getLink('link')
+    >>> link.url
+    'http://localhost/bar?key=value'
+
+
+    In the example above, the base URL was the page URL, but we can also
+    specify a base URL using a <base> tag.
+
+    >>> browser.open('''\
+    ... <html><head><base href="http://localhost/base" /></head><body>
+    ...     <a href="?key=value">link</a>
+    ... </body></html>
+    ... ''', url='http://localhost/base/bar') # doctest: +ELLIPSIS
+    GET /base/bar HTTP/1.1
+    ...
+
+    >>> link = browser.getLink('link')
+    >>> link.url
+    'http://localhost/base?key=value'
+    """
+
+
+class win32CRLFtransformer(object):
+    def sub(self, replacement, text):
+        return text.replace(r'\r', '')
+
+checker = zope.testing.renormalizing.RENormalizing([
+    (re.compile(r'^--\S+\.\S+\.\S+', re.M), '-' * 30),
+    (re.compile(r'boundary=\S+\.\S+\.\S+'), 'boundary=' + '-' * 30),
+    (re.compile(r'^---{10}.*', re.M), '-' * 30),
+    (re.compile(r'boundary=-{10}.*'), 'boundary=' + '-' * 30),
+    (re.compile(r'User-agent:\s+\S+'), 'User-agent: Python-urllib/2.4'),
+    (re.compile(r'HTTP_USER_AGENT:\s+\S+'),
+     'HTTP_USER_AGENT: Python-urllib/2.4'),
+    (re.compile(r'Content-[Ll]ength:.*'), 'Content-Length: 123'),
+    (re.compile(r'Status: 200.*'), 'Status: 200 OK'),
+    (win32CRLFtransformer(), None),
+    (re.compile(r'User-Agent: Python-urllib/2.5'),
+     'User-agent: Python-urllib/2.4'),
+    (re.compile(r'User-Agent: Python-urllib/2.6'),
+     'User-agent: Python-urllib/2.4'),
+    (re.compile(r'Host: localhost'), 'Connection: close'),
+    (re.compile(r'Content-Type: '), 'Content-type: '),
+    (re.compile(r'Content-Disposition: '), 'Content-disposition: '),
+    (re.compile(r'; charset=UTF-8'), ';charset=utf-8'),
+    # webtest quotes cookies differently to zope.publisher
+    (re.compile(r'\'comment\': \'"silly billy"\','), "'comment': 'silly%20billy',"),
+    # webtest seems to expire cookies one second before the date set in set_cookie
+    (re.compile(r"'expires': datetime.datetime\(2029, 12, 31, 23, 59, 59, tzinfo=<UTC>\),"), "'expires': datetime.datetime(2030, 1, 1, 0, 0, tzinfo=<UTC>),"),
+    (re.compile(r"Object: <WSGI application>,"), "Object: <zope.site.folder.Folder object at ...>,"),
+    ])
+
+TestBrowserLayer = zope.app.testing.functional.ZCMLLayer(
+    os.path.join(os.path.split(__file__)[0], 'ftests/ftesting.zcml'),
+    __name__, 'TestBrowserLayer', allow_teardown=True)
+
+
+def test_suite():
+    flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
+
+    this_file = doctest.DocTestSuite(checker=checker)
+    wire = doctest.DocFileSuite('over_the_wire.txt', optionflags=flags)
+    wire.level = 2
+
+    tests = [this_file, wire]
+
+    # Zope Publisher Tests
+    zope_publisher = FunctionalDocFileSuite('zope-publisher.txt', optionflags=flags,
+        checker=checker)
+    zope_publisher.layer = TestBrowserLayer
+
+    tests.append(zope_publisher)
+
+    # WSGI Browser tests
+    def make_browser(*args, **kw):
+        app = WSGITestApplication()
+        test_app = TestApp(app)
+        return WSGIBrowser(test_app, *args, **kw)
+    globals = dict(Browser=make_browser)
+
+    readme = doctest.DocFileSuite('README.txt', optionflags=flags,
+        checker=checker, globs=globals)
+
+    cookies = doctest.DocFileSuite('cookies.txt', optionflags=flags,
+        checker=checker, globs=globals)
+
+    fixed_bugs = doctest.DocFileSuite('fixed-bugs.txt', optionflags=flags,
+        globs=globals)
+
+    wsgi = doctest.DocFileSuite('wsgi.txt', optionflags=flags,
+        checker=checker, globs=globals)
+
+    tests.extend([readme, cookies, fixed_bugs, wsgi])
+
+    return unittest.TestSuite(tests)
+
+
+def run_suite(suite):
+    runner = unittest.TextTestRunner(sys.stdout, verbosity=1)
+    result = runner.run(suite)
+    if not result.wasSuccessful():
+        if len(result.errors) == 1 and not result.failures:
+            err = result.errors[0][1]
+        elif len(result.failures) == 1 and not result.errors:
+            err = result.failures[0][1]
+        else:
+            err = "errors occurred; run in verbose mode for details"
+        print err
+
+if __name__ == "__main__":
+    run_suite(test_suite())

Copied: zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/webtest.py (from rev 119677, zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/wsgi.py)
===================================================================
--- zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/webtest.py	                        (rev 0)
+++ zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/webtest.py	2011-01-30 11:36:35 UTC (rev 120000)
@@ -0,0 +1,152 @@
+##############################################################################
+#
+# Copyright (c) 2010 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""WSGI-specific testing code
+"""
+import cStringIO
+import Cookie
+import httplib
+import socket
+import sys
+
+import mechanize
+
+import zope.testbrowser.browser
+import zope.testbrowser.testing
+
+class WSGIConnection(object):
+    """A ``mechanize`` compatible connection object."""
+
+    def __init__(self, test_app, host, timeout=None):
+        self._test_app = test_app
+        self.host = host
+
+    def set_debuglevel(self, level):
+        pass
+
+    def _quote(self, url):
+        # XXX: is this necessary with WebTest? Was cargeo-culted from the 
+        # Zope Publisher Connection
+        return url.replace(' ', '%20')
+
+    def request(self, method, url, body=None, headers=None):
+        """Send a request to the publisher.
+
+        The response will be stored in ``self.response``.
+        """
+        if body is None:
+            body = ''
+
+        if url == '':
+            url = '/'
+
+        url = self._quote(url)
+
+        # Extract the handle_error option header
+        if sys.version_info >= (2,5):
+            handle_errors_key = 'X-Zope-Handle-Errors'
+        else:
+            handle_errors_key = 'X-zope-handle-errors'
+        handle_errors_header = headers.get(handle_errors_key, True)
+        if handle_errors_key in headers:
+            del headers[handle_errors_key]
+
+        # Translate string to boolean.
+        handle_errors = {'False': False}.get(handle_errors_header, True)
+        extra_environ = {}
+        if not handle_errors:
+            # There doesn't seem to be a "Right Way" to do this
+            extra_environ['wsgi.handleErrors'] = False # zope.app.wsgi does this
+            extra_environ['paste.throw_errors'] = True # the paste way of doing this
+
+        scheme_key = 'X-Zope-Scheme'
+        extra_environ['wsgi.url_scheme'] = headers.get(scheme_key, 'http')
+        if scheme_key in headers:
+            del headers[scheme_key]
+
+        app = self._test_app
+
+        # Here we do a complicated dance to sync the webtest apps idea of what
+        # cookies there are with the testbrowsers. It's not quite perfect as
+        # they can still get un-synced if you don't execute a request via the
+        # testbrowser. But that's a veryvery edge case.
+        app.cookies.clear()
+        for h, v in headers.items():
+            if h.lower() == 'cookie':
+                cookies = Cookie.SimpleCookie()
+                cookies.load(v)
+                for key, morsel in cookies.items():
+                    app.cookies[key] = morsel.value
+                break
+
+        # pass the request to webtest
+        if method == 'GET':
+            assert not body, body
+            response = app.get(url, headers=headers, expect_errors=True, extra_environ=extra_environ)
+        elif method == 'POST':
+            response = app.post(url, body, headers=headers, expect_errors=True, extra_environ=extra_environ)
+        else:
+            raise Exception('Couldnt handle method %s' % method)
+
+        self.response = response
+
+    def getresponse(self):
+        """Return a ``mechanize`` compatible response.
+
+        The goal of ths method is to convert the WebTest's reseponse to
+        a ``mechanize`` compatible response, which is also understood by
+        mechanize.
+        """
+        response = self.response
+        status = int(response.status[:3])
+        reason = response.status[4:]
+
+        headers = response.headers.items()
+        headers.sort()
+        headers.insert(0, ('Status', response.status))
+        headers = '\r\n'.join('%s: %s' % h for h in headers)
+        content = response.body
+        return zope.testbrowser.testing.Response(content, headers, status, reason)
+
+
+class WSGIHTTPHandler(zope.testbrowser.testing.HTTPHandler):
+
+    def __init__(self, test_app, *args, **kw):
+        self._test_app = test_app
+        zope.testbrowser.testing.HTTPHandler.__init__(self, *args, **kw)
+
+    def _connect(self, *args, **kw):
+        return WSGIConnection(self._test_app, *args, **kw)
+
+    def https_request(self, req):
+        req.add_unredirected_header('X-Zope-Scheme', 'https')
+        return self.http_request(req)
+
+
+class WSGIMechanizeBrowser(zope.testbrowser.testing.MechanizeBrowser):
+    """Special ``mechanize`` browser using the WSGI HTTP handler."""
+
+    def __init__(self, test_app, *args, **kw):
+        self._test_app = test_app
+        zope.testbrowser.testing.MechanizeBrowser.__init__(self, *args, **kw)
+
+    def _http_handler(self, *args, **kw):
+        return WSGIHTTPHandler(self._test_app, *args, **kw)
+
+
+class Browser(zope.testbrowser.browser.Browser):
+    """A WSGI `testbrowser` Browser that uses a WebTest wrapped WSGI app."""
+
+    def __init__(self, test_app, url=None):
+        mech_browser = WSGIMechanizeBrowser(test_app)
+        super(Browser, self).__init__(url=url, mech_browser=mech_browser)

Deleted: zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/wsgi.py
===================================================================
--- zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/wsgi.py	2011-01-30 11:22:24 UTC (rev 119999)
+++ zope.testbrowser/branches/jinty-webtest2/src/zope/testbrowser/wsgi.py	2011-01-30 11:36:35 UTC (rev 120000)
@@ -1,152 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2010 Zope Foundation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""WSGI-specific testing code
-"""
-import cStringIO
-import Cookie
-import httplib
-import socket
-import sys
-
-import mechanize
-
-import zope.testbrowser.browser
-import zope.testbrowser.testing
-
-class WSGIConnection(object):
-    """A ``mechanize`` compatible connection object."""
-
-    def __init__(self, test_app, host, timeout=None):
-        self._test_app = test_app
-        self.host = host
-
-    def set_debuglevel(self, level):
-        pass
-
-    def _quote(self, url):
-        # XXX: is this necessary with WebTest? Was cargeo-culted from the 
-        # Zope Publisher Connection
-        return url.replace(' ', '%20')
-
-    def request(self, method, url, body=None, headers=None):
-        """Send a request to the publisher.
-
-        The response will be stored in ``self.response``.
-        """
-        if body is None:
-            body = ''
-
-        if url == '':
-            url = '/'
-
-        url = self._quote(url)
-
-        # Extract the handle_error option header
-        if sys.version_info >= (2,5):
-            handle_errors_key = 'X-Zope-Handle-Errors'
-        else:
-            handle_errors_key = 'X-zope-handle-errors'
-        handle_errors_header = headers.get(handle_errors_key, True)
-        if handle_errors_key in headers:
-            del headers[handle_errors_key]
-
-        # Translate string to boolean.
-        handle_errors = {'False': False}.get(handle_errors_header, True)
-        extra_environ = {}
-        if not handle_errors:
-            # There doesn't seem to be a "Right Way" to do this
-            extra_environ['wsgi.handleErrors'] = False # zope.app.wsgi does this
-            extra_environ['paste.throw_errors'] = True # the paste way of doing this
-
-        scheme_key = 'X-Zope-Scheme'
-        extra_environ['wsgi.url_scheme'] = headers.get(scheme_key, 'http')
-        if scheme_key in headers:
-            del headers[scheme_key]
-
-        app = self._test_app
-
-        # Here we do a complicated dance to sync the webtest apps idea of what
-        # cookies there are with the testbrowsers. It's not quite perfect as
-        # they can still get un-synced if you don't execute a request via the
-        # testbrowser. But that's a veryvery edge case.
-        app.cookies.clear()
-        for h, v in headers.items():
-            if h.lower() == 'cookie':
-                cookies = Cookie.SimpleCookie()
-                cookies.load(v)
-                for key, morsel in cookies.items():
-                    app.cookies[key] = morsel.value
-                break
-
-        # pass the request to webtest
-        if method == 'GET':
-            assert not body, body
-            response = app.get(url, headers=headers, expect_errors=True, extra_environ=extra_environ)
-        elif method == 'POST':
-            response = app.post(url, body, headers=headers, expect_errors=True, extra_environ=extra_environ)
-        else:
-            raise Exception('Couldnt handle method %s' % method)
-
-        self.response = response
-
-    def getresponse(self):
-        """Return a ``mechanize`` compatible response.
-
-        The goal of ths method is to convert the WebTest's reseponse to
-        a ``mechanize`` compatible response, which is also understood by
-        mechanize.
-        """
-        response = self.response
-        status = int(response.status[:3])
-        reason = response.status[4:]
-
-        headers = response.headers.items()
-        headers.sort()
-        headers.insert(0, ('Status', response.status))
-        headers = '\r\n'.join('%s: %s' % h for h in headers)
-        content = response.body
-        return zope.testbrowser.testing.Response(content, headers, status, reason)
-
-
-class WSGIHTTPHandler(zope.testbrowser.testing.HTTPHandler):
-
-    def __init__(self, test_app, *args, **kw):
-        self._test_app = test_app
-        zope.testbrowser.testing.HTTPHandler.__init__(self, *args, **kw)
-
-    def _connect(self, *args, **kw):
-        return WSGIConnection(self._test_app, *args, **kw)
-
-    def https_request(self, req):
-        req.add_unredirected_header('X-Zope-Scheme', 'https')
-        return self.http_request(req)
-
-
-class WSGIMechanizeBrowser(zope.testbrowser.testing.MechanizeBrowser):
-    """Special ``mechanize`` browser using the WSGI HTTP handler."""
-
-    def __init__(self, test_app, *args, **kw):
-        self._test_app = test_app
-        zope.testbrowser.testing.MechanizeBrowser.__init__(self, *args, **kw)
-
-    def _http_handler(self, *args, **kw):
-        return WSGIHTTPHandler(self._test_app, *args, **kw)
-
-
-class Browser(zope.testbrowser.browser.Browser):
-    """A WSGI `testbrowser` Browser that uses a WebTest wrapped WSGI app."""
-
-    def __init__(self, test_app, url=None):
-        mech_browser = WSGIMechanizeBrowser(test_app)
-        super(Browser, self).__init__(url=url, mech_browser=mech_browser)



More information about the checkins mailing list