mercurial/cffi/bdiff.py
author Matt Harbison <matt_harbison@yahoo.com>
Sun, 29 Sep 2024 02:03:20 -0400
changeset 51934 09f3a6790e56
parent 51863 f4733654f144
permissions -rw-r--r--
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.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
32512
0e8b0b9a7acc cffi: split modules from pure
Yuya Nishihara <yuya@tcha.org>
parents: 32506
diff changeset
     1
# bdiff.py - CFFI implementation of bdiff.c
7703
9044d3567f6d pure Python implementation of bdiff.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     2
#
32512
0e8b0b9a7acc cffi: split modules from pure
Yuya Nishihara <yuya@tcha.org>
parents: 32506
diff changeset
     3
# Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
7703
9044d3567f6d pure Python implementation of bdiff.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     4
#
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 7944
diff changeset
     5
# This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 8225
diff changeset
     6
# GNU General Public License version 2 or any later version.
7703
9044d3567f6d pure Python implementation of bdiff.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
     7
51863
f4733654f144 typing: add `from __future__ import annotations` to most files
Matt Harbison <matt_harbison@yahoo.com>
parents: 51792
diff changeset
     8
from __future__ import annotations
27335
c4e3ff497f89 bdiff: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 15530
diff changeset
     9
c4e3ff497f89 bdiff: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 15530
diff changeset
    10
import struct
51934
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    11
import typing
7944
e9b48afd0e78 pure/bdiff: fix circular import
Matt Mackall <mpm@selenic.com>
parents: 7703
diff changeset
    12
49598
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    13
from typing import (
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    14
    List,
51934
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    15
    Optional,
49598
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    16
    Tuple,
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    17
)
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    18
32512
0e8b0b9a7acc cffi: split modules from pure
Yuya Nishihara <yuya@tcha.org>
parents: 32506
diff changeset
    19
from ..pure.bdiff import *
51934
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    20
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    21
from ..interfaces import (
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    22
    modules as intmod,
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    23
)
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    24
46785
521ac0d7047f typing: disable import error warnings that are already handled
Matt Harbison <matt_harbison@yahoo.com>
parents: 43077
diff changeset
    25
from . import _bdiff  # pytype: disable=import-error
7703
9044d3567f6d pure Python implementation of bdiff.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    26
32512
0e8b0b9a7acc cffi: split modules from pure
Yuya Nishihara <yuya@tcha.org>
parents: 32506
diff changeset
    27
ffi = _bdiff.ffi
0e8b0b9a7acc cffi: split modules from pure
Yuya Nishihara <yuya@tcha.org>
parents: 32506
diff changeset
    28
lib = _bdiff.lib
7703
9044d3567f6d pure Python implementation of bdiff.c
Martin Geisler <mg@daimi.au.dk>
parents:
diff changeset
    29
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    30
49598
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    31
def blocks(sa: bytes, sb: bytes) -> List[Tuple[int, int, int, int]]:
51790
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    32
    a = ffi.new("struct bdiff_line**")
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    33
    b = ffi.new("struct bdiff_line**")
51792
472699b5ddb3 cffi: pass bytes instead of str to ffi.new("char[]", …)
Manuel Jacob <me@manueljacob.de>
parents: 51791
diff changeset
    34
    ac = ffi.new("char[]", bytes(sa))
472699b5ddb3 cffi: pass bytes instead of str to ffi.new("char[]", …)
Manuel Jacob <me@manueljacob.de>
parents: 51791
diff changeset
    35
    bc = ffi.new("char[]", bytes(sb))
51790
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    36
    l = ffi.new("struct bdiff_hunk*")
32513
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    37
    try:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    38
        an = lib.bdiff_splitlines(ac, len(sa), a)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    39
        bn = lib.bdiff_splitlines(bc, len(sb), b)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    40
        if not a[0] or not b[0]:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    41
            raise MemoryError
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    42
        count = lib.bdiff_diff(a[0], an, b[0], bn, l)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    43
        if count < 0:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    44
            raise MemoryError
49597
b2666e767029 cffi: adjust the list returned by bdiff.blocks to never have a None entry
Matt Harbison <matt_harbison@yahoo.com>
parents: 48875
diff changeset
    45
        rl = [(0, 0, 0, 0)] * count
