[PATCH 1 of 4] typing: convert py2 type comments to py3 type annotations in `nautilus-thg.py`

2 views
Skip to first unread message

Matt Harbison

unread,
Nov 2, 2024, 8:44:26 PMNov 2
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1730575995 14400
# Sat Nov 02 15:33:15 2024 -0400
# Branch stable
# Node ID a6384e13749a9f39a71813683a4bee3759c16a72
# Parent 555b2f10013012aabd45bda2a0431295ae3c8195
# EXP-Topic py2-to-py3-annotations
typing: convert py2 type comments to py3 type annotations in `nautilus-thg.py`

This was done with tooling[1], and the results left unchanged except to add the
typical `from __future__ import annotations` (in order to delay evaluation of
the annotations), and move the `allvfs` annotation to the class level instead of
putting it in the initialization statement. Additionally, drop `Any` for args
and return types, since these can be individually annotated, unlike when it was
needed as a placeholder in the comments.

[1] https://github.com/ilevkivskyi/com2ann

diff --git a/contrib/nautilus-thg.py b/contrib/nautilus-thg.py
--- a/contrib/nautilus-thg.py
+++ b/contrib/nautilus-thg.py
@@ -5,6 +5,8 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

+from __future__ import annotations
+
this_file = __file__.rsplit('.', 1)[0]
if this_file.endswith('caja-thg'):
from gi.repository import Caja as Nautilus # pytype: disable=import-error
@@ -80,10 +82,11 @@
nofilecmds = 'about serve synch repoconfig userconfig merge unmerge'.split()

class HgExtensionDefault(GObject.GObject):
+ allvfs: Dict[Text, Any]

def __init__(self):
self.scanStack = []
- self.allvfs = {} # type: Dict[Text, Any]
+ self.allvfs = {}
self.inv_dirs = set()

self.hgtk = paths.find_in_path(thg_main)
@@ -110,12 +113,12 @@
self.gmon = Gio.file_new_for_path(self.notify).monitor(Gio.FileMonitorFlags.NONE, None)
self.gmon.connect('changed', self.notified)

- def icon(self, iname):
- # type: (Text) -> Optional[Text]
+ def icon(self, iname: Text) -> Optional[Text]:
return paths.get_tortoise_icon(iname)

- def get_path_for_vfs_file(self, vfs_file, store=True):
- # type: (Any, bool) -> Optional[Text]
+ def get_path_for_vfs_file(self,
+ vfs_file,
+ store: bool = True) -> Optional[Text]:
if vfs_file.get_uri_scheme() != 'file':
return None
# TODO: is get_uri returing unicode?
@@ -127,16 +130,15 @@
self.allvfs[path] = vfs_file
return path

- def get_vfs(self, path):
- # type: (Text) -> Any
+ def get_vfs(self, path: Text):
vfs = self.allvfs.get(path, None)
if vfs and vfs.is_gone():
del self.allvfs[path]
return None
return vfs

