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

1from __future__ import annotations 

2 

3from typing import TYPE_CHECKING, Callable, Optional 

4 

5if TYPE_CHECKING: 

6 from phml.nodes import All_Nodes, Element, Root 

7 

8Test = None | str | list | dict | Callable 

9 

10 

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). 

18 

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. 

27 

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

29 

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. 

37 

38 Returns: 

39 True if all tests pass. 

40 """ 

41 from phml.nodes import Element 

42 

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 

48 

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 

62 

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}")