or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-interface.mdconfiguration.mdenvironment-system.mdexecution-system.mdindex.mdplugin-system.mdsession-management.md

execution-system.mddocs/

0

# Execution System

1

2

Command execution infrastructure for running commands within tox environments. The execution system supports subprocess execution, output capture, execution status tracking, and provides abstractions for different execution backends.

3

4

## Capabilities

5

6

### Execution Request

7

8

Specification for command execution including command, environment, and execution options.

9

10

```python { .api }

11

class ExecuteRequest:

12

"""Specification for command execution."""

13

14

def __init__(

15

self,

16

cmd: list[str],

17

cwd: Path | None = None,

18

env: dict[str, str] | None = None,

19

stdin: str | None = None,

20

run_id: str | None = None

21

) -> None:

22

"""

23

Initialize execution request.

24

25

Args:

26

cmd: Command and arguments to execute

27

cwd: Working directory for execution

28

env: Environment variables

29

stdin: Standard input data

30

run_id: Unique identifier for this execution

31

"""

32

33

@property

34

def cmd(self) -> list[str]:

35

"""Command and arguments."""

36

37

@property

38

def cwd(self) -> Path | None:

39

"""Working directory."""

40

41

@property

42

def env(self) -> dict[str, str] | None:

43

"""Environment variables."""

44

45

@property

46

def stdin(self) -> str | None:

47

"""Standard input data."""

48

49

@property

50

def run_id(self) -> str | None:

51

"""Execution run identifier."""

52

```

53

54

Usage example:

55

```python

56

from tox.execute.request import ExecuteRequest

57

58

# Simple command execution

59

request = ExecuteRequest(['pytest', '--verbose'])

60

61

# Command with working directory

62

request = ExecuteRequest(

63

cmd=['python', 'setup.py', 'test'],

64

cwd=Path('/project/root')

65

)

66

67

# Command with environment variables

68

request = ExecuteRequest(

69

cmd=['pytest'],

70

env={'PYTHONPATH': '/src', 'DEBUG': '1'}

71

)

72

```

73

74

### Execute Interface

75

76

Abstract interface for command execution backends.

77

78

```python { .api }

79

class Execute:

80

"""Command execution abstraction."""

81

82

def __call__(self, request: ExecuteRequest) -> ExecuteStatus:

83

"""

84

Execute command request.

85

86

Args:

87

request: Execution specification

88

89

Returns:

90

ExecuteStatus: Execution result

91

"""

92

93

def __enter__(self):

94

"""Context manager entry."""

95

96

def __exit__(self, exc_type, exc_val, exc_tb):

97

"""Context manager exit."""

98

```

99

100

### Execution Status

101

102

Result of command execution including exit code, output, and metadata.

103

104

```python { .api }

105

class ExecuteStatus:

106

"""Result of command execution."""

107

108

@property

109

def exit_code(self) -> int:

110

"""Process exit code."""

111

112

@property

113

def out(self) -> str:

114

"""Standard output."""

115

116

@property

117

def err(self) -> str:

118

"""Standard error output."""

119

120

@property

121

def duration(self) -> float:

122

"""Execution duration in seconds."""

123

124

@property

125

def success(self) -> bool:

126

"""Whether execution was successful (exit code 0)."""

127

128

class Outcome:

129

"""Execution outcome with additional metadata."""

130

131

@property

132

def status(self) -> ExecuteStatus:

133

"""Execution status."""

134

135

@property

136

def exception(self) -> Exception | None:

137

"""Exception if execution failed."""

138

```

139

140

Usage example:

141

```python

142

# Execute command and check results

143

status = executor(ExecuteRequest(['pytest']))

144

145

print(f"Exit code: {status.exit_code}")

146

print(f"Success: {status.success}")

147

print(f"Duration: {status.duration:.2f}s")

148

149

if not status.success:

150

print(f"Error output: {status.err}")

151

```