- def get_repo_for_path(self, path):
- # type: (Text) -> Optional[localrepo.localrepository]
+ def get_repo_for_path(self,
+ path: Text) -> Optional[localrepo.localrepository]:
'''
Find mercurial repository for vfs_file
Returns hg.repo
@@ -152,8 +154,11 @@
debugf(e)
return None

- def run_dialog(self, menuitem, hgtkcmd, cwd = None, files = None):
- # type: (Any, Text, Optional[Text], Optional[List[Text]]) -> None
+ def run_dialog(self,
+ menuitem,
+ hgtkcmd: Text,
+ cwd: Optional[Text] = None,
+ files: Optional[List[Text]] = None) -> None:
'''
hgtkcmd - hgtk subcommand
'''
@@ -200,8 +205,9 @@
self.cwd = cwd
return self._buildMenu(menus, files)

- def _buildMenu(self, menus, files):
- # type: (menuthg.thg_menu, List[Text]) -> List[Nautilus.MenuItem]
+ def _buildMenu(self,
+ menus: menuthg.thg_menu,
+ files: List[Text]) -> List[Nautilus.MenuItem]:
'''Build one level of a menu'''
items = []
if files:
@@ -257,8 +263,9 @@
"Hg Status",
"Version control status"),

- def _get_file_status(self, localpath, repo=None):
- # type: (Text, Optional[localrepo.localrepository]) -> Any
+ def _get_file_status(self,
+ localpath: Text,
+ repo: Optional[localrepo.localrepository] = None):
cachestate = cachethg.get_state(localpath, repo)
cache2state = {cachethg.UNCHANGED: ('default', 'clean'),
cachethg.ADDED: ('list-add', 'added'),
@@ -290,8 +297,7 @@
if root:
self.invalidate(files, root)

- def invalidate(self, paths, root = ''):
- # type: (List[Text], Text) -> None
+ def invalidate(self, paths: List[Text], root: Text = '') -> None:
started = bool(self.inv_dirs)
if cachethg.cache_pdir == root and root not in self.inv_dirs:
cachethg.overlay_cache.clear()
@@ -319,8 +325,7 @@
self.inv_dirs.clear()

# property page borrowed from http://www.gnome.org/~gpoo/hg/nautilus-hg/
- def __add_row(self, row, label_item, label_value):
- # type: (Any, Text, Text) -> None
+ def __add_row(self, row, label_item: Text, label_value: Text) -> None:
label = Gtk.Label(label_item)
label.set_use_markup(True)
label.set_alignment(1, 0)

Matt Harbison

unread,
Nov 2, 2024, 8:44:27 PMNov 2
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1730578025 14400
# Sat Nov 02 16:07:05 2024 -0400
# Branch stable
# Node ID e833179b82826a2ead33fd616118a459e09987c3
# Parent a6384e13749a9f39a71813683a4bee3759c16a72
# EXP-Topic py2-to-py3-annotations
typing: convert `TortoiseHgOverlayServer.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/TortoiseHgOverlayServer.py b/TortoiseHgOverlayServer.py
--- a/TortoiseHgOverlayServer.py
+++ b/TortoiseHgOverlayServer.py
@@ -118,7 +118,6 @@

if hglib.TYPE_CHECKING:
from typing import (
- Any,
Iterable,
List,
Set,
@@ -135,8 +134,7 @@
def __init__(self):
self.file = None

- def setfile(self, name):
- # type: (Text) -> None
+ def setfile(self, name: Text) -> None:
oname = name + '.old'
try:
rename(hglib.fromunicode(name), hglib.fromunicode(oname))
@@ -146,8 +144,7 @@
self.msg('%s, Version %s' % (APP_TITLE, version.version()))
self.msg('Logging to file started')

- def msg(self, msg):
- # type: (Text) -> None
+ def msg(self, msg: Text) -> None:
ts = '[%s] ' % time.strftime('%c')
f = self.file
if f:
@@ -162,8 +159,7 @@

iconcache = {}

-def load_icon(name):
- # type: (Text) -> Any
+def load_icon(name: Text):
from tortoisehg.util.paths import get_tortoise_icon
iconPathName = get_tortoise_icon(name)
if iconPathName and os.path.isfile(iconPathName):
@@ -174,16 +170,14 @@
hicon = LoadIcon(0, win32con.IDI_APPLICATION)
return hicon

-def get_icon(name):
- # type: (Text) -> Any
+def get_icon(name: Text):
try:
return iconcache[name]
except KeyError:
iconcache[name] = load_icon(name)
return iconcache[name]

-def SetIcon(hwnd, name, add=False):
- # type: (Any, Text, bool) -> None
+def SetIcon(hwnd, name: Text, add: bool = False) -> None:
# Try and find a custom icon
if '--noicon' in sys.argv:
return
@@ -328,8 +322,7 @@

PIPEBUFSIZE = 4096

-def getrepos(batch):
- # type: (Iterable[Text]) -> Tuple[Set[Text], Set[Text]]
+def getrepos(batch: Iterable[Text]) -> Tuple[Set[Text], Set[Text]]:
roots = set()
notifypaths = set()
for path in batch:
@@ -350,8 +343,7 @@
notifypaths.add(path)
return roots, notifypaths

-def update_batch(batch):
- # type: (Iterable[Text]) -> None
+def update_batch(batch: Iterable[Text]) -> None:
'''updates thgstatus for all paths in batch'''
roots, notifypaths = getrepos(batch)
if roots:
@@ -443,8 +435,7 @@
pass
return show_taskbaricon, hgighlight_taskbaricon

-def update(args, hwnd):
- # type: (List[Text], Any) -> None
+def update(args: List[Text], hwnd) -> None:
batch = []
r = args[0]
print("got update request %s (first in batch)" % r)
@@ -475,8 +466,7 @@
if show and highlight:
SetIcon(hwnd, "hg.ico")

-def remove(args):
- # type: (List[Text]) -> None
+def remove(args: List[Text]) -> None:
path = args[0]
logger.msg('Removing ' + path)
roots, notifypaths = getrepos([path])
@@ -496,8 +486,7 @@
if notifypaths:
shlib.shell_notify([hglib.fromunicode(p) for p in notifypaths])

-def dispatch(req, cmd, args, hwnd):
- # type: (Any, Text, List[Text], Any) -> None
+def dispatch(req, cmd: Text, args: List[Text], hwnd) -> None:
print("dispatch(%s)" % req)
if cmd == 'update':
update(args, hwnd)

Matt Harbison

unread,
Nov 2, 2024, 8:44:29 PMNov 2
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# 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

Matt Harbison

unread,
Nov 2, 2024, 8:44:31 PMNov 2
to thg...@googlegroups.com
# HG changeset patch
# User Matt Harbison <matt_h...@yahoo.com>
# Date 1730583308 14400
# Sat Nov 02 17:35:08 2024 -0400
# Branch stable
# Node ID c56b4a6a324b116000ff72998dd12bf9976290a4
# Parent 490d946c2b363ffa7fa2f0e73644cd82dc161898
# EXP-Topic py2-to-py3-annotations
typing: convert the rest of `tortoisehg.util` to py3 type annotations

Same tool used in the previous commit, but nothing interesting about these
fairly small-ish conversions.

diff --git a/tortoisehg/util/cachethg.py b/tortoisehg/util/cachethg.py
--- a/tortoisehg/util/cachethg.py
+++ b/tortoisehg/util/cachethg.py
@@ -27,8 +27,8 @@
debugging = False
enabled = True
localonly = False
-includepaths = [] # type: List[Text]
-excludepaths = [] # type: List[Text]
+includepaths: List[Text] = []
+excludepaths: List[Text] = []

try:
from mercurial.windows import winreg
@@ -79,14 +79,13 @@
UNRESOLVED = 'U'

# file status cache
-overlay_cache = {} # type: Dict[Optional[Text], Optional[Text]]
+overlay_cache: Dict[Optional[Text], Optional[Text]] = {}
cache_tick_count = 0
-cache_root = None # type: Optional[Text]
-cache_pdir = None # type: Optional[Text]
+cache_root: Optional[Text] = None
+cache_pdir: Optional[Text] = None


-def add_dirs(list):
- # type: (List[bytes]) -> None
+def add_dirs(list: List[bytes]) -> None:
dirs = set()
if list:
dirs.add(b'')
@@ -100,8 +99,8 @@
list.extend(dirs)


-def get_state(upath, repo=None):
- # type: (Text, Optional[localrepo.localrepository]) -> Text
+def get_state(upath: Text,
+ repo: Optional[localrepo.localrepository] = None) -> Text:
"""
Get the state of a given path in source control.
"""
@@ -109,8 +108,8 @@
return states and states[0] or NOT_IN_REPO


-def get_states(path, repo=None):
- # type: (Text, Optional[localrepo.localrepository]) -> Text
+def get_states(path: Text,
+ repo: Optional[localrepo.localrepository] = None) -> Text:
"""
Get the states of a given path in source control.
"""
@@ -263,6 +262,5 @@
return status


-def add(path, state):
- # type: (Text, Text) -> None
+def add(path: Text, state: Text) -> None:
overlay_cache[path] = overlay_cache.get(path, '') + state
diff --git a/tortoisehg/util/editor.py b/tortoisehg/util/editor.py
--- a/tortoisehg/util/editor.py
+++ b/tortoisehg/util/editor.py
@@ -21,8 +21,7 @@
)


-def _getplatformexecutablekey():
- # type: () -> bytes
+def _getplatformexecutablekey() -> bytes:
if sys.platform == 'darwin':
key = b'executable-osx'
elif os.name == 'nt':
@@ -33,15 +32,16 @@

_platformexecutablekey = _getplatformexecutablekey()

-def _toolstr(ui, tool, part, default=b""):
- # type: (uimod.ui, bytes, bytes, Optional[bytes]) -> bytes
+def _toolstr(ui: uimod.ui,
+ tool: bytes,
+ part: bytes,
+ default: Optional[bytes] = b"") -> bytes:
val = ui.config(b"editor-tools", tool + b"." + part, default)
assert val is not None # help pytype
return val

toolcache = {}
-def _findtool(ui, tool):
- # type: (uimod.ui, bytes) -> Optional[bytes]
+def _findtool(ui: uimod.ui, tool: bytes) -> Optional[bytes]:
global toolcache
if tool in toolcache:
return toolcache[tool]
@@ -70,8 +70,8 @@
toolcache[tool] = None
return None

-def _findeditor(repo, files):
- # type: (localrepo.localrepository, List[bytes]) -> Tuple[Optional[bytes], bytes]
+def _findeditor(repo: localrepo.localrepository,
+ files: List[bytes]) -> Tuple[Optional[bytes], bytes]:
'''returns tuple of editor name and editor path.