32513
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    46
        h = l.next
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    47
        i = 0
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    48
        while h:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    49
            rl[i] = (h.a1, h.a2, h.b1, h.b2)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    50
            h = h.next
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    51
            i += 1
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    52
    finally:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    53
        lib.free(a[0])
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    54
        lib.free(b[0])
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    55
        lib.bdiff_freehunks(l.next)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    56
    return rl
29834
1ea77b75d266 bdiff: implement cffi version of bdiff
Maciej Fijalkowski <fijall@gmail.com>
parents: 29833
diff changeset
    57
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    58
49598
594fc56c0af7 typing: add type hints to bdiff implementations
Matt Harbison <matt_harbison@yahoo.com>
parents: 49597
diff changeset
    59
def bdiff(sa: bytes, sb: bytes) -> bytes:
51790
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    60
    a = ffi.new("struct bdiff_line**")
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    61
    b = ffi.new("struct bdiff_line**")
51792
472699b5ddb3 cffi: pass bytes instead of str to ffi.new("char[]", …)
Manuel Jacob <me@manueljacob.de>
parents: 51791
diff changeset
    62
    ac = ffi.new("char[]", bytes(sa))
472699b5ddb3 cffi: pass bytes instead of str to ffi.new("char[]", …)
Manuel Jacob <me@manueljacob.de>
parents: 51791
diff changeset
    63
    bc = ffi.new("char[]", bytes(sb))
51790
ecc3a893979d cffi: pass C type and attribute names as str instead of bytes
Manuel Jacob <me@manueljacob.de>
parents: 49598
diff changeset
    64
    l = ffi.new("struct bdiff_hunk*")
32513
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    65
    try:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    66
        an = lib.bdiff_splitlines(ac, len(sa), a)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    67
        bn = lib.bdiff_splitlines(bc, len(sb), b)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    68
        if not a[0] or not b[0]:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    69
            raise MemoryError
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    70
        count = lib.bdiff_diff(a[0], an, b[0], bn, l)
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    71
        if count < 0:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    72
            raise MemoryError
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    73
        rl = []
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    74
        h = l.next
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    75
        la = lb = 0
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    76
        while h:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    77
            if h.a1 != la or h.b1 != lb:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    78
                lgt = (b[0] + h.b1).l - (b[0] + lb).l
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    79
                rl.append(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    80
                    struct.pack(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    81
                        b">lll",
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    82
                        (a[0] + la).l - a[0].l,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    83
                        (a[0] + h.a1).l - a[0].l,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    84
                        lgt,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    85
                    )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 33572
diff changeset
    86
                )
51791
6d7fdf90aa96 cffi: call bytes() instead of str() on CFFI buffer instances
Manuel Jacob <me@manueljacob.de>
parents: 51790
diff changeset
    87
                rl.append(bytes(ffi.buffer((b[0] + lb).l, lgt)))
32513
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    88
            la = h.a2
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    89
            lb = h.b2
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    90
            h = h.next
29834
1ea77b75d266 bdiff: implement cffi version of bdiff
Maciej Fijalkowski <fijall@gmail.com>
parents: 29833
diff changeset
    91
32513
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    92
    finally:
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    93
        lib.free(a[0])
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    94
        lib.free(b[0])
25b37900d6e0 cffi: remove superfluous "if True" blocks
Yuya Nishihara <yuya@tcha.org>
parents: 32512
diff changeset
    95
        lib.bdiff_freehunks(l.next)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
    96
    return b"".join(rl)
51934
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    97
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    98
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
    99
# In order to adhere to the module protocol, these functions must be visible to
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
   100
# the type checker, though they aren't actually implemented by this
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
   101
# implementation of the module protocol.  Callers are responsible for
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
   102
# checking that the implementation is available before using them.
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
   103
if typing.TYPE_CHECKING:
09f3a6790e56 interfaces: add the optional `bdiff.xdiffblocks()` method
Matt Harbison <matt_harbison@yahoo.com>
parents: 51863
diff changeset
   104
    xdiffblocks: Optional[intmod.BDiffBlocksFnc] = None