--- a/mercurial/pycompat.py Wed Dec 14 22:27:22 2022 -0500
+++ b/mercurial/pycompat.py Thu Dec 15 01:05:27 2022 -0500
@@ -29,12 +29,22 @@
import xmlrpc.client as xmlrpclib
from typing import (
+ Any,
+ AnyStr,
+ BinaryIO,
+ Dict,
Iterable,
Iterator,
List,
+ Mapping,
+ NoReturn,
Optional,
+ Sequence,
+ Tuple,
Type,
TypeVar,
+ cast,
+ overload,
)
ispy3 = sys.version_info[0] >= 3
@@ -46,6 +56,8 @@
TYPE_CHECKING = typing.TYPE_CHECKING
+_GetOptResult = Tuple[List[Tuple[bytes, bytes]], List[bytes]]
+_T0 = TypeVar('_T0')
_Tbytestr = TypeVar('_Tbytestr', bound='bytestr')
@@ -56,7 +68,7 @@
FileNotFoundError = builtins.FileNotFoundError
-def identity(a):
+def identity(a: _T0) -> _T0:
return a
@@ -250,6 +262,17 @@
return map(bytechr, s)
+if TYPE_CHECKING:
+
+ @overload
+ def maybebytestr(s: bytes) -> bytestr:
+ ...
+
+ @overload
+ def maybebytestr(s: _T0) -> _T0:
+ ...
+
+
def maybebytestr(s):
"""Promote bytes to bytestr"""
if isinstance(s, bytes):
@@ -257,7 +280,7 @@
return s
-def sysbytes(s):
+def sysbytes(s: AnyStr) -> bytes:
"""Convert an internal str (e.g. keyword, __doc__) back to bytes
This never raises UnicodeEncodeError, but only ASCII characters
@@ -268,7 +291,7 @@
return s.encode('utf-8')
-def sysstr(s):
+def sysstr(s: AnyStr) -> str:
"""Return a keyword str to be passed to Python functions such as
getattr() and str.encode()
@@ -281,26 +304,26 @@
return s.decode('latin-1')
-def strurl(url):
+def strurl(url: AnyStr) -> str:
"""Converts a bytes url back to str"""
if isinstance(url, bytes):
return url.decode('ascii')
return url
-def bytesurl(url):
+def bytesurl(url: AnyStr) -> bytes:
"""Converts a str url to bytes by encoding in ascii"""
if isinstance(url, str):
return url.encode('ascii')
return url
-def raisewithtb(exc, tb):
+def raisewithtb(exc: BaseException, tb) -> NoReturn:
"""Raise exception with the given traceback"""
raise exc.with_traceback(tb)
-def getdoc(obj):
+def getdoc(obj: object) -> Optional[bytes]:
"""Get docstring as bytes; may be None so gettext() won't confuse it
with _('')"""
doc = builtins.getattr(obj, '__doc__', None)
@@ -326,14 +349,22 @@
unicode = str
-def open(name, mode=b'r', buffering=-1, encoding=None):
+def open(
+ name,
+ mode: AnyStr = b'r',
+ buffering: int = -1,
+ encoding: Optional[str] = None,
+) -> Any:
+ # TODO: assert binary mode, and cast result to BinaryIO?
return builtins.open(name, sysstr(mode), buffering, encoding)
safehasattr = _wrapattrfunc(builtins.hasattr)
-def _getoptbwrapper(orig, args, shortlist, namelist):
+def _getoptbwrapper(
+ orig, args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
+) -> _GetOptResult:
"""
Takes bytes arguments, converts them to unicode, pass them to
getopt.getopt(), convert the returned values back to bytes and then
@@ -349,7 +380,7 @@
return opts, args
-def strkwargs(dic):
+def strkwargs(dic: Mapping[bytes, _T0]) -> Dict[str, _T0]:
"""
Converts the keys of a python dictonary to str i.e. unicodes so that
they can be passed as keyword arguments as dictionaries with bytes keys
@@ -359,7 +390,7 @@
return dic
-def byteskwargs(dic):
+def byteskwargs(dic: Mapping[str, _T0]) -> Dict[bytes, _T0]:
"""
Converts keys of python dictionaries to bytes as they were converted to
str to pass that dictonary as a keyword argument on Python 3.
@@ -369,7 +400,9 @@
# TODO: handle shlex.shlex().
-def shlexsplit(s, comments=False, posix=True):
+def shlexsplit(
+ s: bytes, comments: bool = False, posix: bool = True
+) -> List[bytes]:
"""
Takes bytes argument, convert it to str i.e. unicodes, pass that into
shlex.split(), convert the returned value to bytes and return that for
@@ -392,38 +425,51 @@
iswindows: bool = osname == b'nt'
-def getoptb(args, shortlist, namelist):
+def getoptb(
+ args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
+) -> _GetOptResult:
return _getoptbwrapper(getopt.getopt, args, shortlist, namelist)
-def gnugetoptb(args, shortlist, namelist):
+def gnugetoptb(
+ args: Sequence[bytes], shortlist: bytes, namelist: Sequence[bytes]
+) -> _GetOptResult:
return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
-def mkdtemp(suffix=b'', prefix=b'tmp', dir=None):
+def mkdtemp(
+ suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
+) -> bytes:
return tempfile.mkdtemp(suffix, prefix, dir)
# text=True is not supported; use util.from/tonativeeol() instead
-def mkstemp(suffix=b'', prefix=b'tmp', dir=None):
+def mkstemp(
+ suffix: bytes = b'', prefix: bytes = b'tmp', dir: Optional[bytes] = None
+) -> Tuple[int, bytes]:
return tempfile.mkstemp(suffix, prefix, dir)
# TemporaryFile does not support an "encoding=" argument on python2.
# This wrapper file are always open in byte mode.
-def unnamedtempfile(mode=None, *args, **kwargs):
+def unnamedtempfile(mode: Optional[bytes] = None, *args, **kwargs) -> BinaryIO:
if mode is None:
mode = 'w+b'
else:
mode = sysstr(mode)
assert 'b' in mode
- return tempfile.TemporaryFile(mode, *args, **kwargs)
+ return cast(BinaryIO, tempfile.TemporaryFile(mode, *args, **kwargs))
# NamedTemporaryFile does not support an "encoding=" argument on python2.
# This wrapper file are always open in byte mode.
def namedtempfile(
- mode=b'w+b', bufsize=-1, suffix=b'', prefix=b'tmp', dir=None, delete=True
+ mode: bytes = b'w+b',
+ bufsize: int = -1,
+ suffix: bytes = b'',
+ prefix: bytes = b'tmp',
+ dir: Optional[bytes] = None,
+ delete: bool = True,
):
mode = sysstr(mode)
assert 'b' in mode