>>> import mechanize >>> from mechanize._response import test_response >>> from test_browser import TestBrowser2, make_mock_handler Opening a new response should close the old one. >>> class TestHttpHandler(mechanize.BaseHandler): ... def http_open(self, request): ... return test_response(url=request.get_full_url()) >>> class TestHttpBrowser(TestBrowser2): ... handler_classes = TestBrowser2.handler_classes.copy() ... handler_classes["http"] = TestHttpHandler ... default_schemes = ["http"] >>> def response_impl(response): ... return response.wrapped.fp.__class__.__name__ >>> br = TestHttpBrowser() >>> r = br.open("http://example.com") >>> print response_impl(r) StringI >>> r2 = br.open("http://example.com") >>> print response_impl(r2) StringI >>> print response_impl(r) eofresponse So should .set_response() >>> br.set_response(test_response()) >>> print response_impl(r2) eofresponse .visit_response() works very similarly to .open() >>> br = TestHttpBrowser() >>> r = br.open("http://example.com") >>> r2 = test_response(url="http://example.com/2") >>> print response_impl(r2) StringI >>> br.visit_response(r2) >>> print response_impl(r) eofresponse >>> br.geturl() == br.request.get_full_url() == "http://example.com/2" True >>> junk = br.back() >>> br.geturl() == br.request.get_full_url() == "http://example.com" True .back() may reload if the complete response was not read. If so, it should return the new response, not the old one >>> class ReloadCheckBrowser(TestHttpBrowser): ... reloaded = False ... def reload(self): ... self.reloaded = True ... return TestHttpBrowser.reload(self) >>> br = ReloadCheckBrowser() >>> old = br.open("http://example.com") >>> junk = br.open("http://example.com/2") >>> new = br.back() >>> br.reloaded True >>> new.wrapped is not old.wrapped True Warn early about some mistakes setting a response object >>> import StringIO >>> br = TestBrowser2() >>> br.set_response("blah") Traceback (most recent call last): ... ValueError: not a response object >>> br.set_response(StringIO.StringIO()) Traceback (most recent call last): ... ValueError: not a response object .open() without an appropriate scheme handler should fail with URLError >>> br = TestBrowser2() >>> br.open("http://example.com") Traceback (most recent call last): ... URLError: Reload after failed .open() should fail due to failure to open, not with BrowserStateError >>> br.reload() Traceback (most recent call last): ... URLError: .clear_history() should do what it says on the tin. Note that the history does not include the current response! >>> br = TestBrowser2() >>> br.add_handler(make_mock_handler(test_response)([("http_open", None)])) >>> br.response() is None True >>> len(br._history._history) 0 >>> r = br.open("http://example.com/1") >>> br.response() is not None True >>> len(br._history._history) 0 >>> br.clear_history() >>> br.response() is not None True >>> len(br._history._history) 0 >>> r = br.open("http://example.com/2") >>> br.response() is not None True >>> len(br._history._history) 1 >>> br.clear_history() >>> br.response() is not None True >>> len(br._history._history) 0 .open()ing a Request with False .visit does not affect Browser state. Redirections during such a non-visiting request should also be non-visiting. >>> from mechanize import BrowserStateError, Request, HTTPRedirectHandler >>> from test_urllib2 import MockHTTPHandler >>> def make_browser_with_redirect(): ... br = TestBrowser2() ... hh = MockHTTPHandler(302, "Location: http://example.com/\r\n\r\n") ... br.add_handler(hh) ... br.add_handler(HTTPRedirectHandler()) ... return br >>> def raises(exc_class, fn, *args, **kwds): ... try: ... fn(*args, **kwds) ... except exc_class, exc: ... return True ... return False >>> def test_state(br): ... return (br.request is None and ... br.response() is None and ... raises(BrowserStateError, br.back) ... ) >>> br = make_browser_with_redirect() >>> test_state(br) True >>> req = Request("http://example.com") >>> req.visit = False >>> r = br.open(req) >>> test_state(br) True .open_novisit() mutates the request object >>> br = make_browser_with_redirect() >>> test_state(br) True >>> req = Request("http://example.com") >>> print req.visit None >>> r = br.open_novisit(req) >>> test_state(br) True >>> req.visit False ...in fact, any redirection (but not refresh), proxy request, basic or digest auth request, or robots.txt request should be non-visiting, even if .visit is True: >>> from test_urllib2 import MockPasswordManager >>> def test_one_visit(handlers): ... br = TestBrowser2() ... for handler in handlers: br.add_handler(handler) ... req = Request("http://example.com") ... req.visit = True ... br.open(req) ... return br >>> def test_state(br): ... # XXX the _history._history check is needed because of the weird ... # throwing-away of history entries by .back() where response is ... # None, which makes the .back() check insufficient to tell if a ... # history entry was .add()ed. I don't want to change this until ... # post-stable. ... return ( ... br.response() and ... br.request and ... len(br._history._history) == 0 and ... raises(BrowserStateError, br.back)) >>> hh = MockHTTPHandler(302, "Location: http://example.com/\r\n\r\n") >>> br = test_one_visit([hh, HTTPRedirectHandler()]) >>> test_state(br) True >>> class MockPasswordManager: ... def add_password(self, realm, uri, user, password): pass ... def find_user_password(self, realm, authuri): return '', '' >>> ah = mechanize.HTTPBasicAuthHandler(MockPasswordManager()) >>> hh = MockHTTPHandler( ... 401, 'WWW-Authenticate: Basic realm="realm"\r\n\r\n') >>> test_state(test_one_visit([hh, ah])) True >>> ph = mechanize.ProxyHandler(dict(http="proxy.example.com:3128")) >>> ah = mechanize.ProxyBasicAuthHandler(MockPasswordManager()) >>> hh = MockHTTPHandler( ... 407, 'Proxy-Authenticate: Basic realm="realm"\r\n\r\n') >>> test_state(test_one_visit([ph, hh, ah])) True XXX Can't really fix this one properly without significant changes -- the refresh should go onto the history *after* the call, but currently all redirects, including refreshes, are done by recursive .open() calls, which gets the history wrong in this case. Will have to wait until after stable release: #>>> hh = MockHTTPHandler( #... "refresh", 'Location: http://example.com/\r\n\r\n') #>>> br = test_one_visit([hh, HTTPRedirectHandler()]) #>>> br.response() is not None #True #>>> br.request is not None #True #>>> r = br.back() XXX digest, robots .global_form() is separate from the other forms (partly for backwards- compatibility reasons). >>> from mechanize._response import test_response >>> br = TestBrowser2() >>> html = """\ ... ... ...
... ... """ >>> response = test_response(html, headers=[("Content-type", "text/html")]) >>> br.global_form() Traceback (most recent call last): BrowserStateError: not viewing any document >>> br.set_response(response) >>> br.global_form().find_control(nr=0).name 'a' >>> len(list(br.forms())) 1 >>> iter(br.forms()).next().find_control(nr=0).name 'b' .select_form() works with the global form >>> import ClientForm >>> from mechanize._response import test_html_response >>> br = TestBrowser2() >>> br.visit_response(test_html_response("""\ ... ... ...
... ...
... """)) >>> def has_a(form): ... try: ... form.find_control(name="a") ... except ClientForm.ControlNotFoundError: ... return False ... else: ... return True >>> br.select_form(predicate=has_a) >>> br.form.find_control(name="a").value 'b'