| The read_complete flag lets us know if all of the wrapped file's data |
| has been read. We want to know this because Browser.back() must |
| .reload() the response if not. |
| |
| I've noted here the various cases where .read_complete may be set. |
| |
| >>> import mechanize |
| |
| >>> text = "To err is human, to moo, bovine.\n"*10 |
| >>> def get_wrapper(): |
| ... import cStringIO |
| ... from mechanize._response import seek_wrapper |
| ... f = cStringIO.StringIO(text) |
| ... wr = seek_wrapper(f) |
| ... return wr |
| |
| .read() case #1 |
| |
| >>> wr = get_wrapper() |
| >>> wr.read_complete |
| False |
| >>> junk = wr.read() |
| >>> wr.read_complete |
| True |
| >>> wr.seek(0) |
| >>> wr.read_complete |
| True |
| |
| Excercise partial .read() and .readline(), and .seek() case #1 |
| |
| >>> wr = get_wrapper() |
| >>> junk = wr.read(10) |
| >>> wr.read_complete |
| False |
| >>> junk = wr.readline() |
| >>> wr.read_complete |
| False |
| >>> wr.seek(0, 2) |
| >>> wr.read_complete |
| True |
| >>> wr.seek(0) |
| >>> wr.read_complete |
| True |
| |
| .readlines() case #1 |
| |
| >>> wr = get_wrapper() |
| >>> junk = wr.readlines() |
| >>> wr.read_complete |
| True |
| >>> wr.seek(0) |
| >>> wr.read_complete |
| True |
| |
| .seek() case #2 |
| |
| >>> wr = get_wrapper() |
| >>> wr.seek(10) |
| >>> wr.read_complete |
| False |
| >>> wr.seek(1000000) |
| |
| .read() case #2 |
| |
| >>> wr = get_wrapper() |
| >>> junk = wr.read(1000000) |
| >>> wr.read_complete # we read to the end, but don't know it yet |
| False |
| >>> junk = wr.read(10) |
| >>> wr.read_complete |
| True |
| |
| .readline() case #1 |
| |
| >>> wr = get_wrapper() |
| >>> junk = wr.read(len(text)-10) |
| >>> wr.read_complete |
| False |
| >>> junk = wr.readline() |
| >>> wr.read_complete # we read to the end, but don't know it yet |
| False |
| >>> junk = wr.readline() |
| >>> wr.read_complete |
| True |
| |
| Test copying and sharing of .read_complete state |
| |
| >>> import copy |
| >>> wr = get_wrapper() |
| >>> wr2 = copy.copy(wr) |
| >>> wr.read_complete |
| False |
| >>> wr2.read_complete |
| False |
| >>> junk = wr2.read() |
| >>> wr.read_complete |
| True |
| >>> wr2.read_complete |
| True |
| |
| |
| Fix from -r36082: .read() after .close() used to break |
| .read_complete state |
| |
| >>> from mechanize._response import test_response |
| >>> r = test_response(text) |
| >>> junk = r.read(64) |
| >>> r.close() |
| >>> r.read_complete |
| False |
| >>> r.read() |
| '' |
| >>> r.read_complete |
| False |
| |
| |
| |
| Tests for the truly horrendous upgrade_response() |
| |
| >>> def is_response(r): |
| ... names = "get_data read readline readlines close seek code msg".split() |
| ... for name in names: |
| ... if not hasattr(r, name): |
| ... return False |
| ... return r.get_data() == "test data" |
| |
| >>> from cStringIO import StringIO |
| >>> from mechanize._response import upgrade_response, make_headers, \ |
| ... make_response, closeable_response, seek_wrapper |
| >>> data="test data"; url="http://example.com/"; code=200; msg="OK" |
| |
| Normal response (closeable_response wrapped with seek_wrapper): return a copy |
| |
| >>> r1 = make_response(data, [], url, code, msg) |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| >>> r1 is not r2 |
| True |
| >>> r1.wrapped is r2.wrapped |
| True |
| |
| closeable_response with no seek_wrapper: wrap with seek_wrapper |
| |
| >>> r1 = closeable_response(StringIO(data), make_headers([]), url, code, msg) |
| >>> is_response(r1) |
| False |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| >>> r1 is not r2 |
| True |
| >>> r1 is r2.wrapped |
| True |
| |
| addinfourl: extract .fp and wrap it with closeable_response and |
| seek_wrapper |
| |
| >>> from mechanize._urllib2_fork import addinfourl |
| >>> r1= addinfourl(StringIO(data), make_headers([]), url) |
| >>> is_response(r1) |
| False |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| >>> r1 is not r2 |
| True |
| >>> r1 is not r2.wrapped |
| True |
| >>> r1.fp is r2.wrapped.fp |
| True |
| |
| addinfourl with code, msg |
| |
| >>> r1= addinfourl(StringIO(data), make_headers([]), url) |
| >>> r1.code = 206 |
| >>> r1.msg = "cool" |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| >>> r2.code == r1.code |
| True |
| >>> r2.msg == r1.msg |
| True |
| |
| addinfourl with seek wrapper: cached data is not lost |
| |
| >>> r1= addinfourl(StringIO(data), make_headers([]), url) |
| >>> r1 = seek_wrapper(r1) |
| >>> r1.read(4) |
| 'test' |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| |
| addinfourl wrapped with HTTPError -- remains an HTTPError of the same |
| subclass (through horrible trickery) |
| |
| >>> hdrs = make_headers([]) |
| >>> r1 = addinfourl(StringIO(data), hdrs, url) |
| >>> class MyHTTPError(mechanize.HTTPError): pass |
| >>> r1 = MyHTTPError(url, code, msg, hdrs, r1) |
| >>> is_response(r1) |
| False |
| >>> r2 = upgrade_response(r1) |
| >>> is_response(r2) |
| True |
| >>> isinstance(r2, MyHTTPError) |
| True |
| >>> r2 # doctest: +ELLIPSIS |
| <httperror_seek_wrapper (MyHTTPError instance) at ... |
| |
| The trickery does not cause double-wrapping |
| |
| >>> r3 = upgrade_response(r2) |
| >>> is_response(r3) |
| True |
| >>> r3 is not r2 |
| True |
| >>> r3.wrapped is r2.wrapped |
| True |
| |
| Test dynamically-created class __repr__ for case where we have the |
| module name |
| |
| >>> r4 = addinfourl(StringIO(data), hdrs, url) |
| >>> r4 = mechanize.HTTPError(url, code, msg, hdrs, r4) |
| >>> upgrade_response(r4) # doctest: +ELLIPSIS |
| <httperror_seek_wrapper (urllib2.HTTPError instance) at ... |