##// END OF EJS Templates
cleanup: drop the `bytes` compatibility for attribute related function...
marmoute -
r52034:c845479f default
parent child Browse files
Show More
@@ -1,505 +1,489
1 # pycompat.py - portability shim for python 3
1 # pycompat.py - portability shim for python 3
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 """Mercurial portability shim for python 3.
6 """Mercurial portability shim for python 3.
7
7
8 This contains aliases to hide python version-specific details from the core.
8 This contains aliases to hide python version-specific details from the core.
9 """
9 """
10
10
11
11
12 import builtins
12 import builtins
13 import codecs
13 import codecs
14 import concurrent.futures as futures
14 import concurrent.futures as futures
15 import functools
16 import getopt
15 import getopt
17 import http.client as httplib
16 import http.client as httplib
18 import http.cookiejar as cookielib
17 import http.cookiejar as cookielib
19 import inspect
18 import inspect
20 import io
19 import io
21 import json
20 import json
22 import os
21 import os
23 import queue
22 import queue
24 import shlex
23 import shlex
25 import socketserver
24 import socketserver
26 import struct
25 import struct
27 import sys
26 import sys
28 import tempfile
27 import tempfile
29 import xmlrpc.client as xmlrpclib
28 import xmlrpc.client as xmlrpclib
30
29
31 from typing import (
30 from typing import (
32 Any,
31 Any,
33 AnyStr,
32 AnyStr,
34 BinaryIO,
33 BinaryIO,
35 Callable,
34 Callable,
36 Dict,
35 Dict,
37 Iterable,
36 Iterable,
38 Iterator,
37 Iterator,
39 List,
38 List,
40 Mapping,
39 Mapping,
41 NoReturn,
40 NoReturn,
42 Optional,
41 Optional,
43 Sequence,
42 Sequence,
44 Tuple,
43 Tuple,
45 Type,
44 Type,
46 TypeVar,
45 TypeVar,
47 cast,
46 cast,
48 overload,
47 overload,
49 )
48 )
50
49
51 ispy3 = sys.version_info[0] >= 3
50 ispy3 = sys.version_info[0] >= 3
52 ispypy = '__pypy__' in sys.builtin_module_names
51 ispypy = '__pypy__' in sys.builtin_module_names
53 TYPE_CHECKING = False
52 TYPE_CHECKING = False
54
53
55 if not globals(): # hide this from non-pytype users
54 if not globals(): # hide this from non-pytype users
56 import typing
55 import typing
57
56
58 TYPE_CHECKING = typing.TYPE_CHECKING
57 TYPE_CHECKING = typing.TYPE_CHECKING
59
58
60 _GetOptResult = Tuple[List[Tuple[bytes, bytes]], List[bytes]]
59 _GetOptResult = Tuple[List[Tuple[bytes, bytes]], List[bytes]]
61 _T0 = TypeVar('_T0')
60 _T0 = TypeVar('_T0')
62 _T1 = TypeVar('_T1')
61 _T1 = TypeVar('_T1')
63 _S = TypeVar('_S')
62 _S = TypeVar('_S')
64 _Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
63 _Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
65
64
66
65
67 def future_set_exception_info(f, exc_info):
66 def future_set_exception_info(f, exc_info):
68 f.set_exception(exc_info[0])
67 f.set_exception(exc_info[0])
69
68
70
69
71 FileNotFoundError = builtins.FileNotFoundError
70 FileNotFoundError = builtins.FileNotFoundError
72
71
73
72
74 def identity(a: _T0) -> _T0:
73 def identity(a: _T0) -> _T0:
75 return a
74 return a
76
75
77
76
78 def _rapply(f, xs):
77 def _rapply(f, xs):
79 if xs is None:
78 if xs is None:
80 # assume None means non-value of optional data
79 # assume None means non-value of optional data
81 return xs
80 return xs
82 if isinstance(xs, (list, set, tuple)):
81 if isinstance(xs, (list, set, tuple)):
83 return type(xs)(_rapply(f, x) for x in xs)
82 return type(xs)(_rapply(f, x) for x in xs)
84 if isinstance(xs, dict):
83 if isinstance(xs, dict):
85 return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
84 return type(xs)((_rapply(f, k), _rapply(f, v)) for k, v in xs.items())
86 return f(xs)
85 return f(xs)
87
86
88
87
89 def rapply(f, xs):
88 def rapply(f, xs):
90 """Apply function recursively to every item preserving the data structure
89 """Apply function recursively to every item preserving the data structure
91
90
92 >>> def f(x):
91 >>> def f(x):
93 ... return 'f(%s)' % x
92 ... return 'f(%s)' % x
94 >>> rapply(f, None) is None
93 >>> rapply(f, None) is None
95 True
94 True
96 >>> rapply(f, 'a')
95 >>> rapply(f, 'a')
97 'f(a)'
96 'f(a)'
98 >>> rapply(f, {'a'}) == {'f(a)'}
97 >>> rapply(f, {'a'}) == {'f(a)'}
99 True
98 True
100 >>> rapply(f, ['a', 'b', None, {'c': 'd'}, []])
99 >>> rapply(f, ['a', 'b', None, {'c': 'd'}, []])
101 ['f(a)', 'f(b)', None, {'f(c)': 'f(d)'}, []]
100 ['f(a)', 'f(b)', None, {'f(c)': 'f(d)'}, []]
102
101
103 >>> xs = [object()]
102 >>> xs = [object()]
104 >>> rapply(identity, xs) is xs
103 >>> rapply(identity, xs) is xs
105 True
104 True
106 """
105 """
107 if f is identity:
106 if f is identity:
108 # fast path mainly for py2
107 # fast path mainly for py2
109 return xs
108 return xs
110 return _rapply(f, xs)
109 return _rapply(f, xs)
111
110
112
111
113 if os.name == r'nt':
112 if os.name == r'nt':
114 # MBCS (or ANSI) filesystem encoding must be used as before.
113 # MBCS (or ANSI) filesystem encoding must be used as before.
115 # Otherwise non-ASCII filenames in existing repositories would be
114 # Otherwise non-ASCII filenames in existing repositories would be
116 # corrupted.
115 # corrupted.
117 # This must be set once prior to any fsencode/fsdecode calls.
116 # This must be set once prior to any fsencode/fsdecode calls.
118 sys._enablelegacywindowsfsencoding() # pytype: disable=module-attr
117 sys._enablelegacywindowsfsencoding() # pytype: disable=module-attr
119
118
120 fsencode = os.fsencode
119 fsencode = os.fsencode
121 fsdecode = os.fsdecode
120 fsdecode = os.fsdecode
122 oscurdir: bytes = os.curdir.encode('ascii')
121 oscurdir: bytes = os.curdir.encode('ascii')
123 oslinesep: bytes = os.linesep.encode('ascii')
122 oslinesep: bytes = os.linesep.encode('ascii')
124 osname: bytes = os.name.encode('ascii')
123 osname: bytes = os.name.encode('ascii')
125 ospathsep: bytes = os.pathsep.encode('ascii')
124 ospathsep: bytes = os.pathsep.encode('ascii')
126 ospardir: bytes = os.pardir.encode('ascii')
125 ospardir: bytes = os.pardir.encode('ascii')
127 ossep: bytes = os.sep.encode('ascii')
126 ossep: bytes = os.sep.encode('ascii')
128 osaltsep: Optional[bytes] = os.altsep.encode('ascii') if os.altsep else None
127 osaltsep: Optional[bytes] = os.altsep.encode('ascii') if os.altsep else None
129 osdevnull: bytes = os.devnull.encode('ascii')
128 osdevnull: bytes = os.devnull.encode('ascii')
130
129
131 sysplatform: bytes = sys.platform.encode('ascii')
130 sysplatform: bytes = sys.platform.encode('ascii')
132 sysexecutable: bytes = os.fsencode(sys.executable) if sys.executable else b''
131 sysexecutable: bytes = os.fsencode(sys.executable) if sys.executable else b''
133
132
134
133
135 if TYPE_CHECKING:
134 if TYPE_CHECKING:
136
135
137 @overload
136 @overload
138 def maplist(f: Callable[[_T0], _S], arg: Iterable[_T0]) -> List[_S]:
137 def maplist(f: Callable[[_T0], _S], arg: Iterable[_T0]) -> List[_S]:
139 ...
138 ...
140
139
141 @overload
140 @overload
142 def maplist(
141 def maplist(
143 f: Callable[[_T0, _T1], _S], arg1: Iterable[_T0], arg2: Iterable[_T1]
142 f: Callable[[_T0, _T1], _S], arg1: Iterable[_T0], arg2: Iterable[_T1]
144 ) -> List[_S]:
143 ) -> List[_S]:
145 ...
144 ...
146
145
147
146
148 def maplist(f, *args):
147 def maplist(f, *args):
149 return list(map(f, *args))
148 return list(map(f, *args))
150
149
151
150
152 def rangelist(*args) -> List[int]:
151 def rangelist(*args) -> List[int]:
153 return list(range(*args))
152 return list(range(*args))
154
153
155
154
156 def ziplist(*args):
155 def ziplist(*args):
157 return list(zip(*args))
156 return list(zip(*args))
158
157
159
158
160 rawinput = input
159 rawinput = input
161 getargspec = inspect.getfullargspec
160 getargspec = inspect.getfullargspec
162
161
163 long = int
162 long = int
164
163
165 if builtins.getattr(sys, 'argv', None) is not None:
164 if builtins.getattr(sys, 'argv', None) is not None:
166 # On POSIX, the char** argv array is converted to Python str using
165 # On POSIX, the char** argv array is converted to Python str using
167 # Py_DecodeLocale(). The inverse of this is Py_EncodeLocale(), which
166 # Py_DecodeLocale(). The inverse of this is Py_EncodeLocale(), which
168 # isn't directly callable from Python code. In practice, os.fsencode()
167 # isn't directly callable from Python code. In practice, os.fsencode()
169 # can be used instead (this is recommended by Python's documentation
168 # can be used instead (this is recommended by Python's documentation
170 # for sys.argv).
169 # for sys.argv).
171 #
170 #
172 # On Windows, the wchar_t **argv is passed into the interpreter as-is.
171 # On Windows, the wchar_t **argv is passed into the interpreter as-is.
173 # Like POSIX, we need to emulate what Py_EncodeLocale() would do. But
172 # Like POSIX, we need to emulate what Py_EncodeLocale() would do. But
174 # there's an additional wrinkle. What we really want to access is the
173 # there's an additional wrinkle. What we really want to access is the
175 # ANSI codepage representation of the arguments, as this is what
174 # ANSI codepage representation of the arguments, as this is what
176 # `int main()` would receive if Python 3 didn't define `int wmain()`
175 # `int main()` would receive if Python 3 didn't define `int wmain()`
177 # (this is how Python 2 worked). To get that, we encode with the mbcs
176 # (this is how Python 2 worked). To get that, we encode with the mbcs
178 # encoding, which will pass CP_ACP to the underlying Windows API to
177 # encoding, which will pass CP_ACP to the underlying Windows API to
179 # produce bytes.
178 # produce bytes.
180 sysargv: List[bytes] = []
179 sysargv: List[bytes] = []
181 if os.name == r'nt':
180 if os.name == r'nt':
182 sysargv = [a.encode("mbcs", "ignore") for a in sys.argv]
181 sysargv = [a.encode("mbcs", "ignore") for a in sys.argv]
183 else:
182 else:
184 sysargv = [fsencode(a) for a in sys.argv]
183 sysargv = [fsencode(a) for a in sys.argv]
185
184
186 bytechr = struct.Struct('>B').pack
185 bytechr = struct.Struct('>B').pack
187 byterepr = b'%r'.__mod__
186 byterepr = b'%r'.__mod__
188
187
189
188
190 class bytestr(bytes):
189 class bytestr(bytes):
191 """A bytes which mostly acts as a Python 2 str
190 """A bytes which mostly acts as a Python 2 str
192
191
193 >>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
192 >>> bytestr(), bytestr(bytearray(b'foo')), bytestr(u'ascii'), bytestr(1)
194 ('', 'foo', 'ascii', '1')
193 ('', 'foo', 'ascii', '1')
195 >>> s = bytestr(b'foo')
194 >>> s = bytestr(b'foo')
196 >>> assert s is bytestr(s)
195 >>> assert s is bytestr(s)
197
196
198 __bytes__() should be called if provided:
197 __bytes__() should be called if provided:
199
198
200 >>> class bytesable:
199 >>> class bytesable:
201 ... def __bytes__(self):
200 ... def __bytes__(self):
202 ... return b'bytes'
201 ... return b'bytes'
203 >>> bytestr(bytesable())
202 >>> bytestr(bytesable())
204 'bytes'
203 'bytes'
205
204
206 There's no implicit conversion from non-ascii str as its encoding is
205 There's no implicit conversion from non-ascii str as its encoding is
207 unknown:
206 unknown:
208
207
209 >>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
208 >>> bytestr(chr(0x80)) # doctest: +ELLIPSIS
210 Traceback (most recent call last):
209 Traceback (most recent call last):
211 ...
210 ...
212 UnicodeEncodeError: ...
211 UnicodeEncodeError: ...
213
212
214 Comparison between bytestr and bytes should work:
213 Comparison between bytestr and bytes should work:
215
214
216 >>> assert bytestr(b'foo') == b'foo'
215 >>> assert bytestr(b'foo') == b'foo'
217 >>> assert b'foo' == bytestr(b'foo')
216 >>> assert b'foo' == bytestr(b'foo')
218 >>> assert b'f' in bytestr(b'foo')
217 >>> assert b'f' in bytestr(b'foo')
219 >>> assert bytestr(b'f') in b'foo'
218 >>> assert bytestr(b'f') in b'foo'
220
219
221 Sliced elements should be bytes, not integer:
220 Sliced elements should be bytes, not integer:
222
221
223 >>> s[1], s[:2]
222 >>> s[1], s[:2]
224 (b'o', b'fo')
223 (b'o', b'fo')
225 >>> list(s), list(reversed(s))
224 >>> list(s), list(reversed(s))
226 ([b'f', b'o', b'o'], [b'o', b'o', b'f'])
225 ([b'f', b'o', b'o'], [b'o', b'o', b'f'])
227
226
228 As bytestr type isn't propagated across operations, you need to cast
227 As bytestr type isn't propagated across operations, you need to cast
229 bytes to bytestr explicitly:
228 bytes to bytestr explicitly:
230
229
231 >>> s = bytestr(b'foo').upper()
230 >>> s = bytestr(b'foo').upper()
232 >>> t = bytestr(s)
231 >>> t = bytestr(s)
233 >>> s[0], t[0]
232 >>> s[0], t[0]
234 (70, b'F')
233 (70, b'F')
235
234
236 Be careful to not pass a bytestr object to a function which expects
235 Be careful to not pass a bytestr object to a function which expects
237 bytearray-like behavior.
236 bytearray-like behavior.
238
237
239 >>> t = bytes(t) # cast to bytes
238 >>> t = bytes(t) # cast to bytes
240 >>> assert type(t) is bytes
239 >>> assert type(t) is bytes
241 """
240 """
242
241
243 # Trick pytype into not demanding Iterable[int] be passed to __new__(),
242 # Trick pytype into not demanding Iterable[int] be passed to __new__(),
244 # since the appropriate bytes format is done internally.
243 # since the appropriate bytes format is done internally.
245 #
244 #
246 # https://github.com/google/pytype/issues/500
245 # https://github.com/google/pytype/issues/500
247 if TYPE_CHECKING:
246 if TYPE_CHECKING:
248
247
249 def __init__(self, s: object = b'') -> None:
248 def __init__(self, s: object = b'') -> None:
250 pass
249 pass
251
250
252 def __new__(cls: Type[_Tbytestr], s: object = b'') -> _Tbytestr:
251 def __new__(cls: Type[_Tbytestr], s: object = b'') -> _Tbytestr:
253 if isinstance(s, bytestr):
252 if isinstance(s, bytestr):
254 return s
253 return s
255 if not isinstance(
254 if not isinstance(
256 s, (bytes, bytearray)
255 s, (bytes, bytearray)
257 ) and not builtins.hasattr( # hasattr-py3-only
256 ) and not builtins.hasattr( # hasattr-py3-only
258 s, u'__bytes__'
257 s, u'__bytes__'
259 ):
258 ):
260 s = str(s).encode('ascii')
259 s = str(s).encode('ascii')
261 return bytes.__new__(cls, s)
260 return bytes.__new__(cls, s)
262
261
263 # The base class uses `int` return in py3, but the point of this class is to
262 # The base class uses `int` return in py3, but the point of this class is to
264 # behave like py2.
263 # behave like py2.
265 def __getitem__(self, key) -> bytes: # pytype: disable=signature-mismatch
264 def __getitem__(self, key) -> bytes: # pytype: disable=signature-mismatch
266 s = bytes.__getitem__(self, key)
265 s = bytes.__getitem__(self, key)
267 if not isinstance(s, bytes):
266 if not isinstance(s, bytes):
268 s = bytechr(s)
267 s = bytechr(s)
269 return s
268 return s
270
269
271 # The base class expects `Iterator[int]` return in py3, but the point of
270 # The base class expects `Iterator[int]` return in py3, but the point of
272 # this class is to behave like py2.
271 # this class is to behave like py2.
273 def __iter__(self) -> Iterator[bytes]: # pytype: disable=signature-mismatch
272 def __iter__(self) -> Iterator[bytes]: # pytype: disable=signature-mismatch
274 return iterbytestr(bytes.__iter__(self))
273 return iterbytestr(bytes.__iter__(self))
275
274
276 def __repr__(self) -> str:
275 def __repr__(self) -> str:
277 return bytes.__repr__(self)[1:] # drop b''
276 return bytes.__repr__(self)[1:] # drop b''
278
277
279
278
280 def iterbytestr(s: Iterable[int]) -> Iterator[bytes]:
279 def iterbytestr(s: Iterable[int]) -> Iterator[bytes]:
281 """Iterate bytes as if it were a str object of Python 2"""
280 """Iterate bytes as if it were a str object of Python 2"""
282 return map(bytechr, s)
281 return map(bytechr, s)
283
282
284
283
285 if TYPE_CHECKING:
284 if TYPE_CHECKING:
286
285
287 @overload
286 @overload
288 def maybebytestr(s: bytes) -> bytestr:
287 def maybebytestr(s: bytes) -> bytestr:
289 ...
288 ...
290
289
291 @overload
290 @overload
292 def maybebytestr(s: _T0) -> _T0:
291 def maybebytestr(s: _T0) -> _T0:
293 ...
292 ...
294
293
295
294
296 def maybebytestr(s):
295 def maybebytestr(s):
297 """Promote bytes to bytestr"""
296 """Promote bytes to bytestr"""
298 if isinstance(s, bytes):
297 if isinstance(s, bytes):
299 return bytestr(s)
298 return bytestr(s)
300 return s
299 return s
301
300
302
301
303 def sysbytes(s: AnyStr) -> bytes:
302 def sysbytes(s: AnyStr) -> bytes:
304 """Convert an internal str (e.g. keyword, __doc__) back to bytes
303 """Convert an internal str (e.g. keyword, __doc__) back to bytes
305
304
306 This never raises UnicodeEncodeError, but only ASCII characters
305 This never raises UnicodeEncodeError, but only ASCII characters
307 can be round-trip by sysstr(sysbytes(s)).
306 can be round-trip by sysstr(sysbytes(s)).
308 """
307 """
309 if isinstance(s, bytes):
308 if isinstance(s, bytes):
310 return s
309 return s
311 return s.encode('utf-8')
310 return s.encode('utf-8')
312
311
313
312
314 def sysstr(s: AnyStr) -> str:
313 def sysstr(s: AnyStr) -> str:
315 """Return a keyword str to be passed to Python functions such as
314 """Return a keyword str to be passed to Python functions such as
316 getattr() and str.encode()
315 getattr() and str.encode()
317
316
318 This never raises UnicodeDecodeError. Non-ascii characters are
317 This never raises UnicodeDecodeError. Non-ascii characters are
319 considered invalid and mapped to arbitrary but unique code points
318 considered invalid and mapped to arbitrary but unique code points
320 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
319 such that 'sysstr(a) != sysstr(b)' for all 'a != b'.
321 """
320 """
322 if isinstance(s, builtins.str):
321 if isinstance(s, builtins.str):
323 return s
322 return s
324 return s.decode('latin-1')
323 return s.decode('latin-1')
325
324
326
325
327 def strurl(url: AnyStr) -> str:
326 def strurl(url: AnyStr) -> str:
328 """Converts a bytes url back to str"""
327 """Converts a bytes url back to str"""
329 if isinstance(url, bytes):
328 if isinstance(url, bytes):
330 return url.decode('ascii')
329 return url.decode('ascii')
331 return url
330 return url
332
331
333
332
334 def bytesurl(url: AnyStr) -> bytes:
333 def bytesurl(url: AnyStr) -> bytes:
335 """Converts a str url to bytes by encoding in ascii"""
334 """Converts a str url to bytes by encoding in ascii"""
336 if isinstance(url, str):
335 if isinstance(url, str):
337 return url.encode('ascii')
336 return url.encode('ascii')
338 return url
337 return url
339
338
340
339
341 def raisewithtb(exc: BaseException, tb) -> NoReturn:
340 def raisewithtb(exc: BaseException, tb) -> NoReturn:
342 """Raise exception with the given traceback"""
341 """Raise exception with the given traceback"""
343 raise exc.with_traceback(tb)
342 raise exc.with_traceback(tb)
344
343
345
344
346 def getdoc(obj: object) -> Optional[bytes]:
345 def getdoc(obj: object) -> Optional[bytes]:
347 """Get docstring as bytes; may be None so gettext() won't confuse it
346 """Get docstring as bytes; may be None so gettext() won't confuse it
348 with _('')"""
347 with _('')"""
349 doc = builtins.getattr(obj, '__doc__', None)
348 doc = builtins.getattr(obj, '__doc__', None)
350 if doc is None:
349 if doc is None:
351 return doc
350 return doc
352 return sysbytes(doc)
351 return sysbytes(doc)
353
352
354
353
355 def _wrapattrfunc(f):
356 @functools.wraps(f)
357 def w(object, name, *args):
358 if isinstance(name, bytes):
359 from . import util
360
361 msg = b'function "%s" take `str` as argument, not `bytes`'
362 fname = f.__name__.encode('ascii')
363 msg %= fname
364 util.nouideprecwarn(msg, b"6.6", stacklevel=2)
365 return f(object, sysstr(name), *args)
366
367 return w
368
369
370 # these wrappers are automagically imported by hgloader
354 # these wrappers are automagically imported by hgloader
371 delattr = _wrapattrfunc(builtins.delattr)
355 delattr = builtins.delattr
372 getattr = _wrapattrfunc(builtins.getattr)
356 getattr = builtins.getattr
373 hasattr = _wrapattrfunc(builtins.hasattr)
357 hasattr = builtins.hasattr
374 setattr = _wrapattrfunc(builtins.setattr)
358 setattr = builtins.setattr
375 xrange = builtins.range
359 xrange = builtins.range
376 unicode = str
360 unicode = str
377
361
378
362
379 def open(
363 def open(
380 name,
364 name,
381 mode: AnyStr = b'r',
365 mode: AnyStr = b'r',
382 buffering: int = -1,
366 buffering: int = -1,
383 encoding: Optional[str] = None,
367 encoding: Optional[str] = None,
384 ) -> Any:
368 ) -> Any:
385 # TODO: assert binary mode, and cast result to BinaryIO?
369 # TODO: assert binary mode, and cast result to BinaryIO?
386 return builtins.open(name, sysstr(mode), buffering, encoding)
370 return builtins.open(name, sysstr(mode), buffering, encoding)
387
371
388
372
389 safehasattr = _wrapattrfunc(builtins.hasattr)
373 safehasattr = builtins.hasattr
390
374
391
375
392 def _getoptbwrapper(
376 def _getoptbwrapper(
393 orig, args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
377 orig, args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
394 ) -> _GetOptResult:
378 ) -> _GetOptResult:
395 """
379 """
396 Takes bytes arguments, converts them to unicode, pass them to
380 Takes bytes arguments, converts them to unicode, pass them to
397 getopt.getopt(), convert the returned values back to bytes and then
381 getopt.getopt(), convert the returned values back to bytes and then
398 return them for Python 3 compatibility as getopt.getopt() don't accepts
382 return them for Python 3 compatibility as getopt.getopt() don't accepts
399 bytes on Python 3.
383 bytes on Python 3.
400 """
384 """
401 args = [a.decode('latin-1') for a in args]
385 args = [a.decode('latin-1') for a in args]
402 shortlist = shortlist.decode('latin-1')
386 shortlist = shortlist.decode('latin-1')
403 namelist = [a.decode('latin-1') for a in namelist]
387 namelist = [a.decode('latin-1') for a in namelist]
404 opts, args = orig(args, shortlist, namelist)
388 opts, args = orig(args, shortlist, namelist)
405 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1')) for a in opts]
389 opts = [(a[0].encode('latin-1'), a[1].encode('latin-1')) for a in opts]
406 args = [a.encode('latin-1') for a in args]
390 args = [a.encode('latin-1') for a in args]
407 return opts, args
391 return opts, args
408
392
409
393
410 def strkwargs(dic: Mapping[bytes, _T0]) -> Dict[str, _T0]:
394 def strkwargs(dic: Mapping[bytes, _T0]) -> Dict[str, _T0]:
411 """
395 """
412 Converts the keys of a python dictonary to str i.e. unicodes so that
396 Converts the keys of a python dictonary to str i.e. unicodes so that
413 they can be passed as keyword arguments as dictionaries with bytes keys
397 they can be passed as keyword arguments as dictionaries with bytes keys
414 can't be passed as keyword arguments to functions on Python 3.
398 can't be passed as keyword arguments to functions on Python 3.
415 """
399 """
416 dic = {k.decode('latin-1'): v for k, v in dic.items()}
400 dic = {k.decode('latin-1'): v for k, v in dic.items()}
417 return dic
401 return dic
418
402
419
403
420 def byteskwargs(dic: Mapping[str, _T0]) -> Dict[bytes, _T0]:
404 def byteskwargs(dic: Mapping[str, _T0]) -> Dict[bytes, _T0]:
421 """
405 """
422 Converts keys of python dictionaries to bytes as they were converted to
406 Converts keys of python dictionaries to bytes as they were converted to
423 str to pass that dictonary as a keyword argument on Python 3.
407 str to pass that dictonary as a keyword argument on Python 3.
424 """
408 """
425 dic = {k.encode('latin-1'): v for k, v in dic.items()}
409 dic = {k.encode('latin-1'): v for k, v in dic.items()}
426 return dic
410 return dic
427
411
428
412
429 # TODO: handle shlex.shlex().
413 # TODO: handle shlex.shlex().
430 def shlexsplit(
414 def shlexsplit(
431 s: bytes, comments: bool = False, posix: bool = True
415 s: bytes, comments: bool = False, posix: bool = True
432 ) -> List[bytes]:
416 ) -> List[bytes]:
433 """
417 """
434 Takes bytes argument, convert it to str i.e. unicodes, pass that into
418 Takes bytes argument, convert it to str i.e. unicodes, pass that into
435 shlex.split(), convert the returned value to bytes and return that for
419 shlex.split(), convert the returned value to bytes and return that for
436 Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
420 Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
437 """
421 """
438 ret = shlex.split(s.decode('latin-1'), comments, posix)
422 ret = shlex.split(s.decode('latin-1'), comments, posix)
439 return [a.encode('latin-1') for a in ret]
423 return [a.encode('latin-1') for a in ret]
440
424
441
425
442 iteritems = lambda x: x.items()
426 iteritems = lambda x: x.items()
443 itervalues = lambda x: x.values()
427 itervalues = lambda x: x.values()
444
428
445 json_loads = json.loads
429 json_loads = json.loads
446
430
447 isjython: bool = sysplatform.startswith(b'java')
431 isjython: bool = sysplatform.startswith(b'java')
448
432
449 isdarwin: bool = sysplatform.startswith(b'darwin')
433 isdarwin: bool = sysplatform.startswith(b'darwin')
450 islinux: bool = sysplatform.startswith(b'linux')
434 islinux: bool = sysplatform.startswith(b'linux')
451 isposix: bool = osname == b'posix'
435 isposix: bool = osname == b'posix'
452 iswindows: bool = osname == b'nt'
436 iswindows: bool = osname == b'nt'
453
437
454
438
455 def getoptb(
439 def getoptb(
456 args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
440 args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
457 ) -> _GetOptResult:
441 ) -> _GetOptResult:
458 return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
442 return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
459
443
460
444
461 def gnugetoptb(
445 def gnugetoptb(
462 args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
446 args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
463 ) -> _GetOptResult:
447 ) -> _GetOptResult:
464 return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
448 return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
465
449
466
450
467 def mkdtemp(
451 def mkdtemp(
468 suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
452 suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
469 ) -> bytes:
453 ) -> bytes:
470 return tempfile.mkdtemp(suffix, prefix, dir)
454 return tempfile.mkdtemp(suffix, prefix, dir)
471
455
472
456
473 # text=True is not supported; use util.from/tonativeeol() instead
457 # text=True is not supported; use util.from/tonativeeol() instead
474 def mkstemp(
458 def mkstemp(
475 suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
459 suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
476 ) -> Tuple[int, bytes]:
460 ) -> Tuple[int, bytes]:
477 return tempfile.mkstemp(suffix, prefix, dir)
461 return tempfile.mkstemp(suffix, prefix, dir)
478
462
479
463
480 # TemporaryFile does not support an "encoding=" argument on python2.
464 # TemporaryFile does not support an "encoding=" argument on python2.
481 # This wrapper file are always open in byte mode.
465 # This wrapper file are always open in byte mode.
482 def unnamedtempfile(mode: Optional[bytes] = None, *args, **kwargs) -> BinaryIO:
466 def unnamedtempfile(mode: Optional[bytes] = None, *args, **kwargs) -> BinaryIO:
483 if mode is None:
467 if mode is None:
484 mode = 'w+b'
468 mode = 'w+b'
485 else:
469 else:
486 mode = sysstr(mode)
470 mode = sysstr(mode)
487 assert 'b' in mode
471 assert 'b' in mode
488 return cast(BinaryIO, tempfile.TemporaryFile(mode, *args, **kwargs))
472 return cast(BinaryIO, tempfile.TemporaryFile(mode, *args, **kwargs))
489
473
490
474
491 # NamedTemporaryFile does not support an "encoding=" argument on python2.
475 # NamedTemporaryFile does not support an "encoding=" argument on python2.
492 # This wrapper file are always open in byte mode.
476 # This wrapper file are always open in byte mode.
493 def namedtempfile(
477 def namedtempfile(
494 mode: bytes = b'w+b',
478 mode: bytes = b'w+b',
495 bufsize: int = -1,
479 bufsize: int = -1,
496 suffix: bytes = b'',
480 suffix: bytes = b'',
497 prefix: bytes = b'tmp',
481 prefix: bytes = b'tmp',
498 dir: Optional[bytes] = None,
482 dir: Optional[bytes] = None,
499 delete: bool = True,
483 delete: bool = True,
500 ):
484 ):
501 mode = sysstr(mode)
485 mode = sysstr(mode)
502 assert 'b' in mode
486 assert 'b' in mode
503 return tempfile.NamedTemporaryFile(
487 return tempfile.NamedTemporaryFile(
504 mode, bufsize, suffix=suffix, prefix=prefix, dir=dir, delete=delete
488 mode, bufsize, suffix=suffix, prefix=prefix, dir=dir, delete=delete
505 )
489 )
General Comments 0
You need to be logged in to leave comments. Login now