tools matched by pattern are returned as (name, toolpath)
@@ -122,8 +122,8 @@
editor = ui.geteditor()
return None, editor

-def detecteditor(repo, files):
- # type: (localrepo.localrepository, List[bytes]) -> Tuple[bytes, Optional[bytes], Optional[bytes], Optional[bytes]]
+def detecteditor(repo: localrepo.localrepository,
+ files: List[bytes]) -> Tuple[bytes, Optional[bytes], Optional[bytes], Optional[bytes]]:
'returns tuple of editor tool path and arguments'
name, pathorconfig = _findeditor(repo, files)
if name is None:
@@ -134,8 +134,7 @@
argssearch = _toolstr(repo.ui, name, b"argssearch")
return pathorconfig, args, argsln, argssearch

-def findeditors(ui):
- # type: (uimod.ui) -> List[bytes]
+def findeditors(ui: uimod.ui) -> List[bytes]:
seen = set()
for key, value in ui.configitems(b'editor-tools'):
t = key.split(b'.')[0]
diff --git a/tortoisehg/util/gpg.py b/tortoisehg/util/gpg.py
--- a/tortoisehg/util/gpg.py
+++ b/tortoisehg/util/gpg.py
@@ -23,8 +23,7 @@
if os.name == 'nt':
from mercurial.windows import winreg

