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.
Index( key: Union[str, Callable], start: phml.core.nodes.AST.AST | phml.core.nodes.nodes.Root | phml.core.nodes.nodes.Element, condition: Union[NoneType, str, list, dict, Callable, phml.core.nodes.nodes.Root, phml.core.nodes.nodes.Element, phml.core.nodes.nodes.Text, phml.core.nodes.nodes.Comment, phml.core.nodes.nodes.DocType, phml.core.nodes.nodes.Parent, phml.core.nodes.nodes.Node, phml.core.nodes.nodes.Literal] = None)
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 indexingtest
(Test): The test to apply to each node. Only valid/passing nodes- will be indexed
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.
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.
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.
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.