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

Greg Ward greg-hg at gerg.ca
Thu Jul 1 18:18:48 CDT 2010


On Thu, Jul 1, 2010 at 6:28 PM, Renato Cunha <renatoc at gmail.com> wrote:
> # HG changeset patch
> # User Renato Cunha <renatoc at gmail.com>
> # Date 1278023223 10800
> # Node ID 72e426c43985a901c5f3f3f14d55069fbac8106a
> # Parent  b16f77a9ba30bc5053d35926d1fd1a8066d018a6
> 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
> methods (__len__ for constructing the Content-Length header and read, write,
> close and seek for the file-like interface).
>
> 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-like 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)

There's nothing wrong with importing __builtin__ at module level.
It's not like there's a __builtin__.py file somewhere on disk that has
to be read and parsed!

> +    def read(self, size = -1):
> +        # Letting size be negative by default guarantees that the file will
> +        # be read until EOF.
> +        return self._data.read(size)
> +
> +    def write(self, str):
> +        return self._data.write(str)
[...etc...]

A fairly common and highly Pythonic idiom for method delegation is to
do this in the constructor:

  self.read = self._data.read
  self.write = self._data.write
  [...etc...]

It's less code, it's faster (one less cycle of method lookup/call),
and it's blindingly obvious that you're just delegating a bunch of
methods to a wrapped object.  No need to go inspect all those
delegates to make sure they don't play any funny games.

Greg


More information about the Mercurial-devel mailing list