[PATCH 5 of 8] python3: handle urllib/urllib2 refactoring

timeless timeless at gmail.com
Wed Mar 30 00:24:15 EDT 2016


There's a minor bug in this commit, if it's queued, could someone unqueue it?

request.urlencode should be parse.urlencode

On Tue, Mar 29, 2016 at 2:13 PM, timeless <timeless at mozdev.org> wrote:
> # HG changeset patch
> # User timeless <timeless at mozdev.org>
> # Date 1459202612 0
> #      Mon Mar 28 22:03:32 2016 +0000
> # Node ID 9cc313935891c1805c271ef56ec524156eccc806
> # Parent  b2205d49ee6f9a8c6ce8316bce8fd25e5d593775
> python3: handle urllib/urllib2 refactoring
>
> diff --git a/hgext/acl.py b/hgext/acl.py
> --- a/hgext/acl.py
> +++ b/hgext/acl.py
> @@ -194,7 +194,13 @@
>  from __future__ import absolute_import
>
>  import getpass
> -import urllib
> +
> +try:
> +    import urllib
> +    unquote = urllib.unquote
> +except AttributeError:
> +    import urllib.request
> +    unquote = urllib.request.unquote
>
>  from mercurial.i18n import _
>  from mercurial import (
> @@ -287,7 +293,7 @@
>      if source == 'serve' and 'url' in kwargs:
>          url = kwargs['url'].split(':')
>          if url[0] == 'remote' and url[1].startswith('http'):
> -            user = urllib.unquote(url[3])
> +            user = unquote(url[3])
>
>      if user is None:
>          user = getpass.getuser()
> diff --git a/hgext/convert/subversion.py b/hgext/convert/subversion.py
> --- a/hgext/convert/subversion.py
> +++ b/hgext/convert/subversion.py
> @@ -9,10 +9,25 @@
>  import re
>  import sys
>  import tempfile
> -import urllib
> -import urllib2
>  import xml.dom.minidom
>
> +try:
> +    import urllib2
> +    import urllib
> +    httperror = urllib2.HTTPError
> +    build_opener = urllib2.build_opener
> +    quote = urllib.quote
> +    unquote = urllib.unquote
> +    url2pathname = urllib.url2pathname
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    httperror = urllib.error.HTTPError
> +    build_opener = urllib.request.build_opener
> +    quote = urllib.request.quote
> +    unquote = urllib.request.unquote
> +    url2pathname = urllib.request.url2pathname
> +
>  from mercurial import (
>      encoding,
>      error,
> @@ -87,7 +102,7 @@
>          mod = '/' + parts[1]
>      return uuid, mod, revnum
>
> -def quote(s):
> +def svnquote(s):
>      # As of svn 1.7, many svn calls expect "canonical" paths. In
>      # theory, we should call svn.core.*canonicalize() on all paths
>      # before passing them to the API.  Instead, we assume the base url
> @@ -95,7 +110,7 @@
>      # so we can extend it safely with new components. The "safe"
>      # characters were taken from the "svn_uri__char_validity" table in
>      # libsvn_subr/path.c.
> -    return urllib.quote(s, "!$&'()*+,-./:=@_~")
> +    return quote(s, "!$&'()*+,-./:=@_~")
>
>  def geturl(path):
>      try:
> @@ -110,7 +125,7 @@
>          # Module URL is later compared with the repository URL returned
>          # by svn API, which is UTF-8.
>          path = encoding.tolocal(path)
> -        path = 'file://%s' % quote(path)
> +        path = 'file://%s' % svnquote(path)
>      return svn.core.svn_path_canonicalize(path)
>
>  def optrev(number):
> @@ -237,7 +252,7 @@
>          opener = urllib2.build_opener()
>          rsp = opener.open('%s://%s/!svn/ver/0/.svn' % (proto, path))
>          data = rsp.read()
> -    except urllib2.HTTPError as inst:
> +    except httperror as inst:
>          if inst.code != 404:
>              # Except for 404 we cannot know for sure this is not an svn repo
>              ui.warn(_('svn: cannot probe remote repository, assume it could '
> @@ -261,7 +276,7 @@
>              if (os.name == 'nt' and path[:1] == '/' and path[1:2].isalpha()
>                  and path[2:6].lower() == '%3a/'):
>                  path = path[:2] + ':/' + path[6:]
> -            path = urllib.url2pathname(path)
> +            path = url2pathname(path)
>      except ValueError:
>          proto = 'file'
>          path = os.path.abspath(url)
> @@ -331,7 +346,7 @@
>              self.baseurl = svn.ra.get_repos_root(self.ra)
>              # Module is either empty or a repository path starting with
>              # a slash and not ending with a slash.
> -            self.module = urllib.unquote(self.url[len(self.baseurl):])
> +            self.module = unquote(self.url[len(self.baseurl):])
>              self.prevmodule = None
>              self.rootmodule = self.module
>              self.commits = {}
> @@ -395,7 +410,7 @@
>
>      def exists(self, path, optrev):
>          try:
> -            svn.client.ls(self.url.rstrip('/') + '/' + quote(path),
> +            svn.client.ls(self.url.rstrip('/') + '/' + svnquote(path),
>                                   optrev, False, self.ctx)
>              return True
>          except svn.core.SubversionException:
> @@ -447,7 +462,7 @@
>          # Check if branches bring a few more heads to the list
>          if branches:
>              rpath = self.url.strip('/')
> -            branchnames = svn.client.ls(rpath + '/' + quote(branches),
> +            branchnames = svn.client.ls(rpath + '/' + svnquote(branches),
>                                          rev, False, self.ctx)
>              for branch in sorted(branchnames):
>                  module = '%s/%s/%s' % (oldmodule, branches, branch)
> @@ -481,7 +496,7 @@
>          if full or not parents:
>              # Perform a full checkout on roots
>              uuid, module, revnum = revsplit(rev)
> -            entries = svn.client.ls(self.baseurl + quote(module),
> +            entries = svn.client.ls(self.baseurl + svnquote(module),
>                                      optrev(revnum), True, self.ctx)
>              files = [n for n, e in entries.iteritems()
>                       if e.kind == svn.core.svn_node_file]
> @@ -729,7 +744,7 @@
>          """Reparent the svn transport and return the previous parent."""
>          if self.prevmodule == module:
>              return module
> -        svnurl = self.baseurl + quote(module)
> +        svnurl = self.baseurl + svnquote(module)
>          prevmodule = self.prevmodule
>          if prevmodule is None:
>              prevmodule = ''
> @@ -1012,7 +1027,7 @@
>          """Enumerate all files in path at revnum, recursively."""
>          path = path.strip('/')
>          pool = svn.core.Pool()
> -        rpath = '/'.join([self.baseurl, quote(path)]).strip('/')
> +        rpath = '/'.join([self.baseurl, svnquote(path)]).strip('/')
>          entries = svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool)
>          if path:
>              path += '/'
> diff --git a/hgext/largefiles/proto.py b/hgext/largefiles/proto.py
> --- a/hgext/largefiles/proto.py
> +++ b/hgext/largefiles/proto.py
> @@ -4,9 +4,15 @@
>  # GNU General Public License version 2 or any later version.
>
>  import os
> -import urllib2
>  import re
>
> +try:
> +    import urllib2
> +    httperror = urllib2.HTTPError
> +except ImportError:
> +    import urllib.error
> +    httperror = urllib.error.HTTPError
> +
>  from mercurial import error, httppeer, util, wireproto
>  from mercurial.i18n import _
>
> @@ -140,7 +146,7 @@
>              yield result, f
>              try:
>                  yield int(f.value)
> -            except (ValueError, urllib2.HTTPError):
> +            except (ValueError, httperror):
>                  # If the server returns anything but an integer followed by a
>                  # newline, newline, it's not speaking our language; if we get
>                  # an HTTP error, we can't be sure the largefile is present;
> diff --git a/hgext/largefiles/remotestore.py b/hgext/largefiles/remotestore.py
> --- a/hgext/largefiles/remotestore.py
> +++ b/hgext/largefiles/remotestore.py
> @@ -6,7 +6,14 @@
>
>  '''remote largefile store; the base class for wirestore'''
>
> -import urllib2
> +try:
> +    import urllib2
> +    httperror = urllib2.HTTPError
> +    urlerror = urllib2.URLError
> +except ImportError:
> +    import urllib.error
> +    httperror = urllib.error.HTTPError
> +    urlerror = urllib.error.URLError
>
>  from mercurial import util, wireproto, error
>  from mercurial.i18n import _
> @@ -49,11 +56,11 @@
>      def _getfile(self, tmpfile, filename, hash):
>          try:
>              chunks = self._get(hash)
> -        except urllib2.HTTPError as e:
> +        except httperror as e:
>              # 401s get converted to error.Aborts; everything else is fine being
>              # turned into a StoreError
>              raise basestore.StoreError(filename, hash, self.url, str(e))
> -        except urllib2.URLError as e:
> +        except urlerror as e:
>              # This usually indicates a connection problem, so don't
>              # keep trying with the other files... they will probably
>              # all fail too.
> diff --git a/mercurial/bundle2.py b/mercurial/bundle2.py
> --- a/mercurial/bundle2.py
> +++ b/mercurial/bundle2.py
> @@ -152,7 +152,15 @@
>  import string
>  import struct
>  import sys
> -import urllib
> +
> +try:
> +    import urllib
> +    quote = urllib.quote
> +    unquote = urllib.unquote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
> +    unquote = urllib.request.unquote
>
>  from .i18n import _
>  from . import (
> @@ -467,8 +475,8 @@
>      chunks = []
>      for ca in sorted(caps):
>          vals = caps[ca]
> -        ca = urllib.quote(ca)
> -        vals = [urllib.quote(v) for v in vals]
> +        ca = quote(ca)
> +        vals = [quote(v) for v in vals]
>          if vals:
>              ca = "%s=%s" % (ca, ','.join(vals))
>          chunks.append(ca)
> @@ -570,9 +578,9 @@
>          """return a encoded version of all stream parameters"""
>          blocks = []
>          for par, value in self._params:
> -            par = urllib.quote(par)
> +            par = quote(par)
>              if value is not None:
> -                value = urllib.quote(value)
> +                value = quote(value)
>                  par = '%s=%s' % (par, value)
>              blocks.append(par)
>          return ' '.join(blocks)
> diff --git a/mercurial/byterange.py b/mercurial/byterange.py
> --- a/mercurial/byterange.py
> +++ b/mercurial/byterange.py
> @@ -26,22 +26,45 @@
>  import re
>  import socket
>  import stat
> -import urllib
> -import urllib2
>
> -addclosehook = urllib.addclosehook
> -addinfourl = urllib.addinfourl
> -splitattr = urllib.splitattr
> -splitpasswd = urllib.splitpasswd
> -splitport = urllib.splitport
> -splituser = urllib.splituser
> -unquote = urllib.unquote
> +try:
> +    import urllib2
> +    import urllib
> +    basehandler = urllib2.BaseHandler
> +    filehandler = urllib2.FileHandler
> +    ftphandler = urllib2.FTPHandler
> +    ftpwrapper = urllib.ftpwrapper
> +    urlerror = urllib2.URLError
> +    addclosehook = urllib.addclosehook
> +    addinfourl = urllib.addinfourl
> +    splitattr = urllib.splitattr
> +    splitpasswd = urllib.splitpasswd
> +    splitport = urllib.splitport
> +    splituser = urllib.splituser
> +    unquote = urllib.unquote
> +    url2pathname = urllib.url2pathname
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    basehandler = urllib.request.BaseHandler
> +    filehandler = urllib.request.FileHandler
> +    ftphandler = urllib.request.FTPHandler
> +    ftpwrapper = urllib.request.ftpwrapper
> +    urlerror = urllib.error.URLError
> +    addclosehook = urllib.request.addclosehook
> +    addinfourl = urllib.request.addinfourl
> +    splitattr = urllib.request.splitattr
> +    splitpasswd = urllib.request.splitpasswd
> +    splitport = urllib.request.splitport
> +    splituser = urllib.request.splituser
> +    unquote = urllib.request.unquote
> +    url2pathname = urllib.request.url2pathname
>
>  class RangeError(IOError):
>      """Error raised when an unsatisfiable range is requested."""
>      pass
>
> -class HTTPRangeHandler(urllib2.BaseHandler):
> +class HTTPRangeHandler(basehandler):
>      """Handler that enables HTTP Range headers.
>
>      This was extremely simple. The Range header is a HTTP feature to
> @@ -67,7 +90,7 @@
>
>      def http_error_206(self, req, fp, code, msg, hdrs):
>          # 206 Partial Content Response
> -        r = urllib.addinfourl(fp, hdrs, req.get_full_url())
> +        r = addinfourl(fp, hdrs, req.get_full_url())
>          r.code = code
>          r.msg = msg
>          return r
> @@ -204,7 +227,7 @@
>                  raise RangeError('Requested Range Not Satisfiable')
>              pos += bufsize
>
> -class FileRangeHandler(urllib2.FileHandler):
> +class FileRangeHandler(filehandler):
>      """FileHandler subclass that adds Range support.
>      This class handles Range headers exactly like an HTTP
>      server would.
> @@ -212,15 +235,15 @@
>      def open_local_file(self, req):
>          host = req.get_host()
>          file = req.get_selector()
> -        localfile = urllib.url2pathname(file)
> +        localfile = url2pathname(file)
>          stats = os.stat(localfile)
>          size = stats[stat.ST_SIZE]
>          modified = email.Utils.formatdate(stats[stat.ST_MTIME])
>          mtype = mimetypes.guess_type(file)[0]
>          if host:
> -            host, port = urllib.splitport(host)
> +            host, port = splitport(host)
>              if port or socket.gethostbyname(host) not in self.get_names():
> -                raise urllib2.URLError('file not on local host')
> +                raise urlerror('file not on local host')
>          fo = open(localfile,'rb')
>          brange = req.headers.get('Range', None)
>          brange = range_header_to_tuple(brange)
> @@ -236,7 +259,7 @@
>          headers = email.message_from_string(
>              'Content-Type: %s\nContent-Length: %d\nLast-Modified: %s\n' %
>              (mtype or 'text/plain', size, modified))
> -        return urllib.addinfourl(fo, headers, 'file:'+file)
> +        return addinfourl(fo, headers, 'file:'+file)
>
>
>  # FTP Range Support
> @@ -246,7 +269,7 @@
>  # follows:
>  # -- range support modifications start/end here
>
> -class FTPRangeHandler(urllib2.FTPHandler):
> +class FTPRangeHandler(ftphandler):
>      def ftp_open(self, req):
>          host = req.get_host()
>          if not host:
> @@ -270,7 +293,7 @@
>          try:
>              host = socket.gethostbyname(host)
>          except socket.error as msg:
> -            raise urllib2.URLError(msg)
> +            raise urlerror(msg)
>          path, attrs = splitattr(req.get_selector())
>          dirs = path.split('/')
>          dirs = map(unquote, dirs)
> @@ -331,10 +354,10 @@
>              raise IOError('ftp error', msg)
>
>      def connect_ftp(self, user, passwd, host, port, dirs):
> -        fw = ftpwrapper(user, passwd, host, port, dirs)
> +        fw = ftpwrapperrest(user, passwd, host, port, dirs)
>          return fw
>
> -class ftpwrapper(urllib.ftpwrapper):
> +class ftpwrapperrest(ftpwrapper):
>      # range support note:
>      # this ftpwrapper code is copied directly from
>      # urllib. The only enhancement is to add the rest
> diff --git a/mercurial/exchange.py b/mercurial/exchange.py
> --- a/mercurial/exchange.py
> +++ b/mercurial/exchange.py
> @@ -8,8 +8,20 @@
>  from __future__ import absolute_import
>
>  import errno
> -import urllib
> -import urllib2
> +
> +try:
> +    import urllib2
> +    import urllib
> +    httperror = urllib2.HTTPError
> +    urlerror = urllib2.URLError
> +    quote = urllib.quote
> +    unquote = urllib.unquote
> +except ImportError:
> +    import urllib.error
> +    httperror = urllib.error.HTTPError
> +    urlerror = urllib.error.URLError
> +    quote = urllib.request.quote
> +    unquote = urllib.request.unquote
>
>  from .i18n import _
>  from .node import (
> @@ -97,8 +109,8 @@
>                        'missing "=" in parameter: %s') % p)
>
>              key, value = p.split('=', 1)
> -            key = urllib.unquote(key)
> -            value = urllib.unquote(value)
> +            key = unquote(key)
> +            value = unquote(value)
>              params[key] = value
>
>          return version, params
> @@ -236,7 +248,7 @@
>      elif isinstance(b, streamclone.streamcloneapplier):
>          requirements = streamclone.readbundle1header(fh)[2]
>          params = 'requirements=%s' % ','.join(sorted(requirements))
> -        return 'none-packed1;%s' % urllib.quote(params)
> +        return 'none-packed1;%s' % quote(params)
>      else:
>          raise error.Abort(_('unknown bundle type: %s') % b)
>
> @@ -1469,7 +1481,7 @@
>      """return a set with appropriate options to use bundle20 during getbundle"""
>      caps = set(['HG20'])
>      capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
> -    caps.add('bundle2=' + urllib.quote(capsblob))
> +    caps.add('bundle2=' + quote(capsblob))
>      return caps
>
>  # List of names of steps to perform for a bundle2 for getbundle, order matters.
> @@ -1535,7 +1547,7 @@
>      b2caps = {}
>      for bcaps in bundlecaps:
>          if bcaps.startswith('bundle2='):
> -            blob = urllib.unquote(bcaps[len('bundle2='):])
> +            blob = unquote(bcaps[len('bundle2='):])
>              b2caps.update(bundle2.decodecaps(blob))
>      bundler = bundle2.bundle20(repo.ui, b2caps)
>
> @@ -1804,8 +1816,8 @@
>          attrs = {'URL': fields[0]}
>          for rawattr in fields[1:]:
>              key, value = rawattr.split('=', 1)
> -            key = urllib.unquote(key)
> -            value = urllib.unquote(value)
> +            key = unquote(key)
> +            value = unquote(value)
>              attrs[key] = value
>
>              # Parse BUNDLESPEC into components. This makes client-side
> diff --git a/mercurial/hgweb/protocol.py b/mercurial/hgweb/protocol.py
> --- a/mercurial/hgweb/protocol.py
> +++ b/mercurial/hgweb/protocol.py
> @@ -8,7 +8,6 @@
>  from __future__ import absolute_import
>
>  import cgi
> -import urllib
>  import zlib
>
>  try:
> @@ -16,6 +15,13 @@
>  except ImportError:
>      import io
>
> +try:
> +    import urllib
> +    quote = urllib.quote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
> +
>  from .common import (
>      HTTP_OK,
>  )
> @@ -86,8 +92,8 @@
>      def _client(self):
>          return 'remote:%s:%s:%s' % (
>              self.req.env.get('wsgi.url_scheme') or 'http',
> -            urllib.quote(self.req.env.get('REMOTE_HOST', '')),
> -            urllib.quote(self.req.env.get('REMOTE_USER', '')))
> +            quote(self.req.env.get('REMOTE_HOST', '')),
> +            quote(self.req.env.get('REMOTE_USER', '')))
>
>  def iscmd(cmd):
>      return cmd in wireproto.commands
> diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py
> --- a/mercurial/hgweb/server.py
> +++ b/mercurial/hgweb/server.py
> @@ -15,7 +15,13 @@
>  import socket
>  import sys
>  import traceback
> -import urllib
> +
> +try:
> +    import urllib
> +    unquote = urllib.unquote
> +except AttributeError:
> +    import urllib.request
> +    unquote = urllib.request.unquote
>
>  from ..i18n import _
>
> @@ -38,7 +44,7 @@
>          path, query = uri.split('?', 1)
>      else:
>          path, query = uri, ''
> -    return urllib.unquote(path), query
> +    return unquote(path), query
>
>  class _error_logger(object):
>      def __init__(self, handler):
> diff --git a/mercurial/httpconnection.py b/mercurial/httpconnection.py
> --- a/mercurial/httpconnection.py
> +++ b/mercurial/httpconnection.py
> @@ -13,8 +13,23 @@
>  import logging
>  import os
>  import socket
> -import urllib
> -import urllib2
> +
> +try:
> +    import urllib2
> +    import urllib
> +    httphandler = urllib2.HTTPHandler
> +    httpshandler = urllib2.HTTPSHandler
> +    abstracthttphandler = urllib2.AbstractHTTPHandler
> +    addinfourl = urllib.addinfourl
> +    urlerror = urllib2.URLError
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    httphandler = urllib.request.HTTPHandler
> +    httpshandler = urllib.request.HTTPSHandler
> +    abstracthttphandler = urllib.request.AbstractHTTPHandler
> +    addinfourl = urllib.request.addinfourl
> +    urlerror = urllib.error.URLError
>
>  from .i18n import _
>  from . import (
> @@ -123,10 +138,10 @@
>  # Subclass BOTH of these because otherwise urllib2 "helpfully"
>  # reinserts them since it notices we don't include any subclasses of
>  # them.
> -class http2handler(urllib2.HTTPHandler, urllib2.HTTPSHandler):
> +class http2handler(httphandler, httpshandler):
>      def __init__(self, ui, pwmgr):
>          global _configuredlogging
> -        urllib2.AbstractHTTPHandler.__init__(self)
> +        abstracthttphandler.__init__(self)
>          self.ui = ui
>          self.pwmgr = pwmgr
>          self._connections = {}
> @@ -187,7 +202,7 @@
>              proxy = None
>
>          if not host:
> -            raise urllib2.URLError('no host given')
> +            raise urlerror('no host given')
>
>          connkey = use_ssl, host, proxy
>          allconns = self._connections.get(connkey, [])
> @@ -217,13 +232,13 @@
>              h.request(req.get_method(), path, req.data, headers)
>              r = h.getresponse()
>          except socket.error as err: # XXX what error?
> -            raise urllib2.URLError(err)
> +            raise urlerror(err)
>
>          # Pick apart the HTTPResponse object to get the addinfourl
>          # object initialized properly.
>          r.recv = r.read
>
> -        resp = urllib.addinfourl(r, r.headers, req.get_full_url())
> +        resp = addinfourl(r, r.headers, req.get_full_url())
>          resp.code = r.status
>          resp.msg = r.reason
>          return resp
> diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py
> --- a/mercurial/httppeer.py
> +++ b/mercurial/httppeer.py
> @@ -13,10 +13,21 @@
>  import os
>  import socket
>  import tempfile
> -import urllib
> -import urllib2
>  import zlib
>
> +try:
> +    import urllib2
> +    import urllib
> +    request = urllib2.Request
> +    httperror = urllib2.HTTPError
> +    urlencode = urllib.urlencode
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    request = urllib.request.Request
> +    httperror = urllib.error.HTTPError
> +    urlencode = urllib.request.urlencode
> +
>  from .i18n import _
>  from .node import nullid
>  from . import (
> @@ -59,7 +70,7 @@
>          self.ui.debug('using %s\n' % self._url)
>
>          self.urlopener = url.opener(ui, authinfo)
> -        self.requestbuilder = urllib2.Request
> +        self.requestbuilder = request
>
>      def __del__(self):
>          if self.urlopener:
> @@ -105,7 +116,7 @@
>          # object rather than a basestring
>          canmungedata = not data or isinstance(data, basestring)
>          if postargsok and canmungedata:
> -            strargs = urllib.urlencode(sorted(args.items()))
> +            strargs = urlencode(sorted(args.items()))
>              if strargs:
>                  if not data:
>                      data = strargs
> @@ -119,7 +130,7 @@
>                      headersize = int(httpheader.split(',', 1)[0])
>              if headersize > 0:
>                  # The headers can typically carry more data than the URL.
> -                encargs = urllib.urlencode(sorted(args.items()))
> +                encargs = urlencode(sorted(args.items()))
>                  headerfmt = 'X-HgArg-%s'
>                  contentlen = headersize - len(headerfmt % '000' + ': \r\n')
>                  headernum = 0
> @@ -132,7 +143,7 @@
>                  headers['Vary'] = ','.join(varyheaders)
>              else:
>                  q += sorted(args.items())
> -        qs = '?%s' % urllib.urlencode(q)
> +        qs = '?%s' % urlencode(q)
>          cu = "%s%s" % (self._url, qs)
>          size = 0
>          if util.safehasattr(data, 'length'):
> @@ -150,7 +161,7 @@
>              req.add_unredirected_header('Content-Length', '%d' % size)
>          try:
>              resp = self.urlopener.open(req)
> -        except urllib2.HTTPError as inst:
> +        except httperror as inst:
>              if inst.code == 401:
>                  raise error.Abort(_('authorization failed'))
>              raise
> diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
> --- a/mercurial/keepalive.py
> +++ b/mercurial/keepalive.py
> @@ -25,13 +25,23 @@
>
>  """An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive.
>
> ->>> import urllib2
> +>>> try:
> +...     import urllib2
> +...     build_opener = urllib2.build_opener
> +...     install_opener = urllib2.install_opener
> +...     urlopen = urllib2.urlopen
> +... except ImportError:
> +...     import urllib.request
> +...     build_opener = urllib.request.build_opener
> +...     install_opener = urllib.request.install_opener
> +...     urlopen = urllib.request.urlopen
> +
>  >>> from keepalive import HTTPHandler
>  >>> keepalive_handler = HTTPHandler()
> ->>> opener = urllib2.build_opener(keepalive_handler)
> ->>> urllib2.install_opener(opener)
> +>>> opener = build_opener(keepalive_handler)
> +>>> install_opener(opener)
>  >>>
> ->>> fo = urllib2.urlopen('http://www.python.org')
> +>>> fo = urlopen('http://www.python.org')
>
>  If a connection to a given host is requested, and all of the existing
>  connections are still in use, another connection will be opened.  If
> @@ -114,7 +124,22 @@
>  import socket
>  import sys
>  import thread
> -import urllib2
> +
> +try:
> +    import urllib2
> +    build_opener = urllib2.build_opener
> +    install_opener = urllib2.install_opener
> +    urlopen = urllib2.urlopen
> +    httphandler = urllib2.HTTPHandler
> +    urlerror = urllib2.URLError
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    build_opener = urllib.request.build_opener
> +    install_opener = urllib.request.install_opener
> +    urlopen = urllib.request.urlopen
> +    httphandler = urllib.request.HTTPHandler
> +    urlerror = urllib.error.URLError
>
>  DEBUG = None
>
> @@ -227,7 +252,7 @@
>      def do_open(self, http_class, req):
>          host = req.get_host()
>          if not host:
> -            raise urllib2.URLError('no host given')
> +            raise urlerror('no host given')
>
>          try:
>              h = self._cm.get_ready_conn(host)
> @@ -254,7 +279,7 @@
>                  self._start_transaction(h, req)
>                  r = h.getresponse()
>          except (socket.error, httplib.HTTPException) as err:
> -            raise urllib2.URLError(err)
> +            raise urlerror(err)
>
>          # if not a persistent connection, don't try to reuse it
>          if r.will_close:
> @@ -346,14 +371,14 @@
>              else:
>                  h.putrequest('GET', req.get_selector(), **skipheaders)
>          except socket.error as err:
> -            raise urllib2.URLError(err)
> +            raise urlerror(err)
>          for k, v in headers.items():
>              h.putheader(k, v)
>          h.endheaders()
>          if req.has_data():
>              h.send(data)
>
> -class HTTPHandler(KeepAliveHandler, urllib2.HTTPHandler):
> +class HTTPHandler(KeepAliveHandler, httphandler):
>      pass
>
>  class HTTPResponse(httplib.HTTPResponse):
> @@ -593,14 +618,14 @@
>      global HANDLE_ERRORS
>      orig = HANDLE_ERRORS
>      keepalive_handler = HTTPHandler()
> -    opener = urllib2.build_opener(keepalive_handler)
> -    urllib2.install_opener(opener)
> +    opener = build_opener(keepalive_handler)
> +    install_opener(opener)
>      pos = {0: 'off', 1: 'on'}
>      for i in (0, 1):
>          print("  fancy error handling %s (HANDLE_ERRORS = %i)" % (pos[i], i))
>          HANDLE_ERRORS = i
>          try:
> -            fo = urllib2.urlopen(url)
> +            fo = urlopen(url)
>              fo.read()
>              fo.close()
>              try:
> @@ -623,25 +648,25 @@
>      format = '%25s: %s'
>
>      # first fetch the file with the normal http handler
> -    opener = urllib2.build_opener()
> -    urllib2.install_opener(opener)
> -    fo = urllib2.urlopen(url)
> +    opener = build_opener()
> +    install_opener(opener)
> +    fo = urlopen(url)
>      foo = fo.read()
>      fo.close()
>      m = md5(foo)
>      print(format % ('normal urllib', m.hexdigest()))
>
>      # now install the keepalive handler and try again
> -    opener = urllib2.build_opener(HTTPHandler())
> -    urllib2.install_opener(opener)
> +    opener = build_opener(HTTPHandler())
> +    install_opener(opener)
>
> -    fo = urllib2.urlopen(url)
> +    fo = urlopen(url)
>      foo = fo.read()
>      fo.close()
>      m = md5(foo)
>      print(format % ('keepalive read', m.hexdigest()))
>
> -    fo = urllib2.urlopen(url)
> +    fo = urlopen(url)
>      foo = ''
>      while True:
>          f = fo.readline()
> @@ -657,15 +682,15 @@
>
>      sys.stdout.write('  first using the normal urllib handlers')
>      # first use normal opener
> -    opener = urllib2.build_opener()
> -    urllib2.install_opener(opener)
> +    opener = build_opener()
> +    install_opener(opener)
>      t1 = fetch(N, url)
>      print('  TIME: %.3f s' % t1)
>
>      sys.stdout.write('  now using the keepalive handler       ')
>      # now install the keepalive handler and try again
> -    opener = urllib2.build_opener(HTTPHandler())
> -    urllib2.install_opener(opener)
> +    opener = build_opener(HTTPHandler())
> +    install_opener(opener)
>      t2 = fetch(N, url)
>      print('  TIME: %.3f s' % t2)
>      print('  improvement factor: %.2f' % (t1 / t2))
> @@ -677,7 +702,7 @@
>      for i in range(N):
>          if delay and i > 0:
>              time.sleep(delay)
> -        fo = urllib2.urlopen(url)
> +        fo = urlopen(url)
>          foo = fo.read()
>          fo.close()
>          lens.append(len(foo))
> @@ -700,7 +725,7 @@
>          info = warning = error = debug
>      DEBUG = FakeLogger()
>      print("  fetching the file to establish a connection")
> -    fo = urllib2.urlopen(url)
> +    fo = urlopen(url)
>      data1 = fo.read()
>      fo.close()
>
> @@ -714,7 +739,7 @@
>      sys.stderr.write('\r')
>
>      print("  fetching the file a second time")
> -    fo = urllib2.urlopen(url)
> +    fo = urlopen(url)
>      data2 = fo.read()
>      fo.close()
>
> diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
> --- a/mercurial/localrepo.py
> +++ b/mercurial/localrepo.py
> @@ -12,9 +12,15 @@
>  import os
>  import random
>  import time
> -import urllib
>  import weakref
>
> +try:
> +    import urllib
> +    quote = urllib.quote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
> +
>  from .i18n import _
>  from .node import (
>      hex,
> @@ -366,7 +372,7 @@
>          if self.ui.configbool('experimental', 'bundle2-advertise', True):
>              caps = set(caps)
>              capsblob = bundle2.encodecaps(bundle2.getrepocaps(self))
> -            caps.add('bundle2=' + urllib.quote(capsblob))
> +            caps.add('bundle2=' + quote(capsblob))
>          return caps
>
>      def _applyopenerreqs(self):
> diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py
> --- a/mercurial/statichttprepo.py
> +++ b/mercurial/statichttprepo.py
> @@ -11,8 +11,21 @@
>
>  import errno
>  import os
> -import urllib
> -import urllib2
> +
> +try:
> +    import urllib2
> +    import urllib
> +    request = urllib2.Request
> +    httperror = urllib2.HTTPError
> +    quote = urllib.quote
> +    urlerror = urllib2.URLError
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    request = urllib.request.Request
> +    httperror = urllib.error.HTTPError
> +    quote = urllib.request.quote
> +    urlerror = urllib.error.URLError
>
>  from .i18n import _
>  from . import (
> @@ -45,7 +58,7 @@
>      def seek(self, pos):
>          self.pos = pos
>      def read(self, bytes=None):
> -        req = urllib2.Request(self.url)
> +        req = request(self.url)
>          end = ''
>          if bytes:
>              end = self.pos + bytes - 1
> @@ -56,10 +69,10 @@
>              f = self.opener.open(req)
>              data = f.read()
>              code = f.code
> -        except urllib2.HTTPError as inst:
> +        except httperror as inst:
>              num = inst.code == 404 and errno.ENOENT or None
>              raise IOError(num, inst)
> -        except urllib2.URLError as inst:
> +        except urlerror as inst:
>              raise IOError(None, inst.reason[1])
>
>          if code == 200:
> @@ -92,7 +105,7 @@
>          def __call__(self, path, mode='r', *args, **kw):
>              if mode not in ('r', 'rb'):
>                  raise IOError('Permission denied')
> -            f = "/".join((self.base, urllib.quote(path)))
> +            f = "/".join((self.base, quote(path)))
>              return httprangereader(f, urlopener)
>
>          def join(self, path):
> diff --git a/mercurial/templatefilters.py b/mercurial/templatefilters.py
> --- a/mercurial/templatefilters.py
> +++ b/mercurial/templatefilters.py
> @@ -11,7 +11,13 @@
>  import os
>  import re
>  import time
> -import urllib
> +
> +try:
> +    import urllib
> +    quote = urllib.quote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
>
>  from . import (
>      encoding,
> @@ -269,7 +275,7 @@
>      Forward slashes are escaped twice to prevent web servers from prematurely
>      unescaping them. For example, "@foo bar/baz" becomes "@foo%20bar%252Fbaz".
>      """
> -    return urllib.quote(text, safe='/@').replace('/', '%252F')
> +    return quote(text, safe='/@').replace('/', '%252F')
>
>  def rfc3339date(text):
>      """:rfc3339date: Date. Returns a date using the Internet date format
> @@ -342,7 +348,7 @@
>      """:urlescape: Any text. Escapes all "special" characters. For example,
>      "foo bar" becomes "foo%20bar".
>      """
> -    return urllib.quote(text)
> +    return quote(text)
>
>  def userfilter(text):
>      """:user: Any text. Returns a short representation of a user name or email
> diff --git a/mercurial/url.py b/mercurial/url.py
> --- a/mercurial/url.py
> +++ b/mercurial/url.py
> @@ -13,8 +13,39 @@
>  import httplib
>  import os
>  import socket
> -import urllib
> -import urllib2
> +
> +try:
> +    import urllib2
> +    import urllib
> +    build_opener = urllib2.build_opener
> +    pathname2url = urllib.pathname2url
> +    pyhttpbasicauthhandler = urllib2.HTTPBasicAuthHandler
> +    pyhttpdigestauthhandler = urllib2.HTTPDigestAuthHandler
> +    pyhttppasswordmgrwithdefaultrealm = urllib2.HTTPPasswordMgrWithDefaultRealm
> +    pyproxyhandler = urllib2.ProxyHandler
> +
> +    try:
> +        pyhttpshandler = urllib2.HTTPSHandler
> +        has_https = True
> +    except AttributeError:
> +        has_https = False
> +
> +except ImportError:
> +    import urllib.request
> +    import urllib.error
> +    build_opener = urllib.request.build_opener
> +    pathname2url = urllib.request.pathname2url
> +    pyhttpbasicauthhandler = urllib.request.HTTPBasicAuthHandler
> +    pyhttpdigestauthhandler = urllib.request.HTTPDigestAuthHandler
> +    pyhttppasswordmgrwithdefaultrealm = \
> +        urllib.request.HTTPPasswordMgrWithDefaultRealm
> +    pyproxyhandler = urllib.request.ProxyHandler
> +
> +    try:
> +        pyhttpshandler = urllib.request.HTTPSHandler
> +        has_https = True
> +    except AttributeError:
> +        has_https = False
>
>  try:
>      import cStringIO as io
> @@ -30,13 +61,13 @@
>      util,
>  )
>
> -class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
> +class passwordmgr(pyhttppasswordmgrwithdefaultrealm):
>      def __init__(self, ui):
> -        urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
> +        pyhttppasswordmgrwithdefaultrealm.__init__(self)
>          self.ui = ui
>
>      def find_user_password(self, realm, authuri):
> -        authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
> +        authinfo = pyhttppasswordmgrwithdefaultrealm.find_user_password(
>              self, realm, authuri)
>          user, passwd = authinfo
>          if user and passwd:
> @@ -76,10 +107,10 @@
>          self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
>
>      def find_stored_password(self, authuri):
> -        return urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
> +        return pyhttppasswordmgrwithdefaultrealm.find_user_password(
>              self, None, authuri)
>
> -class proxyhandler(urllib2.ProxyHandler):
> +class proxyhandler(pyproxyhandler):
>      def __init__(self, ui):
>          proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
>          # XXX proxyauthinfo = None
> @@ -125,7 +156,7 @@
>                  except OSError:
>                      pass
>
> -        urllib2.ProxyHandler.__init__(self, proxies)
> +        pyproxyhandler.__init__(self, proxies)
>          self.ui = ui
>
>      def proxy_open(self, req, proxy, type_):
> @@ -138,7 +169,7 @@
>              if e.startswith('.') and host.endswith(e[1:]):
>                  return None
>
> -        return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
> +        return pyproxyhandler.proxy_open(self, req, proxy, type_)
>
>  def _gen_sendfile(orgsend):
>      def _sendfile(self, data):
> @@ -152,7 +183,6 @@
>              orgsend(self, data)
>      return _sendfile
>
> -has_https = util.safehasattr(urllib2, 'HTTPSHandler')
>  if has_https:
>      try:
>          _create_connection = socket.create_connection
> @@ -361,10 +391,10 @@
>                  **sslutil.sslkwargs(self.ui, host))
>              sslutil.validator(self.ui, host)(self.sock)
>
> -    class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
> +    class httpshandler(keepalive.KeepAliveHandler, pyhttpshandler):
>          def __init__(self, ui):
>              keepalive.KeepAliveHandler.__init__(self)
> -            urllib2.HTTPSHandler.__init__(self)
> +            pyhttpshandler.__init__(self)
>              self.ui = ui
>              self.pwmgr = passwordmgr(self.ui)
>
> @@ -407,9 +437,9 @@
>              conn.ui = self.ui
>              return conn
>
> -class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
> +class httpdigestauthhandler(pyhttpdigestauthhandler):
>      def __init__(self, *args, **kwargs):
> -        urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
> +        pyhttpdigestauthhandler.__init__(self, *args, **kwargs)
>          self.retried_req = None
>
>      def reset_retry_count(self):
> @@ -423,13 +453,13 @@
>          if req is not self.retried_req:
>              self.retried_req = req
>              self.retried = 0
> -        return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
> +        return pyhttpdigestauthhandler.http_error_auth_reqed(
>                      self, auth_header, host, req, headers)
>
> -class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
> +class httpbasicauthhandler(pyhttpbasicauthhandler):
>      def __init__(self, *args, **kwargs):
>          self.auth = None
> -        urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
> +        pyhttpbasicauthhandler.__init__(self, *args, **kwargs)
>          self.retried_req = None
>
>      def http_request(self, request):
> @@ -455,7 +485,7 @@
>          if req is not self.retried_req:
>              self.retried_req = req
>              self.retried = 0
> -        return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
> +        return pyhttpbasicauthhandler.http_error_auth_reqed(
>                          self, auth_header, host, req, headers)
>
>      def retry_http_basic_auth(self, host, req, realm):
> @@ -498,7 +528,7 @@
>      handlers.extend((httpbasicauthhandler(passmgr),
>                       httpdigestauthhandler(passmgr)))
>      handlers.extend([h(ui, passmgr) for h in handlerfuncs])
> -    opener = urllib2.build_opener(*handlers)
> +    opener = build_opener(*handlers)
>
>      # 1.0 here is the _protocol_ version
>      opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
> @@ -512,6 +542,6 @@
>          url_, authinfo = u.authinfo()
>      else:
>          path = util.normpath(os.path.abspath(url_))
> -        url_ = 'file://' + urllib.pathname2url(path)
> +        url_ = 'file://' + pathname2url(path)
>          authinfo = None
>      return opener(ui, authinfo).open(url_, data)
> diff --git a/mercurial/util.py b/mercurial/util.py
> --- a/mercurial/util.py
> +++ b/mercurial/util.py
> @@ -34,9 +34,15 @@
>  import textwrap
>  import time
>  import traceback
> -import urllib
>  import zlib
>
> +try:
> +    import urllib
> +    quote = urllib.quote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
> +
>  from . import (
>      encoding,
>      error,
> @@ -2368,30 +2374,30 @@
>              if hasdriveletter(self.path):
>                  s += '/'
>          if self.user:
> -            s += urllib.quote(self.user, safe=self._safechars)
> +            s += quote(self.user, safe=self._safechars)
>          if self.passwd:
> -            s += ':' + urllib.quote(self.passwd, safe=self._safechars)
> +            s += ':' + quote(self.passwd, safe=self._safechars)
>          if self.user or self.passwd:
>              s += '@'
>          if self.host:
>              if not (self.host.startswith('[') and self.host.endswith(']')):
> -                s += urllib.quote(self.host)
> +                s += quote(self.host)
>              else:
>                  s += self.host
>          if self.port:
> -            s += ':' + urllib.quote(self.port)
> +            s += ':' + quote(self.port)
>          if self.host:
>              s += '/'
>          if self.path:
>              # TODO: similar to the query string, we should not unescape the
>              # path when we store it, the path might contain '%2f' = '/',
>              # which we should *not* escape.
> -            s += urllib.quote(self.path, safe=self._safepchars)
> +            s += quote(self.path, safe=self._safepchars)
>          if self.query:
>              # we store the query in escaped form.
>              s += '?' + self.query
>          if self.fragment is not None:
> -            s += '#' + urllib.quote(self.fragment, safe=self._safepchars)
> +            s += '#' + quote(self.fragment, safe=self._safepchars)
>          return s
>
>      def authinfo(self):
> diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py
> --- a/mercurial/wireproto.py
> +++ b/mercurial/wireproto.py
> @@ -11,7 +11,15 @@
>  import os
>  import sys
>  import tempfile
> -import urllib
> +
> +try:
> +    import urllib
> +    quote = urllib.quote
> +    unquote = urllib.unquote
> +except AttributeError:
> +    import urllib.request
> +    quote = urllib.request.quote
> +    unquote = urllib.request.unquote
>
>  from .i18n import _
>  from .node import (
> @@ -287,7 +295,7 @@
>              branchmap = {}
>              for branchpart in d.splitlines():
>                  branchname, branchheads = branchpart.split(' ', 1)
> -                branchname = encoding.tolocal(urllib.unquote(branchname))
> +                branchname = encoding.tolocal(unquote(branchname))
>                  branchheads = decodelist(branchheads)
>                  branchmap[branchname] = branchheads
>              yield branchmap
> @@ -632,7 +640,7 @@
>      branchmap = repo.branchmap()
>      heads = []
>      for branch, nodes in branchmap.iteritems():
> -        branchname = urllib.quote(encoding.fromlocal(branch))
> +        branchname = quote(encoding.fromlocal(branch))
>          branchnodes = encodelist(nodes)
>          heads.append('%s %s' % (branchname, branchnodes))
>      return '\n'.join(heads)
> @@ -684,7 +692,7 @@
>              caps.append('streamreqs=%s' % ','.join(sorted(requiredformats)))
>      if repo.ui.configbool('experimental', 'bundle2-advertise', True):
>          capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
> -        caps.append('bundle2=' + urllib.quote(capsblob))
> +        caps.append('bundle2=' + quote(capsblob))
>      caps.append('unbundle=%s' % ','.join(bundle2.bundlepriority))
>      caps.append(
>          'httpheader=%d' % repo.ui.configint('server', 'maxhttpheaderlen', 1024))
> diff --git a/tests/test-check-py3-compat.t b/tests/test-check-py3-compat.t
> --- a/tests/test-check-py3-compat.t
> +++ b/tests/test-check-py3-compat.t
> @@ -165,8 +165,8 @@
>    hgext/largefiles/lfutil.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    hgext/largefiles/localstore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
>    hgext/largefiles/overrides.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
> -  hgext/largefiles/proto.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
> -  hgext/largefiles/remotestore.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
> +  hgext/largefiles/proto.py: error importing: <ImportError> No module named 'httplib' (error at httppeer.py:*) (glob)
> +  hgext/largefiles/remotestore.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    hgext/largefiles/reposetup.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    hgext/largefiles/uisetup.py: error importing module: <SyntaxError> invalid syntax (archival.py, line *) (line *) (glob)
>    hgext/largefiles/wirestore.py: error importing module: <ImportError> No module named 'lfutil' (line *) (glob)
> @@ -189,7 +189,6 @@
>    mercurial/branchmap.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/bundle*.py: invalid syntax: invalid syntax (<unknown>, line *) (glob)
>    mercurial/bundlerepo.py: error importing module: <SyntaxError> invalid syntax (bundle*.py, line *) (line *) (glob)
> -  mercurial/byterange.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
>    mercurial/changegroup.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/changelog.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/cmdutil.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
> @@ -203,7 +202,7 @@
>    mercurial/dirstate.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/discovery.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/dispatch.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
> -  mercurial/exchange.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
> +  mercurial/exchange.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/extensions.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/filelog.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/filemerge.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
> @@ -223,7 +222,7 @@
>    mercurial/hgweb/wsgicgi.py: error importing module: <SystemError> Parent module 'mercurial.hgweb' not loaded, cannot perform relative import (line *) (glob)
>    mercurial/hook.py: error importing: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (error at i18n.py:*) (glob)
>    mercurial/httpclient/_readers.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
> -  mercurial/httpconnection.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
> +  mercurial/httpconnection.py: error importing: <ImportError> No module named 'httplib' (error at __init__.py:*) (glob)
>    mercurial/httppeer.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
>    mercurial/keepalive.py: error importing module: <ImportError> No module named 'httplib' (line *) (glob)
>    mercurial/localrepo.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
> @@ -254,7 +253,7 @@
>    mercurial/sshpeer.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
>    mercurial/sshserver.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
>    mercurial/sslutil.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
> -  mercurial/statichttprepo.py: error importing module: <ImportError> No module named 'urllib2' (line *) (glob)
> +  mercurial/statichttprepo.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
>    mercurial/store.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
>    mercurial/streamclone.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
>    mercurial/subrepo.py: error importing module: <AttributeError> 'NullTranslations' object has no attribute 'ugettext' (line *) (glob)
> diff --git a/tests/test-hgweb-auth.py b/tests/test-hgweb-auth.py
> --- a/tests/test-hgweb-auth.py
> +++ b/tests/test-hgweb-auth.py
> @@ -1,5 +1,12 @@
> +try:
> +    import urllib2
> +    httppasswordmgrwithdefaultrealm = urllib2.HTTPPasswordMgrWithDefaultRealm
> +except AttributeError:
> +    import urllib.request
> +    httppasswordmgrwithdefaultrealm = \
> +        urllib.request.HTTPPasswordMgrWithDefaultRealm
> +
>  from mercurial import demandimport; demandimport.enable()
> -import urllib2
>  from mercurial import ui, util
>  from mercurial import url
>  from mercurial.error import Abort
> @@ -99,7 +106,7 @@
>
>  def testauthinfo(fullurl, authurl):
>      print 'URIs:', fullurl, authurl
> -    pm = urllib2.HTTPPasswordMgrWithDefaultRealm()
> +    pm = httppasswordmgrwithdefaultrealm()
>      pm.add_password(*util.url(fullurl).authinfo()[1])
>      print pm.find_user_password('test', authurl)
>
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list