##// END OF EJS Templates
pycompat: introduce an alias for urllib.unquote...
Augie Fackler -
r30327:e0d9b6aa default
parent child Browse files
Show More
@@ -1,210 +1,212 b''
1 # pycompat.py - portability shim for python 3
1 # pycompat.py - portability shim for python 3
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 """Mercurial portability shim for python 3.
6 """Mercurial portability shim for python 3.
7
7
8 This contains aliases to hide python version-specific details from the core.
8 This contains aliases to hide python version-specific details from the core.
9 """
9 """
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12
12
13 import os
13 import os
14 import sys
14 import sys
15
15
16 ispy3 = (sys.version_info[0] >= 3)
16 ispy3 = (sys.version_info[0] >= 3)
17
17
18 if not ispy3:
18 if not ispy3:
19 import cPickle as pickle
19 import cPickle as pickle
20 import cStringIO as io
20 import cStringIO as io
21 import httplib
21 import httplib
22 import Queue as _queue
22 import Queue as _queue
23 import SocketServer as socketserver
23 import SocketServer as socketserver
24 import urlparse
24 import urlparse
25 urlunquote = urlparse.unquote
25 import xmlrpclib
26 import xmlrpclib
26 else:
27 else:
27 import http.client as httplib
28 import http.client as httplib
28 import io
29 import io
29 import pickle
30 import pickle
30 import queue as _queue
31 import queue as _queue
31 import socketserver
32 import socketserver
32 import urllib.parse as urlparse
33 import urllib.parse as urlparse
34 urlunquote = urlparse.unquote_to_bytes
33 import xmlrpc.client as xmlrpclib
35 import xmlrpc.client as xmlrpclib
34
36
35 if ispy3:
37 if ispy3:
36 import builtins
38 import builtins
37 import functools
39 import functools
38 fsencode = os.fsencode
40 fsencode = os.fsencode
39 fsdecode = os.fsdecode
41 fsdecode = os.fsdecode
40 # A bytes version of os.name.
42 # A bytes version of os.name.
41 osname = os.name.encode('ascii')
43 osname = os.name.encode('ascii')
42 ospathsep = os.pathsep.encode('ascii')
44 ospathsep = os.pathsep.encode('ascii')
43 ossep = os.sep.encode('ascii')
45 ossep = os.sep.encode('ascii')
44
46
45 def sysstr(s):
47 def sysstr(s):
46 """Return a keyword str to be passed to Python functions such as
48 """Return a keyword str to be passed to Python functions such as
47 getattr() and str.encode()
49 getattr() and str.encode()
48
50
49 This never raises UnicodeDecodeError. Non-ascii characters are
51 This never raises UnicodeDecodeError. Non-ascii characters are
50 considered invalid and mapped to arbitrary but unique code points
52 considered invalid and mapped to arbitrary but unique code points
51 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
53 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
52 """
54 """
53 if isinstance(s, builtins.str):
55 if isinstance(s, builtins.str):
54 return s
56 return s
55 return s.decode(u'latin-1')
57 return s.decode(u'latin-1')
56
58
57 def _wrapattrfunc(f):
59 def _wrapattrfunc(f):
58 @functools.wraps(f)
60 @functools.wraps(f)
59 def w(object, name, *args):
61 def w(object, name, *args):
60 return f(object, sysstr(name), *args)
62 return f(object, sysstr(name), *args)
61 return w
63 return w
62
64
63 # these wrappers are automagically imported by hgloader
65 # these wrappers are automagically imported by hgloader
64 delattr = _wrapattrfunc(builtins.delattr)
66 delattr = _wrapattrfunc(builtins.delattr)
65 getattr = _wrapattrfunc(builtins.getattr)
67 getattr = _wrapattrfunc(builtins.getattr)
66 hasattr = _wrapattrfunc(builtins.hasattr)
68 hasattr = _wrapattrfunc(builtins.hasattr)
67 setattr = _wrapattrfunc(builtins.setattr)
69 setattr = _wrapattrfunc(builtins.setattr)
68 xrange = builtins.range
70 xrange = builtins.range
69
71
70 else:
72 else:
71 def sysstr(s):
73 def sysstr(s):
72 return s
74 return s
73
75
74 # Partial backport from os.py in Python 3, which only accepts bytes.
76 # Partial backport from os.py in Python 3, which only accepts bytes.
75 # In Python 2, our paths should only ever be bytes, a unicode path
77 # In Python 2, our paths should only ever be bytes, a unicode path
76 # indicates a bug.
78 # indicates a bug.
77 def fsencode(filename):
79 def fsencode(filename):
78 if isinstance(filename, str):
80 if isinstance(filename, str):
79 return filename
81 return filename
80 else:
82 else:
81 raise TypeError(
83 raise TypeError(
82 "expect str, not %s" % type(filename).__name__)
84 "expect str, not %s" % type(filename).__name__)
83
85
84 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
86 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
85 # better not to touch Python 2 part as it's already working fine.
87 # better not to touch Python 2 part as it's already working fine.
86 def fsdecode(filename):
88 def fsdecode(filename):
87 return filename
89 return filename
88
90
89 osname = os.name
91 osname = os.name
90 ospathsep = os.pathsep
92 ospathsep = os.pathsep
91 ossep = os.sep
93 ossep = os.sep
92
94
93 stringio = io.StringIO
95 stringio = io.StringIO
94 empty = _queue.Empty
96 empty = _queue.Empty
95 queue = _queue.Queue
97 queue = _queue.Queue
96
98
97 class _pycompatstub(object):
99 class _pycompatstub(object):
98 def __init__(self):
100 def __init__(self):
99 self._aliases = {}
101 self._aliases = {}
100
102
101 def _registeraliases(self, origin, items):
103 def _registeraliases(self, origin, items):
102 """Add items that will be populated at the first access"""
104 """Add items that will be populated at the first access"""
103 items = map(sysstr, items)
105 items = map(sysstr, items)
104 self._aliases.update(
106 self._aliases.update(
105 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
107 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
106 for item in items)
108 for item in items)
107
109
108 def __getattr__(self, name):
110 def __getattr__(self, name):
109 try:
111 try:
110 origin, item = self._aliases[name]
112 origin, item = self._aliases[name]
111 except KeyError:
113 except KeyError:
112 raise AttributeError(name)
114 raise AttributeError(name)
113 self.__dict__[name] = obj = getattr(origin, item)
115 self.__dict__[name] = obj = getattr(origin, item)
114 return obj
116 return obj
115
117
116 httpserver = _pycompatstub()
118 httpserver = _pycompatstub()
117 urlreq = _pycompatstub()
119 urlreq = _pycompatstub()
118 urlerr = _pycompatstub()
120 urlerr = _pycompatstub()
119 if not ispy3:
121 if not ispy3:
120 import BaseHTTPServer
122 import BaseHTTPServer
121 import CGIHTTPServer
123 import CGIHTTPServer
122 import SimpleHTTPServer
124 import SimpleHTTPServer
123 import urllib2
125 import urllib2
124 import urllib
126 import urllib
125 urlreq._registeraliases(urllib, (
127 urlreq._registeraliases(urllib, (
126 "addclosehook",
128 "addclosehook",
127 "addinfourl",
129 "addinfourl",
128 "ftpwrapper",
130 "ftpwrapper",
129 "pathname2url",
131 "pathname2url",
130 "quote",
132 "quote",
131 "splitattr",
133 "splitattr",
132 "splitpasswd",
134 "splitpasswd",
133 "splitport",
135 "splitport",
134 "splituser",
136 "splituser",
135 "unquote",
137 "unquote",
136 "url2pathname",
138 "url2pathname",
137 "urlencode",
139 "urlencode",
138 ))
140 ))
139 urlreq._registeraliases(urllib2, (
141 urlreq._registeraliases(urllib2, (
140 "AbstractHTTPHandler",
142 "AbstractHTTPHandler",
141 "BaseHandler",
143 "BaseHandler",
142 "build_opener",
144 "build_opener",
143 "FileHandler",
145 "FileHandler",
144 "FTPHandler",
146 "FTPHandler",
145 "HTTPBasicAuthHandler",
147 "HTTPBasicAuthHandler",
146 "HTTPDigestAuthHandler",
148 "HTTPDigestAuthHandler",
147 "HTTPHandler",
149 "HTTPHandler",
148 "HTTPPasswordMgrWithDefaultRealm",
150 "HTTPPasswordMgrWithDefaultRealm",
149 "HTTPSHandler",
151 "HTTPSHandler",
150 "install_opener",
152 "install_opener",
151 "ProxyHandler",
153 "ProxyHandler",
152 "Request",
154 "Request",
153 "urlopen",
155 "urlopen",
154 ))
156 ))
155 urlerr._registeraliases(urllib2, (
157 urlerr._registeraliases(urllib2, (
156 "HTTPError",
158 "HTTPError",
157 "URLError",
159 "URLError",
158 ))
160 ))
159 httpserver._registeraliases(BaseHTTPServer, (
161 httpserver._registeraliases(BaseHTTPServer, (
160 "HTTPServer",
162 "HTTPServer",
161 "BaseHTTPRequestHandler",
163 "BaseHTTPRequestHandler",
162 ))
164 ))
163 httpserver._registeraliases(SimpleHTTPServer, (
165 httpserver._registeraliases(SimpleHTTPServer, (
164 "SimpleHTTPRequestHandler",
166 "SimpleHTTPRequestHandler",
165 ))
167 ))
166 httpserver._registeraliases(CGIHTTPServer, (
168 httpserver._registeraliases(CGIHTTPServer, (
167 "CGIHTTPRequestHandler",
169 "CGIHTTPRequestHandler",
168 ))
170 ))
169
171
170 else:
172 else:
171 import urllib.request
173 import urllib.request
172 urlreq._registeraliases(urllib.request, (
174 urlreq._registeraliases(urllib.request, (
173 "AbstractHTTPHandler",
175 "AbstractHTTPHandler",
174 "addclosehook",
176 "addclosehook",
175 "addinfourl",
177 "addinfourl",
176 "BaseHandler",
178 "BaseHandler",
177 "build_opener",
179 "build_opener",
178 "FileHandler",
180 "FileHandler",
179 "FTPHandler",
181 "FTPHandler",
180 "ftpwrapper",
182 "ftpwrapper",
181 "HTTPHandler",
183 "HTTPHandler",
182 "HTTPSHandler",
184 "HTTPSHandler",
183 "install_opener",
185 "install_opener",
184 "pathname2url",
186 "pathname2url",
185 "HTTPBasicAuthHandler",
187 "HTTPBasicAuthHandler",
186 "HTTPDigestAuthHandler",
188 "HTTPDigestAuthHandler",
187 "HTTPPasswordMgrWithDefaultRealm",
189 "HTTPPasswordMgrWithDefaultRealm",
188 "ProxyHandler",
190 "ProxyHandler",
189 "quote",
191 "quote",
190 "Request",
192 "Request",
191 "splitattr",
193 "splitattr",
192 "splitpasswd",
194 "splitpasswd",
193 "splitport",
195 "splitport",
194 "splituser",
196 "splituser",
195 "unquote",
197 "unquote",
196 "url2pathname",
198 "url2pathname",
197 "urlopen",
199 "urlopen",
198 ))
200 ))
199 import urllib.error
201 import urllib.error
200 urlerr._registeraliases(urllib.error, (
202 urlerr._registeraliases(urllib.error, (
201 "HTTPError",
203 "HTTPError",
202 "URLError",
204 "URLError",
203 ))
205 ))
204 import http.server
206 import http.server
205 httpserver._registeraliases(http.server, (
207 httpserver._registeraliases(http.server, (
206 "HTTPServer",
208 "HTTPServer",
207 "BaseHTTPRequestHandler",
209 "BaseHTTPRequestHandler",
208 "SimpleHTTPRequestHandler",
210 "SimpleHTTPRequestHandler",
209 "CGIHTTPRequestHandler",
211 "CGIHTTPRequestHandler",
210 ))
212 ))
General Comments 0
You need to be logged in to leave comments. Login now