view mercurial/interfaces/modules.py @ 51938:fa7059f031a9

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
author Matt Harbison <matt_harbison@yahoo.com>
date Fri, 04 Oct 2024 23:21:41 -0400
parents 09f3a6790e56
children 54d9f496f07a
line wrap: on
line source

# modules.py - protocol classes for dynamically loaded modules
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

from __future__ import annotations

import typing

from typing import (
    Callable,
    List,
    Optional,
    Protocol,
    Tuple,
)

if typing.TYPE_CHECKING:
    BDiffBlock = Tuple[int, int, int, int]
    """An entry in the list returned by bdiff.{xdiff,}blocks()."""

    BDiffBlocksFnc = Callable[[bytes, bytes], List[BDiffBlock]]
    """The signature of `bdiff.blocks()` and `bdiff.xdiffblocks()`."""


class Base85(Protocol):
    """A Protocol class for the various base85 module implementations."""

    def b85encode(self, text: bytes, pad: bool = False) -> bytes:
        """encode text in base85 format"""

    def b85decode(self, text: bytes) -> bytes:
        """decode base85-encoded text"""


class BDiff(Protocol):
    """A Protocol class for the various bdiff module implementations."""

    def splitnewlines(self, text: bytes) -> List[bytes]:
        """like str.splitlines, but only split on newlines."""

    def bdiff(self, a: bytes, b: bytes) -> bytes:
        ...

    def blocks(self, a: bytes, b: bytes) -> List[BDiffBlock]:
        ...

    def fixws(self, text: bytes, allws: bool) -> bytes:
        ...

    xdiffblocks: Optional[BDiffBlocksFnc]
    """This method is currently only available in the ``cext`` module."""