changeset 51716:f3b34386d3e0

typing: add type hints to `mercurial.dirstatemap` Somewhere since 10db46e128d4, pytype stopped being able to infer the type of the `identity` field. Fill in some obvious other hints along the way. These hints caused pytype to flag a missing attribute: File "/mnt/c/Users/Matt/hg/mercurial/dirstatemap.py", line 714, in _v1_map: No attribute 'stat' on mercurial.windows.cachestat [attribute-error] In Union[Any, mercurial.posix.cachestat, mercurial.windows.cachestat] File "/mnt/c/Users/Matt/hg/mercurial/dirstatemap.py", line 715, in _v1_map: No attribute 'stat' on mercurial.windows.cachestat [attribute-error] In Union[Any, mercurial.posix.cachestat, mercurial.windows.cachestat] In practice, the `identity` field is NOT replaced with None if it isn't cacheable, so it's probably safer to just add the field and set it to None, since that check is already in place on line 715.
author Matt Harbison <matt_harbison@yahoo.com>
date Thu, 18 Jul 2024 19:57:42 -0400
parents 7601978f9e9f
children f841de63a5aa
files mercurial/dirstatemap.py mercurial/posix.py mercurial/typelib.py mercurial/windows.py
diffstat 4 files changed, 55 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/dirstatemap.py	Thu Jul 18 19:55:51 2024 -0400
+++ b/mercurial/dirstatemap.py	Thu Jul 18 19:57:42 2024 -0400
@@ -4,6 +4,11 @@
 # GNU General Public License version 2 or any later version.
 
 
+from typing import (
+    Optional,
+    TYPE_CHECKING,
+)
+
 from .i18n import _
 
 from . import (
@@ -12,6 +17,7 @@
     policy,
     testing,
     txnutil,
+    typelib,
     util,
 )
 
@@ -20,6 +26,11 @@
     v2,
 )
 
+if TYPE_CHECKING:
+    from . import (
+        ui as uimod,
+    )
+
 parsers = policy.importmod('parsers')
 rustmod = policy.importrust('dirstate')
 
@@ -46,12 +57,31 @@
     class, with and without Rust extensions enabled.
     """
 
+    _use_dirstate_v2: bool
+    _nodeconstants: typelib.NodeConstants
+    _ui: "uimod.ui"
+    _root: bytes
+    _filename: bytes
+    _nodelen: int
+    _dirtyparents: bool
+    _docket: Optional["docketmod.DirstateDocket"]
+    _write_mode: int
+    _pendingmode: Optional[bool]
+    identity: Optional[typelib.CacheStat]
+
     # please pytype
 
     _map = None
     copymap = None
 
-    def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
+    def __init__(
+        self,
+        ui: "uimod.ui",
+        opener,
+        root: bytes,
+        nodeconstants: typelib.NodeConstants,
+        use_dirstate_v2: bool,
+    ) -> None:
         self._use_dirstate_v2 = use_dirstate_v2
         self._nodeconstants = nodeconstants
         self._ui = ui
@@ -76,16 +106,16 @@
         # for consistent view between _pl() and _read() invocations
         self._pendingmode = None
 
-    def _set_identity(self):
+    def _set_identity(self) -> None:
         self.identity = self._get_current_identity()
 
-    def _get_current_identity(self):
+    def _get_current_identity(self) -> Optional[typelib.CacheStat]:
         try:
             return util.cachestat(self._opener.join(self._filename))
         except FileNotFoundError:
             return None
 
-    def may_need_refresh(self):
+    def may_need_refresh(self) -> bool:
         if 'identity' not in vars(self):
             # no existing identity, we need a refresh
             return True
@@ -104,7 +134,7 @@
             return True
         return current_identity != self.identity
 
-    def preload(self):
+    def preload(self) -> None:
         """Loads the underlying data, if it's not already loaded"""
         self._map
 
@@ -135,7 +165,7 @@
         self._pendingmode = mode
         return fp
 
-    def _readdirstatefile(self, size=-1):
+    def _readdirstatefile(self, size: int = -1) -> bytes:
         try:
             with self._opendirstatefile() as fp:
                 return fp.read(size)
@@ -144,7 +174,7 @@
             return b''
 
     @property
-    def docket(self):
+    def docket(self) -> "docketmod.DirstateDocket":
         if not self._docket:
             if not self._use_dirstate_v2:
                 raise error.ProgrammingError(
--- a/mercurial/posix.py	Thu Jul 18 19:55:51 2024 -0400
+++ b/mercurial/posix.py	Thu Jul 18 19:57:42 2024 -0400
@@ -707,6 +707,8 @@
 
 
 class cachestat:
+    stat: os.stat_result
+
     def __init__(self, path: bytes) -> None:
         self.stat = os.stat(path)
 
--- a/mercurial/typelib.py	Thu Jul 18 19:55:51 2024 -0400
+++ b/mercurial/typelib.py	Thu Jul 18 19:57:42 2024 -0400
@@ -21,8 +21,21 @@
 if TYPE_CHECKING:
     from typing import (
         BinaryIO,
+        Union,
+    )
+
+    from . import (
+        node,
+        posix,
+        windows,
     )
 
     BinaryIO_Proxy = BinaryIO
+    CacheStat = Union[posix.cachestat, windows.cachestat]
+    NodeConstants = node.sha1nodeconstants
 else:
+    from typing import Any
+
     BinaryIO_Proxy = object
+    CacheStat = Any
+    NodeConstants = Any
--- a/mercurial/windows.py	Thu Jul 18 19:55:51 2024 -0400
+++ b/mercurial/windows.py	Thu Jul 18 19:57:42 2024 -0400
@@ -675,8 +675,10 @@
 
 
 class cachestat:
+    stat: Optional[os.stat_result]
+
     def __init__(self, path: bytes) -> None:
-        pass
+        self.stat = None
 
     def cacheable(self) -> bool:
         return False