##// END OF EJS Templates
scmutil: explicitly subclass the `Status` protocol...
scmutil: explicitly subclass the `Status` protocol We shouldn't have to explicitly subclass, but PyCharm has a nifty feature that puts a jump point in the gutter to navigate back and forth between the base class and subclasses (and override functions and base class functions) when there's an explicit subclassing. Additionally, PyCharm will immediately flag signature mismatches without a 40m pytype run. It was also hoped that with explicit subclassing, we would get interface checking for free. Unfortunately when I tried adding methods and fields to the Protocol class to test this theory, pytype happily accepted an assignment of the concrete class without the new field and methods, to a variable annotated with the Protocol class with them. It appears that this is what happens when explicit subclassing is used, since dropping that caused pytype to complain. By making the methods abstract here like the `mercurial.wireprototypes` classes in fd200f5bcaea, pytype will complain in that case outlined that a subclass with abstract methods (not replaced by the subclass itself) cannot be instantiated. That doesn't help with the fields. Making an `abstractproperty` likely isn't appropriate in general, because that effectively becomes a read-only property. This seems like a pretty gaping hole, but I think the benefits of explicit subclassing are worth the risk. (Though I guess it shouldn't be surprising, because a class can be both a Protocol and an implementation, so subclassing something with an empty body method doesn't really signal that it is a requirement for the subclass to implement.)

File last commit:

r52827:09f3a679 default
r53348:f5d134e5 default
Show More
bdiff.py
104 lines | 2.8 KiB | text/x-python | PythonLexer
# bdiff.py - CFFI implementation of bdiff.c
#
# Copyright 2016 Maciej Fijalkowski <fijall@gmail.com>
#
# 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 struct
import typing
from typing import (
List,
Optional,
Tuple,
)
from ..pure.bdiff import *
from ..interfaces import (
modules as intmod,
)
from . import _bdiff # pytype: disable=import-error
ffi = _bdiff.ffi
lib = _bdiff.lib
def blocks(sa: bytes, sb: bytes) -> List[Tuple[int, int, int, int]]:
a = ffi.new("struct bdiff_line**")
b = ffi.new("struct bdiff_line**")
ac = ffi.new("char[]", bytes(sa))
bc = ffi.new("char[]", bytes(sb))
l = ffi.new("struct bdiff_hunk*")
try:
an = lib.bdiff_splitlines(ac, len(sa), a)
bn = lib.bdiff_splitlines(bc, len(sb), b)
if not a[0] or not b[0]:
raise MemoryError
count = lib.bdiff_diff(a[0], an, b[0], bn, l)
if count < 0:
raise MemoryError
rl = [(0, 0, 0, 0)] * count
h = l.next
i = 0
while h:
rl[i] = (h.a1, h.a2, h.b1, h.b2)
h = h.next
i += 1
finally:
lib.free(a[0])
lib.free(b[0])
lib.bdiff_freehunks(l.next)
return rl
def bdiff(sa: bytes, sb: bytes) -> bytes:
a = ffi.new("struct bdiff_line**")
b = ffi.new("struct bdiff_line**")
ac = ffi.new("char[]", bytes(sa))
bc = ffi.new("char[]", bytes(sb))
l = ffi.new("struct bdiff_hunk*")
try:
an = lib.bdiff_splitlines(ac, len(sa), a)
bn = lib.bdiff_splitlines(bc, len(sb), b)
if not a[0] or not b[0]:
raise MemoryError
count = lib.bdiff_diff(a[0], an, b[0], bn, l)
if count < 0:
raise MemoryError
rl = []
h = l.next
la = lb = 0
while h:
if h.a1 != la or h.b1 != lb:
lgt = (b[0] + h.b1).l - (b[0] + lb).l
rl.append(
struct.pack(
b">lll",
(a[0] + la).l - a[0].l,
(a[0] + h.a1).l - a[0].l,
lgt,
)
)
rl.append(bytes(ffi.buffer((b[0] + lb).l, lgt)))
la = h.a2
lb = h.b2
h = h.next
finally:
lib.free(a[0])
lib.free(b[0])
lib.bdiff_freehunks(l.next)
return b"".join(rl)
# In order to adhere to the module protocol, these functions must be visible to
# the type checker, though they aren't actually implemented by this
# implementation of the module protocol. Callers are responsible for
# checking that the implementation is available before using them.
if typing.TYPE_CHECKING:
xdiffblocks: Optional[intmod.BDiffBlocksFnc] = None