Coverage for src/features/actions.py: 100.00%

56 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-22 10:53 +0000

1#!/usr/bin/env python3 

2 

3# Standard libraries 

4from argparse import Namespace 

5from typing import List, Optional 

6 

7# Components 

8from ..lib.executor import Executor 

9 

10# ActionsFeature class 

11class ActionsFeature: 

12 

13 # Members 

14 __actions: List[str] 

15 __executor: Optional[Executor] = None 

16 __result: bool 

17 

18 # Key action class, pylint: disable=too-few-public-methods 

19 class ActionKey: 

20 def __init__(self, key: str) -> None: 

21 self.key = str(key) 

22 

23 # Key action class, pylint: disable=too-few-public-methods 

24 class ActionKeyControl: 

25 def __init__(self, key: str) -> None: 

26 self.key = str(key) 

27 

28 # Finish action class, pylint: disable=too-few-public-methods 

29 class ActionFinish: 

30 def __init__(self) -> None: 

31 self.finish = True 

32 

33 # Read action class, pylint: disable=too-few-public-methods 

34 class ActionRead: 

35 def __init__(self) -> None: 

36 self.read = True 

37 

38 # Wait action class, pylint: disable=too-few-public-methods 

39 class ActionWait: 

40 def __init__(self, wait: str) -> None: 

41 self.wait = float(wait) 

42 

43 # Constructor 

44 def __init__(self, command: str, options: Namespace) -> None: 

45 

46 # Store actions 

47 self.__actions = options.actions 

48 

49 # Configure executor 

50 Executor.configure( 

51 host=options.host, 

52 tool=options.tool, 

53 masks=options.masks, 

54 ) 

55 

56 # Create executor 

57 try: 

58 self.__result = False 

59 self.__executor = Executor( 

60 command=command, delay_init=options.delay_init, 

61 delay_press=options.delay_press, delay_prompt=options.delay_prompt, 

62 hold_prompt=options.hold_prompt, workdir=options.workdir) 

63 

64 # Intercept interruptions 

65 except KeyboardInterrupt: 

66 self.finish(force=True) 

67 

68 # Finish 

69 def finish(self, force: bool = False) -> None: 

70 

71 # Finish executor 

72 if self.__executor: 

73 self.__result = self.__executor.finish(force=force) == 0 

74 self.__executor = None 

75 

76 # Run 

77 def run(self) -> bool: 

78 

79 # Wrap executor 

80 try: 

81 

82 # Interact with executor 

83 for index, action in enumerate(self.__actions if self.__actions else []): 

84 

85 # Validate executor 

86 if not self.__executor: 

87 break 

88 

89 # Key actions 

90 if isinstance(action, ActionsFeature.ActionKey): 

91 self.__executor.press(action.key) 

92 

93 # Ctrl+key actions 

94 if isinstance(action, ActionsFeature.ActionKeyControl): 

95 self.__executor.press(action.key, control=True) 

96 

97 # Read actions 

98 elif isinstance(action, ActionsFeature.ActionRead): 

99 self.__executor.read() 

100 break 

101 

102 # Wait actions 

103 elif isinstance(action, ActionsFeature.ActionWait): 

104 self.__executor.wait(action.wait) 

105 

106 # Finish actions 

107 elif isinstance(action, ActionsFeature.ActionFinish): 

108 self.finish(force=True) 

109 break 

110 

111 # Read outputs 

112 next_finish = index + 1 < len(self.__actions) and isinstance( 

113 self.__actions[index + 1], ActionsFeature.ActionFinish) 

114 if not next_finish: 

115 self.__executor.read() 

116 

117 # Catch interruptions 

118 except KeyboardInterrupt: 

119 self.finish(force=True) 

120 

121 # Finish executor 

122 self.finish() 

123 

124 # Result 

125 return self.__result