D12366: pycompat: add return type annotations
indygreg (Gregory Szorc)
phabricator at mercurial-scm.org
Thu Mar 10 01:08:37 UTC 2022
indygreg created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.
REVISION SUMMARY
Now that we're using Python 3.6+, we can start using inline type
annotations.
I figured a good a place as any to start would be pycompat. So this
commit defines type annotations throughout the file.
Because we can't use deferred annotations parsing (since this feature
requires Python 3.7), complex types relying on symbols from the `typing`
module use quoted expressions. This achieves some of the benefit of
deferred parsing without compromising the ability for type checkers to
infer things.
When annotating `open()` as part of this change, pytype started
complaining about a type mismatch in `profiling.py`. This turned out
to be a false positive. So the error was suppressed.
REPOSITORY
rHG Mercurial
BRANCH
default
REVISION DETAIL
https://phab.mercurial-scm.org/D12366
AFFECTED FILES
mercurial/profiling.py
mercurial/pycompat.py
CHANGE DETAILS
diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py
--- a/mercurial/pycompat.py
+++ b/mercurial/pycompat.py
@@ -36,6 +36,16 @@
if not globals(): # hide this from non-pytype users
import typing
+ from typing import (
+ Any,
+ AnyStr,
+ Dict,
+ IO,
+ Iterator,
+ List,
+ NoReturn,
+ Tuple,
+ )
TYPE_CHECKING = typing.TYPE_CHECKING
@@ -112,15 +122,15 @@
sysexecutable = os.fsencode(sysexecutable)
-def maplist(*args):
+def maplist(*args) -> 'List[Any]':
return list(map(*args))
-def rangelist(*args):
+def rangelist(*args) -> 'List[int]':
return list(range(*args))
-def ziplist(*args):
+def ziplist(*args) -> 'List[Any]':
return list(zip(*args))
@@ -226,20 +236,20 @@
s = str(s).encode('ascii')
return bytes.__new__(cls, s)
- def __getitem__(self, key):
+ def __getitem__(self, key) -> bytes:
s = bytes.__getitem__(self, key)
if not isinstance(s, bytes):
s = bytechr(s)
return s
- def __iter__(self):
+ def __iter__(self) -> 'Iterator[bytes]':
return iterbytestr(bytes.__iter__(self))
- def __repr__(self):
+ def __repr__(self) -> str:
return bytes.__repr__(self)[1:] # drop b''
-def iterbytestr(s):
+def iterbytestr(s) -> 'Iterator[bytes]':
"""Iterate bytes as if it were a str object of Python 2"""
return map(bytechr, s)
@@ -251,7 +261,7 @@
return s
-def sysbytes(s):
+def sysbytes(s) -> bytes:
"""Convert an internal str (e.g. keyword, __doc__) back to bytes
This never raises UnicodeEncodeError, but only ASCII characters
@@ -262,7 +272,7 @@
return s.encode('utf-8')
-def sysstr(s):
+def sysstr(s) -> str:
"""Return a keyword str to be passed to Python functions such as
getattr() and str.encode()
@@ -275,26 +285,26 @@
return s.decode('latin-1')
-def strurl(url):
+def strurl(url) -> str:
"""Converts a bytes url back to str"""
if isinstance(url, bytes):
return url.decode('ascii')
return url
-def bytesurl(url):
+def bytesurl(url) -> 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, tb) -> 'NoReturn':
"""Raise exception with the given traceback"""
raise exc.with_traceback(tb)
-def getdoc(obj):
+def getdoc(obj) -> bytes:
"""Get docstring as bytes; may be None so gettext() won't confuse it
with _('')"""
doc = getattr(obj, '__doc__', None)
@@ -320,14 +330,16 @@
unicode = str
-def open(name, mode=b'r', buffering=-1, encoding=None):
+def open(name, mode=b'r', buffering=-1, encoding=None) -> 'IO[AnyStr]':
return builtins.open(name, sysstr(mode), buffering, encoding)
safehasattr = _wrapattrfunc(builtins.hasattr)
-def _getoptbwrapper(orig, args, shortlist, namelist):
+def _getoptbwrapper(
+ orig, args, shortlist, namelist
+) -> 'Tuple[List[Tuple[bytes, bytes]], List[bytes]]':
"""
Takes bytes arguments, converts them to unicode, pass them to
getopt.getopt(), convert the returned values back to bytes and then
@@ -343,7 +355,7 @@
return opts, args
-def strkwargs(dic):
+def strkwargs(dic) -> 'Dict[str, Any]':
"""
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
@@ -353,7 +365,7 @@
return dic
-def byteskwargs(dic):
+def byteskwargs(dic) -> 'Dict[bytes, Any]':
"""
Converts keys of python dictionaries to bytes as they were converted to
str to pass that dictonary as a keyword argument on Python 3.
@@ -363,7 +375,7 @@
# TODO: handle shlex.shlex().
-def shlexsplit(s, comments=False, posix=True):
+def shlexsplit(s, comments=False, posix=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
@@ -394,18 +406,18 @@
return _getoptbwrapper(getopt.gnu_getopt, args, shortlist, namelist)
-def mkdtemp(suffix=b'', prefix=b'tmp', dir=None):
+def mkdtemp(suffix=b'', prefix=b'tmp', dir=None) -> 'AnyStr':
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=b'', prefix=b'tmp', dir=None) -> 'Tuple[int, AnyStr]':
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=None, *args, **kwargs) -> 'IO[AnyStr]':
if mode is None:
mode = 'w+b'
else:
diff --git a/mercurial/profiling.py b/mercurial/profiling.py
--- a/mercurial/profiling.py
+++ b/mercurial/profiling.py
@@ -272,7 +272,12 @@
exception_type, exception_value, traceback
)
if self._output == b'blackbox':
+ # We always use io.BytesIO if self._output == b"blackbox". But
+ # pytype doesn't realize this and thinks we're attempting to
+ # access .getvalue() on an IO type.
+ # pytype: disable=attribute-error
val = b'Profile:\n%s' % self._fp.getvalue()
+ # pytype: enable=attribute-error
# ui.log treats the input as a format string,
# so we need to escape any % signs.
val = val.replace(b'%', b'%%')
To: indygreg, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
More information about the Mercurial-devel
mailing list