- def findgpg(ui):
- # type: (uimod.ui) -> List[Text]
+ def findgpg(ui: uimod.ui) -> List[Text]:
path = []
for key in (r"Software\GNU\GnuPG", r"Software\Wow6432Node\GNU\GnuPG"):
try:
@@ -43,6 +42,5 @@
return path

else:
- def findgpg(ui):
- # type: (uimod.ui) -> List[Text]
+ def findgpg(ui: uimod.ui) -> List[Text]:
return []
diff --git a/tortoisehg/util/menuthg.py b/tortoisehg/util/menuthg.py
--- a/tortoisehg/util/menuthg.py
+++ b/tortoisehg/util/menuthg.py
@@ -30,8 +30,7 @@
MenuT = List[Union["TortoiseMenu", "TortoiseMenuSep"]]


-def _(msgid):
- # type: (Text) -> Dict[Text, Text]
+def _(msgid: Text) -> Dict[Text, Text]:
return {'id': msgid, 'str': gettext(msgid)}

thgcmenu = {
@@ -115,8 +114,12 @@

class TortoiseMenu(object):

- def __init__(self, menutext, helptext, hgcmd, icon=None, state=True):
- # type: (Text, Text, Optional[Text], Optional[Text], bool) -> None
+ def __init__(self,
+ menutext: Text,
+ helptext: Text,
+ hgcmd: Optional[Text],
+ icon: Optional[Text] = None,
+ state: bool = True) -> None:
self.menutext = menutext
self.helptext = helptext
self.hgcmd = hgcmd
@@ -132,15 +135,22 @@

class TortoiseSubmenu(TortoiseMenu):

- def __init__(self, menutext, helptext, menus=None, icon=None):
- # type: (Text, Text, Optional[MenuT], Optional[Text]) -> None
+ def __init__(self,
+ menutext: Text,
+ helptext: Text,
+ menus: Optional[MenuT] = None,
+ icon: Optional[Text] = None) -> None:
TortoiseMenu.__init__(self, menutext, helptext, None, icon)
if menus is None:
- menus = [] # type: MenuT
+ menus: MenuT = []
self.menus = menus[:]

- def add_menu(self, menutext, helptext, hgcmd, icon=None, state=True):
- # type: (Text, Text, Optional[Text], Optional[Text], bool) -> None
+ def add_menu(self,
+ menutext: Text,
+ helptext: Text,
+ hgcmd: Optional[Text],
+ icon: Optional[Text] = None,
+ state: bool = True) -> None:
self.menus.append(TortoiseMenu(menutext, helptext,
hgcmd, icon, state))

@@ -170,16 +180,22 @@

class thg_menu(object):

- def __init__(self, ui, promoted, name = "TortoiseHg"):
- # type: (uimod.ui, List[Text], Text) -> None
- self.menus = [[]] # type: List[MenuT]
+ menus: List[MenuT]
+
+ def __init__(self,
+ ui: uimod.ui,
+ promoted: List[Text],
+ name: Text = "TortoiseHg") -> None:
+ self.menus = [[]]
self.ui = ui
self.name = name
self.sep = [False]
self.promoted = promoted

- def add_menu(self, hgcmd, icon=None, state=True):
- # type: (Text, Optional[Text], bool) -> None
+ def add_menu(self,
+ hgcmd: Text,
+ icon: Optional[Text] = None,
+ state: bool = True) -> None:
if hgcmd in self.promoted:
pos = 0
else:
@@ -199,8 +215,7 @@
def add_sep(self):
self.sep = [True for _s in self.sep]

- def get(self):
- # type: () -> MenuT
+ def get(self) -> MenuT:
menu = self.menus[0][:]
for submenu in self.menus[1:]:
menu.append(TortoiseSubmenu(self.name, 'Mercurial', submenu, "hg.ico"))
@@ -211,8 +226,7 @@
return iter(self.get())


-def open_repo(path):
- # type: (Text) -> Optional[localrepo.localrepository]
+def open_repo(path: Text) -> Optional[localrepo.localrepository]:
root = paths.find_root(path)
if root:
try:
@@ -230,8 +244,7 @@
class menuThg:
"""shell extension that adds context menu items"""

- def __init__(self, internal=False):
- # type: (bool) -> None
+ def __init__(self, internal: bool = False) -> None:
self.name = "TortoiseHg"
promoted = []
pl = hglib.loadui().config(b'tortoisehg', b'promoteditems', b'commit,log')
@@ -249,8 +262,9 @@
self.promoted = promoted


- def get_commands_dragdrop(self, srcfiles, destfolder):
- # type: (List[Text], Text) -> Union[List[Text], thg_menu]
+ def get_commands_dragdrop(self,
+ srcfiles: List[Text],
+ destfolder: Text) -> Union[List[Text], thg_menu]:
"""
Get a list of commands valid for the current selection.

@@ -281,8 +295,7 @@
menu.add_menu('dndsynch')
return menu

- def get_norepo_commands(self, cwd, files):
- # type: (Text, List[Text]) -> thg_menu
+ def get_norepo_commands(self, cwd: Text, files: List[Text]) -> thg_menu:
menu = thg_menu(hglib.loadui(), self.promoted, self.name)
menu.add_menu('clone')
menu.add_menu('init')
@@ -292,8 +305,10 @@
menu.add_sep()
return menu

- def get_commands(self, repo, cwd, files):
- # type: (localrepo.localrepository, Text, List[Text]) -> thg_menu
+ def get_commands(self,
+ repo: localrepo.localrepository,
+ cwd: Text,
+ files: List[Text]) -> thg_menu:
"""
Get a list of commands valid for the current selection.

diff --git a/tortoisehg/util/paths.py b/tortoisehg/util/paths.py
--- a/tortoisehg/util/paths.py
+++ b/tortoisehg/util/paths.py
@@ -40,12 +40,10 @@
)

