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