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