@overload
- def _find_root(p, dn):
- # type: (Text, Text) -> Optional[Text]
+ def _find_root(p: Text, dn: Text) -> Optional[Text]:
pass
@overload
- def _find_root(p, dn):
- # type: (bytes, bytes) -> Optional[bytes]
+ def _find_root(p: bytes, dn: bytes) -> Optional[bytes]:
pass


@@ -59,16 +57,13 @@
return None
return p

-def find_root(path=None):
- # type: (Optional[Text]) -> Optional[Text]
+def find_root(path: Optional[Text] = None) -> Optional[Text]:
return _find_root(path or os.getcwd(), '.hg')

-def find_root_bytes(path=None):
- # type: (Optional[bytes]) -> Optional[bytes]
+def find_root_bytes(path: Optional[bytes] = None) -> Optional[bytes]:
return _find_root(path or encoding.getcwd(), b'.hg')

-def get_tortoise_icon(icon):
- # type: (Text) -> Optional[Text]
+def get_tortoise_icon(icon: Text) -> Optional[Text]:
"Find a tortoisehg icon"
icopath = os.path.join(get_icon_path(), icon)
if os.path.isfile(icopath):
@@ -77,27 +72,22 @@
print('icon not found', icon)
return None

-def get_icon_path():
- # type: () -> Text
+def get_icon_path() -> Text:
global icon_path
return icon_path or os.path.join(get_prog_root(), 'icons')

