[wwwsearch-commits] r23242 - in wwwsearch/ClientCookie/trunk: . ClientCookie

jjlee at codespeak.net jjlee at codespeak.net
Sun Feb 12 03:17:37 CET 2006


Author: jjlee
Date: Sun Feb 12 03:17:29 2006
New Revision: 23242

Modified:
   wwwsearch/ClientCookie/trunk/ClientCookie/_Util.py
   wwwsearch/ClientCookie/trunk/ClientCookie/_urllib2_support.py
   wwwsearch/ClientCookie/trunk/functional_tests.py
Log:
Fix dangling-reference problem, in which all but one of a set of copied responses broke after closing a single member of the set.  Fixed by moving most of response_seek_wrapper down into urllib.addinfourl level (replacing the latter class with a work-alike that still works after .close()).

Modified: wwwsearch/ClientCookie/trunk/ClientCookie/_Util.py
==============================================================================
--- wwwsearch/ClientCookie/trunk/ClientCookie/_Util.py	(original)
+++ wwwsearch/ClientCookie/trunk/ClientCookie/_Util.py	Sun Feb 12 03:17:29 2006
@@ -13,7 +13,7 @@
     True = 1
     False = 0
 
-import re, string, time, copy
+import re, string, time, copy, urllib
 from types import TupleType
 from cStringIO import StringIO
 
@@ -538,17 +538,38 @@
     xreadlines = __iter__
 
     def __repr__(self):
-        return ("<%s at %s whose wrapped object = %s>" %
-                (self.__class__.__name__, `id(self)`, `self.wrapped`))
+        return ("<%s at %s whose wrapped object = %r>" %
+                (self.__class__.__name__, hex(id(self)), self.wrapped))
+
+
+class response_seek_wrapper(seek_wrapper):
+
+    """
+    Supports copying response objects and setting response body data.
+
+    """
+
+    def __init__(self, wrapped):
+        seek_wrapper.__init__(self, wrapped)
+        self._headers = self.wrapped.info()
+
+    def __copy__(self):
+        cpy = seek_wrapper.__copy__(self)
+        # copy headers from delegate
+        cpy._headers = copy.copy(self.info())
+        return cpy
+
+    def info(self):
+        return self._headers
+
+    def set_data(self, data):
+        self.seek(0)
+        self.read()
+        self.close()
+        cache = self._seek_wrapper__cache = StringIO()
+        cache.write(data)
+        self.seek(0)
 
-    def close(self):
-        self.__cache = None
-        self.read = None
-        self.readline = None
-        self.readlines = None
-        self.seek = None
-        if self.wrapped: self.wrapped.close()
-        self.wrapped = None
 
 class eoffile:
     # file-like object that always claims to be at end-of-file...
@@ -558,9 +579,21 @@
     def next(self): return ""
     def close(self): pass
 
-class response_seek_wrapper(seek_wrapper):
+class eofresponse(eoffile):
+    def __init__(self, url, headers, code, msg):
+        self._url = url
+        self._headers = headers
+        self.code = code
+        self.msg = msg
+    def geturl(self): return self._url
+    def info(self): return self._headers
+
+
+class closeable_response:
     """Avoids unnecessarily clobbering urllib.addinfourl methods on .close().
 
+    Only supports responses returned by ClientCookie.HTTPHandler.
+
     After .close(), the following methods are supported:
 
     .read()
@@ -574,8 +607,7 @@
     .next()
     .close()
 
-    and the following attributes are supported if present (i.e. in Python 2.4
-    or newer):
+    and the following attributes are supported:
 
     .code
     .msg
@@ -585,48 +617,43 @@
 
     """
 
