Mercurial > public > mercurial-scm > hg-stable
diff hgext/git/manifest.py @ 52521:48cdbd4d5443
typing: align the signatures of `repository.imanifestdict` overrides
This is the same procedure as 048c11993d6a, where we bounce around to the
various subclasses and steal their type hints to keep everything happy when the
interface is explicitly subclassed.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Wed, 23 Oct 2024 15:56:48 -0400 |
parents | c855943e334b |
children | db6efd74cf14 |
line wrap: on
line diff
--- a/hgext/git/manifest.py Thu Oct 24 22:24:46 2024 -0400 +++ b/hgext/git/manifest.py Wed Oct 23 15:56:48 2024 -0400 @@ -1,5 +1,13 @@ from __future__ import annotations +import typing + +from typing import ( + Any, + Iterator, + Set, +) + from mercurial import ( match as matchmod, pathutil, @@ -12,6 +20,10 @@ ) from . import gitutil +if typing.TYPE_CHECKING: + from typing import ( + ByteString, # TODO: change to Buffer for 3.14 + ) pygit2 = gitutil.get_pygit2() @@ -71,16 +83,16 @@ raise ValueError('unsupported mode %s' % oct(ent.filemode)) return ent.id.raw, flags - def __getitem__(self, path): + def __getitem__(self, path: bytes) -> bytes: return self._resolve_entry(path)[0] - def find(self, path): + def find(self, path: bytes) -> tuple[bytes, bytes]: return self._resolve_entry(path) - def __len__(self): + def __len__(self) -> int: return len(list(self.walk(matchmod.always()))) - def __nonzero__(self): + def __nonzero__(self) -> bool: try: next(iter(self)) return True @@ -89,30 +101,30 @@ __bool__ = __nonzero__ - def __contains__(self, path): + def __contains__(self, path: bytes) -> bool: try: self._resolve_entry(path) return True except KeyError: return False - def iterkeys(self): + def iterkeys(self) -> Iterator[bytes]: return self.walk(matchmod.always()) - def keys(self): + def keys(self) -> list[bytes]: return list(self.iterkeys()) - def __iter__(self): + def __iter__(self) -> Iterator[bytes]: return self.iterkeys() - def __setitem__(self, path, node): + def __setitem__(self, path: bytes, node: bytes) -> None: self._pending_changes[path] = node, self.flags(path) - def __delitem__(self, path): + def __delitem__(self, path: bytes) -> None: # TODO: should probably KeyError for already-deleted files? self._pending_changes[path] = None - def filesnotin(self, other, match=None): + def filesnotin(self, other, match=None) -> Set[bytes]: if match is not None: match = matchmod.badmatch(match, lambda path, msg: None) sm2 = set(other.walk(match)) @@ -123,10 +135,18 @@ def _dirs(self): return pathutil.dirs(self) - def hasdir(self, dir): + def hasdir(self, dir: bytes) -> bool: return dir in self._dirs - def diff(self, other, match=lambda x: True, clean=False): + def diff( + self, + other: Any, # TODO: 'manifestdict' or (better) equivalent interface + match: Any = lambda x: True, # TODO: Optional[matchmod.basematcher] = None, + clean: bool = False, + ) -> dict[ + bytes, + tuple[tuple[bytes | None, bytes], tuple[bytes | None, bytes]] | None, + ]: """Finds changes between the current manifest and m2. The result is returned as a dict with filename as key and @@ -200,42 +220,43 @@ return result - def setflag(self, path, flag): + def setflag(self, path: bytes, flag: bytes) -> None: node, unused_flag = self._resolve_entry(path) self._pending_changes[path] = node, flag - def get(self, path, default=None): + def get(self, path: bytes, default=None) -> bytes | None: try: return self._resolve_entry(path)[0] except KeyError: return default - def flags(self, path): + def flags(self, path: bytes) -> bytes: try: return self._resolve_entry(path)[1] except KeyError: return b'' - def copy(self): + def copy(self) -> 'gittreemanifest': return gittreemanifest( self._git_repo, self._tree, dict(self._pending_changes) ) - def items(self): + def items(self) -> Iterator[tuple[bytes, bytes]]: for f in self: # TODO: build a proper iterator version of this yield f, self[f] - def iteritems(self): + def iteritems(self) -> Iterator[tuple[bytes, bytes]]: return self.items() - def iterentries(self): + def iterentries(self) -> Iterator[tuple[bytes, bytes, bytes]]: for f in self: # TODO: build a proper iterator version of this yield f, *self._resolve_entry(f) - def text(self): - assert False # TODO can this method move out of the manifest iface? + def text(self) -> ByteString: + # TODO can this method move out of the manifest iface? + raise NotImplementedError def _walkonetree(self, tree, match, subdir): for te in tree: @@ -249,7 +270,7 @@ elif match(realname): yield pycompat.fsencode(realname) - def walk(self, match): + def walk(self, match: matchmod.basematcher) -> Iterator[bytes]: # TODO: this is a very lazy way to merge in the pending # changes. There is absolutely room for optimization here by # being clever about walking over the sets...