interfaces: convert the zope `Attribute` attrs to regular fields
authorMatt Harbison <matt_harbison@yahoo.com>
Thu, 26 Sep 2024 18:15:36 -0400
changeset 51923 b455dfddfed0
parent 51922 13aa17512583
child 51924 51be8bf8c986
interfaces: convert the zope `Attribute` attrs to regular fields At this point, we should have a useful protocol class. The file syntax requires the type to be supplied for any fields that are declared, but we'll leave the complex ones partially unspecified for now, for simplicity. (Also, the things documented as `Callable` are really as future type annotating worked showed- roll with it for now, but they're marked as TODO for fixing later.) All of the fields and all of the attrs will need type annotations, or the type rules say they are considered to be `Any`. That can be done in a separate pass, possibly applying the `dirstate.pyi` file generated from the concrete class. The first cut of this turned the `interfaceutil.Attribute` fields into plain fields, and thus the types on them. PyCharm flagged a few things as having incompatible signatures when the concrete dirstate class subclassed this, when the concrete class has them declared as `@property`. So they've been changed to `@property` here in those cases. The remaining fields that are decorated in the concrete class have comments noting the differences. We'll see if they need to be changed going forward, but leave them for now. We'll be in trouble if the `@util.propertycache` is needed, because we can't import that module here at runtime, due to circular imports.
mercurial/interfaces/dirstate.py
--- a/mercurial/interfaces/dirstate.py	Thu Sep 26 18:09:33 2024 -0400
+++ b/mercurial/interfaces/dirstate.py	Thu Sep 26 18:15:36 2024 -0400
@@ -1,12 +1,19 @@
 from __future__ import annotations
 
 import contextlib
+import typing
 
 from typing import (
+    Callable,
     Protocol,
 )
 
-from . import util as interfaceutil
+if typing.TYPE_CHECKING:
+    # Almost all mercurial modules are only imported in the type checking phase
+    # to avoid circular imports
+    from .. import (
+        match as matchmod,
+    )
 
 
 class idirstate(Protocol):
@@ -31,16 +38,22 @@
 
     # TODO: all these private methods and attributes should be made
     # public or removed from the interface.
-    _ignore = interfaceutil.Attribute("""Matcher for ignored files.""")
-    is_changing_any = interfaceutil.Attribute(
+
+    # TODO: decorate with `@rootcache(b'.hgignore')` like dirstate class?
+    _ignore: matchmod.basematcher
+    """Matcher for ignored files."""
+
+    @property
+    def is_changing_any(self) -> bool:
         """True if any changes in progress."""
-    )
-    is_changing_parents = interfaceutil.Attribute(
+
+    @property
+    def is_changing_parents(self) -> bool:
         """True if parents changes in progress."""
-    )
-    is_changing_files = interfaceutil.Attribute(
+
+    @property
+    def is_changing_files(self) -> bool:
         """True if file tracking changes in progress."""
-    )
 
     def _ignorefiles(self):
         """Return a list of files containing patterns to ignore."""
@@ -48,8 +61,19 @@
     def _ignorefileandline(self, f):
         """Given a file `f`, return the ignore file and line that ignores it."""
 
-    _checklink = interfaceutil.Attribute("""Callable for checking symlinks.""")
-    _checkexec = interfaceutil.Attribute("""Callable for checking exec bits.""")
+    # TODO: decorate with `@util.propertycache` like dirstate class?
+    #  (can't because circular import)
+    # TODO: The doc looks wrong- the core class has this as a @property, not a
+    #  callable.
+    _checklink: Callable
+    """Callable for checking symlinks."""
+
+    # TODO: decorate with `@util.propertycache` like dirstate class?
+    #  (can't because circular import)
+    # TODO: The doc looks wrong- the core class has this as a @property, not a
+    #  callable.
+    _checkexec: Callable
+    """Callable for checking exec bits."""
 
     @contextlib.contextmanager
     def changing_parents(self, repo):