phml.utilities.locate.index

  1from typing import Any, Callable, overload
  2
  3from phml.nodes import MISSING, Element, Parent
  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[Any, list[Element]]
 15    """The indexed collection of elements"""
 16
 17    def __init__(
 18        self,
 19        start: Parent,
 20        key: str | Callable[[Element], str],
 21        condition: Test | None = None,
 22    ) -> None:
 23        """
 24        Args:
 25            `key` (str | Callable): Str represents the attribute to use as an index. Callable
 26            represents a function to call on each element to generate a key. The returned key
 27            must be able to be converted to a string. If none then element is skipped.
 28            `start` (Parent): The root or node to start at while indexing
 29            `test` (Test): The test to apply to each node. Only valid/passing nodes
 30            will be indexed
 31        """
 32        from phml.utilities import (  # pylint: disable=import-outside-toplevel
 33            check,
 34            walk,
 35        )
 36
 37        self.indexed_tree = {}
 38        self.key = key
 39
 40        for node in walk(start):
 41            if isinstance(node, Element):
 42                if condition is not None:
 43                    if check(node, condition):
 44                        self.add(node)
 45                else:
 46                    self.add(node)
 47
 48    def __iter__(self):
 49        return iter(self.indexed_tree)
 50
 51    def __contains__(self, _key: str) -> bool:
 52        return _key in self.indexed_tree
 53
 54    def __str__(self):
 55        return str(self.indexed_tree)
 56
 57    def items(self):  # pragma: no cover
 58        """Get the key value pairs of all indexes."""
 59        return self.indexed_tree.items()
 60
 61    def values(self):  # pragma: no cover
 62        """Get all the values in the collection."""
 63        return self.indexed_tree.values()
 64
 65    def keys(self):  # pragma: no cover
 66        """Get all the keys in the collection."""
 67        return self.indexed_tree.keys()
 68
 69    def add(self, node: Element):
 70        """Adds element to indexed collection if not already there."""
 71
 72        key = node.get(self.key, "") if isinstance(self.key, str) else self.key(node)
 73        if key not in self.indexed_tree:
 74            self.indexed_tree[key] = [node]
 75
 76        if node not in self.indexed_tree[key]:
 77            self.indexed_tree[key].append(node)
 78
 79    def remove(self, node: Element):
 80        """Removes element from indexed collection if there."""
 81
 82        key = self.key if isinstance(self.key, str) else self.key(node)
 83        if key in self.indexed_tree and node in self.indexed_tree[key]:
 84            self.indexed_tree[key].remove(node)
 85            if len(self.indexed_tree[key]) == 0:
 86                self.indexed_tree.pop(key, None)
 87
 88    def __getitem__(self, key: Any) -> list[Element]:
 89        return self.indexed_tree[key]
 90
 91    @overload
 92    def get(self, _key: str, _default: Any = MISSING) -> list[Element] | Any:
 93        ...
 94
 95    @overload
 96    def get(self, _key: str) -> list[Element] | None:
 97        ...
 98
 99    def get(
100        self, _key: str, _default: Any = MISSING
101    ) -> list[Element] | None:  # pragma: no cover
102        """Get a specific index from the indexed tree."""
103        if _default != MISSING:
104            return self.indexed_tree.get(_key, _default)
105        return self.indexed_tree.get(_key, None)
106
107    # Built in key functions
108
109    @staticmethod
110    def key_by_tag(node: Element) -> str:
111        """Builds the key from an elements tag. If the node is not an element
112        then the node's type is returned."""
113
114        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[Any, list[Element]]
 16    """The indexed collection of elements"""
 17
 18    def __init__(
 19        self,
 20        start: Parent,
 21        key: str | Callable[[Element], str],
 22        condition: Test | None = None,
 23    ) -> None:
 24        """
 25        Args:
 26            `key` (str | Callable): Str represents the attribute to use as an index. Callable
 27            represents a function to call on each element to generate a key. The returned key
 28            must be able to be converted to a string. If none then element is skipped.
 29            `start` (Parent): The root or node to start at while indexing
 30            `test` (Test): The test to apply to each node. Only valid/passing nodes
 31            will be indexed
 32        """
 33        from phml.utilities import (  # pylint: disable=import-outside-toplevel
 34            check,
 35            walk,
 36        )
 37
 38        self.indexed_tree = {}
 39        self.key = key
 40
 41        for node in walk(start):
 42            if isinstance(node, Element):
 43                if condition is not None:
 44                    if check(node, condition):
 45                        self.add(node)
 46                else:
 47                    self.add(node)
 48
 49    def __iter__(self):
 50        return iter(self.indexed_tree)
 51
 52    def __contains__(self, _key: str) -> bool:
 53        return _key in self.indexed_tree
 54
 55    def __str__(self):
 56        return str(self.indexed_tree)
 57
 58    def items(self):  # pragma: no cover
 59        """Get the key value pairs of all indexes."""
 60        return self.indexed_tree.items()
 61
 62    def values(self):  # pragma: no cover
 63        """Get all the values in the collection."""
 64        return self.indexed_tree.values()
 65
 66    def keys(self):  # pragma: no cover
 67        """Get all the keys in the collection."""
 68        return self.indexed_tree.keys()
 69
 70    def add(self, node: Element):
 71        """Adds element to indexed collection if not already there."""
 72
 73        key = node.get(self.key, "") if isinstance(self.key, str) else self.key(node)
 74        if key not in self.indexed_tree:
 75            self.indexed_tree[key] = [node]
 76
 77        if node not in self.indexed_tree[key]:
 78            self.indexed_tree[key].append(node)
 79
 80    def remove(self, node: Element):
 81        """Removes element from indexed collection if there."""
 82
 83        key = self.key if isinstance(self.key, str) else self.key(node)
 84        if key in self.indexed_tree and node in self.indexed_tree[key]:
 85            self.indexed_tree[key].remove(node)
 86            if len(self.indexed_tree[key]) == 0:
 87                self.indexed_tree.pop(key, None)
 88
 89    def __getitem__(self, key: Any) -> list[Element]:
 90        return self.indexed_tree[key]
 91
 92    @overload
 93    def get(self, _key: str, _default: Any = MISSING) -> list[Element] | Any:
 94        ...
 95
 96    @overload
 97    def get(self, _key: str) -> list[Element] | None:
 98        ...
 99
