typing: add type hints to the `charencode` module
authorMatt Harbison <matt_harbison@yahoo.com>
Fri, 19 Jul 2024 20:09:48 -0400
changeset 51722 43adbe03079b
parent 51721 ed28085827ec
child 51723 9367571fea21
typing: add type hints to the `charencode` module Since this module is dynamically imported from either `mercurial.pure` or `mercurial.cext`, these hints aren't detected in `mercurial.encoding`, and need to be imported directly there during the type-checking phase. This keeps the runtime selection via the policy config in place, but allows pytype to see these as functions with proper signatures instead of just `Any`. We don't attempt to import the `mercurial.cext` version yet because there's no types stubs for that module, but this will get the ball rolling. I thought this would spill over into other modules from there, but the only two *.pyi files that changed were for `encoding` and `charencode`. Applying this to other dynamically selected modules will clean some things up in other files, so this is a start. I had originally redefined the functions in the type-checking block (like some of the `os.path` aliasing in `mercurial.util`), but this is better because we won't have another duplication of the definitions that may get out of date.
mercurial/encoding.py
mercurial/pure/charencode.py
--- a/mercurial/encoding.py	Fri Jul 19 16:49:46 2024 -0400
+++ b/mercurial/encoding.py	Fri Jul 19 20:09:48 2024 -0400
@@ -40,6 +40,16 @@
 
 unichr = chr
 
+if typing.TYPE_CHECKING:
+    # TODO: make a stub file for .cext.charencode, and import here
+    from .pure.charencode import (
+        asciilower,
+        asciiupper,
+        isasciistr,
+        jsonescapeu8fast as _jsonescapeu8fast,
+    )
+
+
 # These unicode characters are ignored by HFS+ (Apple Technote 1150,
 # "Unicode Subtleties"), so we need to ignore them in some places for
 # sanity.
@@ -524,7 +534,7 @@
     other = 0
 
 
-def jsonescape(s: Any, paranoid: Any = False) -> Any:
+def jsonescape(s: bytes, paranoid: bool = False) -> bytes:
     """returns a string suitable for JSON
 
     JSON is problematic for us because it doesn't support non-Unicode
--- a/mercurial/pure/charencode.py	Fri Jul 19 16:49:46 2024 -0400
+++ b/mercurial/pure/charencode.py	Fri Jul 19 20:09:48 2024 -0400
@@ -11,7 +11,7 @@
 from .. import pycompat
 
 
-def isasciistr(s):
+def isasciistr(s: bytes) -> bool:
     try:
         s.decode('ascii')
         return True
@@ -19,7 +19,7 @@
         return False
 
 
-def asciilower(s):
+def asciilower(s: bytes) -> bytes:
     """convert a string to lowercase if ASCII
 
     Raises UnicodeDecodeError if non-ASCII characters are found."""
@@ -27,7 +27,7 @@
     return s.lower()
 
 
-def asciiupper(s):
+def asciiupper(s: bytes) -> bytes:
     """convert a string to uppercase if ASCII
 
     Raises UnicodeDecodeError if non-ASCII characters are found."""
@@ -52,7 +52,7 @@
 _jsonmap.extend(pycompat.bytechr(x) for x in range(128, 256))
 
 
-def jsonescapeu8fast(u8chars, paranoid):
+def jsonescapeu8fast(u8chars: bytes, paranoid: bool) -> bytes:
     """Convert a UTF-8 byte string to JSON-escaped form (fast path)
 
     Raises ValueError if non-ASCII characters have to be escaped.
@@ -70,7 +70,7 @@
 _utf8strict = r'surrogatepass'
 
 
-def jsonescapeu8fallback(u8chars, paranoid):
+def jsonescapeu8fallback(u8chars: bytes, paranoid: bool) -> bytes:
     """Convert a UTF-8 byte string to JSON-escaped form (slow path)
 
     Escapes all non-ASCII characters no matter if paranoid is False.