-def get_license_path():
- # type: () -> Text
+def get_license_path() -> Text:
global license_path
return license_path or os.path.join(get_prog_root(), 'COPYING.txt')

-def get_locale_path():
- # type: () -> Text
+def get_locale_path() -> Text:
global locale_path
return locale_path or os.path.join(get_prog_root(), 'locale')

-def _get_hg_path():
- # type: () -> Text
+def _get_hg_path() -> Text:
return os.path.abspath(os.path.join(mercurial.__file__, '..', '..'))

-def get_hg_command():
- # type: () -> List[Text]
+def get_hg_command() -> List[Text]:
"""List of command to execute hg (equivalent to mercurial.util.hgcmd)"""
global _hg_command
if _hg_command is None:
@@ -114,8 +104,7 @@
if os.name == 'nt':
import win32file # pytype: disable=import-error

- def find_in_path(pgmname):
- # type: (Text) -> Optional[Text]
+ def find_in_path(pgmname: Text) -> Optional[Text]:
"return first executable found in search path"
global bin_path
ospath = os.environ['PATH'].split(os.pathsep)
@@ -129,8 +118,7 @@
return ppath + ext
return None

- def _find_hg_command():
- # type: () -> List[Text]
+ def _find_hg_command() -> List[Text]:
if hasattr(sys, 'frozen'):
progdir = get_prog_root()
exe = os.path.join(progdir, 'hg.exe')
@@ -155,25 +143,21 @@
return [python, exe[:-4]]
return [exe]

- def get_prog_root():
- # type: () -> Text
+ def get_prog_root() -> Text:
if getattr(sys, 'frozen', False):
return os.path.dirname(sys.executable)
return os.path.dirname(os.path.dirname(os.path.dirname(__file__)))

- def get_thg_command():
- # type: () -> List[Text]
+ def get_thg_command() -> List[Text]:
if getattr(sys, 'frozen', False):
return [sys.executable]
return [sys.executable] + sys.argv[:1]

- def is_unc_path(path):
- # type: (bytes) -> bool
+ def is_unc_path(path: bytes) -> bool:
unc, rest = os.path.splitdrive(path)
return len(unc) > 2

- def is_on_fixed_drive(path):
- # type: (bytes) -> bool
+ def is_on_fixed_drive(path: bytes) -> bool:
if is_unc_path(path):
# All UNC paths (\\host\mount) are considered not-fixed
return False
@@ -186,8 +170,7 @@

else: # Not Windows

- def find_in_path(pgmname):
- # type: (Text) -> Optional[Text]
+ def find_in_path(pgmname: Text) -> Optional[Text]:
""" return first executable found in search path """
global bin_path
ospath = os.environ['PATH'].split(os.pathsep)
@@ -198,8 +181,7 @@
return ppath
return None

