Coverage for phml\utils\validate\test.py: 48%
33 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 09:38 -0600
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-30 09:38 -0600
1from __future__ import annotations
3from typing import TYPE_CHECKING, Callable, Optional
5if TYPE_CHECKING:
6 from phml.nodes import All_Nodes, Element, Root
8Test = None | str | list | dict | Callable
11def test(
12 node: All_Nodes,
13 _test: Test,
14 index: Optional[int] = None,
15 parent: Optional[Root | Element] = None,
16) -> bool:
17 """Test if a node passes the given test(s).
19 Test Types:
20 - `None`: Just checks that the node is a valid node.
21 - `str`: Checks that the test value is == the `node.type`.
22 - `dict`: Checks all items are valid attributes on the node.
23 and that the values are strictly equal.
24 - `Callable`: Passes the given function the node and it's index, if provided,
25 and checks if the callable returned true.
26 - `list[Test]`: Apply all the rules above for each Test in the list.
28 If the `parent` arg is passed so should the `index` arg.
30 Args:
31 node (All_Nodes): Node to test. Can be any phml node.
32 test (Test): Test to apply to the node. See previous section
33 for more info.
34 index (Optional[int], optional): Index in the parent where the
35 node exists. Defaults to None.
36 parent (Optional[Root | Element], optional): The nodes parent. Defaults to None.
38 Returns:
39 True if all tests pass.
40 """
41 from phml.nodes import Element
43 if parent is not None:
44 # If parent is given then index has to be also.
45 # Validate index is correct in parent.children
46 if index is None or parent.children[index] != node:
47 return False
49 if _test is None:
50 if not isinstance(node, All_Nodes):
51 return False
52 else:
53 return True
54 elif isinstance(_test, str):
55 # If string then validate that the type is the same
56 return hasattr(node, "type") and node.type == _test
57 elif isinstance(_test, dict):
58 # If dict validate all items with properties are the same
59 # Either in attributes or in
60 if not isinstance(node, Element):
61 return False
63 for key, value in _test.items():
64 if not hasattr(node, key) or value != getattr(node, key):
65 if (
66 not hasattr(node, "properties")
67 or key not in node.properties
68 or value != node.properties[key]
69 ):
70 return False
71 return True
72 elif isinstance(_test, list):
73 # If list then recursively apply tests
74 for t in _test:
75 if isinstance(t, Test):
76 if not test(node, t, index, parent):
77 return False
78 return True
79 elif isinstance(_test, Callable):
80 # If callable return result of collable after passing node, index, and parent
81 return _test(node, index, node.parent)
82 else:
83 print(f"NOTHING TO SEE HERE: {_test}")