[PATCH] url.py: Remove 'file' inheritance in the httpsendfile class

Renato Cunha renatoc at gmail.com
Mon Jun 28 14:38:56 CDT 2010


Hi,

> We use it to stream files in HTTP POST.
> urllib2 uses len() on the object passed in data= to construct the
> Content-length header (but since we already have a work-around to add
> the headers manually because of potential overflow, we can probably
> get rid of it in httpsendfile).
> 
> Then we override send() from HTTPConnection to stream the file when
> it's an instance of httpsendfile.

In that case, would the following patch be adequate to handle it the right
way? (2to3 can convert the __builtin__ call correctly, so no problem here)

Regards.

# HG changeset patch
# User Renato Cunha <renatoc at gmail.com>
# Date 1277753903 10800
# Node ID 1f44f75c4ffee26a80726b2611244fb8951cf7fd
# Parent  8b452fe4bf506a1a08bbc7e1bac81aceda8f4d10
url.py: Remove 'file' inheritance in the httpsendfile class.

Since py3k doesn't have a "file" builtin and, consequently, doesn't support
inheriting from it, this patch refactors the httpsendfile class to wrap the
objects returned by the builtin open function while adding the necessary
__len__ method to them.

diff --git a/mercurial/url.py b/mercurial/url.py
--- a/mercurial/url.py
+++ b/mercurial/url.py
@@ -7,7 +7,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO
+import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO, types
 from i18n import _
 import keepalive, util
 
@@ -250,9 +250,33 @@
 
         return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
 
-class httpsendfile(file):
+class httpsendfile(object):
+    """This is a wrapper around the objects returned by python's "open".
+
+    Its purpose is to send file objects via HTTP and, to do so, it defines a
+    __len__ attribute to feed the Content-Length header.
+    """
+
+    def __init__(self, *args, **kwargs):
+        import __builtin__
+        self._data = __builtin__.open(*args, **kwargs)
+
     def __len__(self):
-        return os.fstat(self.fileno()).st_size
+        return os.fstat(self._data.fileno()).st_size
+
+    def __getattr__(self, attr):
+        if attr == '_data':
+            return self._data
+        elif hasattr(self._data, attr):
+            value = getattr(self._data, attr)
+            if isinstance(value, types.MethodType):
+                def callable(*args, **kwargs):
+                    return value(*args, **kwargs)
+                return callable
+            else:
+                return value
+        else:
+            raise AttributeError
 
 def _gen_sendfile(connection):
     def _sendfile(self, data):


More information about the Mercurial-devel mailing list