diff -r 1232f7fa00c3 -r 192f7b126ed2 mercurial/urllibcompat.py --- a/mercurial/urllibcompat.py Sun Oct 01 12:14:21 2017 -0400 +++ b/mercurial/urllibcompat.py Wed Oct 04 11:58:00 2017 -0400 @@ -8,7 +8,99 @@ from . import pycompat +_sysstr = pycompat.sysstr + +class _pycompatstub(object): + def __init__(self): + self._aliases = {} + + def _registeraliases(self, origin, items): + """Add items that will be populated at the first access""" + items = map(_sysstr, items) + self._aliases.update( + (item.replace(_sysstr('_'), _sysstr('')).lower(), (origin, item)) + for item in items) + + def _registeralias(self, origin, attr, name): + """Alias ``origin``.``attr`` as ``name``""" + self._aliases[_sysstr(name)] = (origin, _sysstr(attr)) + + def __getattr__(self, name): + try: + origin, item = self._aliases[name] + except KeyError: + raise AttributeError(name) + self.__dict__[name] = obj = getattr(origin, item) + return obj + +httpserver = _pycompatstub() +urlreq = _pycompatstub() +urlerr = _pycompatstub() + if pycompat.ispy3: + import urllib.parse + urlreq._registeraliases(urllib.parse, ( + "splitattr", + "splitpasswd", + "splitport", + "splituser", + "urlparse", + "urlunparse", + )) + urlreq._registeralias(urllib.parse, "unquote_to_bytes", "unquote") + import urllib.request + urlreq._registeraliases(urllib.request, ( + "AbstractHTTPHandler", + "BaseHandler", + "build_opener", + "FileHandler", + "FTPHandler", + "ftpwrapper", + "HTTPHandler", + "HTTPSHandler", + "install_opener", + "pathname2url", + "HTTPBasicAuthHandler", + "HTTPDigestAuthHandler", + "HTTPPasswordMgrWithDefaultRealm", + "ProxyHandler", + "Request", + "url2pathname", + "urlopen", + )) + import urllib.response + urlreq._registeraliases(urllib.response, ( + "addclosehook", + "addinfourl", + )) + import urllib.error + urlerr._registeraliases(urllib.error, ( + "HTTPError", + "URLError", + )) + import http.server + httpserver._registeraliases(http.server, ( + "HTTPServer", + "BaseHTTPRequestHandler", + "SimpleHTTPRequestHandler", + "CGIHTTPRequestHandler", + )) + + # urllib.parse.quote() accepts both str and bytes, decodes bytes + # (if necessary), and returns str. This is wonky. We provide a custom + # implementation that only accepts bytes and emits bytes. + def quote(s, safe=r'/'): + s = urllib.parse.quote_from_bytes(s, safe=safe) + return s.encode('ascii', 'strict') + + # urllib.parse.urlencode() returns str. We use this function to make + # sure we return bytes. + def urlencode(query, doseq=False): + s = urllib.parse.urlencode(query, doseq=doseq) + return s.encode('ascii') + + urlreq.quote = quote + urlreq.urlencode = urlencode def getfullurl(req): return req.full_url @@ -25,6 +117,60 @@ def hasdata(req): return req.data is not None else: + import BaseHTTPServer + import CGIHTTPServer + import SimpleHTTPServer + import urllib2 + import urllib + import urlparse + urlreq._registeraliases(urllib, ( + "addclosehook", + "addinfourl", + "ftpwrapper", + "pathname2url", + "quote", + "splitattr", + "splitpasswd", + "splitport", + "splituser", + "unquote", + "url2pathname", + "urlencode", + )) + urlreq._registeraliases(urllib2, ( + "AbstractHTTPHandler", + "BaseHandler", + "build_opener", + "FileHandler", + "FTPHandler", + "HTTPBasicAuthHandler", + "HTTPDigestAuthHandler", + "HTTPHandler", + "HTTPPasswordMgrWithDefaultRealm", + "HTTPSHandler", + "install_opener", + "ProxyHandler", + "Request", + "urlopen", + )) + urlreq._registeraliases(urlparse, ( + "urlparse", + "urlunparse", + )) + urlerr._registeraliases(urllib2, ( + "HTTPError", + "URLError", + )) + httpserver._registeraliases(BaseHTTPServer, ( + "HTTPServer", + "BaseHTTPRequestHandler", + )) + httpserver._registeraliases(SimpleHTTPServer, ( + "SimpleHTTPRequestHandler", + )) + httpserver._registeraliases(CGIHTTPServer, ( + "CGIHTTPRequestHandler", + )) def gethost(req): return req.get_host()