##// END OF EJS Templates
pycompat: add xrange alias for Python 2...
Gregory Szorc -
r38805:7eba8f83 default
parent child Browse files
Show More
@@ -1,428 +1,429 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 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 # os.getcwd() on Python 3 returns string, but it has os.getcwdb() which
101 101 # returns bytes.
102 102 getcwd = os.getcwdb
103 103 sysplatform = sys.platform.encode('ascii')
104 104 sysexecutable = sys.executable
105 105 if sysexecutable:
106 106 sysexecutable = os.fsencode(sysexecutable)
107 107 bytesio = io.BytesIO
108 108 # TODO deprecate stringio name, as it is a lie on Python 3.
109 109 stringio = bytesio
110 110
111 111 def maplist(*args):
112 112 return list(map(*args))
113 113
114 114 def rangelist(*args):
115 115 return list(range(*args))
116 116
117 117 def ziplist(*args):
118 118 return list(zip(*args))
119 119
120 120 rawinput = input
121 121 getargspec = inspect.getfullargspec
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('>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='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 xrange = xrange
334 335 unicode = unicode
335 336 bytechr = chr
336 337 byterepr = repr
337 338 bytestr = str
338 339 iterbytestr = iter
339 340 maybebytestr = identity
340 341 sysbytes = identity
341 342 sysstr = identity
342 343 strurl = identity
343 344 bytesurl = identity
344 345
345 346 # this can't be parsed on Python 3
346 347 exec('def raisewithtb(exc, tb):\n'
347 348 ' raise exc, None, tb\n')
348 349
349 350 def fsencode(filename):
350 351 """
351 352 Partial backport from os.py in Python 3, which only accepts bytes.
352 353 In Python 2, our paths should only ever be bytes, a unicode path
353 354 indicates a bug.
354 355 """
355 356 if isinstance(filename, str):
356 357 return filename
357 358 else:
358 359 raise TypeError(
359 360 "expect str, not %s" % type(filename).__name__)
360 361
361 362 # In Python 2, fsdecode() has a very chance to receive bytes. So it's
362 363 # better not to touch Python 2 part as it's already working fine.
363 364 fsdecode = identity
364 365
365 366 def getdoc(obj):
366 367 return getattr(obj, '__doc__', None)
367 368
368 369 _notset = object()
369 370
370 371 def safehasattr(thing, attr):
371 372 return getattr(thing, attr, _notset) is not _notset
372 373
373 374 def _getoptbwrapper(orig, args, shortlist, namelist):
374 375 return orig(args, shortlist, namelist)
375 376
376 377 strkwargs = identity
377 378 byteskwargs = identity
378 379
379 380 oscurdir = os.curdir
380 381 oslinesep = os.linesep
381 382 osname = os.name
382 383 ospathsep = os.pathsep
383 384 ospardir = os.pardir
384 385 ossep = os.sep
385 386 osaltsep = os.altsep
386 387 stdin = sys.stdin
387 388 stdout = sys.stdout
388 389 stderr = sys.stderr
389 390 if getattr(sys, 'argv', None) is not None:
390 391 sysargv = sys.argv
391 392 sysplatform = sys.platform
392 393 getcwd = os.getcwd
393 394 sysexecutable = sys.executable
394 395 shlexsplit = shlex.split
395 396 bytesio = cStringIO.StringIO
396 397 stringio = bytesio
397 398 maplist = map
398 399 rangelist = range
399 400 ziplist = zip
400 401 rawinput = raw_input
401 402 getargspec = inspect.getargspec
402 403
403 404 isjython = sysplatform.startswith('java')
404 405
405 406 isdarwin = sysplatform == 'darwin'
406 407 isposix = osname == 'posix'
407 408 iswindows = osname == 'nt'
408 409
409 410 def getoptb(args, shortlist, namelist):
410 411 return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
411 412
412 413 def gnugetoptb(args, shortlist, namelist):
413 414 return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
414 415
415 416 def mkdtemp(suffix=b'', prefix=b'tmp', dir=None):
416 417 return tempfile.mkdtemp(suffix, prefix, dir)
417 418
418 419 # text=True is not supported; use util.from/tonativeeol() instead
419 420 def mkstemp(suffix=b'', prefix=b'tmp', dir=None):
420 421 return tempfile.mkstemp(suffix, prefix, dir)
421 422
422 423 # mode must include 'b'ytes as encoding= is not supported
423 424 def namedtempfile(mode=b'w+b', bufsize=-1, suffix=b'', prefix=b'tmp', dir=None,
424 425 delete=True):
425 426 mode = sysstr(mode)
426 427 assert r'b' in mode
427 428 return tempfile.NamedTemporaryFile(mode, bufsize, suffix=suffix,
428 429 prefix=prefix, dir=dir, delete=delete)
General Comments 0
You need to be logged in to leave comments. Login now