mercurial/pycompat.py
changeset 49902 c5a06cc37401
parent 49898 55d45d0de4e7
child 50150 b900f40c343e
equal deleted inserted replaced
49901:9eb69fa5a783 49902:c5a06cc37401
    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,
       
    33     AnyStr,
       
    34     BinaryIO,
       
    35     Dict,
    32     Iterable,
    36     Iterable,
    33     Iterator,
    37     Iterator,
    34     List,
    38     List,
       
    39     Mapping,
       
    40     NoReturn,
    35     Optional,
    41     Optional,
       
    42     Sequence,
       
    43     Tuple,
    36     Type,
    44     Type,
    37     TypeVar,
    45     TypeVar,
       
    46     cast,
       
    47     overload,
    38 )
    48 )
    39 
    49 
    40 ispy3 = sys.version_info[0] >= 3
    50 ispy3 = sys.version_info[0] >= 3
    41 ispypy = '__pypy__' in sys.builtin_module_names
    51 ispypy = '__pypy__' in sys.builtin_module_names
    42 TYPE_CHECKING = False
    52 TYPE_CHECKING = False
    44 if not globals():  # hide this from non-pytype users
    54 if not globals():  # hide this from non-pytype users
    45     import typing
    55     import typing
    46 
    56 
    47     TYPE_CHECKING = typing.TYPE_CHECKING
    57     TYPE_CHECKING = typing.TYPE_CHECKING
    48 
    58 
       
    59 _GetOptResult = Tuple[List[Tuple[bytes, bytes]], List[bytes]]
       
    60 _T0 = TypeVar('_T0')
    49 _Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
    61 _Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
    50 
    62 
    51 
    63 
    52 def future_set_exception_info(f, exc_info):
    64 def future_set_exception_info(f, exc_info):
    53     f.set_exception(exc_info[0])
    65     f.set_exception(exc_info[0])
    54 
    66 
    55 
    67 
    56 FileNotFoundError = builtins.FileNotFoundError
    68 FileNotFoundError = builtins.FileNotFoundError
    57 
    69 
    58 
    70 
    59 def identity(a):
    71 def identity(a: _T0) -> _T0:
    60     return a
    72     return a
    61 
    73 
    62 
    74 
    63 def _rapply(f, xs):
    75 def _rapply(f, xs):
    64     if xs is None:
    76     if xs is None:
   248 def iterbytestr(s: Iterable[int]) -> Iterator[bytes]:
   260 def iterbytestr(s: Iterable[int]) -> Iterator[bytes]:
   249     """Iterate bytes as if it were a str object of Python 2"""
   261     """Iterate bytes as if it were a str object of Python 2"""
   250     return map(bytechr, s)
   262     return map(bytechr, s)
   251 
   263 
   252 
   264 
       
   265 if TYPE_CHECKING:
       
   266 
       
   267     @overload
       
   268     def maybebytestr(s: bytes) -> bytestr:
       
   269         ...
       
   270 
       
   271     @overload
       
   272     def maybebytestr(s: _T0) -> _T0:
       
   273         ...
       
   274 
       
   275 
   253 def maybebytestr(s):
   276 def maybebytestr(s):
   254     """Promote bytes to bytestr"""
   277     """Promote bytes to bytestr"""
   255     if isinstance(s, bytes):
   278     if isinstance(s, bytes):
   256         return bytestr(s)
   279         return bytestr(s)
   257     return s
   280     return s
   258 
   281 
   259 
   282 
   260 def sysbytes(s):
   283 def sysbytes(s: AnyStr) -> bytes:
   261     """Convert an internal str (e.g. keyword, __doc__) back to bytes
   284     """Convert an internal str (e.g. keyword, __doc__) back to bytes
   262 
   285 
   263     This never raises UnicodeEncodeError, but only ASCII characters
   286     This never raises UnicodeEncodeError, but only ASCII characters
   264     can be round-trip by sysstr(sysbytes(s)).
   287     can be round-trip by sysstr(sysbytes(s)).
   265     """
   288     """
   266     if isinstance(s, bytes):
   289     if isinstance(s, bytes):
   267         return s
   290         return s
   268     return s.encode('utf-8')
   291     return s.encode('utf-8')
   269 
   292 
   270 
   293 
   271 def sysstr(s):
   294 def sysstr(s: AnyStr) -> str:
   272     """Return a keyword str to be passed to Python functions such as
   295     """Return a keyword str to be passed to Python functions such as
   273     getattr() and str.encode()
   296     getattr() and str.encode()
   274 
   297 
   275     This never raises UnicodeDecodeError. Non-ascii characters are
   298     This never raises UnicodeDecodeError. Non-ascii characters are
   276     considered invalid and mapped to arbitrary but unique code points
   299     considered invalid and mapped to arbitrary but unique code points
   279     if isinstance(s, builtins.str):
   302     if isinstance(s, builtins.str):
   280         return s
   303         return s
   281     return s.decode('latin-1')
   304     return s.decode('latin-1')
   282 
   305 
   283 
   306 
   284 def strurl(url):
   307 def strurl(url: AnyStr) -> str:
   285     """Converts a bytes url back to str"""
   308     """Converts a bytes url back to str"""
   286     if isinstance(url, bytes):
   309     if isinstance(url, bytes):
   287         return url.decode('ascii')
   310         return url.decode('ascii')
   288     return url
   311     return url
   289 
   312 
   290 
   313 
   291 def bytesurl(url):
   314 def bytesurl(url: AnyStr) -> bytes:
   292     """Converts a str url to bytes by encoding in ascii"""
   315     """Converts a str url to bytes by encoding in ascii"""
   293     if isinstance(url, str):
   316     if isinstance(url, str):
   294         return url.encode('ascii')
   317         return url.encode('ascii')
   295     return url
   318     return url
   296 
   319 
   297 
   320 
   298 def raisewithtb(exc, tb):
   321 def raisewithtb(exc: BaseException, tb) -> NoReturn:
   299     """Raise exception with the given traceback"""
   322     """Raise exception with the given traceback"""
   300     raise exc.with_traceback(tb)
   323     raise exc.with_traceback(tb)
   301 
   324 
   302 
   325 
   303 def getdoc(obj):
   326 def getdoc(obj: object) -> Optional[bytes]:
   304     """Get docstring as bytes; may be None so gettext() won't confuse it
   327     """Get docstring as bytes; may be None so gettext() won't confuse it
   305     with _('')"""
   328     with _('')"""
   306     doc = builtins.getattr(obj, '__doc__', None)
   329     doc = builtins.getattr(obj, '__doc__', None)
   307     if doc is None:
   330     if doc is None:
   308         return doc
   331         return doc
   324 setattr = _wrapattrfunc(builtins.setattr)
   347 setattr = _wrapattrfunc(builtins.setattr)
   325 xrange = builtins.range
   348 xrange = builtins.range
   326 unicode = str
   349 unicode = str
   327 
   350 
   328 
   351 
   329 def open(name, mode=b'r', buffering=-1, encoding=None):
   352 def open(
       
   353     name,
       
   354     mode: AnyStr = b'r',
       
   355     buffering: int = -1,
       
   356     encoding: Optional[str] = None,
       
   357 ) -> Any:
       
   358     # TODO: assert binary mode, and cast result to BinaryIO?
   330     return builtins.open(name, sysstr(mode), buffering, encoding)
   359     return builtins.open(name, sysstr(mode), buffering, encoding)
   331 
   360 
   332 
   361 
   333 safehasattr = _wrapattrfunc(builtins.hasattr)
   362 safehasattr = _wrapattrfunc(builtins.hasattr)
   334 
   363 
   335 
   364 
   336 def _getoptbwrapper(orig, args, shortlist, namelist):
   365 def _getoptbwrapper(
       
   366     orig, args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
       
   367 ) -> _GetOptResult:
   337     """
   368     """
   338     Takes bytes arguments, converts them to unicode, pass them to
   369     Takes bytes arguments, converts them to unicode, pass them to
   339     getopt.getopt(), convert the returned values back to bytes and then
   370     getopt.getopt(), convert the returned values back to bytes and then
   340     return them for Python 3 compatibility as getopt.getopt() don't accepts
   371     return them for Python 3 compatibility as getopt.getopt() don't accepts
   341     bytes on Python 3.
   372     bytes on Python 3.
   347     opts = [(a[0].encode('latin-1'), a[1].encode('latin-1')) for a in opts]
   378     opts = [(a[0].encode('latin-1'), a[1].encode('latin-1')) for a in opts]
   348     args = [a.encode('latin-1') for a in args]
   379     args = [a.encode('latin-1') for a in args]
   349     return opts, args
   380     return opts, args
   350 
   381 
   351 
   382 
   352 def strkwargs(dic):
   383 def strkwargs(dic: Mapping[bytes, _T0]) -> Dict[str, _T0]:
   353     """
   384     """
   354     Converts the keys of a python dictonary to str i.e. unicodes so that
   385     Converts the keys of a python dictonary to str i.e. unicodes so that
   355     they can be passed as keyword arguments as dictionaries with bytes keys
   386     they can be passed as keyword arguments as dictionaries with bytes keys
   356     can't be passed as keyword arguments to functions on Python 3.
   387     can't be passed as keyword arguments to functions on Python 3.
   357     """
   388     """
   358     dic = {k.decode('latin-1'): v for k, v in dic.items()}
   389     dic = {k.decode('latin-1'): v for k, v in dic.items()}
   359     return dic
   390     return dic
   360 
   391 
   361 
   392 
   362 def byteskwargs(dic):
   393 def byteskwargs(dic: Mapping[str, _T0]) -> Dict[bytes, _T0]:
   363     """
   394     """
   364     Converts keys of python dictionaries to bytes as they were converted to
   395     Converts keys of python dictionaries to bytes as they were converted to
   365     str to pass that dictonary as a keyword argument on Python 3.
   396     str to pass that dictonary as a keyword argument on Python 3.
   366     """
   397     """
   367     dic = {k.encode('latin-1'): v for k, v in dic.items()}
   398     dic = {k.encode('latin-1'): v for k, v in dic.items()}
   368     return dic
   399     return dic
   369 
   400 
   370 
   401 
   371 # TODO: handle shlex.shlex().
   402 # TODO: handle shlex.shlex().
   372 def shlexsplit(s, comments=False, posix=True):
   403 def shlexsplit(
       
   404     s: bytes, comments: bool = False, posix: bool = True
       
   405 ) -> List[bytes]:
   373     """
   406     """
   374     Takes bytes argument, convert it to str i.e. unicodes, pass that into
   407     Takes bytes argument, convert it to str i.e. unicodes, pass that into
   375     shlex.split(), convert the returned value to bytes and return that for
   408     shlex.split(), convert the returned value to bytes and return that for
   376     Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
   409     Python 3 compatibility as shelx.split() don't accept bytes on Python 3.
   377     """
   410     """
   390 islinux: bool = sysplatform.startswith(b'linux')
   423 islinux: bool = sysplatform.startswith(b'linux')
   391 isposix: bool = osname == b'posix'
   424 isposix: bool = osname == b'posix'
   392 iswindows: bool = osname == b'nt'
   425 iswindows: bool = osname == b'nt'
   393 
   426 
   394 
   427 
   395 def getoptb(args, shortlist, namelist):
   428 def getoptb(
       
   429     args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
       
   430 ) -> _GetOptResult:
   396     return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
   431     return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
   397 
   432 
   398 
   433 
   399 def gnugetoptb(args, shortlist, namelist):
   434 def gnugetoptb(
       
   435     args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
       
   436 ) -> _GetOptResult:
   400     return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
   437     return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
   401 
   438 
   402 
   439 
   403 def mkdtemp(suffix=b'', prefix=b'tmp', dir=None):
   440 def mkdtemp(
       
   441     suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
       
   442 ) -> bytes:
   404     return tempfile.mkdtemp(suffix, prefix, dir)
   443     return tempfile.mkdtemp(suffix, prefix, dir)
   405 
   444 
   406 
   445 
   407 # text=True is not supported; use util.from/tonativeeol() instead
   446 # text=True is not supported; use util.from/tonativeeol() instead
   408 def mkstemp(suffix=b'', prefix=b'tmp', dir=None):
   447 def mkstemp(
       
   448     suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
       
   449 ) -> Tuple[int, bytes]:
   409     return tempfile.mkstemp(suffix, prefix, dir)
   450     return tempfile.mkstemp(suffix, prefix, dir)
   410 
   451 
   411 
   452 
   412 # TemporaryFile does not support an "encoding=" argument on python2.
   453 # TemporaryFile does not support an "encoding=" argument on python2.
   413 # This wrapper file are always open in byte mode.
   454 # This wrapper file are always open in byte mode.
   414 def unnamedtempfile(mode=None, *args, **kwargs):
   455 def unnamedtempfile(mode: Optional[bytes] = None, *args, **kwargs) -> BinaryIO:
   415     if mode is None:
   456     if mode is None:
   416         mode = 'w+b'
   457         mode = 'w+b'
   417     else:
   458     else:
   418         mode = sysstr(mode)
   459         mode = sysstr(mode)
   419     assert 'b' in mode
   460     assert 'b' in mode
   420     return tempfile.TemporaryFile(mode, *args, **kwargs)
   461     return cast(BinaryIO, tempfile.TemporaryFile(mode, *args, **kwargs))
   421 
   462 
   422 
   463 
   423 # NamedTemporaryFile does not support an "encoding=" argument on python2.
   464 # NamedTemporaryFile does not support an "encoding=" argument on python2.
   424 # This wrapper file are always open in byte mode.
   465 # This wrapper file are always open in byte mode.
   425 def namedtempfile(
   466 def namedtempfile(
   426     mode=b'w+b', bufsize=-1, suffix=b'', prefix=b'tmp', dir=None, delete=True
   467     mode: bytes = b'w+b',
       
   468     bufsize: int = -1,
       
   469     suffix: bytes = b'',
       
   470     prefix: bytes = b'tmp',
       
   471     dir: Optional[bytes] = None,
       
   472     delete: bool = True,
   427 ):
   473 ):
   428     mode = sysstr(mode)
   474     mode = sysstr(mode)
   429     assert 'b' in mode
   475     assert 'b' in mode
   430     return tempfile.NamedTemporaryFile(
   476     return tempfile.NamedTemporaryFile(
   431         mode, bufsize, suffix=suffix, prefix=prefix, dir=dir, delete=delete
   477         mode, bufsize, suffix=suffix, prefix=prefix, dir=dir, delete=delete