100    def get(
101        self, _key: str, _default: Any = MISSING
102    ) -> list[Element] | None:  # pragma: no cover
103        """Get a specific index from the indexed tree."""
104        if _default != MISSING:
105            return self.indexed_tree.get(_key, _default)
106        return self.indexed_tree.get(_key, None)
107
108    # Built in key functions
109
110    @staticmethod
111    def key_by_tag(node: Element) -> str:
112        """Builds the key from an elements tag. If the node is not an element
113        then the node's type is returned."""
114
115        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.

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

The indexed collection of elements

def items(self):
58    def items(self):  # pragma: no cover
59        """Get the key value pairs of all indexes."""
60        return self.indexed_tree.items()

Get the key value pairs of all indexes.

def values(self):
62    def values(self):  # pragma: no cover
63        """Get all the values in the collection."""
64        return self.indexed_tree.values()

Get all the values in the collection.

def keys(self):
66    def keys(self):  # pragma: no cover
67        """Get all the keys in the collection."""
68        return self.indexed_tree.keys()

Get all the keys in the collection.

def add(self, node: phml.nodes.Element):
70    def add(self, node: Element):
71        """Adds element to indexed collection if not already there."""
72
73        key = node.get(self.key, "") if isinstance(self.key, str) else self.key(node)
74        if key not in self.indexed_tree:
75            self.indexed_tree[key] = [node]
76
77        if node not in self.indexed_tree[key]:
78            self.indexed_tree[key].append(node)

Adds element to indexed collection if not already there.

def remove(self, node: phml.nodes.Element):
80    def remove(self, node: Element):
81        """Removes element from indexed collection if there."""
82
83        key = self.key if isinstance(self.key, str) else self.key(node)
84        if key in self.indexed_tree and node in self.indexed_tree[key]:
85            self.indexed_tree[key].remove(node)
86            if len(self.indexed_tree[key]) == 0:
87                self.indexed_tree.pop(key, None)

Removes element from indexed collection if there.

def get( self, _key: str, _default: Any = <phml.nodes.Missing object>) -> list[phml.nodes.Element] | None:
100    def get(
101        self, _key: str, _default: Any = MISSING
102    ) -> list[Element] | None:  # pragma: no cover
103        """Get a specific index from the indexed tree."""
104        if _default != MISSING:
105            return self.indexed_tree.get(_key, _default)
106        return self.indexed_tree.get(_key, None)

Get a specific index from the indexed tree.

@staticmethod
def key_by_tag(node: phml.nodes.Element) -> str:
110    @staticmethod
111    def key_by_tag(node: Element) -> str:
112        """Builds the key from an elements tag. If the node is not an element
113        then the node's type is returned."""
114
115        return node.tag

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