Coverage for src/gentrie/nodes.py: 95%
32 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"""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 """
28 def __init__(self, token: TrieKeyToken, parent: "GeneralizedTrie | Node", value: Optional[Any] = None) -> None:
29 self.ident: Optional[TrieId] = None
30 self.token: TrieKeyToken = token
31 self.value: Optional[Any] = value
32 self.parent: Optional["GeneralizedTrie | Node"] = parent
33 self.children: dict[TrieKeyToken, "Node"] = {}
35 def __str__(self) -> str:
36 """Generates a stringified version of the trie for visual examination.
38 The output IS NOT executable code but more in the nature of debug and testing support."""
39 output: list[str] = ["{"]
40 if self.parent is None: 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 output.append(" parent = None")
42 else:
43 from .trie import GeneralizedTrie # pylint: disable=import-outside-toplevel
44 if isinstance(self.parent, GeneralizedTrie):
45 output.append(" parent = root node")
46 else:
47 output.append(f" parent = {repr(self.parent.token)}")
48 output.append(f" node token = {repr(self.token)}")
49 if self.ident:
50 output.append(f" trie id = {self.ident}")
51 if self.children:
52 output.append(" children = {")
53 for child_key, child_value in self.children.items():
54 output.append(f" {repr(child_key)} = " + indent(str(child_value), " ").lstrip())
55 output.append(" }")
56 output.append("}")
57 return "\n".join(output)
59 def _as_dict(self) -> dict[str, Any]:
60 """Converts the node to a dictionary representation.
62 This is useful for tests and debugging purposes and is not intended
63 for general purpose serialization of the trie. It's output is not
64 suitable for use with :func:`json.dumps()` or similar functions and
65 is subject to change without notice. This is NOT a public API - it is
66 intended for internal use by tests only.
68 Returns:
69 :class:`dict[str, Any]`: Dictionary representation of the node.
70 The dictionary contains the following keys:
71 - "ident": The unique identifier of the node.
72 - "token": The token of the node.
73 - "value": The value associated with the node.
74 - "parent": The token of the parent node, or None if there is no parent.
75 - "children": A dictionary of child nodes, where the keys are the tokens
76 of the child nodes and the values are dictionaries representing the child nodes.
77 """
78 # pylint: disable=protected-access
79 # Using deepcopy to ensure that the dictionary is a copy of the data in the trie,
80 # not a dictionary of live references to it
81 return deepcopy(
82 {
83 "ident": self.ident,
84 "token": self.token,
85 "value": self.value,
86 "parent": self.parent.token if self.parent else None,
87 "children": {str(k): v._as_dict() for k, v in self.children.items()},
88 }
89 )