##// END OF EJS Templates
pycompat: adding Linux detection and fixing Mac...
rdamazio@google.com -
r40563:1b49b84d default
parent child Browse files
Show More
@@ -1,429 +1,430
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 inspect
15 15 import os
16 16 import shlex
17 17 import sys
18 18 import tempfile
19 19
20 20 ispy3 = (sys.version_info[0] >= 3)
21 21 ispypy = (r'__pypy__' in sys.builtin_module_names)
22 22
23 23 if not ispy3:
24 24 import cookielib
25 25 import cPickle as pickle
26 26 import httplib
27 27 import Queue as queue
28 28 import SocketServer as socketserver
29 29 import xmlrpclib
30 30
31 31 from .thirdparty.concurrent import futures
32 32
33 33 def future_set_exception_info(f, exc_info):
34 34 f.set_exception_info(*exc_info)
35 35 else:
36 36 import concurrent.futures as futures
37 37 import http.cookiejar as cookielib
38 38 import http.client as httplib
39 39 import pickle
40 40 import queue as queue
41 41 import socketserver
42 42 import xmlrpc.client as xmlrpclib
43 43
44 44 def future_set_exception_info(f, exc_info):
45 45 f.set_exception(exc_info[0])
46 46
47 47 def identity(a):
48 48 return a
49 49
50 50 def _rapply(f, xs):
51 51 if xs is None:
52 52 # assume None means non-value of optional data
53 53 return xs
54 54 if isinstance(xs, (list, set, tuple)):
55 55 return type(xs)(_rapply(f, x) for x in xs)
56 56 if isinstance(xs, dict):
57 57 return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
58 58 return f(xs)
59 59
60 60 def rapply(f, xs):
61 61 """Apply function recursively to every item preserving the data structure
62 62
63 63 >>> def f(x):
64 64 ... return 'f(%s)' % x
65 65 >>> rapply(f, None) is None
66 66 True
67 67 >>> rapply(f, 'a')
68 68 'f(a)'
69 69 >>> rapply(f, {'a'}) == {'f(a)'}
70 70 True
71 71 >>> rapply(f, ['a', 'b', None, {'c': 'd'}, []])
72 72 ['f(a)', 'f(b)', None, {'f(c)': 'f(d)'}, []]
73 73
74 74 >>> xs = [object()]
75 75 >>> rapply(identity, xs) is xs
76 76 True
77 77 """
78 78 if f is identity:
79 79 # fast path mainly for py2
80 80 return xs
81 81 return _rapply(f, xs)
82 82
83 83 if ispy3:
84 84 import builtins
85 85 import functools
86 86 import io
87 87 import struct
88 88
89 89 fsencode = os.fsencode
90 90 fsdecode = os.fsdecode
91 91 oscurdir = os.curdir.encode('ascii')
92 92 oslinesep = os.linesep.encode('ascii')
93 93 osname = os.name.encode('ascii')
94 94 ospathsep = os.pathsep.encode('ascii')
95 95 ospardir = os.pardir.encode('ascii')
96 96 ossep = os.sep.encode('ascii')
97 97 osaltsep = os.altsep
98 98 if osaltsep:
99 99 osaltsep = osaltsep.encode('ascii')
100 100
101 101 sysplatform = sys.platform.encode('ascii')
102 102 sysexecutable = sys.executable
103 103 if sysexecutable:
104 104 sysexecutable = os.fsencode(sysexecutable)
105 105 bytesio = io.BytesIO
106 106 # TODO deprecate stringio name, as it is a lie on Python 3.
107 107 stringio = bytesio
108 108
109 109 def maplist(*args):
110 110 return list(map(*args))
111 111
112 112 def rangelist(*args):
113 113 return list(range(*args))
114 114
115 115 def ziplist(*args):
116 116 return list(zip(*args))
117 117
118 118 rawinput = input
119 119 getargspec = inspect.getfullargspec
120 120
121 121 long = int
122 122
123 123 # TODO: .buffer might not exist if std streams were replaced; we'll need
124 124 # a silly wrapper to make a bytes stream backed by a unicode one.
125 125 stdin = sys.stdin.buffer
126 126 stdout = sys.stdout.buffer
127 127 stderr = sys.stderr.buffer
128 128
129 129 # Since Python 3 converts argv to wchar_t type by Py_DecodeLocale() on Unix,
130 130 # we can use os.fsencode() to get back bytes argv.
131 131 #
132 132 # https://hg.python.org/cpython/file/v3.5.1/Programs/python.c#l55
133 133 #
134 134 # TODO: On Windows, the native argv is wchar_t, so we'll need a different
135 135 # workaround to simulate the Python 2 (i.e. ANSI Win32 API) behavior.
136 136 if getattr(sys, 'argv', None) is not None:
137 137 sysargv = list(map(os.fsencode, sys.argv))
138 138
139 139 bytechr = struct.Struct(r'>B').pack
140 140 byterepr = b'%r'.__mod__
141 141
142 142 class bytestr(bytes):
143 143 """A bytes which mostly acts as a Python 2 str
144 144
145 145 >>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
146 146 ('', 'foo', 'ascii', '1')
147 147 >>> s = bytestr(b'foo')
148 148 >>> assert s is bytestr(s)
149 149
150 150 __bytes__() should be called if provided:
151 151
152 152 >>> class bytesable(object):
153 153 ... def __bytes__(self):
154 154 ... return b'bytes'
155 155 >>> bytestr(bytesable())
156 156 'bytes'
157 157
158 158 There's no implicit conversion from non-ascii str as its encoding is
159 159 unknown:
160 160
161 161 >>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
162 162 Traceback (most recent call last):
163 163 ...
164 164 UnicodeEncodeError: ...
165 165
166 166 Comparison between bytestr and bytes should work:
167 167
168 168 >>> assert bytestr(b'foo') == b'foo'
169 169 >>> assert b'foo' == bytestr(b'foo')
170 170 >>> assert b'f' in bytestr(b'foo')
171 171 >>> assert bytestr(b'f') in b'foo'
172 172
173 173 Sliced elements should be bytes, not integer:
174 174
175 175 >>> s[1], s[:2]
176 176 (b'o', b'fo')
177 177 >>> list(s), list(reversed(s))
178 178 ([b'f', b'o', b'o'], [b'o', b'o', b'f'])
179 179
180 180 As bytestr type isn't propagated across operations, you need to cast
181 181 bytes to bytestr explicitly:
182 182
183 183 >>> s = bytestr(b'foo').upper()
184 184 >>> t = bytestr(s)
185 185 >>> s[0], t[0]
186 186 (70, b'F')
187 187
188 188 Be careful to not pass a bytestr object to a function which expects
189 189 bytearray-like behavior.
190 190
191 191 >>> t = bytes(t) # cast to bytes
192 192 >>> assert type(t) is bytes
193 193 """
194 194
195 195 def __new__(cls, s=b''):
196 196 if isinstance(s, bytestr):
197 197 return s
198 198 if (not isinstance(s, (bytes, bytearray))
199 199 and not hasattr(s, u'__bytes__')): # hasattr-py3-only
200 200 s = str(s).encode(u'ascii')
201 201 return bytes.__new__(cls, s)
202 202
203 203 def __getitem__(self, key):
204 204 s = bytes.__getitem__(self, key)
205 205 if not isinstance(s, bytes):
206 206 s = bytechr(s)
207 207 return s
208 208
209 209 def __iter__(self):
210 210 return iterbytestr(bytes.__iter__(self))
211 211
212 212 def __repr__(self):
213 213 return bytes.__repr__(self)[1:] # drop b''
214 214
215 215 def iterbytestr(s):
216 216 """Iterate bytes as if it were a str object of Python 2"""
217 217 return map(bytechr, s)
218 218
219 219 def maybebytestr(s):
220 220 """Promote bytes to bytestr"""
221 221 if isinstance(s, bytes):
222 222 return bytestr(s)
223 223 return s
224 224
225 225 def sysbytes(s):
226 226 """Convert an internal str (e.g. keyword, __doc__) back to bytes
227 227
228 228 This never raises UnicodeEncodeError, but only ASCII characters
229 229 can be round-trip by sysstr(sysbytes(s)).
230 230 """
231 231 return s.encode(u'utf-8')
232 232
233 233 def sysstr(s):
234 234 """Return a keyword str to be passed to Python functions such as
235 235 getattr() and str.encode()
236 236
237 237 This never raises UnicodeDecodeError. Non-ascii characters are
238 238 considered invalid and mapped to arbitrary but unique code points
239 239 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
240 240 """
241 241 if isinstance(s, builtins.str):
242 242 return s
243 243 return s.decode(u'latin-1')
244 244
245 245 def strurl(url):
246 246 """Converts a bytes url back to str"""
247 247 if isinstance(url, bytes):
248 248 return url.decode(u'ascii')
249 249 return url
250 250
251 251 def bytesurl(url):
252 252 """Converts a str url to bytes by encoding in ascii"""
253 253 if isinstance(url, str):
254 254 return url.encode(u'ascii')
255 255 return url
256 256
257 257 def raisewithtb(exc, tb):
258 258 """Raise exception with the given traceback"""
259 259 raise exc.with_traceback(tb)
260 260
261 261 def getdoc(obj):
262 262 """Get docstring as bytes; may be None so gettext() won't confuse it
263 263 with _('')"""
264 264 doc = getattr(obj, u'__doc__', None)
265 265 if doc is None:
266 266 return doc
267 267 return sysbytes(doc)
268 268
269 269 def _wrapattrfunc(f):
270 270 @functools.wraps(f)
271 271 def w(object, name, *args):
272 272 return f(object, sysstr(name), *args)
273 273 return w
274 274
275 275 # these wrappers are automagically imported by hgloader
276 276 delattr = _wrapattrfunc(builtins.delattr)
277 277 getattr = _wrapattrfunc(builtins.getattr)
278 278 hasattr = _wrapattrfunc(builtins.hasattr)
279 279 setattr = _wrapattrfunc(builtins.setattr)
280 280 xrange = builtins.range
281 281 unicode = str
282 282
283 283 def open(name, mode=b'r', buffering=-1, encoding=None):
284 284 return builtins.open(name, sysstr(mode), buffering, encoding)
285 285
286 286 safehasattr = _wrapattrfunc(builtins.hasattr)
287 287
288 288 def _getoptbwrapper(orig, args, shortlist, namelist):
289 289 """
290 290 Takes bytes arguments, converts them to unicode, pass them to
291 291 getopt.getopt(), convert the returned values back to bytes and then
292 292 return them for Python 3 compatibility as getopt.getopt() don't accepts
293 293 bytes on Python 3.
294 294 """
295 295 args = [a.decode('latin-1') for a in args]
296 296 shortlist = shortlist.decode('latin-1')
297 297 namelist = [a.decode('latin-1') for a in namelist]
298 298 opts, args = orig(args, shortlist, namelist)
299 299 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1'))
300 300 for a in opts]
301 301 args = [a.encode('latin-1') for a in args]
302 302 return opts, args
303 303
304 304 def strkwargs(dic):
305 305 """
306 306 Converts the keys of a python dictonary to str i.e. unicodes so that
307 307 they can be passed as keyword arguments as dictonaries with bytes keys
308 308 can't be passed as keyword arguments to functions on Python 3.
309 309 """
310 310 dic = dict((k.decode('latin-1'), v) for k, v in dic.iteritems())
311 311 return dic
312 312
313 313 def byteskwargs(dic):
314 314 """
315 315 Converts keys of python dictonaries to bytes as they were converted to
316 316 str to pass that dictonary as a keyword argument on Python 3.
317 317 """
318 318 dic = dict((k.encode('latin-1'), v) for k, v in dic.iteritems())
319 319 return dic
320 320
321 321 # TODO: handle shlex.shlex().
322 322 def shlexsplit(s, comments=False, posix=True):
323 323 """
324 324 Takes bytes argument, convert it to str i.e. unicodes, pass that into
325 325 shlex.split(), convert the returned value to bytes and return that for
326 326 Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
327 327 """
328 328 ret = shlex.split(s.decode('latin-1'), comments, posix)
329 329 return [a.encode('latin-1') for a in ret]
330 330
331 331 else:
332 332 import cStringIO
333 333
334 334 xrange = xrange
335 335 unicode = unicode
336 336 bytechr = chr
337 337 byterepr = repr
338 338 bytestr = str
339 339 iterbytestr = iter
340 340 maybebytestr = identity
341 341 sysbytes = identity
342 342 sysstr = identity
343 343 strurl = identity
344 344 bytesurl = identity
345 345
346 346 # this can't be parsed on Python 3
347 347 exec('def raisewithtb(exc, tb):\n'
348 348 ' raise exc, None, tb\n')
349 349
350 350 def fsencode(filename):
351 351 """
352 352 Partial backport from os.py in Python 3, which only accepts bytes.
353 353 In Python 2, our paths should only ever be bytes, a unicode path
354 354 indicates a bug.
355 355 """
356 356 if isinstance(filename, str):
357 357 return filename
358 358 else:
359 359 raise TypeError(
360 360 r"expect str, not %s" % type(filename).__name__)
361 361
362 362 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
363 363 # better not to touch Python 2 part as it's already working fine.
364 364 fsdecode = identity
365 365
366 366 def getdoc(obj):
367 367 return getattr(obj, '__doc__', None)
368 368
369 369 _notset = object()
370 370
371 371 def safehasattr(thing, attr):
372 372 return getattr(thing, attr, _notset) is not _notset
373 373
374 374 def _getoptbwrapper(orig, args, shortlist, namelist):
375 375 return orig(args, shortlist, namelist)
376 376
377 377 strkwargs = identity
378 378 byteskwargs = identity
379 379
380 380 oscurdir = os.curdir
381 381 oslinesep = os.linesep
382 382 osname = os.name
383 383 ospathsep = os.pathsep
384 384 ospardir = os.pardir
385 385 ossep = os.sep
386 386 osaltsep = os.altsep
387 387 long = long
388 388 stdin = sys.stdin
389 389 stdout = sys.stdout
390 390 stderr = sys.stderr
391 391 if getattr(sys, 'argv', None) is not None:
392 392 sysargv = sys.argv
393 393 sysplatform = sys.platform
394 394 sysexecutable = sys.executable
395 395 shlexsplit = shlex.split
396 396 bytesio = cStringIO.StringIO
397 397 stringio = bytesio
398 398 maplist = map
399 399 rangelist = range
400 400 ziplist = zip
401 401 rawinput = raw_input
402 402 getargspec = inspect.getargspec
403 403
404 404 isjython = sysplatform.startswith(b'java')
405 405
406 isdarwin = sysplatform == b'darwin'
406 isdarwin = sysplatform.startswith(b'darwin')
407 islinux = sysplatform.startswith(b'linux')
407 408 isposix = osname == b'posix'
408 409 iswindows = osname == b'nt'
409 410
410 411 def getoptb(args, shortlist, namelist):
411 412 return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
412 413
413 414 def gnugetoptb(args, shortlist, namelist):
414 415 return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
415 416
416 417 def mkdtemp(suffix=b'', prefix=b'tmp', dir=None):
417 418 return tempfile.mkdtemp(suffix, prefix, dir)
418 419
419 420 # text=True is not supported; use util.from/tonativeeol() instead
420 421 def mkstemp(suffix=b'', prefix=b'tmp', dir=None):
421 422 return tempfile.mkstemp(suffix, prefix, dir)
422 423
423 424 # mode must include 'b'ytes as encoding= is not supported
424 425 def namedtempfile(mode=b'w+b', bufsize=-1, suffix=b'', prefix=b'tmp', dir=None,
425 426 delete=True):
426 427 mode = sysstr(mode)
427 428 assert r'b' in mode
428 429 return tempfile.NamedTemporaryFile(mode, bufsize, suffix=suffix,
429 430 prefix=prefix, dir=dir, delete=delete)
General Comments 0
You need to be logged in to leave comments. Login now