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