152

153

### Local Subprocess Execution

154

155

Concrete implementation for local subprocess execution.

156

157

```python { .api }

158

class LocalSubProcessExecute(Execute):

159

"""Local subprocess executor."""

160

161

def __init__(self, colored: bool = True) -> None:

162

"""

163

Initialize subprocess executor.

164

165

Args:

166

colored: Whether to preserve ANSI color codes

167

"""

168

169

def __call__(self, request: ExecuteRequest) -> ExecuteStatus:

170

"""Execute command as local subprocess."""

171

172

def interrupt(self) -> None:

173

"""Interrupt running subprocess."""

174

175

def terminate(self) -> None:

176

"""Terminate running subprocess."""

177

```

178

179

## Command Execution Patterns

180

181

### Basic Execution

182

183

Simple command execution within an environment:

184

185

```python

186

from tox.execute.request import ExecuteRequest

187

from tox.execute.local_sub_process import LocalSubProcessExecute

188

189

# Create executor

190

executor = LocalSubProcessExecute()

191

192

# Execute command

193

request = ExecuteRequest(['python', '--version'])

194

status = executor(request)

195

196

print(f"Python version output: {status.out}")

197

```

198

199

### Environment Integration

200

201

Execution integrated with tox environments:

202

203

```python

204

# Within a ToxEnv implementation

205

def execute(self, request: ExecuteRequest) -> ExecuteStatus:

206

"""Execute command in this environment."""

207

208

# Prepare environment-specific execution context

209

env_vars = dict(os.environ)

210

env_vars.update(self.conf.get('setenv', {}))

211

212

# Create request with environment context

213

env_request = ExecuteRequest(

214

cmd=request.cmd,

215

cwd=self.conf.get('changedir', self.work_dir),

216

env=env_vars,

217

run_id=request.run_id

218

)

219

220

# Execute with environment's executor

221

return self._executor(env_request)

222

```

223

224

### Output Streaming

225

226

Handle real-time output during execution:

227

228

```python

229

class StreamingExecutor(Execute):

230

"""Executor with streaming output."""

231

232

def __call__(self, request: ExecuteRequest) -> ExecuteStatus:

233

"""Execute with streaming output."""

234

process = subprocess.Popen(

235

request.cmd,

236

stdout=subprocess.PIPE,

237

stderr=subprocess.PIPE,

238

cwd=request.cwd,

239

env=request.env,

240

text=True,

241

bufsize=1,

242

universal_newlines=True

243

)

244

245

# Stream output in real-time

246

for line in process.stdout:

247

print(line.rstrip())

248

249

exit_code = process.wait()

250

return ExecuteStatus(exit_code, "", "")

251

```

252

253

## Process Management

254

255

### Process Lifecycle

256

257

The execution system manages the complete process lifecycle:

258

259

1. **Preparation**: Setup working directory, environment variables

260

2. **Execution**: Start subprocess with specified parameters

261

3. **Monitoring**: Track process status and capture output

262

4. **Completion**: Collect exit code and output

263

5. **Cleanup**: Release resources and handle interrupts

264

265

### Signal Handling

266

267

Handle interrupts and termination gracefully:

268

269

```python

270

class ManagedExecutor(Execute):

271

"""Executor with signal handling."""

272

273

def __init__(self):

274

self._current_process = None

275

276

def __call__(self, request):

277

"""Execute with signal handling."""

278

try:

279

self._current_process = subprocess.Popen(...)

280

return self._wait_for_completion()

281

except KeyboardInterrupt:

282

self.interrupt()

283

raise

284

285

def interrupt(self):

286

"""Handle interrupt signal."""

287

if self._current_process:

288

self._current_process.terminate()

289

# Wait for graceful termination

290

try:

291

self._current_process.wait(timeout=5)

292

except subprocess.TimeoutExpired:

293

self._current_process.kill()

294

```

295

