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