debugantivirusrunning: use bytes when opening a vfs file
I noticed this when searching for "base85" to see if anything else in the
previous commit needed to be annotated. This was added in
87047efbc6a6, after
the mass byteification in
687b865b95ad.
interfaces: introduce and use a protocol class for the `base85` module
See
f2832de2a46c for details when this was done for the `bdiff` module.
It looks like PEP-688 removed the special casing of `bytes` being a standin
for any type of `ByteString`, and defines a `typing.Buffer` class (with a
backport in `typing_extensions` for Python prior to 3.12). There's been a lot
of churn in this area with pytype, but recent versions of pytype and PyCharm
recognize this, and e.g. have `mercurial.node.hex()` defined as:
from typing_extensions import Buffer
def hex(data: Buffer, sep: str | bytes = ..., bytes_per_sep: int = ...) -> bytes
This covers `bytes`, `bytearray`, and `memoryview` by default. Both of the C
functions here use `y#` to parse the arguments, which means the arg is a
byte-like object[2], so the args would appear to be better typed as `Buffer`.
However, pytype has a bug that prevents using this from `typing_extensions`[3],
and mypy complained `Unsupported left operand type for + ("memoryview")` in the
pure module on line 37 (meaning it's only a subset of `Buffer`). So hold off on
changing any of that for now.
[1] https://peps.python.org/pep-0688/#no-special-meaning-for-bytes
[2] https://docs.python.org/3/glossary.html#term-bytes-like-object
[3] https://github.com/google/pytype/issues/1772
base85: avoid a spurious use-before-initialized warning in `pure` module
The error wasn't possible because the only way for `acc` to not be initialized
was if `len(text) == 0`. But then `0 % 5 == 0`, so no attempt at padding was
done. It's a simple enough fix to not have PyCharm flag this though. The value
needs to be reset on each loop iteration, so it's a line copy, not a line move.
typing: add type annotations to `mercurial/mdiff.py`
We'll leave converting `diffopts` to `attrs` as another project.
mdiff: convert a few block definitions from lists to tuples
These were flagged by adding type hints. Some places were using a tuple of 4
ints to define a block, and others were using a list of 4. A tuple is better
for typing, because we can define the length and the type of each entry. One of
the places had to redefine the tuple, since writing to a tuple at an index isn't
supported.
This change spills out into the tests, and archeology says it was added to the
repo in this state. There was no reason given for the divergence, and I suspect
it wasn't intentional.
It looks like `splitblock()` is completely unused in the codebase.
interfaces: add the optional `bdiff.xdiffblocks()` method
PyCharm flagged where this was called on the protocol class in `mdiff.py` in the
previous commit, but pytype completely missed it. PyCharm is correct here, but
I'm committing this separately to highlight this potential problem- some of the
implementations don't implement _all_ of the methods the others do, and there's
not a great way to indicate on a protocol class that a method or attribute is
optional- that's kinda the opposite of what static typing is about.
Making the method an `Optional[Callable]` attribute works here, and keeps both
PyCharm and pytype happy, and the generated `mdiff.pyi` and `modules.pyi` look
reasonable. We might be getting a little lucky, because the method isn't
invoked directly- it is returned from another method that selects which block
function to use. Except since it is declared on the protocol class, every
module needs this attribute (in theory, but in practice this doesn't seem to be
checked), so the check for it on the module has to change from `hasattr()` to
`getattr(..., None)`. We defer defining the optional attrs to the type checking
phase as an extra precaution- that way it isn't an attr with a `None` value at
runtime if someone is still using `hasattr()`.
As to why pytype missed this, I have no clue. The generated `mdiff.pyi` even
has the global variable typed as `bdiff: intmod.BDiff`, so uses of it really
should comply with what is on the class, protocol class or not.