296

### Resource Management

297

298

Proper resource management for subprocess execution:

299

300

```python

301

def execute_with_resources(self, request: ExecuteRequest) -> ExecuteStatus:

302

"""Execute with proper resource management."""

303

304

with tempfile.TemporaryDirectory() as temp_dir:

305

# Setup temporary resources

306

log_file = Path(temp_dir) / "execution.log"

307

308

try:

309

# Execute command

310

process = subprocess.Popen(...)

311

312

# Monitor and log

313

with open(log_file, 'w') as log:

314

# Capture output

315

pass

316

317

finally:

318

# Cleanup resources

319

if process and process.poll() is None:

320

process.terminate()

321

```

322

323

## Execution Context

324

325

### Environment Variables

326

327

Control execution environment through variables:

328

329

```python

330

def create_execution_env(self, tox_env: ToxEnv) -> dict[str, str]:

331

"""Create execution environment."""

332

333

# Start with system environment

334

env = dict(os.environ)

335

336

# Add tox-specific variables

337

env.update({

338

'TOX_ENV_NAME': tox_env.name,

339

'TOX_ENV_DIR': str(tox_env.env_dir),

340

'TOX_WORK_DIR': str(tox_env.work_dir),

341

})

342

343

# Add environment-specific variables

344

env.update(tox_env.conf.get('setenv', {}))

345

346

# Filter through passenv

347

passenv = tox_env.conf.get('passenv', [])

348

if passenv:

349

filtered_env = {}

350

for key in passenv:

351

if key in env:

352

filtered_env[key] = env[key]

353

env = filtered_env

354

355

return env

356

```

357

358

### Working Directory

359

360

Manage working directory for command execution:

361

362

```python

363

def determine_working_dir(self, tox_env: ToxEnv, request: ExecuteRequest) -> Path:

364

"""Determine working directory for execution."""

365

366

if request.cwd:

367

return request.cwd

368

369

# Check environment configuration

370

changedir = tox_env.conf.get('changedir')

371

if changedir:

372

return Path(changedir)

373

374

# Default to environment directory

375

return tox_env.env_dir

376

```

377

378

## Error Handling

379

380

### Execution Errors

381

382

Handle various execution error conditions:

383

384

```python { .api }

385

class ExecuteError(Exception):

386

"""Base execution error."""

387

388

class CommandNotFoundError(ExecuteError):

389

"""Command not found in PATH."""

390

391

class TimeoutError(ExecuteError):

392

"""Command execution timeout."""

393

394

class InterruptError(ExecuteError):

395

"""Command execution interrupted."""

396

```

397

398

### Error Recovery

399

400

Implement error recovery strategies:

401

402

```python

403

def execute_with_retry(self, request: ExecuteRequest, max_retries: int = 3) -> ExecuteStatus:

404

"""Execute command with retry logic."""

405

406

for attempt in range(max_retries):

407

try:

408

status = self._executor(request)

409

410

# Return on success

411

if status.success:

412

return status

413

414

# Check if retry is appropriate

415

if self._should_retry(status):

416

print(f"Retrying command (attempt {attempt + 1}/{max_retries})")

417

continue

418

else:

419

return status

420

421

except ExecuteError as e:

422

if attempt == max_retries - 1:

423

raise

424

print(f"Execution failed, retrying: {e}")

425

426

return status

427

```

428

429

## Integration with Tox Environments

430

431

The execution system integrates closely with tox environments:

432

433

- **Command Preparation**: Environments prepare commands with substitutions

434

- **Environment Setup**: Execution context includes environment variables and paths

435

- **Output Handling**: Environments control output formatting and logging

436

- **Error Propagation**: Execution errors are handled by environment lifecycle

437

- **Resource Cleanup**: Environments ensure proper cleanup after execution

438

439

This tight integration ensures that commands execute correctly within the isolated environment context while maintaining proper resource management and error handling.