-    def __init__(self, wrapped):
-        seek_wrapper.__init__(self, wrapped)
-        self.url = self.wrapped.geturl()
-        try:
-            self.msg = wrapped.msg
-            self.code = wrapped.code
-        except AttributeError:
-            pass  # pre-2.4
-        self._headers = self.wrapped.info()
-
-    def close(self):
-        wrapped = self.wrapped
-        wrapped.close()
+    def __init__(self, fp, headers, url, code, msg):
+        self._set_fp(fp)
+        self._headers = headers
+        self._url = url
+        self.code = code
+        self.msg = msg
+
+    def _set_fp(self, fp):
+        self.fp = fp
+        self.read = self.fp.read
+        self.readline = self.fp.readline
+        if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines
+        if hasattr(self.fp, "fileno"):
+            self.fileno = self.fp.fileno
+        else:
+            self.fileno = lambda: None
+        if hasattr(self.fp, "__iter__"):
+            self.__iter__ = self.fp.__iter__
+            if hasattr(self.fp, "next"):
+                self.next = self.fp.next
 
-        new_wrapped = eoffile()
-        new_wrapped.url = self.url
-        try:
-            new_wrapped.url = self.url
-            new_wrapped.code = self.code
-        except AttributeError:
-            pass  # pre-2.4
-        new_wrapped._headers = self._headers
-        self.wrapped = new_wrapped
+    def __repr__(self):
+        return '<%s at %s whose fp = %r>' % (
+            self.__class__.__name__, hex(id(self)), self.fp)
 
     def info(self):
         return self._headers
 
     def geturl(self):
-        return self.url
+        return self._url
 
-    def __copy__(self):
-        cpy = seek_wrapper.__copy__(self)
-        cpy._headers = copy.copy(self._headers)
-        return cpy
-
-    def set_data(self, data):
-        self.seek(0)
-        self.read()
-        self.close()
-        cache = self._seek_wrapper__cache = StringIO()
-        cache.write(data)
-        self.seek(0)
+    def close(self):
+        wrapped = self.fp
+        wrapped.close()
+        new_wrapped = eofresponse(
+            self._url, self._headers, self.code, self.msg)
+        self._set_fp(new_wrapped)
 
     def __getstate__(self):
         # There are three obvious options here:
@@ -641,5 +668,7 @@
         # So we do 1.
 
         state = self.__dict__.copy()
-        state["wrapped"] = eoffile()
+        new_wrapped = eofresponse(
+            self._url, self._headers, self.code, self.msg)
+        state["wrapped"] = new_wrapped
         return state

Modified: wwwsearch/ClientCookie/trunk/ClientCookie/_urllib2_support.py
==============================================================================
--- wwwsearch/ClientCookie/trunk/ClientCookie/_urllib2_support.py	(original)
+++ wwwsearch/ClientCookie/trunk/ClientCookie/_urllib2_support.py	Sun Feb 12 03:17:29 2006
@@ -15,7 +15,7 @@
 
 import ClientCookie
 from _ClientCookie import CookieJar, request_host
-from _Util import isstringlike, startswith, getheaders
+from _Util import isstringlike, startswith, getheaders, closeable_response
 from _HeadersUtil import is_html
 from _Debug import getLogger
 debug = getLogger("ClientCookie.cookies").debug
@@ -629,9 +629,8 @@
             r.recv = r.read
             fp = socket._fileobject(r, 'rb', -1)
 
-            resp = urllib.addinfourl(fp, r.msg, req.get_full_url())
-            resp.code = r.status
-            resp.msg = r.reason
+            resp = closeable_response(fp, r.msg, req.get_full_url(),
+                                      r.status, r.reason)
             return resp
 
 

Modified: wwwsearch/ClientCookie/trunk/functional_tests.py
==============================================================================
--- wwwsearch/ClientCookie/trunk/functional_tests.py	(original)
+++ wwwsearch/ClientCookie/trunk/functional_tests.py	Sun Feb 12 03:17:29 2006
@@ -51,11 +51,11 @@
             install_opener(o)
             try:
                 r = urlopen("http://wwwsearch.sf.net/cgi-bin/cookietest.cgi")
-            except URLError, e:
-                print e.read()
+            except urllib2.URLError, e:
+                #print e.read()
                 raise
             data = r.read()
-            print data
+            #print data
             self.assert_(
                 string.find(data, "Your browser supports cookies!") >= 0)
             self.assert_(len(cj) == 1)


More information about the wwwsearch-commits mailing list