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