diff --git a/_prepare_dev_data.py b/_prepare_dev_data.py index 135c557..2583517 100755 --- a/_prepare_dev_data.py +++ b/_prepare_dev_data.py @@ -2,6 +2,7 @@ """ Script for building test DAWGs. """ + import struct import dawg @@ -40,7 +41,6 @@ def create_int_completion_dawg(): def build_test_data() -> None: - dawg.CompletionDAWG(["f", "bar", "foo", "foobar"]).save("dev_data/small/completion.dawg") dawg.CompletionDAWG([]).save("dev_data/small/completion-empty.dawg") diff --git a/bench/speed.py b/bench/speed.py index 84b1973..cd2790e 100644 --- a/bench/speed.py +++ b/bench/speed.py @@ -69,7 +69,6 @@ def load_int_dawg(): def benchmark() -> None: - tests = [ ("__getitem__ (hits)", "for word in WORDS100k: data[word]", "M ops/sec", 0.1, 3), ("get() (hits)", "for word in WORDS100k: data.get(word)", "M ops/sec", 0.1, 3), @@ -109,14 +108,14 @@ def benchmark() -> None: # DAWG-specific benchmarks for struct_name, setup in structures[1:]: - _bench_data = [ + _bench_data_pairs = [ ("hits", "WORDS100k"), ("mixed", "MIXED_WORDS100k"), ("misses", "NON_WORDS100k"), ] for meth in ["prefixes"]: - for name, data in _bench_data: + for name, data in _bench_data_pairs: bench( f"{struct_name}.{meth} ({name})", timeit.Timer( @@ -126,14 +125,14 @@ def benchmark() -> None: runs=3, ) - _bench_data = [ + _bench_data_triples = [ ("xxx", "avg_len(res)==415", "PREFIXES_3_1k"), ("xxxxx", "avg_len(res)==17", "PREFIXES_5_1k"), ("xxxxxxxx", "avg_len(res)==3", "PREFIXES_8_1k"), ("xxxxx..xx", "avg_len(res)==1.4", "PREFIXES_15_1k"), ("xxx", "NON_EXISTING", "NON_WORDS_1k"), ] - for xxx, avg, data in _bench_data: + for xxx, avg, data in _bench_data_triples: for meth in ["keys", "items"]: bench( f'{struct_name}.{meth}(prefix="{xxx}"), {avg}', diff --git a/dawg_python/dawgs.py b/dawg_python/dawgs.py index 64bcb02..c993db9 100644 --- a/dawg_python/dawgs.py +++ b/dawg_python/dawgs.py @@ -1,34 +1,47 @@ +from __future__ import annotations + import struct from binascii import a2b_base64 +from typing import TYPE_CHECKING from . import wrapper +if TYPE_CHECKING: + from pathlib import Path + from typing import Any, Iterator, Mapping + + from typing_extensions import Self, TypeAlias + + Replaces: TypeAlias = Mapping[str, str | list[str]] + CompiledReplaces: TypeAlias = Mapping[str, list[tuple[bytes, str]]] + class DAWG: """ Base DAWG wrapper. """ + dct: wrapper.Dictionary | None + def __init__(self) -> None: self.dct = None - def __contains__(self, key) -> bool: + def __contains__(self, key: str | bytes) -> bool: if not isinstance(key, bytes): key = key.encode("utf8") return self.dct.contains(key) - def load(self, path): + def load(self, path: str | Path) -> Self: """ Loads DAWG from a file. """ self.dct = wrapper.Dictionary.load(path) return self - def _has_value(self, index): + def _has_value(self, index: int) -> bool: return self.dct.has_value(index) - def _similar_keys(self, current_prefix, key, index, replace_chars): - + def _similar_keys(self, current_prefix: str, key: str, index: int, replace_chars: CompiledReplaces) -> list[str]: res = [] start_pos = len(current_prefix) end_pos = len(key) @@ -38,7 +51,7 @@ def _similar_keys(self, current_prefix, key, index, replace_chars): b_step = key[word_pos].encode("utf8") if b_step in replace_chars: - for (b_replace_char, u_replace_char) in replace_chars[b_step]: + for b_replace_char, u_replace_char in replace_chars[b_step]: next_index = index next_index = self.dct.follow_bytes(b_replace_char, next_index) @@ -60,7 +73,7 @@ def _similar_keys(self, current_prefix, key, index, replace_chars): return res - def similar_keys(self, key, replaces): + def similar_keys(self, key: str, replaces: CompiledReplaces) -> list[str]: """ Returns all variants of ``key`` in this DAWG according to ``replaces``. @@ -74,26 +87,22 @@ def similar_keys(self, key, replaces): """ return self._similar_keys("", key, self.dct.ROOT, replaces) - @classmethod - def compile_replaces(cls, replaces): - - for k,v in replaces.items(): + @staticmethod + def compile_replaces(replaces: Replaces) -> CompiledReplaces: + for k, v in replaces.items(): if len(k) != 1: msg = "Keys must be single-char unicode strings." raise ValueError(msg) - if (isinstance(v, str) and len(v) != 1): + if isinstance(v, str) and len(v) != 1: msg = "Values must be single-char unicode strings or non-empty lists of such." raise ValueError(msg) if isinstance(v, list) and (any(len(v_entry) != 1 for v_entry in v) or len(v) < 1): msg = "Values must be single-char unicode strings or non-empty lists of such." raise ValueError(msg) - return { - k.encode("utf8"): [(v_entry.encode("utf8"), v_entry) for v_entry in v] - for k, v in replaces.items() - } + return {k.encode("utf8"): [(v_entry.encode("utf8"), v_entry) for v_entry in v] for k, v in replaces.items()} - def prefixes(self, key): + def prefixes(self, key: str | bytes) -> list[str]: """ Returns a list with keys of this DAWG that are prefixes of the ``key``. """ @@ -121,28 +130,16 @@ class CompletionDAWG(DAWG): DAWG with key completion support. """ + guide: wrapper.Guide | None + def __init__(self) -> None: super().__init__() self.guide = None - def keys(self, prefix=""): - b_prefix = prefix.encode("utf8") - res = [] - - index = self.dct.follow_bytes(b_prefix, self.dct.ROOT) - if index is None: - return res - - completer = wrapper.Completer(self.dct, self.guide) - completer.start(index, b_prefix) - - while completer.next(): - key = completer.key.decode("utf8") - res.append(key) + def keys(self, prefix: str = "") -> list[str]: + return list(self.iterkeys(prefix)) - return res - - def iterkeys(self, prefix=""): + def iterkeys(self, prefix: str = "") -> Iterator[str]: b_prefix = prefix.encode("utf8") index = self.dct.follow_bytes(b_prefix, self.dct.ROOT) if index is None: @@ -154,7 +151,7 @@ def iterkeys(self, prefix=""): while completer.next(): yield completer.key.decode("utf8") - def load(self, path): + def load(self, path: str | Path) -> Self: """ Loads DAWG from a file. """ @@ -181,22 +178,22 @@ class BytesDAWG(CompletionDAWG): {unicode -> list of bytes objects} mapping. """ - def __init__(self, payload_separator=PAYLOAD_SEPARATOR) -> None: + def __init__(self, payload_separator: bytes = PAYLOAD_SEPARATOR) -> None: super().__init__() self._payload_separator = payload_separator - def __contains__(self, key) -> bool: + def __contains__(self, key: str | bytes) -> bool: if not isinstance(key, bytes): key = key.encode("utf8") return bool(self._follow_key(key)) - def __getitem__(self, key): + def __getitem__(self, key: str | bytes) -> list[bytes]: res = self.get(key) if res is None: raise KeyError(key) return res - def get(self, key, default=None): + def get(self, key: str | bytes, default: list[bytes] | None = None) -> list[bytes] | None: """ Returns a list of payloads (as byte objects) for a given key or ``default`` if the key is not found. @@ -206,18 +203,18 @@ def get(self, key, default=None): return self.b_get_value(key) or default - def _follow_key(self, b_key): + def _follow_key(self, b_key: bytes) -> int | None: index = self.dct.follow_bytes(b_key, self.dct.ROOT) if not index: - return False + return None index = self.dct.follow_bytes(self._payload_separator, index) if not index: - return False + return None return index - def _value_for_index(self, index): + def _value_for_index(self, index: int) -> list[bytes]: res = [] completer = wrapper.Completer(self.dct, self.guide) @@ -229,34 +226,16 @@ def _value_for_index(self, index): return res - def b_get_value(self, b_key): + def b_get_value(self, b_key: bytes) -> list[bytes]: index = self._follow_key(b_key) if not index: return [] return self._value_for_index(index) - def keys(self, prefix=""): - if not isinstance(prefix, bytes): - prefix = prefix.encode("utf8") - res = [] + def keys(self, prefix: str | bytes = "") -> list[str]: + return list(self.iterkeys(prefix)) - index = self.dct.ROOT - - if prefix: - index = self.dct.follow_bytes(prefix, index) - if not index: - return res - - completer = wrapper.Completer(self.dct, self.guide) - completer.start(index, prefix) - - while completer.next(): - payload_idx = completer.key.index(self._payload_separator) - u_key = completer.key[:payload_idx].decode("utf8") - res.append(u_key) - return res - - def iterkeys(self, prefix=""): + def iterkeys(self, prefix: str | bytes = "") -> Iterator[bytes]: if not isinstance(prefix, bytes): prefix = prefix.encode("utf8") @@ -275,27 +254,10 @@ def iterkeys(self, prefix=""): u_key = completer.key[:payload_idx].decode("utf8") yield u_key - def items(self, prefix=""): - if not isinstance(prefix, bytes): - prefix = prefix.encode("utf8") - res = [] - - index = self.dct.ROOT - if prefix: - index = self.dct.follow_bytes(prefix, index) - if not index: - return res - - completer = wrapper.Completer(self.dct, self.guide) - completer.start(index, prefix) - - while completer.next(): - key, value = completer.key.split(self._payload_separator) - res.append((key.decode("utf8"), a2b_base64(value))) - - return res + def items(self, prefix: str | bytes = "") -> list[tuple[str, bytes]]: + return list(self.iteritems(prefix)) - def iteritems(self, prefix=""): + def iteritems(self, prefix: str | bytes = "") -> Iterator[tuple[str, bytes]]: if not isinstance(prefix, bytes): prefix = prefix.encode("utf8") @@ -313,11 +275,16 @@ def iteritems(self, prefix=""): item = (key.decode("utf8"), a2b_base64(value)) yield item - def _has_value(self, index): + def _has_value(self, index: int) -> int | None: return self.dct.follow_bytes(PAYLOAD_SEPARATOR, index) - def _similar_items(self, current_prefix, key, index, replace_chars): - + def _similar_items( + self, + current_prefix: str, + key: str, + index: int, + replace_chars: CompiledReplaces, + ) -> list[tuple[str, bytes]]: res = [] start_pos = len(current_prefix) end_pos = len(key) @@ -327,7 +294,7 @@ def _similar_items(self, current_prefix, key, index, replace_chars): b_step = key[word_pos].encode("utf8") if b_step in replace_chars: - for (b_replace_char, u_replace_char) in replace_chars[b_step]: + for b_replace_char, u_replace_char in replace_chars[b_step]: next_index = index next_index = self.dct.follow_bytes(b_replace_char, next_index) @@ -351,7 +318,7 @@ def _similar_items(self, current_prefix, key, index, replace_chars): return res - def similar_items(self, key, replaces): + def similar_items(self, key: str, replaces: CompiledReplaces) -> list[tuple[str, bytes]]: """ Returns a list of (key, value) tuples for all variants of ``key`` in this DAWG according to ``replaces``. @@ -363,7 +330,13 @@ def similar_items(self, key, replaces): """ return self._similar_items("", key, self.dct.ROOT, replaces) - def _similar_item_values(self, start_pos, key, index, replace_chars): + def _similar_item_values( + self, + start_pos: int, + key: str, + index: int, + replace_chars: CompiledReplaces, + ) -> list[bytes]: res = [] end_pos = len(key) word_pos = start_pos @@ -372,7 +345,7 @@ def _similar_item_values(self, start_pos, key, index, replace_chars): b_step = key[word_pos].encode("utf8") if b_step in replace_chars: - for (b_replace_char, _u_replace_char) in replace_chars[b_step]: + for b_replace_char, _u_replace_char in replace_chars[b_step]: next_index = index next_index = self.dct.follow_bytes(b_replace_char, next_index) @@ -394,7 +367,7 @@ def _similar_item_values(self, start_pos, key, index, replace_chars): return res - def similar_item_values(self, key, replaces): + def similar_item_values(self, key: str, replaces: CompiledReplaces) -> list[bytes]: """ Returns a list of values for all variants of the ``key`` in this DAWG according to ``replaces``. @@ -408,20 +381,19 @@ def similar_item_values(self, key, replaces): class RecordDAWG(BytesDAWG): - def __init__(self, fmt, payload_separator=PAYLOAD_SEPARATOR) -> None: + def __init__(self, fmt: str | bytes, payload_separator: bytes = PAYLOAD_SEPARATOR) -> None: super().__init__(payload_separator) - self._struct = struct.Struct(str(fmt)) + self._struct = struct.Struct(fmt) self.fmt = fmt - def _value_for_index(self, index): + def _value_for_index(self, index: int) -> list[tuple[Any, ...]]: value = super()._value_for_index(index) return [self._struct.unpack(val) for val in value] - def items(self, prefix=""): - res = super().items(prefix) - return [(key, self._struct.unpack(val)) for (key, val) in res] + def items(self, prefix: str | bytes = "") -> list[tuple[str, tuple[Any, ...]]]: + return list(self.iteritems(prefix)) - def iteritems(self, prefix=""): + def iteritems(self, prefix: str | bytes = "") -> Iterator[tuple[str, tuple[Any, ...]]]: res = super().iteritems(prefix) return ((key, self._struct.unpack(val)) for (key, val) in res) @@ -435,13 +407,13 @@ class IntDAWG(DAWG): It can store integer values for unicode keys. """ - def __getitem__(self, key): + def __getitem__(self, key: str | bytes) -> int | None: res = self.get(key, LOOKUP_ERROR) if res == LOOKUP_ERROR: raise KeyError(key) return res - def get(self, key, default=None): + def get(self, key: str | bytes, default: int | None = None) -> int | None: """ Return value for the given key or ``default`` if the key is not found. """ @@ -452,7 +424,7 @@ def get(self, key, default=None): return default return res - def b_get_value(self, key): + def b_get_value(self, key: bytes) -> int: return self.dct.find(key) @@ -462,26 +434,10 @@ class IntCompletionDAWG(CompletionDAWG, IntDAWG): It can store integer values for unicode keys and support key completion. """ - def items(self, prefix=""): - if not isinstance(prefix, bytes): - prefix = prefix.encode("utf8") - res = [] - index = self.dct.ROOT - - if prefix: - index = self.dct.follow_bytes(prefix, index) - if not index: - return res - - completer = wrapper.Completer(self.dct, self.guide) - completer.start(index, prefix) - - while completer.next(): - res.append((completer.key.decode("utf8"), completer.value())) - - return res + def items(self, prefix: str | bytes = "") -> list[tuple[str, int]]: + return list(self.iteritems(prefix)) - def iteritems(self, prefix=""): + def iteritems(self, prefix: str | bytes = "") -> Iterator[tuple[str, int]]: if not isinstance(prefix, bytes): prefix = prefix.encode("utf8") index = self.dct.ROOT diff --git a/dawg_python/units.py b/dawg_python/units.py index b2df91e..50dd411 100644 --- a/dawg_python/units.py +++ b/dawg_python/units.py @@ -1,6 +1,7 @@ """ Unit of a dictionary """ + PRECISION_MASK = 0xFFFFFFFF OFFSET_MAX = 1 << 21 @@ -9,21 +10,21 @@ EXTENSION_BIT = 1 << 9 -def has_leaf(base, _mask=HAS_LEAF_BIT): +def has_leaf(base: int, _mask: int = HAS_LEAF_BIT) -> bool: """Check if a unit has a leaf as a child or not.""" return bool(base & _mask) -def value(base, _mask=~IS_LEAF_BIT & PRECISION_MASK): +def value(base: int, _mask: int = ~IS_LEAF_BIT & PRECISION_MASK) -> int: """Check if a unit corresponds to a leaf or not.""" return base & _mask -def label(base, _mask=IS_LEAF_BIT | 0xFF): +def label(base: int, _mask: int = IS_LEAF_BIT | 0xFF) -> int: """Read a label with a leaf flag from a non-leaf unit.""" return base & _mask -def offset(base): +def offset(base: int) -> int: """Read an offset to child units from a non-leaf unit.""" return ((base >> 10) << ((base & EXTENSION_BIT) >> 6)) & PRECISION_MASK diff --git a/dawg_python/wrapper.py b/dawg_python/wrapper.py index 3d77243..9d16134 100644 --- a/dawg_python/wrapper.py +++ b/dawg_python/wrapper.py @@ -1,8 +1,17 @@ +from __future__ import annotations + import array import struct +from typing import TYPE_CHECKING from . import units +if TYPE_CHECKING: + from io import BytesIO + from pathlib import Path + + from typing_extensions import Self + class Dictionary: """ @@ -15,29 +24,29 @@ def __init__(self) -> None: ROOT = 0 "Root index" - def has_value(self, index): + def has_value(self, index: int) -> bool: """Checks if a given index is related to the end of a key.""" return units.has_leaf(self._units[index]) - def value(self, index): + def value(self, index: int) -> int: """Gets a value from a given index.""" offset = units.offset(self._units[index]) value_index = (index ^ offset) & units.PRECISION_MASK return units.value(self._units[value_index]) - def read(self, fp) -> None: + def read(self, fp: BytesIO) -> None: """Reads a dictionary from an input stream.""" base_size = struct.unpack("=I", fp.read(4))[0] self._units.fromfile(fp, base_size) - def contains(self, key): + def contains(self, key: bytes) -> bool: """Exact matching.""" index = self.follow_bytes(key, self.ROOT) if index is None: return False return self.has_value(index) - def find(self, key): + def find(self, key: bytes) -> int: """Exact matching (returns value)""" index = self.follow_bytes(key, self.ROOT) if index is None: @@ -46,7 +55,7 @@ def find(self, key): return -1 return self.value(index) - def follow_char(self, label, index): + def follow_char(self, label: int, index: int) -> int | None: """Follows a transition""" offset = units.offset(self._units[index]) next_index = (index ^ offset ^ label) & units.PRECISION_MASK @@ -56,7 +65,7 @@ def follow_char(self, label, index): return next_index - def follow_bytes(self, s, index): + def follow_bytes(self, s: bytes, index: int) -> int | None: """Follows transitions.""" for ch in s: index = self.follow_char(ch, index) @@ -66,7 +75,7 @@ def follow_bytes(self, s, index): return index @classmethod - def load(cls, path): + def load(cls, path: str | Path) -> Self: dawg = cls() with open(path, "rb") as f: dawg.read(f) @@ -74,35 +83,37 @@ def load(cls, path): class Guide: - ROOT = 0 def __init__(self) -> None: self._units = array.array("B") - def child(self, index): + def child(self, index: int) -> int: return self._units[index * 2] - def sibling(self, index): + def sibling(self, index: int) -> int: return self._units[index * 2 + 1] - def read(self, fp) -> None: + def read(self, fp: BytesIO) -> None: base_size = struct.unpack("=I", fp.read(4))[0] self._units.fromfile(fp, base_size * 2) - def size(self): + def size(self) -> int: return len(self._units) class Completer: - def __init__(self, dic=None, guide=None) -> None: + _dic: Dictionary | None + _guide: Guide | None + + def __init__(self, dic: Dictionary | None = None, guide: Guide | None = None) -> None: self._dic = dic self._guide = guide - def value(self): + def value(self) -> int: return self._dic.value(self._last_index) - def start(self, index, prefix=b"") -> None: + def start(self, index: int, prefix: bytes = b"") -> None: self.key = bytearray(prefix) if self._guide.size(): @@ -111,7 +122,7 @@ def start(self, index, prefix=b"") -> None: else: self._index_stack = [] - def next(self): + def next(self) -> bool: "Gets the next key" if not self._index_stack: @@ -120,7 +131,6 @@ def next(self): index = self._index_stack[-1] if self._last_index != self._dic.ROOT: - child_label = self._guide.child(index) # UCharType if child_label: @@ -149,7 +159,7 @@ def next(self): return self._find_terminal(index) - def _follow(self, label, index): + def _follow(self, label: int, index: int) -> int | None: next_index = self._dic.follow_char(label, index) if next_index is None: return None @@ -158,7 +168,7 @@ def _follow(self, label, index): self._index_stack.append(next_index) return next_index - def _find_terminal(self, index) -> bool: + def _find_terminal(self, index: int) -> bool: while not self._dic.has_value(index): label = self._guide.child(index) diff --git a/poetry.lock b/poetry.lock index 613c30f..ae179b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand. [[package]] name = "colorama" @@ -6,6 +6,8 @@ version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["dev"] +markers = "sys_platform == \"win32\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -13,63 +15,84 @@ files = [ [[package]] name = "coverage" -version = "7.6.0" +version = "7.6.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "coverage-7.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dff044f661f59dace805eedb4a7404c573b6ff0cdba4a524141bc63d7be5c7fd"}, - {file = "coverage-7.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8659fd33ee9e6ca03950cfdcdf271d645cf681609153f218826dd9805ab585c"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7792f0ab20df8071d669d929c75c97fecfa6bcab82c10ee4adb91c7a54055463"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4b3cd1ca7cd73d229487fa5caca9e4bc1f0bca96526b922d61053ea751fe791"}, - {file = "coverage-7.6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7e128f85c0b419907d1f38e616c4f1e9f1d1b37a7949f44df9a73d5da5cd53c"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a94925102c89247530ae1dab7dc02c690942566f22e189cbd53579b0693c0783"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dcd070b5b585b50e6617e8972f3fbbee786afca71b1936ac06257f7e178f00f6"}, - {file = "coverage-7.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d50a252b23b9b4dfeefc1f663c568a221092cbaded20a05a11665d0dbec9b8fb"}, - {file = "coverage-7.6.0-cp310-cp310-win32.whl", hash = "sha256:0e7b27d04131c46e6894f23a4ae186a6a2207209a05df5b6ad4caee6d54a222c"}, - {file = "coverage-7.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dece71673b3187c86226c3ca793c5f891f9fc3d8aa183f2e3653da18566169"}, - {file = "coverage-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7b525ab52ce18c57ae232ba6f7010297a87ced82a2383b1afd238849c1ff933"}, - {file = "coverage-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bea27c4269234e06f621f3fac3925f56ff34bc14521484b8f66a580aacc2e7d"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed8d1d1821ba5fc88d4a4f45387b65de52382fa3ef1f0115a4f7a20cdfab0e94"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01c322ef2bbe15057bc4bf132b525b7e3f7206f071799eb8aa6ad1940bcf5fb1"}, - {file = "coverage-7.6.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03cafe82c1b32b770a29fd6de923625ccac3185a54a5e66606da26d105f37dac"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0d1b923fc4a40c5832be4f35a5dab0e5ff89cddf83bb4174499e02ea089daf57"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4b03741e70fb811d1a9a1d75355cf391f274ed85847f4b78e35459899f57af4d"}, - {file = "coverage-7.6.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a73d18625f6a8a1cbb11eadc1d03929f9510f4131879288e3f7922097a429f63"}, - {file = "coverage-7.6.0-cp311-cp311-win32.whl", hash = "sha256:65fa405b837060db569a61ec368b74688f429b32fa47a8929a7a2f9b47183713"}, - {file = "coverage-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:6379688fb4cfa921ae349c76eb1a9ab26b65f32b03d46bb0eed841fd4cb6afb1"}, - {file = "coverage-7.6.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f7db0b6ae1f96ae41afe626095149ecd1b212b424626175a6633c2999eaad45b"}, - {file = "coverage-7.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bbdf9a72403110a3bdae77948b8011f644571311c2fb35ee15f0f10a8fc082e8"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc44bf0315268e253bf563f3560e6c004efe38f76db03a1558274a6e04bf5d5"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da8549d17489cd52f85a9829d0e1d91059359b3c54a26f28bec2c5d369524807"}, - {file = "coverage-7.6.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0086cd4fc71b7d485ac93ca4239c8f75732c2ae3ba83f6be1c9be59d9e2c6382"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1fad32ee9b27350687035cb5fdf9145bc9cf0a094a9577d43e909948ebcfa27b"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:044a0985a4f25b335882b0966625270a8d9db3d3409ddc49a4eb00b0ef5e8cee"}, - {file = "coverage-7.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:76d5f82213aa78098b9b964ea89de4617e70e0d43e97900c2778a50856dac605"}, - {file = "coverage-7.6.0-cp312-cp312-win32.whl", hash = "sha256:3c59105f8d58ce500f348c5b56163a4113a440dad6daa2294b5052a10db866da"}, - {file = "coverage-7.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca5d79cfdae420a1d52bf177de4bc2289c321d6c961ae321503b2ca59c17ae67"}, - {file = "coverage-7.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d39bd10f0ae453554798b125d2f39884290c480f56e8a02ba7a6ed552005243b"}, - {file = "coverage-7.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:beb08e8508e53a568811016e59f3234d29c2583f6b6e28572f0954a6b4f7e03d"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2e16f4cd2bc4d88ba30ca2d3bbf2f21f00f382cf4e1ce3b1ddc96c634bc48ca"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6616d1c9bf1e3faea78711ee42a8b972367d82ceae233ec0ac61cc7fec09fa6b"}, - {file = "coverage-7.6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad4567d6c334c46046d1c4c20024de2a1c3abc626817ae21ae3da600f5779b44"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d17c6a415d68cfe1091d3296ba5749d3d8696e42c37fca5d4860c5bf7b729f03"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9146579352d7b5f6412735d0f203bbd8d00113a680b66565e205bc605ef81bc6"}, - {file = "coverage-7.6.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:cdab02a0a941af190df8782aafc591ef3ad08824f97850b015c8c6a8b3877b0b"}, - {file = "coverage-7.6.0-cp38-cp38-win32.whl", hash = "sha256:df423f351b162a702c053d5dddc0fc0ef9a9e27ea3f449781ace5f906b664428"}, - {file = "coverage-7.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:f2501d60d7497fd55e391f423f965bbe9e650e9ffc3c627d5f0ac516026000b8"}, - {file = "coverage-7.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7221f9ac9dad9492cecab6f676b3eaf9185141539d5c9689d13fd6b0d7de840c"}, - {file = "coverage-7.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ddaaa91bfc4477d2871442bbf30a125e8fe6b05da8a0015507bfbf4718228ab2"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4cbe651f3904e28f3a55d6f371203049034b4ddbce65a54527a3f189ca3b390"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:831b476d79408ab6ccfadaaf199906c833f02fdb32c9ab907b1d4aa0713cfa3b"}, - {file = "coverage-7.6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c3d091059ad0b9c59d1034de74a7f36dcfa7f6d3bde782c49deb42438f2450"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4d5fae0a22dc86259dee66f2cc6c1d3e490c4a1214d7daa2a93d07491c5c04b6"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:07ed352205574aad067482e53dd606926afebcb5590653121063fbf4e2175166"}, - {file = "coverage-7.6.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:49c76cdfa13015c4560702574bad67f0e15ca5a2872c6a125f6327ead2b731dd"}, - {file = "coverage-7.6.0-cp39-cp39-win32.whl", hash = "sha256:482855914928c8175735a2a59c8dc5806cf7d8f032e4820d52e845d1f731dca2"}, - {file = "coverage-7.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:543ef9179bc55edfd895154a51792b01c017c87af0ebaae092720152e19e42ca"}, - {file = "coverage-7.6.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:6fe885135c8a479d3e37a7aae61cbd3a0fb2deccb4dda3c25f92a49189f766d6"}, - {file = "coverage-7.6.0.tar.gz", hash = "sha256:289cc803fa1dc901f84701ac10c9ee873619320f2f9aff38794db4a4a0268d51"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, ] [package.dependencies] @@ -84,6 +107,7 @@ version = "0.13.1" description = "Fast and memory efficient DAWG (DAFSA) for Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "DAWG2-0.13.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86a7068d70d22f29e66789e3dc0ebd82d810ff84d819b3421b4945496c0186bb"}, {file = "DAWG2-0.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:37d1f4a676d4405f561a8303fbb274d475d41178c4b4199da820e63f275fe2ff"}, @@ -142,6 +166,8 @@ version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version < \"3.11\"" files = [ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, @@ -152,13 +178,15 @@ test = ["pytest (>=6)"] [[package]] name = "flake8" -version = "7.1.1" +version = "7.1.2" description = "the modular source code checker: pep8 pyflakes and co" optional = false python-versions = ">=3.8.1" +groups = ["dev"] +markers = "python_full_version >= \"3.8.1\"" files = [ - {file = "flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213"}, - {file = "flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38"}, + {file = "flake8-7.1.2-py2.py3-none-any.whl", hash = "sha256:1cbc62e65536f65e6d754dfe6f1bada7f5cf392d6f5db3c2b85892466c3e7c1a"}, + {file = "flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd"}, ] [package.dependencies] @@ -172,6 +200,7 @@ version = "2.0.0" description = "brain-dead simple config-ini parsing" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, @@ -183,6 +212,8 @@ version = "0.7.0" description = "McCabe checker, plugin for flake8" optional = false python-versions = ">=3.6" +groups = ["dev"] +markers = "python_full_version >= \"3.8.1\"" files = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, @@ -190,13 +221,14 @@ files = [ [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -205,6 +237,7 @@ version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, @@ -216,13 +249,15 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pycodestyle" -version = "2.12.0" +version = "2.12.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_full_version >= \"3.8.1\"" files = [ - {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, - {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, + {file = "pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3"}, + {file = "pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521"}, ] [[package]] @@ -231,6 +266,8 @@ version = "3.2.0" description = "passive checker of Python programs" optional = false python-versions = ">=3.8" +groups = ["dev"] +markers = "python_full_version >= \"3.8.1\"" files = [ {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, @@ -242,6 +279,7 @@ version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, @@ -264,6 +302,7 @@ version = "5.0.0" description = "Pytest plugin for measuring coverage." optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, @@ -282,6 +321,7 @@ version = "0.9.4" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "ruff-0.9.4-py3-none-linux_armv6l.whl", hash = "sha256:64e73d25b954f71ff100bb70f39f1ee09e880728efb4250c632ceed4e4cdf706"}, {file = "ruff-0.9.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6ce6743ed64d9afab4fafeaea70d3631b4d4b28b592db21a5c2d1f0ef52934bf"}, @@ -305,16 +345,61 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_full_version <= \"3.11.0a6\"" +files = [ + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "python_version < \"3.11\"" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [metadata] -lock-version = "2.0" +lock-version = "2.1" python-versions = "^3.8" -content-hash = "71e63adaf5db81d1cf3b4bdea92da6db84b814d7d6870fd00bed13e5ca516fbf" +content-hash = "fa18dea0d8bdf4f1786d1cf2a843f9a494c2a8a33da8dbbc9905565a8639ecb5" diff --git a/pyproject.toml b/pyproject.toml index 9eb7267..2b9c61c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ repository = "https://github.com/pymorphy2-fork/DAWG-Python/" [tool.poetry.dependencies] python = "^3.8" +typing-extensions = { version = ">=4.0", python = "<3.11" } [tool.poetry.group.dev.dependencies] flake8 = { version = ">=6.1,<8.0", python = "^3.8.1" } @@ -41,14 +42,7 @@ target-version = "py38" [tool.ruff.lint] select = ["ALL"] ignore = [ - "ANN001", - "ANN002", - "ANN201", - "ANN202", - "ANN204", - "ANN206", - # ^^^ Silence warnings about the type annotations for now - + "COM812", "D", "PTH123", ] @@ -56,6 +50,10 @@ fixable = ["ALL"] [tool.ruff.lint.per-file-ignores] "_prepare_dev_data.py" = [ + "ANN001", + "ANN002", + "ANN201", + "ANN202", "ERA001", ] @@ -64,6 +62,10 @@ fixable = ["ALL"] ] "bench/*" = [ + "ANN001", + "ANN002", + "ANN201", + "ANN202", "ERA001", "PERF401", "PLR0913", @@ -82,4 +84,4 @@ fixable = ["ALL"] "S101", "S301", "S324", -] \ No newline at end of file +] diff --git a/tests/test_payload_dawg.py b/tests/test_payload_dawg.py index 5378548..d4e7a04 100644 --- a/tests/test_payload_dawg.py +++ b/tests/test_payload_dawg.py @@ -6,7 +6,6 @@ class TestBytesDAWG: - DATA = ( ("foo", b"data1"), ("bar", b"data2"), @@ -82,7 +81,6 @@ def test_prefixes(self): class TestRecordDAWG: - STRUCTURED_DATA = ( ("foo", (3, 2, 256)), ("bar", (3, 1, 0)), diff --git a/tests/test_prediction.py b/tests/test_prediction.py index b7b8a36..8b988ac 100644 --- a/tests/test_prediction.py +++ b/tests/test_prediction.py @@ -13,7 +13,6 @@ def encode(w): class TestPrediction: - REPLACES = dawg_python.DAWG.compile_replaces({"Е": "Ё"}) DATA = ["ЁЖИК", "ЁЖИКЕ", "ЁЖ", "ДЕРЕВНЯ", "ДЕРЁВНЯ", "ЕМ", "ОЗЕРА", "ОЗЁРА", "ОЗЕРО"] @@ -73,7 +72,6 @@ def test_record_dawg_items_values(self, word, prediction): class TestMultiValuedPrediction: - REPLACES = dawg_python.DAWG.compile_replaces({"е": ["ё", "ѣ"], "и": "і"}) DATA = "хлѣб ёлка ель лѣс лѣсное всё всѣ бѣлёная изобрѣтён лев лёв лѣв вѣнскій".split(" ") @@ -101,9 +99,9 @@ class TestMultiValuedPrediction: SUITE_ITEMS = [ ( - it[0], # key + it[0], # key [ - (w, [encode(w)]) # item, value pair + (w, [encode(w)]) # item, value pair for w in it[1] ], ) @@ -112,7 +110,7 @@ class TestMultiValuedPrediction: SUITE_VALUES = [ ( - it[0], # key + it[0], # key [[encode(w)] for w in it[1]], ) for it in SUITE