0
# Task Execution
1
2
Core task execution engine that handles task discovery, execution, pre/post hooks, and process management with comprehensive signal handling.
3
4
## Capabilities
5
6
### TaskRunner Class
7
8
The central class for managing and executing tasks within a project directory.
9
10
```python { .api }
11
class TaskRunner:
12
def __init__(self, cwd: Union[str, Path]):
13
"""
14
Initialize TaskRunner with working directory.
15
16
Args:
17
cwd: Working directory path (str or Path object)
18
"""
19
```
20
21
### Task Listing
22
23
Display available tasks with descriptions and commands in a formatted output.
24
25
```python { .api }
26
def list(self):
27
"""
28
Lists tasks to stdout.
29
30
Displays all available tasks with their names and descriptions
31
(or commands if no description provided) in a formatted table.
32
"""
33
```
34
35
### Task Execution
36
37
Execute a named task with optional arguments, including pre/post hook processing.
38
39
```python { .api }
40
def run(self, task_name: str, args: List[str]) -> int:
41
"""
42
Execute a task with optional arguments.
43
44
Args:
45
task_name: Name of the task to run
46
args: Arguments to pass to the task command
47
48
Returns:
49
Exit code (0 for success, >0 for error)
50
"""
51
```
52
53
## Usage Examples
54
55
### Basic Task Execution
56
57
```python
58
from taskipy.task_runner import TaskRunner
59
from pathlib import Path
60
61
# Initialize runner
62
runner = TaskRunner(Path('/path/to/project'))
63
64
# List available tasks
65
runner.list()
66
67
# Run a task
68
exit_code = runner.run('test', [])
69
70
# Run a task with arguments
71
exit_code = runner.run('test', ['--verbose', '--failfast'])
72
```
73
74
### Error Handling
75
76
```python
77
from taskipy.task_runner import TaskRunner
78
from taskipy.exceptions import TaskNotFoundError, TaskipyError
79
80
runner = TaskRunner(Path('.'))
81
82
try:
83
exit_code = runner.run('nonexistent_task', [])
84
except TaskNotFoundError as e:
85
print(f"Task not found: {e}")
86
if e.suggestion:
87
print(f"Did you mean: {e.suggestion}")
88
except TaskipyError as e:
89
print(f"Taskipy error: {e}")
90
exit_code = e.exit_code
91
```
92
93
### Working with Different Project Structures
94
95
```python
96
# Multi-project repository
97
runner = TaskRunner(Path('/path/to/monorepo/subproject'))
98
99
# Project with custom pyproject.toml location
100
# TaskRunner automatically searches parent directories for pyproject.toml
101
runner = TaskRunner(Path('/path/to/nested/directory'))
102
```
103
104
## Pre and Post Hooks
105
106
TaskRunner automatically executes pre and post hooks for tasks:
107
108
### Hook Execution Order
109
110
1. **Pre-hook**: `pre_{task_name}` (if exists)
111
2. **Main task**: `{task_name}`
112
3. **Post-hook**: `post_{task_name}` (if exists)
113
114
### Hook Behavior
115
116
- If pre-hook fails (non-zero exit code), main task and post-hook are not executed
117
- If main task fails, post-hook is not executed
118
- If main task succeeds but post-hook fails, overall execution returns post-hook's exit code
119
120
### Example Configuration
121
122
```toml
123
[tool.taskipy.tasks]
124
pre_test = "echo 'Setting up test environment'"
125
test = "python -m pytest"
126
post_test = "echo 'Cleaning up test artifacts'"
127
128
pre_lint = "echo 'Preparing linting'"
129
lint = "pylint src tests"
130
post_lint = "echo 'Linting complete'"
131
```
132
133
## Variable Substitution
134
135
TaskRunner handles variable substitution in task commands when enabled:
136
137
```python
138
# Variables are resolved before command execution
139
# Example with variables enabled:
140
# Task: "pylint {src_path}"
141
# Variables: {"src_path": "src/mypackage"}
142
# Executed: "pylint src/mypackage"
143
```
144
145
## Process Management
146
147
### Signal Handling
148
149
TaskRunner provides intelligent process management with proper signal handling:
150
151
- **SIGTERM**: Gracefully terminates child processes
152
- **SIGINT** (Ctrl+C): Handles keyboard interrupts appropriately
153
- **Cross-platform**: Different behavior on macOS vs Linux for shell process handling
154
155
### Working Directory Management
156
157
- Tasks can specify custom working directories via `cwd` parameter
158
- Global `cwd` setting applies to all tasks
159
- Per-task `cwd` overrides global setting
160
- Paths are resolved relative to pyproject.toml location
161
162
### Command Execution
163
164
```python
165
# Commands are executed through shell with proper argument quoting
166
# Example: task test --verbose "with spaces"
167
# Becomes: python -m pytest --verbose "with spaces"
168
```
169
170
## Advanced Features
171
172
### Custom Runners
173
174
TaskRunner supports custom command runners that prefix all task executions:
175
176
```toml
177
[tool.taskipy.settings]
178
runner = "poetry run"
179
```
180
181
This prefixes all task commands with the runner, useful for:
182
- Virtual environment activation
183
- Environment variable loading (e.g., `dotenv run`)
184
- Remote execution (e.g., `ssh server`)
185
186
### Argument Passing
187
188
Arguments passed to tasks are properly quoted and appended to the task command:
189
190
```python
191
# runner.run('test', ['--verbose', '--output-file', 'results.xml'])
192
# Executes: python -m pytest --verbose --output-file results.xml
193
```
194
195
Note: Arguments are only passed to the main task, not to pre/post hooks.
196
197
### Task Suggestions
198
199
When a task is not found, TaskRunner provides intelligent suggestions using difflib:
200
201
```python
202
# If user types 'tets' instead of 'test'
203
# TaskNotFoundError will include suggestion: "did you mean 'test'?"
204
```
205
206
## Process Architecture
207
208
TaskRunner creates subprocess with:
209
- **Shell execution**: Commands run through system shell
210
- **Working directory**: Configurable per task or globally
211
- **Signal forwarding**: Proper signal handling to child processes
212
- **Exit code propagation**: Task exit codes are preserved and returned