# Date 1730583185 14400
# Sat Nov 02 17:33:05 2024 -0400
# Branch stable
# Node ID 490d946c2b363ffa7fa2f0e73644cd82dc161898
# Parent e833179b82826a2ead33fd616118a459e09987c3
# EXP-Topic py2-to-py3-annotations
typing: convert `tortoisehg/util/hglib.py` to py3 type annotations
Same tool used in the previous commit, and also manually dropped `Any` where it
was a placeholder in the py2 comments.
diff --git a/tortoisehg/util/hglib.py b/tortoisehg/util/hglib.py
--- a/tortoisehg/util/hglib.py
+++ b/tortoisehg/util/hglib.py
@@ -69,7 +69,6 @@
if TYPE_CHECKING:
from typing import (
AbstractSet,
- Any,
Callable,
Dict,
Optional,
@@ -113,12 +112,10 @@
if TYPE_CHECKING:
@overload
- def tounicode(s):
- # type: (Union[bytes, pycompat.unicode]) -> pycompat.unicode
+ def tounicode(s: Union[bytes, pycompat.unicode]) -> pycompat.unicode:
pass
@overload
- def tounicode(s):
- # type: (None) -> None
+ def tounicode(s: None) -> None:
pass
def tounicode(s):
@@ -145,12 +142,10 @@
if TYPE_CHECKING:
@overload
- def fromunicode(s, errors='strict'):
- # type: (Text, Text) -> bytes
+ def fromunicode(s: Text, errors: Text = 'strict') -> bytes:
pass
@overload
- def fromunicode(s, errors='strict'):
- # type: (None, Text) -> None
+ def fromunicode(s: None, errors: Text = 'strict') -> None:
pass
def fromunicode(s, errors='strict'):
@@ -179,12 +174,10 @@
if TYPE_CHECKING:
@overload
- def toutf(s):
- # type: (bytes) -> bytes
+ def toutf(s: bytes) -> bytes:
pass
@overload
- def toutf(s):
- # type: (None) -> None
+ def toutf(s: None) -> None:
pass
def toutf(s):
@@ -201,12 +194,10 @@
if TYPE_CHECKING:
@overload
- def fromutf(s):
- # type: (bytes) -> bytes
+ def fromutf(s: bytes) -> bytes:
pass
@overload
- def fromutf(s):
- # type: (None) -> None
+ def fromutf(s: None) -> None:
pass
def fromutf(s):
@@ -230,12 +221,10 @@
return isinstance(x, str)
getcwdu = os.getcwd
-def activebookmark(repo):
- # type: (...) -> bytes
+def activebookmark(repo) -> bytes:
return repo._activebookmark
-def namedbranches(repo):
- # type: (...) -> List[bytes]
+def namedbranches(repo) -> List[bytes]:
branchmap = repo.branchmap()
dead = repo.deadbranches
return sorted(br for br, _heads, _tip, isclosed
@@ -252,24 +241,20 @@
return repo[rev]
return repo[nullrev]
-def revsymbol(repo, rev):
- # type: (localrepo.localrepository, bytes) -> HgContext
+def revsymbol(repo: localrepo.localrepository, rev: bytes) -> HgContext:
ctx = scmutil.revsymbol(repo, rev)
assert isinstance(ctx, (context.changectx, context.workingctx))
return ctx
-def shortrepoid(repo):
- # type: (...) -> str
+def shortrepoid(repo) -> str:
"""Short hash of the first root changeset; can be used for settings key"""
return str(_firstchangectx(repo))
-def repoidnode(repo):
- # type: (...) -> bytes
+def repoidnode(repo) -> bytes:
"""Hash of the first root changeset in binary form"""
return _firstchangectx(repo).node()
-def _getfirstrevisionlabel(repo, ctx):
- # type: (...) -> Optional[bytes]
+def _getfirstrevisionlabel(repo, ctx) -> Optional[bytes]:
# see context.changectx for look-up order of labels
bookmarks = ctx.bookmarks()
@@ -290,8 +275,7 @@
if repo.branchtip(branch) == ctx.node():
return branch
-def getrevisionlabel(repo, rev):
- # type: (Any, Optional[int]) -> Optional[Text]
+def getrevisionlabel(repo, rev: Optional[int]) -> Optional[Text]:
"""Return symbolic name for the specified revision or stringfy it"""
if rev is None:
return None # no symbol for working revision
@@ -303,8 +287,7 @@
return '%d' % rev
-def getmqpatchtags(repo):
- # type: (...) -> List[bytes]
+def getmqpatchtags(repo) -> List[bytes]:
'''Returns all tag names used by MQ patches, or []'''
if hasattr(repo, 'mq'):
repo.mq.parseseries()
@@ -312,18 +295,16 @@
else:
return []
-def getcurrentqqueue(repo):
- # type: (...) -> Optional[bytes]
+def getcurrentqqueue(repo) -> Optional[bytes]:
"""Return the name of the current patch queue."""
if not hasattr(repo, 'mq'):
return None
- cur = os.path.basename(repo.mq.path) # type: bytes
+ cur: bytes = os.path.basename(repo.mq.path)
if cur.startswith(b'patches-'):
cur = cur[8:]
return cur
-def gitcommit_full(ctx):
- # type: (...) -> Optional[Text]
+def gitcommit_full(ctx) -> Optional[Text]:
"""
If the hggit extension is loaded, and the repository is a git clone,
returns the complete git commit hash of the current revision
@@ -340,8 +321,7 @@
return fullgitnode
-def gitcommit_short(ctx):
- # type: (...) -> Optional[Text]
+def gitcommit_short(ctx) -> Optional[Text]:
"""
If the hggit extension is loaded, and the repository is a git clone,
returns the short (12 digits) git commit hash of the current revision
@@ -350,8 +330,7 @@
fullgitnode = gitcommit_full(ctx)
return None if fullgitnode is None else fullgitnode[:12]
-def getqqueues(repo):
- # type: (...) -> List[Text]
+def getqqueues(repo) -> List[Text]:
ui = repo.ui.copy()
ui.quiet = True # don't append "(active)"
ui.pushbuffer()
@@ -363,8 +342,7 @@
qqueues = []
return qqueues
-def readgraftstate(repo):
- # type: (...) -> Optional[List[bytes]]
+def readgraftstate(repo) -> Optional[List[bytes]]:
"""Read a list of nodes from graftstate; or None if nothing in progress"""
graftstate = statemod.cmdstate(repo, b'graftstate')
if graftstate.exists():
@@ -377,29 +355,25 @@
readmergestate = mergestate.read
-def operation_in_progress(repo, statename):
- # type: (localrepo.localrepository, bytes) -> bool
+def operation_in_progress(repo: localrepo.localrepository,
+ statename: bytes) -> bool:
"""Indicates if a long term operation is in progress"""
return statemod.cmdstate(repo, statename).exists()
-def graft_in_progress(repo):
- # type: (localrepo.localrepository) -> bool
+def graft_in_progress(repo: localrepo.localrepository) -> bool:
return operation_in_progress(repo, b"graftstate")
-def pick_in_progress(repo):
- # type: (localrepo.localrepository) -> bool
+def pick_in_progress(repo: localrepo.localrepository) -> bool:
return operation_in_progress(repo, b"pickstate")
-def rebase_in_progress(repo):
- # type: (localrepo.localrepository) -> bool
+def rebase_in_progress(repo: localrepo.localrepository) -> bool:
return operation_in_progress(repo, b"rebasestate")
-def readundodesc(repo):
- # type: (...) -> Tuple[Text, int]
+def readundodesc(repo) -> Tuple[Text, int]:
"""Read short description and changelog size of last transaction"""
if os.path.exists(repo.sjoin(b'undo')):
try:
@@ -409,8 +383,13 @@
pass
return '', len(repo)
-def unidifftext(a, ad, b, bd, fn1, fn2, opts=mdiff.defaultopts):
- # type: (bytes, bytes, bytes, bytes, bytes, bytes, mdiff.diffopts) -> bytes
+def unidifftext(a: bytes,
+ ad: bytes,
+ b: bytes,
+ bd: bytes,
+ fn1: bytes,
+ fn2: bytes,
+ opts: mdiff.diffopts = mdiff.defaultopts) -> bytes:
binary = stringutil.binary(a) or stringutil.binary(b)
headers, hunks = mdiff.unidiff(a, ad, b, bd, fn1, fn2,
binary=binary, opts=opts)
@@ -419,20 +398,17 @@
text = b''.join(sum((list(hlines) for _hrange, hlines in hunks), []))
return b'\n'.join(headers) + b'\n' + text
-def enabledextensions():
- # type: () -> Dict[Text, bytes]
+def enabledextensions() -> Dict[Text, bytes]:
"""Return the {name: shortdesc} dict of enabled extensions
shortdesc is in local encoding.
"""
return {pycompat.sysstr(k): v for k, v in extensions.enabled().items()}
-def disabledextensions():
- # type: () -> Dict[Text, bytes]
+def disabledextensions() -> Dict[Text, bytes]:
return {pycompat.sysstr(k): v for k, v in extensions.disabled().items()}
-def allextensions():
- # type: () -> Dict[Text, bytes]
+def allextensions() -> Dict[Text, bytes]:
"""Return the {name: shortdesc} dict of known extensions
shortdesc is in local encoding.
@@ -455,8 +431,7 @@
return exts
-def validateextensions(enabledexts):
- # type: (AbstractSet[Text]) -> Dict[Text, bytes]
+def validateextensions(enabledexts: AbstractSet[Text]) -> Dict[Text, bytes]:
"""Report extensions which should be disabled
Returns the dict {name: message} of extensions expected to be disabled.
@@ -490,15 +465,13 @@
extensions.wrapfunction(extensions, 'load',
_loadextensionwithblacklist)
-def loadextensions(ui):
- # type: (uimod.ui) -> None
+def loadextensions(ui: uimod.ui) -> None:
"""Load and setup extensions for GUI process"""
_wrapextensionsloader() # enable blacklist of extensions
extensions.loadall(ui)
-def hastopicext(repo):
- # type: (localrepo.localrepository) -> bool
+def hastopicext(repo: localrepo.localrepository) -> bool:
"""Indicate is the topic extension is enabled for ``repo``."""
hastopicext = False
@@ -510,8 +483,7 @@
return hastopicext
# TODO: provide singular canonpath() wrapper instead?
-def canonpaths(list):
- # type: (Iterable[bytes]) -> List[bytes]
+def canonpaths(list: Iterable[bytes]) -> List[bytes]:
'Get canonical paths (relative to root) for list of files'
# This is a horrible hack. Please remove this when HG acquires a
# decent case-folding solution.
@@ -535,15 +507,13 @@
return canonpats
-def normpath(path):
- # type: (Text) -> Text
+def normpath(path: Text) -> Text:
"""Normalize a path in the same manner as mercurial.util.normpath()."""
# TODO: Do a unicode port of util.normpath() here.
return tounicode(util.normpath(fromunicode(path)))
-def normreporoot(path):
- # type: (Text) -> Text
+def normreporoot(path: Text) -> Text:
"""Normalize repo root path in the same manner as localrepository"""
# see localrepo.localrepository and scmutil.vfs
lpath = fromunicode(path)
@@ -551,8 +521,7 @@
return tounicode(lpath)
-def mergetools(ui):
- # type: (uimod.ui) -> List[bytes]
+def mergetools(ui: uimod.ui) -> List[bytes]:
'''returns a list of bytestring names of the configured and internal merge
tools'''
values = []
@@ -573,9 +542,8 @@
return values
-_difftools = None # type: Optional[DiffTools]
-def difftools(ui):
- # type: (uimod.ui) -> DiffTools
+_difftools: Optional[DiffTools] = None
+def difftools(ui: uimod.ui) -> DiffTools:
'''Return mapping from tool name to tuples with tool name,
diff args, and merge args, all as bytecode strings'''
global _difftools
@@ -593,7 +561,7 @@
mergeopts = []
return diffopts, mergeopts
- tools = {} # type: DiffTools
+ tools: DiffTools = {}
for cmd, path in ui.configitems(b'extdiff'):
if cmd.startswith(b'cmd.'):
cmd = cmd[4:]
@@ -637,8 +605,8 @@
'and revision details)')),
)
-def tortoisehgtools(uiorconfig, selectedlocation=None):
- # type: (Union[IniConfig, uimod.ui], Optional[Text]) -> Tuple[Dict[Text, Dict[Text, Union[Text, bool]]], List[Text]]
+def tortoisehgtools(uiorconfig: Union[IniConfig, uimod.ui],
+ selectedlocation: Optional[Text] = None) -> Tuple[Dict[Text, Dict[Text, Union[Text, bool]]], List[Text]]:
"""Parse 'tortoisehg-tools' section of ini file.
>>> from pprint import pprint
@@ -754,7 +722,7 @@
def configlist(section, name):
return uiorconfig.get(section, name, b'').split()
- tools = {} # type: Dict[Text, Dict[Text, Union[Text, bool]]]
+ tools: Dict[Text, Dict[Text, Union[Text, bool]]] = {}
for key, value in configitems(b'tortoisehg-tools'):
toolname, field = tounicode(key).split('.', 1)
if toolname not in tools:
@@ -778,8 +746,8 @@
guidef = configlist(b'tortoisehg',
pycompat.sysbytes(selectedlocation)) or []
- toollist = [] # type: List[Text]
- selectedtools = {} # type: Dict[Text, Dict[Text, Union[Text, bool]]]
+ toollist: List[Text] = []
+ selectedtools: Dict[Text, Dict[Text, Union[Text, bool]]] = {}
for name in guidef:
name = tounicode(name)
if name != '|':
@@ -790,10 +758,9 @@
toollist.append(name)
return selectedtools, toollist
-loadui = uimod.ui.load # type: Callable[[], uimod.ui]
+loadui: Callable[[], uimod.ui] = uimod.ui.load
-def copydynamicconfig(srcui, destui):
- # type: (uimod.ui, uimod.ui) -> None
+def copydynamicconfig(srcui: uimod.ui, destui: uimod.ui) -> None:
"""Copy config values that come from command line or code
>>> srcui = uimod.ui()
@@ -817,8 +784,7 @@
source = b''
destui.setconfig(section, name, value, source)
-def shortreponame(ui):
- # type: (uimod.ui) -> Optional[bytes]
+def shortreponame(ui: uimod.ui) -> Optional[bytes]:
name = ui.config(b'web', b'name', None)
if not name:
return
@@ -829,8 +795,7 @@
return
return name
-def extractchoices(prompttext):
- # type: (Text) -> Tuple[Text, List[Tuple[Text, Text]]]
+def extractchoices(prompttext: Text) -> Tuple[Text, List[Tuple[Text, Text]]]:
"""Extract prompt message and list of choice (char, label) pairs
This is slightly different from ui.extractchoices() in that
@@ -851,12 +816,10 @@
resps = [p[p.index('&') + 1].lower() for p in choices]
return msg, pycompat.ziplist(resps, choices)
-def displaytime(date):
- # type: (Optional[Tuple[float, int]]) -> bytes
+def displaytime(date: Optional[Tuple[float, int]]) -> bytes:
return dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2')
-def utctime(date):
- # type: (Tuple[float, int]) -> str
+def utctime(date: Tuple[float, int]) -> str:
return time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(date[0]))
agescales = [
@@ -869,8 +832,7 @@
((lambda n: ngettext("%d second", "%d seconds", n)), 1),
]
-def age(date):
- # type: (Tuple[int, int]) -> bytes
+def age(date: Tuple[int, int]) -> bytes:
'''turn a (timestamp, tzoff) tuple into an age string.'''
# This is i18n-ed version of mercurial.templatefilters.age().
@@ -925,8 +887,7 @@
return tostr()
-def configuredusername(ui):
- # type: (uimod.ui) -> Optional[bytes]
+def configuredusername(ui: uimod.ui) -> Optional[bytes]:
# need to check the existence before calling ui.username(); otherwise it
# may fall back to the system default.
if (not os.environ.get('HGUSER')
@@ -938,15 +899,13 @@
except error.Abort:
return None
-def username(user):
- # type: (bytes) -> bytes
+def username(user: bytes) -> bytes:
author = stringutil.person(user)
if not author:
author = stringutil.shortuser(user)
return author
-def user(ctx):
- # type: (...) -> bytes
+def user(ctx) -> bytes:
'''
Get the username of the change context. Does not abort and just returns
an empty string if ctx is a working context and no username has been set
@@ -962,8 +921,7 @@
user = b''
return user
-def getestimatedsize(fctx):
- # type: (...) -> int
+def getestimatedsize(fctx) -> int:
"""Return the size of the given fctx without loading the revision text"""
FILE_SIZE_UNKNOWN =
2147483647
@@ -980,8 +938,8 @@
# on a shallow repo
return FILE_SIZE_UNKNOWN
-def get_revision_desc(fctx, curpath=None):
- # type: (Any, Optional[bytes]) -> pycompat.unicode
+def get_revision_desc(fctx,
+ curpath: Optional[bytes] = None) -> pycompat.unicode:
"""return the revision description as a string"""
author = tounicode(username(fctx.user()))
rev = fctx.rev()
@@ -995,8 +953,8 @@
summary = l and l[0] or ''
return u'%s@%s%s:%s "%s"' % (author, rev, source, date, summary)
-def longsummary(description, limit=None):
- # type: (Union[bytes, Text], Optional[int]) -> Text
+def longsummary(description: Union[bytes, Text],
+ limit: Optional[int] = None) -> Text:
summary = tounicode(description)
lines = summary.splitlines()
if not lines:
@@ -1019,8 +977,8 @@
summary += u' \u2026' # ellipsis ...
return summary
-def getDeepestSubrepoContainingFile(wfile, ctx):
- # type: (bytes, context.changectx) -> Tuple[Optional[bytes], bytes, context.changectx]
+def getDeepestSubrepoContainingFile(wfile: bytes,
+ ctx: context.changectx) -> Tuple[Optional[bytes], bytes, context.changectx]:
"""
Given a filename and context, get the deepest subrepo that contains the file
@@ -1034,8 +992,8 @@
# correct type instead of Any.
for wsub in ctx.substate: # type: bytes
if wfile.startswith(wsub):
- srev = ctx.substate[wsub][1] # type: bytes
- stype = ctx.substate[wsub][2] # type: bytes
+ srev: bytes = ctx.substate[wsub][1]
+ stype: bytes = ctx.substate[wsub][2]
if stype != b'hg':
continue
if not os.path.exists(ctx.repo().wjoin(wsub)):
@@ -1044,7 +1002,7 @@
try:
s = ctx.sub(wsub)
assert isinstance(s, subrepo.hgsubrepo) # help pytype
- sctx = s._repo[srev] # type: context.changectx
+ sctx: context.changectx = s._repo[srev]
except:
# The selected revision does not exist in the working copy
continue
@@ -1060,8 +1018,7 @@
return os.path.join(wsub, wsubsub), wfileinsub, sctx
return None, wfile, ctx
-def getLineSeparator(line):
- # type: (Text) -> Text
+def getLineSeparator(line: Text) -> Text:
"""Get the line separator used on a given line"""
# By default assume the default OS line separator
linesep = os.linesep
@@ -1072,8 +1029,8 @@
break
return linesep
-def parseconfigopts(ui, args):
- # type: (uimod.ui, List[bytes]) -> List[Tuple[bytes, bytes, bytes]]
+def parseconfigopts(ui: uimod.ui,
+ args: List[bytes]) -> List[Tuple[bytes, bytes, bytes]]:
"""Pop the --config options from the command line and apply them
>>> u = uimod.ui()
@@ -1110,8 +1067,7 @@
def _escapecharrepl(m):
return _escapecharmap[ord(m.group(0))]
-def escapeascii(s):
- # type: (Text) -> Text
+def escapeascii(s: Text) -> Text:
r"""Escape string to be embedded as a literal; like Python string_escape,
but keeps 8bit characters and can process unicode
@@ -1123,8 +1079,7 @@
s = _stringify(s)
return _escapecharre.sub(_escapecharrepl, s)
-def escapepath(path):
- # type: (Text) -> Text
+def escapepath(path: Text) -> Text:
r"""Convert path to command-line-safe string; path must be relative to
the repository root
@@ -1140,8 +1095,7 @@
else:
return p
-def escaperev(rev, default=None):
- # type: (int, Optional[Text]) -> Text
+def escaperev(rev: int, default: Optional[Text] = None) -> Text:
"""Convert revision number to command-line-safe string"""
if rev is None:
return default
@@ -1156,8 +1110,7 @@
else:
return '%s:%s' % (escaperev(a), escaperev(b))
-def compactrevs(revs):
- # type: (List[int]) -> Text
+def compactrevs(revs: List[int]) -> Text:
"""Build command-line-safe revspec from list of revision numbers; revs
should be sorted in ascending order to get compact form
@@ -1242,8 +1195,7 @@
return ''.join(ret)
-def formatfilespec(expr, *args):
- # type: (Text, Any) -> Text
+def formatfilespec(expr: Text, *args) -> Text:
"""Build fileset expression by template and positional arguments
Supported arguments:
@@ -1259,8 +1211,7 @@
listfuncs = {}
return _formatspec(expr, args, filesetlang.parse, listfuncs)
-def formatrevspec(expr, *args):
- # type: (Text, Any) -> Text
+def formatrevspec(expr: Text, *args) -> Text:
r"""Build revset expression by template and positional arguments
Supported arguments:
@@ -1286,8 +1237,7 @@
listfuncs = {'d': '_intlist', 's': '_list'}
return _formatspec(expr, args, revsetlang.parse, listfuncs)
-def buildcmdargs(name, *args, **opts):
- # type: (Text, Any, Any) -> List[Text]
+def buildcmdargs(name: Text, *args, **opts) -> List[Text]:
r"""Build list of command-line arguments
>>> buildcmdargs('push', branch='foo')
@@ -1379,8 +1329,7 @@
else:
return arg
-def prettifycmdline(cmdline):
- # type: (List[Text]) -> Text
+def prettifycmdline(cmdline: List[Text]) -> Text:
r"""Build pretty command-line string for display
>>> prettifycmdline(['log', 'foo\\bar', '', 'foo bar', 'foo"bar'])
@@ -1397,8 +1346,7 @@
"""
return ' '.join(_reprcmdarg(e) for e in cmdline)
-def parsecmdline(cmdline, cwd):
- # type: (Text, Text) -> List[Text]
+def parsecmdline(cmdline: Text, cwd: Text) -> List[Text]:
r"""Split command line string to imitate a unix shell
>>> origfuncs = glob.glob, os.path.expanduser, os.path.expandvars