diff mercurial/urllibcompat.py @ 34468:192f7b126ed2

urllibcompat: move some adapters from pycompat to urllibcompat These are all the httpserver and urllib.* aliases. They seem to make more sense in the slightly-more-specific urllibcompat package than the general-purpose pycompat. Differential Revision: https://phab.mercurial-scm.org/D935
author Augie Fackler <augie@google.com>
date Wed, 04 Oct 2017 11:58:00 -0400
parents 80d4681150b9
children a3d42d1865f1
line wrap: on
line diff
--- 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()