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.
--- 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):