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 _______________________________________________ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel