[PATCH 5 of 8] python3: handle urllib/urllib2 refactoring
timeless
timeless at mozdev.org
Tue Mar 29 14:13:07 EDT 2016
# 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)
More information about the Mercurial-devel
mailing list