phml.utils.validate.test

phml.utils.validate.test

Logic that allows nodes to be tested against a series of conditions.

 1"""phml.utils.validate.test
 2
 3Logic that allows nodes to be tested against a series of conditions.
 4"""
 5
 6from __future__ import annotations
 7
 8from typing import TYPE_CHECKING, Callable, Optional
 9
10from phml.nodes import Element
11
12if TYPE_CHECKING:
13    from phml.nodes import All_Nodes, Root
14
15Test = None | str | list | dict | Callable
16
17
18def test(
19    node: All_Nodes,
20    _test: Test,
21    index: Optional[int] = None,
22    parent: Optional[Root | Element] = None,
23) -> bool:
24    """Test if a node passes the given test(s).
25
26    Test Types:
27        - `None`: Just checks that the node is a valid node.
28        - `str`: Checks that the test value is == the `node.type`.
29        - `dict`: Checks all items are valid attributes on the node.
30        and that the values are strictly equal.
31        - `Callable`: Passes the given function the node and it's index, if provided,
32        and checks if the callable returned true.
33        - `list[Test]`: Apply all the rules above for each Test in the list.
34
35    If the `parent` arg is passed so should the `index` arg.
36
37    Args:
38        node (All_Nodes): Node to test. Can be any phml node.
39        test (Test): Test to apply to the node. See previous section
40        for more info.
41        index (Optional[int], optional): Index in the parent where the
42        node exists. Defaults to None.
43        parent (Optional[Root | Element], optional): The nodes parent. Defaults to None.
44
45    Returns:
46        True if all tests pass.
47    """
48
49    if parent is not None:
50        # If parent is given then index has to be also.
51        #   Validate index is correct in parent.children
52        if index is None or parent.children[index] != node:
53            return False
54
55    if isinstance(_test, str):
56        # If string then validate that the type is the same
57        return hasattr(node, "type") and node.type == _test
58
59    if isinstance(_test, dict):
60        # If dict validate all items with properties are the same
61        # Either in attributes or in
62        return bool(
63            isinstance(node, Element)
64            and all(
65                (hasattr(node, key) and value == getattr(node, key))
66                or (
67                    hasattr(node, "properties")
68                    and key in node.properties
69                    and value == node.properties[key]
70                )
71                for key, value in _test.items()
72            )
73        )
74
75    if isinstance(_test, list):
76        # If list then recursively apply tests
77        return bool(
78            all(isinstance(cond, Test) and test(node, cond, index, parent) for cond in _test)
79        )
80
81    if isinstance(_test, Callable):
82        # If callable return result of collable after passing node, index, and parent
83        return _test(node, index, node.parent)
84
85    raise Exception("Invalid test condition")
def test( node: phml.nodes.root.Root | phml.nodes.element.Element | phml.nodes.text.Text | phml.nodes.comment.Comment | phml.nodes.doctype.DocType | phml.nodes.parent.Parent | phml.nodes.node.Node | phml.nodes.literal.Literal, _test: Union[NoneType, str, list, dict, Callable], index: Optional[int] = None, parent: Union[phml.nodes.element.Element, phml.nodes.root.Root, NoneType] = None) -> bool:
19def test(
20    node: All_Nodes,
21    _test: Test,
22    index: Optional[int] = None,
23    parent: Optional[Root | Element] = None,
24) -> bool:
25    """Test if a node passes the given test(s).
26
27    Test Types:
28        - `None`: Just checks that the node is a valid node.
29        - `str`: Checks that the test value is == the `node.type`.
30        - `dict`: Checks all items are valid attributes on the node.
31        and that the values are strictly equal.
32        - `Callable`: Passes the given function the node and it's index, if provided,
33        and checks if the callable returned true.
34        - `list[Test]`: Apply all the rules above for each Test in the list.
35
36    If the `parent` arg is passed so should the `index` arg.
37
38    Args:
39        node (All_Nodes): Node to test. Can be any phml node.
40        test (Test): Test to apply to the node. See previous section
41        for more info.
42        index (Optional[int], optional): Index in the parent where the
43        node exists. Defaults to None.
44        parent (Optional[Root | Element], optional): The nodes parent. Defaults to None.
45
46    Returns:
47        True if all tests pass.
48    """
49
50    if parent is not None:
51        # If parent is given then index has to be also.
52        #   Validate index is correct in parent.children
53        if index is None or parent.children[index] != node:
54            return False
55
56    if isinstance(_test, str):
57        # If string then validate that the type is the same
58        return hasattr(node, "type") and node.type == _test
59
60    if isinstance(_test, dict):
61        # If dict validate all items with properties are the same
62        # Either in attributes or in
63        return bool(
64            isinstance(node, Element)
65            and all(
66                (hasattr(node, key) and value == getattr(node, key))
67                or (
68                    hasattr(node, "properties")
69                    and key in node.properties
70                    and value == node.properties[key]
71                )
72                for key, value in _test.items()
73            )
74        )
75
76    if isinstance(_test, list):
77        # If list then recursively apply tests
78        return bool(
79            all(isinstance(cond, Test) and test(node, cond, index, parent) for cond in _test)
80        )
81
82    if isinstance(_test, Callable):
83        # If callable return result of collable after passing node, index, and parent
84        return _test(node, index, node.parent)
85
86    raise Exception("Invalid test condition")

Test if a node passes the given test(s).

Test Types
  • None: Just checks that the node is a valid node.
  • str: Checks that the test value is == the node.type.
  • dict: Checks all items are valid attributes on the node. and that the values are strictly equal.
  • Callable: Passes the given function the node and it's index, if provided, and checks if the callable returned true.
  • list[Test]: Apply all the rules above for each Test in the list.

If the parent arg is passed so should the index arg.

Args
  • node (All_Nodes): Node to test. Can be any phml node.
  • test (Test): Test to apply to the node. See previous section
  • for more info.
  • index (Optional[int], optional): Index in the parent where the
  • node exists. Defaults to None.
  • parent (Optional[Root | Element], optional): The nodes parent. Defaults to None.
Returns

True if all tests pass.