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