or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

alternative-spawning.mdindex.mdpattern-matching.mdprocess-control.mdrepl-automation.mdssh-operations.mdutilities.md

utilities.mddocs/

0

# Utilities and Helpers

1

2

Utility functions for common tasks including executable finding, command line parsing, and file system operations that support pexpect's functionality.

3

4

## Capabilities

5

6

### Executable Location

7

8

Functions for finding executable files in the system PATH.

9

10

```python { .api }

11

def which(filename, env=None):

12

"""

13

Find executable file in PATH.

14

15

Searches for the given filename in the directories listed in the PATH

16

environment variable and returns the full path to the first executable

17

file found.

18

19

Parameters:

20

- filename (str): Name of executable to find

21

- env (dict): Environment variables (uses os.environ if None)

22

23

Returns:

24

str or None: Full path to executable, or None if not found

25

"""

26

27

def is_executable_file(path):

28

"""

29

Check if a file is executable.

30

31

Checks that the path points to an executable regular file or symlink

32

to an executable file. Handles platform-specific executable detection.

33

34

Parameters:

35

- path (str): Path to check

36

37

Returns:

38

bool: True if file exists and is executable, False otherwise

39

"""

40

```

41

42

### Command Line Parsing

43

44

Functions for parsing and processing command line strings.

45

46

```python { .api }

47

def split_command_line(command_line):

48

"""

49

Split command line into argument list.

50

51

Parses a command line string into a list of arguments, handling

52

quoted strings and escape sequences properly.

53

54

Parameters:

55

- command_line (str): Command line string to parse

56

57

Returns:

58

list: List of command arguments

59

"""

60

```

61

62

### Low-Level I/O Utilities

63

64

Internal utility functions for handling I/O operations with proper interrupt handling.

65

66

```python { .api }

67

def select_ignore_interrupts(iwtd, owtd, ewtd, timeout=None):

68

"""

69

Wrapper around select.select() that ignores interrupts.

70

71

Provides robust select() operation that retries on EINTR,

72

making pexpect more reliable on systems with signal handling.

73

74

Parameters:

75

- iwtd (list): Input wait list (file descriptors to read)

76

- owtd (list): Output wait list (file descriptors to write)

77

- ewtd (list): Error wait list (file descriptors for exceptions)

78

- timeout (float): Timeout in seconds (None for blocking)

79

80

Returns:

81

tuple: (readable, writable, exceptional) file descriptor lists

82

"""

83

84

def poll_ignore_interrupts(fd_list, timeout=None):

85

"""

86

Wrapper around select.poll() that ignores interrupts.

87

88

Provides robust poll() operation that retries on EINTR.

89

90

Parameters:

91

- fd_list (list): List of (fd, event_mask) tuples

92

- timeout (int): Timeout in milliseconds (None for blocking)

93

94

Returns:

95

list: List of (fd, event) tuples for ready file descriptors

96

"""

97

```

98

99

### Type Compatibility

100

101

Constants and utilities for Python 2/3 compatibility.

102

103

```python { .api }

104

string_types: tuple

105

"""

106

Tuple of string types for isinstance() checks.

107

(str,) on Python 3, (unicode, str) on Python 2.

108

"""

109

```

110

111

## Usage Examples

112

113

### Finding Executables

114

115

```python

116

import pexpect

117

118

# Find common executables

119

ssh_path = pexpect.which('ssh')

120

if ssh_path:

121

print(f"SSH found at: {ssh_path}")

122

child = pexpect.spawn(ssh_path)

123

else:

124

print("SSH not found in PATH")

125

126

# Check multiple possible names

127

for cmd in ['python3', 'python', 'python2']:

128

python_path = pexpect.which(cmd)

129

if python_path:

130

print(f"Python found: {python_path}")

131

break

132

else:

133

print("No Python interpreter found")

134

135

# Use custom environment

136

custom_env = os.environ.copy()

137

custom_env['PATH'] = '/usr/local/bin:/usr/bin:/bin'

138

git_path = pexpect.which('git', env=custom_env)

139

print(f"Git in custom PATH: {git_path}")

140

```

141

142

### Validating Executable Files

143

144

