##// END OF EJS Templates
pycompat: alias urllib symbols directly...
Gregory Szorc -
r31399:1ed169c5 default
parent child Browse files
Show More
@@ -1,309 +1,315 b''
1 1 # pycompat.py - portability shim for python 3
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6 """Mercurial portability shim for python 3.
7 7
8 8 This contains aliases to hide python version-specific details from the core.
9 9 """
10 10
11 11 from __future__ import absolute_import
12 12
13 13 import getopt
14 14 import os
15 15 import shlex
16 16 import sys
17 17
18 18 ispy3 = (sys.version_info[0] >= 3)
19 19
20 20 if not ispy3:
21 21 import cPickle as pickle
22 22 import httplib
23 23 import Queue as _queue
24 24 import SocketServer as socketserver
25 25 import urlparse
26 26 urlunquote = urlparse.unquote
27 27 import xmlrpclib
28 28 else:
29 29 import http.client as httplib
30 30 import pickle
31 31 import queue as _queue
32 32 import socketserver
33 33 import urllib.parse as urlparse
34 34 urlunquote = urlparse.unquote_to_bytes
35 35 import xmlrpc.client as xmlrpclib
36 36
37 37 if ispy3:
38 38 import builtins
39 39 import functools
40 40 import io
41 41
42 42 fsencode = os.fsencode
43 43 fsdecode = os.fsdecode
44 44 # A bytes version of os.name.
45 45 osname = os.name.encode('ascii')
46 46 ospathsep = os.pathsep.encode('ascii')
47 47 ossep = os.sep.encode('ascii')
48 48 osaltsep = os.altsep
49 49 if osaltsep:
50 50 osaltsep = osaltsep.encode('ascii')
51 51 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
52 52 # returns bytes.
53 53 getcwd = os.getcwdb
54 54 sysplatform = sys.platform.encode('ascii')
55 55 sysexecutable = sys.executable
56 56 if sysexecutable:
57 57 sysexecutable = os.fsencode(sysexecutable)
58 58 stringio = io.BytesIO
59 59
60 60 # TODO: .buffer might not exist if std streams were replaced; we'll need
61 61 # a silly wrapper to make a bytes stream backed by a unicode one.
62 62 stdin = sys.stdin.buffer
63 63 stdout = sys.stdout.buffer
64 64 stderr = sys.stderr.buffer
65 65
66 66 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
67 67 # we can use os.fsencode() to get back bytes argv.
68 68 #
69 69 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
70 70 #
71 71 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
72 72 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
73 73 if getattr(sys, 'argv', None) is not None:
74 74 sysargv = list(map(os.fsencode, sys.argv))
75 75
76 76 def bytechr(i):
77 77 return bytes([i])
78 78
79 79 def iterbytestr(s):
80 80 """Iterate bytes as if it were a str object of Python 2"""
81 81 return iter(s[i:i + 1] for i in range(len(s)))
82 82
83 83 def sysstr(s):
84 84 """Return a keyword str to be passed to Python functions such as
85 85 getattr() and str.encode()
86 86
87 87 This never raises UnicodeDecodeError. Non-ascii characters are
88 88 considered invalid and mapped to arbitrary but unique code points
89 89 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
90 90 """
91 91 if isinstance(s, builtins.str):
92 92 return s
93 93 return s.decode(u'latin-1')
94 94
95 95 def _wrapattrfunc(f):
96 96 @functools.wraps(f)
97 97 def w(object, name, *args):
98 98 return f(object, sysstr(name), *args)
99 99 return w
100 100
101 101 # these wrappers are automagically imported by hgloader
102 102 delattr = _wrapattrfunc(builtins.delattr)
103 103 getattr = _wrapattrfunc(builtins.getattr)
104 104 hasattr = _wrapattrfunc(builtins.hasattr)
105 105 setattr = _wrapattrfunc(builtins.setattr)
106 106 xrange = builtins.range
107 107
108 108 def open(name, mode='r', buffering=-1):
109 109 return builtins.open(name, sysstr(mode), buffering)
110 110
111 111 # getopt.getopt() on Python 3 deals with unicodes internally so we cannot
112 112 # pass bytes there. Passing unicodes will result in unicodes as return
113 113 # values which we need to convert again to bytes.
114 114 def getoptb(args, shortlist, namelist):
115 115 args = [a.decode('latin-1') for a in args]
116 116 shortlist = shortlist.decode('latin-1')
117 117 namelist = [a.decode('latin-1') for a in namelist]
118 118 opts, args = getopt.getopt(args, shortlist, namelist)
119 119 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
120 120 for a in opts]
121 121 args = [a.encode('latin-1') for a in args]
122 122 return opts, args
123 123
124 124 # keys of keyword arguments in Python need to be strings which are unicodes
125 125 # Python 3. This function takes keyword arguments, convert the keys to str.
126 126 def strkwargs(dic):
127 127 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
128 128 return dic
129 129
130 130 # keys of keyword arguments need to be unicode while passing into
131 131 # a function. This function helps us to convert those keys back to bytes
132 132 # again as we need to deal with bytes.
133 133 def byteskwargs(dic):
134 134 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
135 135 return dic
136 136
137 137 # shlex.split() accepts unicodes on Python 3. This function takes bytes
138 138 # argument, convert it into unicodes, pass into shlex.split(), convert the
139 139 # returned value to bytes and return that.
140 140 # TODO: handle shlex.shlex().
141 141 def shlexsplit(s):
142 142 ret = shlex.split(s.decode('latin-1'))
143 143 return [a.encode('latin-1') for a in ret]
144 144
145 145 else:
146 146 import cStringIO
147 147
148 148 bytechr = chr
149 149 iterbytestr = iter
150 150
151 151 def sysstr(s):
152 152 return s
153 153
154 154 # Partial backport from os.py in Python 3, which only accepts bytes.
155 155 # In Python 2, our paths should only ever be bytes, a unicode path
156 156 # indicates a bug.
157 157 def fsencode(filename):
158 158 if isinstance(filename, str):
159 159 return filename
160 160 else:
161 161 raise TypeError(
162 162 "expect str, not %s" % type(filename).__name__)
163 163
164 164 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
165 165 # better not to touch Python 2 part as it's already working fine.
166 166 def fsdecode(filename):
167 167 return filename
168 168
169 169 def getoptb(args, shortlist, namelist):
170 170 return getopt.getopt(args, shortlist, namelist)
171 171
172 172 def strkwargs(dic):
173 173 return dic
174 174
175 175 def byteskwargs(dic):
176 176 return dic
177 177
178 178 osname = os.name
179 179 ospathsep = os.pathsep
180 180 ossep = os.sep
181 181 osaltsep = os.altsep
182 182 stdin = sys.stdin
183 183 stdout = sys.stdout
184 184 stderr = sys.stderr
185 185 if getattr(sys, 'argv', None) is not None:
186 186 sysargv = sys.argv
187 187 sysplatform = sys.platform
188 188 getcwd = os.getcwd
189 189 sysexecutable = sys.executable
190 190 shlexsplit = shlex.split
191 191 stringio = cStringIO.StringIO
192 192
193 193 empty = _queue.Empty
194 194 queue = _queue.Queue
195 195
196 196 class _pycompatstub(object):
197 197 def __init__(self):
198 198 self._aliases = {}
199 199
200 200 def _registeraliases(self, origin, items):
201 201 """Add items that will be populated at the first access"""
202 202 items = map(sysstr, items)
203 203 self._aliases.update(
204 204 (item.replace(sysstr('_'), sysstr('')).lower(), (origin, item))
205 205 for item in items)
206 206
207 207 def __getattr__(self, name):
208 208 try:
209 209 origin, item = self._aliases[name]
210 210 except KeyError:
211 211 raise AttributeError(name)
212 212 self.__dict__[name] = obj = getattr(origin, item)
213 213 return obj
214 214
215 215 httpserver = _pycompatstub()
216 216 urlreq = _pycompatstub()
217 217 urlerr = _pycompatstub()
218 218 if not ispy3:
219 219 import BaseHTTPServer
220 220 import CGIHTTPServer
221 221 import SimpleHTTPServer
222 222 import urllib2
223 223 import urllib
224 224 urlreq._registeraliases(urllib, (
225 225 "addclosehook",
226 226 "addinfourl",
227 227 "ftpwrapper",
228 228 "pathname2url",
229 229 "quote",
230 230 "splitattr",
231 231 "splitpasswd",
232 232 "splitport",
233 233 "splituser",
234 234 "unquote",
235 235 "url2pathname",
236 236 "urlencode",
237 237 ))
238 238 urlreq._registeraliases(urllib2, (
239 239 "AbstractHTTPHandler",
240 240 "BaseHandler",
241 241 "build_opener",
242 242 "FileHandler",
243 243 "FTPHandler",
244 244 "HTTPBasicAuthHandler",
245 245 "HTTPDigestAuthHandler",
246 246 "HTTPHandler",
247 247 "HTTPPasswordMgrWithDefaultRealm",
248 248 "HTTPSHandler",
249 249 "install_opener",
250 250 "ProxyHandler",
251 251 "Request",
252 252 "urlopen",
253 253 ))
254 254 urlerr._registeraliases(urllib2, (
255 255 "HTTPError",
256 256 "URLError",
257 257 ))
258 258 httpserver._registeraliases(BaseHTTPServer, (
259 259 "HTTPServer",
260 260 "BaseHTTPRequestHandler",
261 261 ))
262 262 httpserver._registeraliases(SimpleHTTPServer, (
263 263 "SimpleHTTPRequestHandler",
264 264 ))
265 265 httpserver._registeraliases(CGIHTTPServer, (
266 266 "CGIHTTPRequestHandler",
267 267 ))
268 268
269 269 else:
270 import urllib.parse
271 urlreq._registeraliases(urllib.parse, (
272 "quote",
273 "splitattr",
274 "splitpasswd",
275 "splitport",
276 "splituser",
277 "unquote",
278 ))
270 279 import urllib.request
271 280 urlreq._registeraliases(urllib.request, (
272 281 "AbstractHTTPHandler",
273 "addclosehook",
274 "addinfourl",
275 282 "BaseHandler",
276 283 "build_opener",
277 284 "FileHandler",
278 285 "FTPHandler",
279 286 "ftpwrapper",
280 287 "HTTPHandler",
281 288 "HTTPSHandler",
282 289 "install_opener",
283 290 "pathname2url",
284 291 "HTTPBasicAuthHandler",
285 292 "HTTPDigestAuthHandler",
286 293 "HTTPPasswordMgrWithDefaultRealm",
287 294 "ProxyHandler",
288 "quote",
289 295 "Request",
290 "splitattr",
291 "splitpasswd",
292 "splitport",
293 "splituser",
294 "unquote",
295 296 "url2pathname",
296 297 "urlopen",
297 298 ))
299 import urllib.response
300 urlreq._registeraliases(urllib.response, (
301 "addclosehook",
302 "addinfourl",
303 ))
298 304 import urllib.error
299 305 urlerr._registeraliases(urllib.error, (
300 306 "HTTPError",
301 307 "URLError",
302 308 ))
303 309 import http.server
304 310 httpserver._registeraliases(http.server, (
305 311 "HTTPServer",
306 312 "BaseHTTPRequestHandler",
307 313 "SimpleHTTPRequestHandler",
308 314 "CGIHTTPRequestHandler",
309 315 ))
General Comments 0
You need to be logged in to leave comments. Login now