phml.utilities.locate.index

 1from typing import Callable, Optional
 2
 3from phml.core.nodes import AST, Element, Root
 4from phml.utilities.validate.check import Test
 5
 6
 7class Index:
 8    """Uses the given key or key generator and creates a mutable dict of key value pairs
 9    that can be easily indexed.
10
11    Nodes that don't match the condition or don't have a valid key are not indexed.
12    """
13
14    indexed_tree: dict[str, list[Element]]
15    """The indexed collection of elements"""
16
17    def __init__(
18        self, key: str | Callable, start: AST | Root | Element, condition: Optional[Test] = None
19    ):
20        """
21        Args:
22            `key` (str | Callable): Str represents the property to use as an index. Callable
23            represents a function to call on each element to generate a key. The returned key
24            must be able to be converted to a string. If none then element is skipped.
25            `start` (AST | Root | Element): The root or node to start at while indexing
26            `test` (Test): The test to apply to each node. Only valid/passing nodes
27            will be indexed
28        """
29        from phml.utilties import check, walk  # pylint: disable=import-outside-toplevel
30
31        if isinstance(start, AST):
32            start = start.tree
33
34        self.indexed_tree = {}
35        self.key = key
36
37        for node in walk(start):
38            if isinstance(node, Element):
39                if condition is not None:
40                    if check(node, condition):
41                        self.add(node)
42                else:
43                    self.add(node)
44
45    def __iter__(self):
46        return iter(self.indexed_tree)
47
48    def items(self) -> tuple[str, list]:
49        """Get the key value pairs of all indexes."""
50        return self.indexed_tree.items()
51
52    def values(self) -> list[list]:
53        """Get all the values in the collection."""
54        return self.indexed_tree.values()
55
56    def keys(self) -> list[str]:
57        """Get all the keys in the collection."""
58        return self.indexed_tree.keys()
59
60    def add(self, node: Element):
61        """Adds element to indexed collection if not already there."""
62
63        key = node[self.key] if isinstance(self.key, str) else self.key(node)
64        if key not in self.indexed_tree:
65            self.indexed_tree[key] = [node]
66
67        if node not in self.indexed_tree[key]:
68            self.indexed_tree[key].append(node)
69
70    def remove(self, node: Element):
71        """Removes element from indexed collection if there."""
72
73        key = node[self.key] if isinstance(self.key, str) else self.key(node)
74        if key in self.indexed_tree and node in self.indexed_tree[key]:
75            self.indexed_tree[key].remove(node)
76            if len(self.indexed_tree[key]) == 0:
77                self.indexed_tree.pop(key, None)
78
79    def get(self, _key: str) -> Optional[list[Element]]:
80        """Get a specific index from the indexed tree."""
81        return self.indexed_tree.get(_key)
82
83    # Built in key functions
84
85    @classmethod
86    def key_by_tag(cls, node: Element) -> str:
87        """Builds the key from an elements tag. If the node is not an element
88        then the node's type is returned."""
89
90        return node.tag
class Index:
 8class Index:
 9    """Uses the given key or key generator and creates a mutable dict of key value pairs
10    that can be easily indexed.
11
12    Nodes that don't match the condition or don't have a valid key are not indexed.
13    """
14
15    indexed_tree: dict[str, list[Element]]
16    """The indexed collection of elements"""
17
18    def __init__(
19        self, key: str | Callable, start: AST | Root | Element, condition: Optional[Test] = None
20    ):
21        """
22        Args:
23            `key` (str | Callable): Str represents the property to use as an index. Callable
24            represents a function to call on each element to generate a key. The returned key
25            must be able to be converted to a string. If none then element is skipped.
26            `start` (AST | Root | Element): The root or node to start at while indexing
27            `test` (Test): The test to apply to each node. Only valid/passing nodes
28            will be indexed
29        """
30        from phml.utilties import check, walk  # pylint: disable=import-outside-toplevel
31
32        if isinstance(start, AST):
33            start = start.tree
34
35        self.indexed_tree = {}
36        self.key = key
37
38        for node in walk(start):
39            if isinstance(node, Element):
40                if condition is not None:
41                    if check(node, condition):
42                        self.add(node)
43                else:
44                    self.add(node)
45
46    def __iter__(self):
47        return iter(self.indexed_tree)
48
49    def items(self) -> tuple[str, list]:
50        """Get the key value pairs of all indexes."""
51        return self.indexed_tree.items()
52
53    def values(self) -> list[list]:
54        """Get all the values in the collection."""
55        return self.indexed_tree.values()
56
57    def keys(self) -> list[str]:
58        """Get all the keys in the collection."""
59        return self.indexed_tree.keys()
60
61    def add(self, node: Element):
62        """Adds element to indexed collection if not already there."""
63
64        key = node[self.key] if isinstance(self.key, str) else self.key(node)
65        if key not in self.indexed_tree:
66            self.indexed_tree[key] = [node]
67
68        if node not in self.indexed_tree[key]:
69            self.indexed_tree[key].append(node)
70
71    def remove(self, node: Element):
72        """Removes element from indexed collection if there."""
73
74        key = node[self.key] if isinstance(self.key, str) else self.key(node)
75        if key in self.indexed_tree and node in self.indexed_tree[key]:
76            self.indexed_tree[key].remove(node)
77            if len(self.indexed_tree[key]) == 0:
78                self.indexed_tree.pop(key, None)
79
80    def get(self, _key: str) -> Optional[list[Element]]:
81        """Get a specific index from the indexed tree."""
82        return self.indexed_tree.get(_key)
83
84    # Built in key functions
85
86    @classmethod
87    def key_by_tag(cls, node: Element) -> str:
88        """Builds the key from an elements tag. If the node is not an element
89        then the node's type is returned."""
90
91        return node.tag

