[wwwsearch-commits] r32397 - wwwsearch/mechanize/trunk/mechanize

jjlee at codespeak.net jjlee at codespeak.net
Sun Sep 17 00:09:45 CEST 2006


Author: jjlee
Date: Sun Sep 17 00:09:44 2006
New Revision: 32397

Modified:
   wwwsearch/mechanize/trunk/mechanize/_mechanize.py
   wwwsearch/mechanize/trunk/mechanize/_response.py
Log:
HTTPError didn't support .get_data() or .seek() -- fix that by upgrading it to a closeable_response; Don't treat any non-response HTTPErrors as responses (not sure if any of these '.fp is None' HTTPErrors are actually raised any more, but urllib2.HTTPError's c'tor knows about this case); Apply eager-read workaround to .set_response() (not just .open()); Don't multiple-.seek() wrap

Modified: wwwsearch/mechanize/trunk/mechanize/_mechanize.py
==============================================================================
--- wwwsearch/mechanize/trunk/mechanize/_mechanize.py	(original)
+++ wwwsearch/mechanize/trunk/mechanize/_mechanize.py	Sun Sep 17 00:09:44 2006
@@ -155,6 +155,8 @@
             response = UserAgent.open(self, self.request, data)
         except urllib2.HTTPError, error:
             success = False
+            if error.fp is None:  # not a response
+                raise
             response = error
 ##         except (IOError, socket.error, OSError), error:
 ##             # Yes, urllib2 really does raise all these :-((
@@ -169,16 +171,11 @@
 ##             raise
         self.set_response(response)
 
-        # XXX
-        # Temporary hack to eagerly read data (otherwise, History can contain
-        # closed and partially-read responses).  Proper fix is for responses to
-        # know if they're partially read or not; .back() should then .reload()
-        # if required.
-        response.get_data()
+        response = copy.copy(self._response)
 
         if not success:
-            raise error
-        return copy.copy(self._response)
+            raise response
+        return response
 
     def __str__(self):
         text = []
@@ -209,15 +206,15 @@
             raise ValueError("not a response object")
 
         self.form = None
+        self._response = _upgrade.upgrade_response(response)
 
-        if not hasattr(response, "seek"):
-            response = response_seek_wrapper(response)
-        if not hasattr(response, "closeable_response"):
-            response = _upgrade.upgrade_response(response)
-        else:
-            response = copy.copy(response)
+        # XXX
+        # Temporary hack to eagerly read data (otherwise, History can contain
+        # closed and partially-read responses).  Proper fix is for responses to
+        # know if they're partially read or not; .back() should then .reload()
+        # if required.
+        self._response.get_data()
 
-        self._response = response
         self._factory.set_response(self._response)
 
     def geturl(self):

Modified: wwwsearch/mechanize/trunk/mechanize/_response.py
==============================================================================
--- wwwsearch/mechanize/trunk/mechanize/_response.py	(original)
+++ wwwsearch/mechanize/trunk/mechanize/_response.py	Sun Sep 17 00:09:44 2006
@@ -10,6 +10,7 @@
 
 import copy, mimetools
 from cStringIO import StringIO
+from urllib2 import HTTPError
 
 # XXX Andrew Dalke kindly sent me a similar class in response to my request on
 # comp.lang.python, which I then proceeded to lose.  I wrote this class
@@ -218,6 +219,27 @@
         self.seek(0)
 
 
+class httperror_seek_wrapper(response_seek_wrapper, HTTPError):
+
+    # this only derives from HTTPError in order to be a subclass --
+    # the HTTPError behaviour comes from delegation
+
+    def __init__(self, wrapped):
+        assert isinstance(wrapped, closeable_response), wrapped
+        response_seek_wrapper.__init__(self, wrapped)
+        # be compatible with undocumented HTTPError attributes :-(
+        self.hdrs = wrapped._headers
+        self.filename = wrapped._url
+
+    # we don't want the HTTPError implementation of these
+
+    def geturl(self):
+        return self.wrapped.geturl()
+
+    def close(self):
+        self.wrapped.close()
+
+
 class eoffile:
     # file-like object that always claims to be at end-of-file...
     def read(self, size=-1): return ""
@@ -338,12 +360,27 @@
     r = closeable_response(StringIO(data), mime_headers, url, code, msg)
     return response_seek_wrapper(r)
 
+
 # Horrible, but needed, at least until fork urllib2.  Even then, may want
 # to preseve urllib2 compatibility.
 def upgrade_response(response):
+    """Return a copy of response that supports mechanize response interface.
+
+    Accepts responses from both mechanize and urllib2 handlers.
+    """
+    if isinstance(response, HTTPError):
+        wrapper_class = httperror_seek_wrapper
+    else:
+        wrapper_class = response_seek_wrapper
+
+    if hasattr(response, "closeable_response"):
+        if not hasattr(response, "seek"):
+            response = wrapper_class(response)
+        return copy.copy(response)
+
     # a urllib2 handler constructed the response, i.e. the response is an
-    # urllib.addinfourl, instead of a _Util.closeable_response as returned
-    # by e.g. mechanize.HTTPHandler
+    # urllib.addinfourl or a urllib2.HTTPError, instead of a
+    # _Util.closeable_response as returned by e.g. mechanize.HTTPHandler
     try:
         code = response.code
     except AttributeError:
@@ -361,7 +398,7 @@
 
     response = closeable_response(
         response.fp, response.info(), response.geturl(), code, msg)
-    response = response_seek_wrapper(response)
+    response = wrapper_class(response)
     if data:
         response.set_data(data)
     return response


More information about the wwwsearch-commits mailing list