- def _find_hg_command():
- # type: () -> List[Text]
+ def _find_hg_command() -> List[Text]:
# look for in-place build, i.e. "make local"
exe = os.path.join(_get_hg_path(), 'hg')
if os.path.exists(exe):
@@ -210,20 +192,16 @@
return ['hg']
return [exe]

- def get_prog_root():
- # type: () -> Text
+ def get_prog_root() -> Text:
path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
return path

- def get_thg_command():
- # type: () -> List[Text]
+ def get_thg_command() -> List[Text]:
return sys.argv[:1]

- def is_unc_path(path):
- # type: (bytes) -> bool
+ def is_unc_path(path: bytes) -> bool:
return False

- def is_on_fixed_drive(path):
- # type: (bytes) -> bool
+ def is_on_fixed_drive(path: bytes) -> bool:
return True

diff --git a/tortoisehg/util/shlib.py b/tortoisehg/util/shlib.py
--- a/tortoisehg/util/shlib.py
+++ b/tortoisehg/util/shlib.py
@@ -31,8 +31,7 @@
)

if os.name == 'nt':
- def shell_notify(paths, noassoc=False):
- # type: (List[bytes], bool) -> None
+ def shell_notify(paths: List[bytes], noassoc: bool = False) -> None:
try:
from win32com.shell import ( # pytype: disable=import-error
shell, shellcon
@@ -100,9 +99,8 @@
with lfutil.lfstatus(repo):
repostate = repo.status() # will update dirstate as a side effect

- dirstatus = {} # type: Dict[bytes, bytes]
- def dirname(f):
- # type: (bytes) -> bytes
+ dirstatus: Dict[bytes, bytes] = {}
+ def dirname(f: bytes) -> bytes:
return b'/'.join(f.split(b'/')[:-1])
for fn in repostate.added:
dirstatus[dirname(fn)] = b'a'
@@ -117,7 +115,7 @@
with repo.vfs(b'thgstatus', b'rb') as f:
for dn in sorted(dirstatus):
s = dirstatus[dn]
- e = f.readline() # type: bytes
+ e: bytes = f.readline()
if e.startswith(b'@@noicons'):
break
if e == b'' or e[0:1] != s or e[1:-1] != dn:
@@ -138,8 +136,7 @@
return update

else:
- def shell_notify(paths, noassoc=False):
- # type: (List[bytes], bool) -> None
+ def shell_notify(paths: List[bytes], noassoc: bool = False) -> None:
if not paths:
return
notify = os.environ.get('THG_NOTIFY', '.tortoisehg/notify')
diff --git a/tortoisehg/util/terminal.py b/tortoisehg/util/terminal.py
--- a/tortoisehg/util/terminal.py
+++ b/tortoisehg/util/terminal.py
@@ -16,8 +16,7 @@
)


-def defaultshell():
- # type: () -> Optional[bytes]
+def defaultshell() -> Optional[bytes]:
if sys.platform == 'darwin':
shell = None # Terminal.App does not support open-to-folder
elif os.name == 'nt':
@@ -28,8 +27,7 @@

_defaultshell = defaultshell()

-def _getplatformexecutablekey():
- # type: () -> bytes
+def _getplatformexecutablekey() -> bytes:
if sys.platform == 'darwin':
key = b'executable-osx'
elif os.name == 'nt':
@@ -40,15 +38,16 @@

_platformexecutablekey = _getplatformexecutablekey()

-def _toolstr(ui, tool, part, default=b""):
- # type: (uimod.ui, bytes, bytes, bytes) -> bytes
+def _toolstr(ui: uimod.ui,
+ tool: bytes,
+ part: bytes,
+ default: bytes = b"") -> bytes:
val = ui.config(b"terminal-tools", tool + b"." + part, default)
assert val is not None # help pytype
return val

toolcache = {}
-def _findtool(ui, tool):
- # type: (uimod.ui, bytes) -> Optional[bytes]
+def _findtool(ui: uimod.ui, tool: bytes) -> Optional[bytes]:
global toolcache
if tool in toolcache:
return toolcache[tool]
@@ -77,8 +76,7 @@
toolcache[tool] = None
return None