Uses the given key or key generator and creates a mutable dict of key value pairs that can be easily indexed.

Nodes that don't match the condition or don't have a valid key are not indexed.

18    def __init__(
19        self, key: str | Callable, start: AST | Root | Element, condition: Optional[Test] = None
20    ):
21        """
22        Args:
23            `key` (str | Callable): Str represents the property to use as an index. Callable
24            represents a function to call on each element to generate a key. The returned key
25            must be able to be converted to a string. If none then element is skipped.
26            `start` (AST | Root | Element): The root or node to start at while indexing
27            `test` (Test): The test to apply to each node. Only valid/passing nodes
28            will be indexed
29        """
30        from phml.utilties import check, walk  # pylint: disable=import-outside-toplevel
31
32        if isinstance(start, AST):
33            start = start.tree
34
35        self.indexed_tree = {}
36        self.key = key
37
38        for node in walk(start):
39            if isinstance(node, Element):
40                if condition is not None:
41                    if check(node, condition):
42                        self.add(node)
43                else:
44                    self.add(node)
Args
  • key (str | Callable): Str represents the property to use as an index. Callable
  • represents a function to call on each element to generate a key. The returned key
  • must be able to be converted to a string. If none then element is skipped.
  • start (AST | Root | Element): The root or node to start at while indexing
  • test (Test): The test to apply to each node. Only valid/passing nodes
  • will be indexed
indexed_tree: dict[str, list[phml.core.nodes.nodes.Element]]

The indexed collection of elements

def items(self) -> tuple[str, list]:
49    def items(self) -> tuple[str, list]:
50        """Get the key value pairs of all indexes."""
51        return self.indexed_tree.items()

Get the key value pairs of all indexes.

def values(self) -> list[list]:
53    def values(self) -> list[list]:
54        """Get all the values in the collection."""
55        return self.indexed_tree.values()

Get all the values in the collection.

def keys(self) -> list[str]:
57    def keys(self) -> list[str]:
58        """Get all the keys in the collection."""
59        return self.indexed_tree.keys()

Get all the keys in the collection.

def add(self, node: phml.core.nodes.nodes.Element):
61    def add(self, node: Element):
62        """Adds element to indexed collection if not already there."""
63
64        key = node[self.key] if isinstance(self.key, str) else self.key(node)
65        if key not in self.indexed_tree:
66            self.indexed_tree[key] = [node]
67
68        if node not in self.indexed_tree[key]:
69            self.indexed_tree[key].append(node)

Adds element to indexed collection if not already there.

def remove(self, node: phml.core.nodes.nodes.Element):
71    def remove(self, node: Element):
72        """Removes element from indexed collection if there."""
73
74        key = node[self.key] if isinstance(self.key, str) else self.key(node)
75        if key in self.indexed_tree and node in self.indexed_tree[key]:
76            self.indexed_tree[key].remove(node)
77            if len(self.indexed_tree[key]) == 0:
78                self.indexed_tree.pop(key, None)

Removes element from indexed collection if there.

def get(self, _key: str) -> Optional[list[phml.core.nodes.nodes.Element]]:
80    def get(self, _key: str) -> Optional[list[Element]]:
81        """Get a specific index from the indexed tree."""
82        return self.indexed_tree.get(_key)

Get a specific index from the indexed tree.

@classmethod
def key_by_tag(cls, node: phml.core.nodes.nodes.Element) -> str:
86    @classmethod
87    def key_by_tag(cls, node: Element) -> str:
88        """Builds the key from an elements tag. If the node is not an element
89        then the node's type is returned."""
90
91        return node.tag

Builds the key from an elements tag. If the node is not an element then the node's type is returned.