```python

145

import pexpect

146

import os

147

148

# Check if file is executable before spawning

149

script_path = '/usr/local/bin/myscript.sh'

150

151

if os.path.exists(script_path):

152

if pexpect.is_executable_file(script_path):

153

print(f"{script_path} is executable")

154

child = pexpect.spawn(script_path)

155

else:

156

print(f"{script_path} exists but is not executable")

157

else:

158

print(f"{script_path} does not exist")

159

160

# Check multiple candidates

161

candidates = [

162

'/usr/bin/python3',

163

'/usr/local/bin/python3',

164

'/opt/python/bin/python3'

165

]

166

167

for candidate in candidates:

168

if pexpect.is_executable_file(candidate):

169

print(f"Using Python: {candidate}")

170

python = pexpect.spawn(candidate)

171

break

172

else:

173

print("No valid Python executable found")

174

```

175

176

### Command Line Parsing

177

178

```python

179

import pexpect

180

181

# Parse complex command lines

182

command_line = 'ssh -o "StrictHostKeyChecking no" user@host "ls -la /tmp"'

183

args = pexpect.split_command_line(command_line)

184

print("Parsed arguments:")

185

for i, arg in enumerate(args):

186

print(f" {i}: {arg}")

187

188

# Use with spawn

189

child = pexpect.spawn(args[0], args[1:])

190

191

# Handle commands with quotes and escapes

192

complex_cmd = r'echo "Hello \"World\"" && ls -la'

193

parsed = pexpect.split_command_line(complex_cmd)

194

print(f"Complex command parsed: {parsed}")

195

```

196

197

### Building Dynamic Commands

198

199

```python

200

import pexpect

201

202

def find_and_run(program, args=None, **kwargs):

203

"""

204

Find program in PATH and run it with pexpect.

205

"""

206

program_path = pexpect.which(program)

207

if not program_path:

208

raise FileNotFoundError(f"Program '{program}' not found in PATH")

209

210

if not pexpect.is_executable_file(program_path):

211

raise PermissionError(f"Program '{program_path}' is not executable")

212

213

# Build command

214

if args:

215

return pexpect.spawn(program_path, args, **kwargs)

216

else:

217

return pexpect.spawn(program_path, **kwargs)

218

219

# Usage examples

220

try:

221

# Run git with arguments

222

git = find_and_run('git', ['status', '--porcelain'])

223

git.expect(pexpect.EOF)

224

print("Git status:", git.before.decode())

225

git.close()

226

227

# Run Python interpreter

228

python = find_and_run('python3', ['-c', 'print("Hello from Python")'])

229

python.expect(pexpect.EOF)

230

print("Python output:", python.before.decode())

231

python.close()

232

233

except (FileNotFoundError, PermissionError) as e:

234

print(f"Error: {e}")

235

```

236

237

### Cross-Platform Executable Search

238

239

```python

240

import pexpect

241

import sys

242

import os

243

244

def find_editor():

245

"""Find a suitable text editor across platforms."""

246

247

if sys.platform == 'win32':

248

# Windows editors

249

editors = ['notepad.exe', 'wordpad.exe', 'write.exe']

250

else:

251

# Unix/Linux editors

252

editors = ['nano', 'vim', 'vi', 'emacs', 'gedit']

253

254

for editor in editors:

255

editor_path = pexpect.which(editor)

256

if editor_path and pexpect.is_executable_file(editor_path):

257

return editor_path

258

259

return None

260

261

# Find and use editor

262

editor = find_editor()

263

if editor:

264

print(f"Found editor: {editor}")

265

# Could spawn editor here

266

else:

267

print("No suitable editor found")

268

```

269

270

### Environment-Aware Executable Search

271

272

```python

273

import pexpect

274

import os

275

276

def find_in_custom_paths(program, extra_paths=None):

277

"""

278

Find executable in PATH plus additional custom paths.

279

"""

280

# Try standard PATH first

281

result = pexpect.which(program)

282

if result:

283

return result

284

285

# Try additional paths

286

if extra_paths:

287

original_path = os.environ.get('PATH', '')

288

try:

289

# Temporarily extend PATH

290

extended_path = os.pathsep.join(extra_paths + [original_path])

291

custom_env = os.environ.copy()

292

custom_env['PATH'] = extended_path

293

294

result = pexpect.which(program, env=custom_env)

295

return result

296

297

finally:

298

# PATH is restored automatically since we used a copy

299

pass

300

301

return None

302

303

# Usage

304

extra_search_paths = [

305

'/opt/local/bin',

306

'/usr/local/sbin',

307

'~/bin'

308

]

309

310

program = find_in_custom_paths('special_tool', extra_search_paths)

311

if program:

312

print(f"Found special_tool at: {program}")

313

```

314

315

### Robust Command Execution

316

317

