Coverage for src/gentrie/trie/base.py: 98%
39 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-08-17 11:24 -0700
« prev ^ index » next coverage.py v7.6.10, created at 2025-08-17 11:24 -0700
1# -*- coding: utf-8 -*-
2"""Base trie functionality and initialization."""
4from copy import deepcopy
5from textwrap import indent
6from typing import Any, Optional, TYPE_CHECKING
8from ..nodes import Node
9from ..protocols import TrieKeyToken
10from ..types import TrieEntry, TrieId
12if TYPE_CHECKING:
13 from .trie_mixins import TrieMixinsInterface
16class TrieBase:
17 """Base class providing core trie structure and utilities.
19 Properties:
20 runtime_validation (bool): Whether to enable runtime validation of keys.
21 """
23 def __init__(self, runtime_validation: bool = True) -> None:
24 """Initializes a new TrieBase instance.
26 By default, runtime validation of keys is enabled. If your code is well tested,
27 you can disable it for improved performance. How the code will react to invalid
28 keys when validation is disabled is not defined and may lead to unexpected
29 behavior.
31 Args:
32 runtime_validation (bool, default=True): Whether to enable runtime validation of keys.
34 """
35 self.runtime_validation: bool = bool(runtime_validation)
36 self.token: Optional[TrieKeyToken] = None
37 self.value: Optional[Any] = None
38 # The parent of the root node is always None.
39 # Typing it as the protocol interface makes it compatible with the
40 # final GeneralizedTrie class.
41 self.parent: Optional["TrieMixinsInterface"] = None
42 self.children: dict[TrieKeyToken, Node] = {}
43 self.ident: Optional[TrieId] = None
44 # Counter for the next unique identifier to assign to a key in the trie.
45 self._ident_counter: int = 0
46 # Mapping of unique identifiers to their corresponding trie nodes.
47 self._trie_index: dict[TrieId, Node] = {}
48 # Mapping of unique identifiers to their corresponding TrieEntry instances.
49 self._trie_entries: dict[TrieId, TrieEntry] = {}
51 def clear(self) -> None:
52 """Clears all keys from the trie."""
53 self.ident = None
54 self.token = None
55 self.value = None
56 self.parent = None
57 self.children.clear()
58 self._trie_index.clear()
59 self._trie_entries.clear()
60 # Reset the ident counter
61 self._ident_counter = 0
63 def __str__(self) -> str:
64 """Generates a stringified version of the trie for visual examination."""
65 output: list[str] = ["{"]
66 output.append(f" trie number = {self._ident_counter}")
67 if self.children: 67 ↛ 72line 67 didn't jump to line 72 because the condition on line 67 was always true
68 output.append(" children = {")
69 for child_key, child_value in self.children.items():
70 output.append(f" {repr(child_key)} = " + indent(str(child_value), " ").lstrip())
71 output.append(" }")
72 output.append(f" trie index = {self._trie_index.keys()}")
73 output.append("}")
74 return "\n".join(output)
76 def _as_dict(self) -> dict[str, Any]:
77 """Converts the trie to a dictionary representation."""
78 # pylint: disable=protected-access, no-member
79 return deepcopy({
80 "ident": self.ident,
81 "children": {
82 k: v._as_dict() # type: ignore[reportPrivateUsage]
83 for k, v in self.children.items()
84 },
85 "trie_index": sorted(self._trie_index.keys()),
86 "trie_entries": {
87 k: repr(v)
88 for k, v in self._trie_entries.items()
89 }
90 })