diff mercurial/cmdutil.py @ 52629:89215c5b714c

cmdutil: switch the `mode` on `cmdutil.makefileobj()` to str I think the typing around whether `open()` returns `IO[bytes]` or `IO[str]` hinges on the content of the mode string. Converting from bytes instead of using a literal can suppress that (though PyCharm currently complains about this). Instead, we can mandate the use of a (vastly reduced) set of mode options. For now, none of the 3 callers provide this argument, so it's not a big deal. Ideally, this would always enforce binary mode. There's a little extra typing required to pull this off. The `_unclosablefile` class can't subclass `typing.BinaryIO`, because there were a bunch of test failures around writing to stdout. Strangely, pytype didn't complain that the abstract methods on `typing.BinaryIO` weren't overridden in this case. Whatever was going on, it's a simple proxy class, so we can just cast to the expected type in the one place it is used.
author Matt Harbison <matt_harbison@yahoo.com>
date Mon, 16 Dec 2024 21:50:24 -0500
parents 9d79ffeed7c0
children 24ee91ba9aa8
line wrap: on
line diff
--- a/mercurial/cmdutil.py	Tue Dec 31 22:36:56 2024 -0500
+++ b/mercurial/cmdutil.py	Mon Dec 16 21:50:24 2024 -0500
@@ -17,8 +17,10 @@
 from typing import (
     Any,
     AnyStr,
+    BinaryIO,
     Dict,
     Iterable,
+    Literal,
     Optional,
     TYPE_CHECKING,
     cast,
@@ -1360,7 +1362,7 @@
     return b''.join(newname)
 
 
-def makefilename(ctx, pat, **props):
+def makefilename(ctx, pat: bytes, **props):
     if not pat:
         return pat
     tmpl = _buildfntemplate(pat, **props)
@@ -1376,7 +1378,7 @@
 
 
 class _unclosablefile:
-    def __init__(self, fp):
+    def __init__(self, fp: BinaryIO) -> None:
         self._fp = fp
 
     def close(self):
@@ -1395,8 +1397,10 @@
         pass
 
 
-def makefileobj(ctx, pat, mode=b'wb', **props):
-    writable = mode not in (b'r', b'rb')
+def makefileobj(
+    ctx, pat: bytes, mode: Literal['rb', 'wb'] = 'wb', **props
+) -> BinaryIO:
+    writable = mode not in ('r', 'rb')
 
     if isstdiofilename(pat):
         repo = ctx.repo()
@@ -1404,9 +1408,9 @@
             fp = repo.ui.fout
         else:
             fp = repo.ui.fin
-        return _unclosablefile(fp)
+        return typing.cast(BinaryIO, _unclosablefile(fp))
     fn = makefilename(ctx, pat, **props)
-    return open(fn, pycompat.sysstr(mode))
+    return open(fn, mode)
 
 
 def openstorage(repo, cmd, file_, opts, returnrevlog=False):