Coverage for src/gentrie/nodes.py: 100%
31 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-08-20 09:42 -0700
« prev ^ index » next coverage.py v7.6.10, created at 2025-08-20 09:42 -0700
1# -*- coding: utf-8 -*-
2"""Internal node implementation for the gentrie package."""
4from copy import deepcopy
5from textwrap import indent
6from typing import Any, Optional, TYPE_CHECKING
8from .protocols import TrieKeyToken
9from .types import TrieId
11if TYPE_CHECKING:
12 from .trie import GeneralizedTrie
15class Node: # pylint: disable=too-few-public-methods
16 """A node in the trie.
18 A node is a container for a key in the trie. It has a unique identifier
19 and a reference to the key.
21 Attributes:
22 ident (TrieId): Unique identifier for the key.
23 token (TrieKeyToken): Token for the key.
24 parent (Optional[GeneralizedTrie | Node): Reference to the parent node.
25 children (dict[TrieKeyToken, Node]): Dictionary of child nodes.
26 """
27 __slots__ = ('ident', 'token', 'value', 'parent', 'children')
29 def __init__(self, token: TrieKeyToken, parent: "GeneralizedTrie | Node", value: Optional[Any] = None) -> None:
30 self.ident: Optional[TrieId] = None
31 self.token: TrieKeyToken = token
32 self.value: Optional[Any] = value
33 self.parent: Optional["GeneralizedTrie | Node"] = parent
34 self.children: dict[TrieKeyToken, "Node"] = {}
36 def __str__(self) -> str:
37 """Generates a stringified version of the trie for visual examination.
39 The output IS NOT executable code but more in the nature of debug and testing support."""
40 output: list[str] = ["{"]
42 from .trie import GeneralizedTrie # pylint: disable=import-outside-toplevel
43 if isinstance(self.parent, None | GeneralizedTrie):
44 output.append(" parent = root node")
45 else:
46 output.append(f" parent = {repr(self.parent.token)}") # pyright: ignore[reportOptionalMemberAccess]
47 output.append(f" node token = {repr(self.token)}")
48 if self.ident:
49 output.append(f" trie id = {self.ident}")
50 if self.children:
51 output.append(" children = {")
52 for child_key, child_value in self.children.items():
53 output.append(f" {repr(child_key)} = " + indent(str(child_value), " ").lstrip())
54 output.append(" }")
55 output.append("}")
56 return "\n".join(output)
58 def _as_dict(self) -> dict[str, Any]:
59 """Converts the node to a dictionary representation.
61 This is useful for tests and debugging purposes and is not intended
62 for general purpose serialization of the trie. It's output is not
63 suitable for use with :func:`json.dumps()` or similar functions and
64 is subject to change without notice. This is NOT a public API - it is
65 intended for internal use by tests only.
67 Returns:
68 :class:`dict[str, Any]`: Dictionary representation of the node.
69 The dictionary contains the following keys:
70 - "ident": The unique identifier of the node.
71 - "token": The token of the node.
72 - "value": The value associated with the node.
73 - "parent": The token of the parent node, or None if there is no parent.
74 - "children": A dictionary of child nodes, where the keys are the tokens
75 of the child nodes and the values are dictionaries representing the child nodes.
76 """
77 # pylint: disable=protected-access
78 # Using deepcopy to ensure that the dictionary is a copy of the data in the trie,
79 # not a dictionary of live references to it
80 return deepcopy(
81 {
82 "ident": self.ident,
83 "token": self.token,
84 "value": self.value,
85 "parent": self.parent.token if self.parent else None,
86 "children": {str(k): v._as_dict() for k, v in self.children.items()},
87 }
88 )