add support for slices in Editops.__delitem__

This commit is contained in:
Max Bachmann 2022-08-18 22:44:47 +02:00
parent f9e04fc2a9
commit 9c25719946
6 changed files with 76 additions and 15 deletions

View File

@ -5,7 +5,7 @@
- fix hashing for custom classes
#### Added
- add support for slicing in `Editops.__getitem__`
- add support for slicing in `Editops.__getitem__`/`Editops.__delitem__`
### [2.5.0] - 2022-08-14
#### Added

@ -1 +1 @@
Subproject commit d937555ad76a6f1ed853ab4b7102a7b22b6f0fcf
Subproject commit ac6ae2e61ecd3b6fc19ac7568c2db7ad8b100a47

View File

@ -109,6 +109,7 @@ cdef extern from "rapidfuzz/details/types.hpp" namespace "rapidfuzz" nogil:
RfEditops inverse() except +
RfEditops remove_subsequence(const RfEditops& subsequence) except +
RfEditops slice(int, int, int) except +
void remove_slice(int, int, int) except +
int64_t get_src_len()
void set_src_len(int64_t)
int64_t get_dest_len()

View File

@ -1,4 +1,4 @@
from typing import Tuple, List, Union, Any
from typing import Tuple, List, Union
from . import (
Hamming as Hamming,
@ -50,7 +50,7 @@ class Editops:
def copy(self) -> Editops: ...
def inverse(self) -> Editops: ...
def remove_subsequence(self, subsequence: Editops) -> Editops: ...
def apply(self, source_string: str | bytes, destination_string: str | bytes) -> str: ...
def apply(self, source_string: Union[str, bytes], destination_string: Union[str, bytes]) -> str: ...
@property
def src_len(self) -> int: ...
@src_len.setter
@ -59,8 +59,8 @@ class Editops:
def dest_len(self) -> int: ...
@dest_len.setter
def dest_len(self, value: int) -> None: ...
def __delitem__(self, item: int) -> None: ...
def __getitem__(self, key: int) -> Editop: ...
def __delitem__(self, item: Union[int, slice]) -> None: ...
def __getitem__(self, key: Union[int, slice]) -> Editop: ...
def __repr__(self) -> str: ...
class Opcode:
@ -91,7 +91,7 @@ class Opcodes:
def __len__(self) -> int: ...
def copy(self) -> Opcodes: ...
def inverse(self) -> Opcodes: ...
def apply(self, source_string: str | bytes, destination_string: str | bytes) -> str: ...
def apply(self, source_string: Union[str, bytes], destination_string: Union[str, bytes]) -> str: ...
@property
def src_len(self) -> int: ...
@src_len.setter

View File

@ -500,15 +500,27 @@ cdef class Editops:
def __len__(self):
return self.editops.size()
def __delitem__(self, item):
cdef Py_ssize_t index = item
if index < 0:
index += <Py_ssize_t>self.editops.size()
def __delitem__(self, key):
cdef Py_ssize_t index
cdef Py_ssize_t start, stop, step
if index < 0 or index >= <Py_ssize_t>self.editops.size():
raise IndexError("Editops index out of range")
if isinstance(key, int):
index = key
if index < 0:
index += <Py_ssize_t>self.editops.size()
self.editops.erase(self.editops.begin() + index)
if index < 0 or index >= <Py_ssize_t>self.editops.size():
raise IndexError("Editops index out of range")
self.editops.erase(self.editops.begin() + index)
elif isinstance(key, slice):
start, stop, step = key.indices(<Py_ssize_t>self.editops.size())
if step < 0:
raise ValueError("step sizes below 0 lead to an invalid order of editops")
self.editops.remove_slice(start, stop, step)
else:
raise TypeError("Expected index or slice")
def __getitem__(self, key):
cdef Py_ssize_t index
@ -535,7 +547,7 @@ cdef class Editops:
(<Editops>x).editops = self.editops.slice(start, stop, step)
return x
else:
raise TypeError("Expected index")
raise TypeError("Expected index or slice")
def __repr__(self):
return "Editops([" + ", ".join(repr(op) for op in self) + f"], src_len={self.editops.get_src_len()}, dest_len={self.editops.get_dest_len()})"

View File

@ -71,6 +71,7 @@ def test_editops_get_index():
with pytest.raises(IndexError):
ops[-6]
def test_editops_get_slice():
"""
test __getitem__ with slice of Editops
@ -110,6 +111,53 @@ def test_editops_get_slice():
with pytest.raises(ValueError):
ops[::-1]
def test_editops_del_slice():
"""
test __delitem__ with slice of Editops
"""
ops = Editops(
[
("delete", 1, 1),
("replace", 2, 1),
("insert", 6, 5),
("insert", 6, 6),
("insert", 6, 7),
],
7,
9,
)
ops_list = [
("delete", 1, 1),
("replace", 2, 1),
("insert", 6, 5),
("insert", 6, 6),
("insert", 6, 7),
]
def del_test(key):
_ops = ops[::]
_ops_list = ops_list[::]
del _ops[key]
del _ops_list[key]
assert _ops.as_list() == _ops_list
del_test(slice(None, 4, None))
del_test(slice(1, None, None))
del_test(slice(1, 4, None))
del_test(slice(None, 4, 2))
del_test(slice(1, None, 2))
del_test(slice(1, 4, 2))
del_test(slice(None, -1, None))
del_test(slice(-4, None, None))
del_test(slice(-4, -1, None))
del_test(slice(None, -1, 2))
del_test(slice(-4, None, 2))
del_test(slice(-4, -1, 2))
def test_editops_inversion():
"""
test correct inversion of Editops