```python

318

import pexpect

319

import shlex

320

321

def safe_spawn(command_line, **kwargs):

322

"""

323

Safely spawn a command with proper argument parsing.

324

"""

325

# Parse the command line

326

try:

327

if isinstance(command_line, str):

328

args = pexpect.split_command_line(command_line)

329

else:

330

args = command_line

331

332

if not args:

333

raise ValueError("Empty command")

334

335

program = args[0]

336

program_args = args[1:] if len(args) > 1 else []

337

338

# Find the executable

339

program_path = pexpect.which(program)

340

if not program_path:

341

raise FileNotFoundError(f"Command '{program}' not found")

342

343

# Verify it's executable

344

if not pexpect.is_executable_file(program_path):

345

raise PermissionError(f"Command '{program_path}' is not executable")

346

347

# Spawn with full path

348

return pexpect.spawn(program_path, program_args, **kwargs)

349

350

except Exception as e:

351

raise RuntimeError(f"Failed to spawn '{command_line}': {e}")

352

353

# Usage examples

354

try:

355

# Safe command execution

356

child = safe_spawn('ls -la /tmp')

357

child.expect(pexpect.EOF)

358

print("Directory listing:")

359

print(child.before.decode())

360

child.close()

361

362

# With complex quoting

363

child = safe_spawn('find /tmp -name "*.tmp" -type f')

364

child.expect(pexpect.EOF)

365

print("Temp files:")

366

print(child.before.decode())

367

child.close()

368

369

except RuntimeError as e:

370

print(f"Command failed: {e}")

371

```

372

373

### String Type Compatibility

374

375

```python

376

import pexpect

377

from pexpect.utils import string_types

378

379

def handle_mixed_input(data):

380

"""

381

Handle both string and bytes input across Python versions.

382

"""

383

if isinstance(data, string_types):

384

# It's a string type (str in Python 3, str/unicode in Python 2)

385

print(f"Got string: {data}")

386

return data.encode('utf-8')

387

elif isinstance(data, bytes):

388

print(f"Got bytes: {data}")

389

return data

390

else:

391

raise TypeError(f"Expected string or bytes, got {type(data)}")

392

393

# Usage

394

text_data = "Hello, World!"

395

byte_data = b"Hello, World!"

396

397

processed_text = handle_mixed_input(text_data)

398

processed_bytes = handle_mixed_input(byte_data)

399

400

print(f"Processed text: {processed_text}")

401

print(f"Processed bytes: {processed_bytes}")

402

```

403

404

## Integration Examples

405

406

### Command Validation Pipeline

407

408

```python

409

import pexpect

410

import os

411

412

class CommandValidator:

413

"""Validate and prepare commands for pexpect execution."""

414

415

def __init__(self, extra_paths=None):

416

self.extra_paths = extra_paths or []

417

418

def validate_command(self, command_line):

419

"""

420

Validate that a command can be executed.

421

422

Returns:

423

tuple: (program_path, args) if valid

424

425

Raises:

426

ValueError: If command is invalid or not found

427

"""

428

# Parse command line

429

args = pexpect.split_command_line(command_line)

430

if not args:

431

raise ValueError("Empty command line")

432

433

program = args[0]

434

program_args = args[1:]

435

436

# Find executable

437

program_path = pexpect.which(program)

438

if not program_path and self.extra_paths:

439

# Try extra paths

440

old_path = os.environ.get('PATH', '')

441

try:

442

new_path = os.pathsep.join(self.extra_paths + [old_path])

443

env = os.environ.copy()

444

env['PATH'] = new_path

445

program_path = pexpect.which(program, env=env)

446

finally:

447

pass

448

449

if not program_path:

450

raise ValueError(f"Command '{program}' not found in PATH")

451

452

if not pexpect.is_executable_file(program_path):

453

raise ValueError(f"File '{program_path}' is not executable")

454

455

return program_path, program_args

456

457

def safe_spawn(self, command_line, **kwargs):

458

"""Spawn command after validation."""

459

program_path, args = self.validate_command(command_line)

460

return pexpect.spawn(program_path, args, **kwargs)

461

462

# Usage

463

validator = CommandValidator(extra_paths=['/opt/local/bin', '/usr/local/sbin'])

464

465

try:

466

child = validator.safe_spawn('git status --porcelain')

467

child.expect(pexpect.EOF)

468

print("Git status output:")

469

print(child.before.decode())

470

child.close()

471

472

except ValueError as e:

473

print(f"Command validation failed: {e}")

474

```