or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

actions.mdcli.mdcore-api.mdexceptions.mdindex.mdtask-definition.mdtools.md

actions.mddocs/

0

# Actions and Execution

1

2

Classes and utilities for defining task actions, including shell commands, Python functions, and specialized interactive actions for different execution scenarios.

3

4

## Capabilities

5

6

### Action Base Classes

7

8

Foundation classes for all task actions providing common functionality and interfaces.

9

10

```python { .api }

11

class BaseAction:

12

"""

13

Base class for all actions.

14

15

All action classes inherit from this base and must implement the execute method.

16

Provides common functionality for preparing keyword arguments from task metadata.

17

"""

18

19

def execute(self, out=None, err=None):

20

"""Execute the action (must be implemented by subclasses)"""

21

22

@staticmethod

23

def _prepare_kwargs(task, func, args, kwargs):

24

"""Prepare keyword arguments with task metadata and command line options"""

25

```

26

27

### Shell Command Actions

28

29

Actions for executing shell commands with different interaction patterns and output handling.

30

31

```python { .api }

32

class LongRunning(CmdAction):

33

"""

34

Action to handle long running shell processes (servers, services).

35

36

Properties:

37

- Output is never captured

38

- Always considered successful (return code ignored)

39

- Swallows KeyboardInterrupt for graceful shutdown

40

41

Use for processes that run indefinitely like web servers, background services,

42

or any process where you want to ignore the exit code.

43

"""

44

45

def execute(self, out=None, err=None):

46

"""Execute long-running command, handling KeyboardInterrupt gracefully"""

47

```

48

49

```python { .api }

50

class Interactive(CmdAction):

51

"""

52

Action to handle interactive shell processes.

53

54

Properties:

55

- Output is never captured (allows user interaction)

56

- Respects return code for success/failure

57

- Suitable for processes requiring user input

58

59

Use for commands that need user interaction like editors, prompts,

60

or any process where you need to preserve stdin/stdout/stderr.

61

"""

62

63

def execute(self, out=None, err=None):

64

"""Execute interactive command, preserving user interaction"""

65

```

66

67

### Python Function Actions

68

69

Actions for executing Python functions with different interaction and output patterns.

70

71

```python { .api }

72

class PythonInteractiveAction(PythonAction):

73

"""

74

Action to handle interactive Python function execution.

75

76

Properties:

77

- Output is never captured

78

- Successful unless exception is raised

79

- Allows function to interact directly with user

80

- Can return string results or dictionaries

81

82

Use for Python functions that need direct user interaction or

83

when you want to avoid output capture.

84

"""

85

86

def execute(self, out=None, err=None):

87

"""Execute Python function interactively, handling return values and exceptions"""

88

```

89

90

### Action Factory Functions

91

92

Utility functions for creating and normalizing action objects from various input formats.

93

94

```python { .api }

95

def normalize_callable(ref):

96

"""

97

Return a list with (callable, *args, **kwargs) from various input formats.

98

99

Handles both simple callables and tuples containing callable with arguments.

100

101

Args:

102

ref: A callable or tuple (callable, args, kwargs)

103

104

Returns:

105

list: [callable, args_tuple, kwargs_dict]

106

"""

107

```

108

109

### Legacy Support

110

111

Deprecated aliases maintained for backward compatibility.

112

113

```python { .api }

114

InteractiveAction = LongRunning # Deprecated alias for LongRunning (removed in 0.25)

115

```

116

117

### Usage Examples

118

119

#### Long Running Service

120

121

```python

122

from doit.tools import LongRunning

123

124

def task_start_server():

125

"""Start development server"""

126

return {

127

'actions': [LongRunning('python manage.py runserver 8000')],

128

'verbosity': 2

129

}

130

131

# Server will run until Ctrl+C, then gracefully shut down

132

```

133

134

#### Interactive Command

135

136

```python

137

from doit.tools import Interactive

138

139

def task_edit_config():

140

"""Edit configuration file interactively"""

141

return {

142

'actions': [Interactive('nano config.yaml')],

143

'file_dep': ['config.yaml']

144

}

145

146

# Opens editor for user interaction, respects exit code

147

```

148

149

#### Interactive Python Function

150

151

```python

152

from doit.tools import PythonInteractiveAction

153

154

def interactive_setup():

155

"""Interactive setup with user prompts"""

156

name = input("Enter project name: ")

157

version = input("Enter version [1.0.0]: ") or "1.0.0"

158

159

config = {'name': name, 'version': version}

160

print(f"Creating project {name} v{version}")

161

162

# Return dict to save as task values

163

return config

164

165

def task_setup():

166

"""Interactive project setup"""

167

return {

168

'actions': [PythonInteractiveAction(interactive_setup)],

169

'verbosity': 2

170

}

171

```

172

173

#### Mixed Action Types

174

175

```python

176

from doit.tools import Interactive, LongRunning

177

178

def task_development():

179

"""Complete development workflow"""

180

return {

181

'actions': [

182

'python setup.py develop', # Regular command

183

Interactive('git add .'), # Interactive for commit message

184

Interactive('git commit'), # Interactive for commit message

185

LongRunning('python -m pytest --watch') # Long-running test watcher

186

],

187

'verbosity': 2

188

}

189

```

190

191

#### Normalized Callable Usage

192

193

```python

194

from doit.action import normalize_callable

195

196

def my_function(arg1, arg2, kwarg1=None):

197

return f"Called with {arg1}, {arg2}, {kwarg1}"

198

199

# Various ways to specify callables

200

callable_formats = [

201

my_function, # Simple function

202

(my_function, ('hello', 'world'), {'kwarg1': 'test'}), # Full specification

203

(my_function, ('hello',), {}), # Partial specification

204

]

205

206

for fmt in callable_formats:

207

func, args, kwargs = normalize_callable(fmt)

208

print(func(*args, **kwargs))

209

```