-def _findterminal(ui):
- # type: (uimod.ui) -> Tuple[Optional[bytes], Optional[bytes]]
+def _findterminal(ui: uimod.ui) -> Tuple[Optional[bytes], Optional[bytes]]:
'''returns tuple of terminal name and terminal path.

tools matched by pattern are returned as (name, toolpath)
@@ -119,8 +117,7 @@
global _defaultshell
return None, _defaultshell

-def detectterminal(ui_):
- # type: (uimod.ui) -> Tuple[Optional[bytes], Optional[bytes]]
+def detectterminal(ui_: uimod.ui) -> Tuple[Optional[bytes], Optional[bytes]]:
'returns tuple of terminal tool path and arguments'
if ui_ is None:
ui_ = hglib.loadui()
@@ -131,8 +128,7 @@
args = _toolstr(ui_, name, b"args")
return pathorconfig, args

-def findterminals(ui):
- # type: (uimod.ui) -> List[bytes]
+def findterminals(ui: uimod.ui) -> List[bytes]:
seen = set()
for key, value in ui.configitems(b'terminal-tools'):
t = key.split(b'.')[0]
diff --git a/tortoisehg/util/wconfig.py b/tortoisehg/util/wconfig.py
--- a/tortoisehg/util/wconfig.py
+++ b/tortoisehg/util/wconfig.py
@@ -149,8 +149,8 @@
- A "set foo = bar", B "del foo" => "" (last one wins)
"""

- def __init__(self, data=None):
- # type: (Optional[Union[_wconfig, config_mod.config]]) -> None
+ def __init__(self,
+ data: Optional[Union[_wconfig, config_mod.config]] = None) -> None:
self._config = config_mod.config(data)
self._readfiles = [] # list of read (path, fp, sections, remap)
self._sections: Dict[bytes, _wsortdict] = {}
diff --git a/tortoisehg/util/win32ill.py b/tortoisehg/util/win32ill.py
--- a/tortoisehg/util/win32ill.py
+++ b/tortoisehg/util/win32ill.py
@@ -177,8 +177,7 @@

class messageserver(object):

- def __init__(self, logfile):
- # type: (Optional[BinaryIO]) -> None
+ def __init__(self, logfile: Optional[BinaryIO]) -> None:
self._logfile = logfile
self._thread = threading.Thread(target=self._mainloop)
self._thread.setDaemon(True) # skip global join before atexit
@@ -205,8 +204,7 @@
_PostMessage(hwnd, _WM_STOPMESSAGELOOP, 0, 0)
self._thread.join()

- def _log(self, msg):
- # type: (bytes) -> None
+ def _log(self, msg: bytes) -> None:
if not self._logfile:
return
self._logfile.write(msg + b'\n')
@@ -253,16 +251,14 @@
return 0
return _DefWindowProc(hwnd, msg, wparam, lparam)

-def _openlogfile(ui):
- # type: (uimod.ui) -> Optional[BinaryIO]
+def _openlogfile(ui: uimod.ui) -> Optional[BinaryIO]:
log = ui.config(b'win32ill', b'log')
if log == b'-':
return ui.ferr
elif log:
return open(log, 'ab')

-def uisetup(ui):
- # type: (uimod.ui) -> None
+def uisetup(ui: uimod.ui) -> None:
if os.name != 'nt':
ui.warn(_('win32ill: unsupported platform: %s\n') % os.name)
return

Yuya Nishihara

unread,
Nov 3, 2024, 6:11:40 AMNov 3
to Matt Harbison, thg...@googlegroups.com
On Sat, 02 Nov 2024 20:44:21 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_h...@yahoo.com>
> # Date 1730575995 14400
> # Sat Nov 02 15:33:15 2024 -0400
> # Branch stable
> # Node ID a6384e13749a9f39a71813683a4bee3759c16a72
> # Parent 555b2f10013012aabd45bda2a0431295ae3c8195
> # EXP-Topic py2-to-py3-annotations
> typing: convert py2 type comments to py3 type annotations in `nautilus-thg.py`

Queued, thanks.
Reply all
Reply to author
Forward
0 new messages