or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aliases.mdapi-package.mdbuiltins-api.mdcompletion.mdconfiguration.mddirectory-management.mdevents.mdindex.mdscripting.mdshell-interface.md

scripting.mddocs/

0

# Scripting

1

2

## Overview

3

4

Xonsh provides seamless integration between Python and shell scripting, allowing execution of xonsh code (Python + shell syntax), subprocess management, and pipeline creation. The Execer class handles code parsing and execution, while the API modules provide clean interfaces for subprocess operations.

5

6

## Code Execution Engine

7

8

### Execer Class

9

```python { .api }

10

from xonsh.execer import Execer

11

12

class Execer:

13

"""Executes xonsh code in a context-aware manner."""

14

15

def __init__(self, filename: str = "<xonsh-code>",

16

debug_level: int = 0,

17

parser_args: dict = None,

18

scriptcache: bool = True,

19

cacheall: bool = False):

20

"""Initialize code executer.

21

22

Parameters

23

----------

24

filename : str, default "<xonsh-code>"

25

Name for executed code (error reporting)

26

debug_level : int, default 0

27

Debug level for parsing (0-2)

28

parser_args : dict, optional

29

Additional parser configuration

30

scriptcache : bool, default True

31

Whether to cache compiled bytecode

32

cacheall : bool, default False

33

Whether to cache all code including interactive input

34

"""

35

36

def parse(self, input: str, ctx: dict, mode: str = "exec",

37

filename: str = None, transform: bool = True) -> object:

38

"""Parse xonsh code with context awareness.

39

40

Parameters

41

----------

42

input : str

43

Code string to parse

44

ctx : dict

45

Execution context/namespace

46

mode : str, default "exec"

47

Parsing mode ("exec", "eval", "single")

48

filename : str, optional

49

Filename for error reporting

50

transform : bool, default True

51

Whether to apply context-aware transformations

52

53

Returns

54

-------

55

object

56

Parsed AST or None if parsing failed

57

"""

58

59

def eval(self, input: str, ctx: dict = None, filename: str = None) -> object:

60

"""Evaluate xonsh expression and return result.

61

62

Parameters

63

----------

64

input : str

65

Expression to evaluate

66

ctx : dict, optional

67

Execution context

68

filename : str, optional

69

Filename for error reporting

70

71

Returns

72

-------

73

object

74

Evaluation result

75

"""

76

77

def exec(self, input: str, ctx: dict = None, filename: str = None) -> None:

78

"""Execute xonsh code statement(s).

79

80

Parameters

81

----------

82

input : str

83

Code to execute

84

ctx : dict, optional

85

Execution context

86

filename : str, optional

87

Filename for error reporting

88

"""

89

90

# Usage examples

91

execer = Execer()

92

93

# Execute shell commands

94

execer.exec("ls -la")

95

execer.exec("echo 'Hello World'")

96

97

# Execute Python code

98

execer.exec("x = 10")

99

result = execer.eval("x * 2") # Returns 20

100

101

# Mixed Python and shell

102

execer.exec("""

103

import os

104

files = $(ls).strip().split('\n')

105

for f in files:

106

print(f"File: {f}")

107

""")

108

```

109

110

### Context-Aware Execution

111

```python { .api }

112

from xonsh.built_ins import XSH

113

114

# Execute with custom context

115

context = {

116

'my_var': 'hello',

117

'my_func': lambda x: x.upper()

118

}

119

120

# Code that uses the context

121

code = """

122

result = my_func(my_var)

123

echo @(result) # Outputs: HELLO

124

"""

125

126

XSH.execer.exec(code, ctx=context)

127

128

# Access results from context

129

final_context = context.copy()

130

XSH.execer.exec("output = $(date)", ctx=final_context)

131

date_output = final_context['output']

132

```

133

134

## Subprocess API

135

136

### High-Level Subprocess Functions

137

```python { .api }

138

from xonsh.api.subprocess import run, check_call, check_output

139

140

def run(cmd: str|list[str], cwd: str = None, check: bool = False) -> object:

141

"""Execute subprocess with xonsh syntax.

142

143

Parameters

144

----------

145

cmd : str or list[str]

146

Command to execute

147

cwd : str, optional

148

Working directory for command

149

check : bool, default False

150

Whether to raise exception on non-zero exit

151

152

Returns

153

-------

154

object

155

Process object with returncode, stdout, stderr

156

"""

157

158

def check_call(cmd: str|list[str], cwd: str = None) -> int:

159

"""Execute subprocess, raise exception on failure.

160

161

Parameters

162

----------

163

cmd : str or list[str]

164

Command to execute

165

cwd : str, optional

166

Working directory

167

168

Returns

169

-------

170

int

171

Return code (0 on success)

172

173

Raises

174

------

175

XonshCalledProcessError

176

If command returns non-zero exit code

177

"""

178

179

def check_output(cmd: str|list[str], cwd: str = None) -> bytes:

180

"""Execute subprocess and return stdout.

181

182

Parameters

183

----------

184

cmd : str or list[str]

185

Command to execute

186

cwd : str, optional

187

Working directory

188

189

Returns

190

-------

191

bytes

192

Captured stdout content

193

194

Raises

195

------

196

XonshCalledProcessError

197

If command returns non-zero exit code

198

"""

199

200

# Usage examples

201

import tempfile

202

203

# Basic subprocess execution

204

result = run(['ls', '-la'])

205

print(f"Exit code: {result.returncode}")

206

207

# Execute in specific directory

208

with tempfile.TemporaryDirectory() as tmpdir:

209

result = run('touch test.txt', cwd=tmpdir)

210

211

# Check command success

212

try:

213

check_call(['git', 'status'])

214

print("Git repository detected")

215

except Exception:

216

print("Not a git repository")

217

218

# Capture command output

219

try:

220

output = check_output(['git', 'branch', '--show-current'])

221

branch = output.decode().strip()

222

print(f"Current branch: {branch}")

223

except Exception:

224

print("Could not get git branch")

225

```

226

227

### Low-Level Subprocess Control

228

```python { .api }

229

from xonsh.procs.specs import SubprocSpec

230

from xonsh.procs.pipelines import run_subproc

231

232

def create_subprocess_spec(cmd: list[str], **kwargs) -> SubprocSpec:

233

"""Create subprocess specification.

234

235

Parameters

236

----------

237

cmd : list[str]

238

Command and arguments

239

**kwargs

240

Additional subprocess options

241

242

Returns

243

-------

244

SubprocSpec

245

Subprocess specification object

246

"""

247

248

# Create and run subprocess

249

spec = SubprocSpec(['ls', '-la'],

250

captured='stdout',

251

stack=None)

252

result = run_subproc(spec)

253

```

254

255

## Pipeline Management

256

257

### Pipeline Creation and Execution

258

```python { .api }

259

from xonsh.procs.pipelines import Pipeline

260

261

class Pipeline:

262

"""Manages subprocess pipelines."""

263

264

def __init__(self, specs: list[SubprocSpec]):

265

"""Initialize pipeline.

266

267

Parameters

268

----------

269

specs : list[SubprocSpec]

270

List of subprocess specifications

271

"""

272

273

def run(self) -> object:

274

"""Execute the pipeline.

275

276

Returns

277

-------

278

object

279

Pipeline execution result

280

"""

281

282

# Pipeline examples using built-in functions

283

from xonsh.built_ins import subproc_captured_stdout

284

285

# Simple pipeline (command | command)

286

output = subproc_captured_stdout(['ls', '-la'])

287

lines = output.strip().split('\n')

288

python_files = [line for line in lines if '.py' in line]

289

290

# Multi-stage pipeline simulation

291

def pipeline_ls_grep_wc():

292

"""Simulate: ls | grep .py | wc -l"""

293

files = subproc_captured_stdout(['ls']).strip().split('\n')

294

py_files = [f for f in files if '.py' in f]

295

return len(py_files)

296

297

count = pipeline_ls_grep_wc()

298

```

299

300

### Process Communication

301

```python { .api }

302

from xonsh.procs.proxies import ProcProxy

303

304

# Process proxy for advanced control

305

def create_interactive_process(cmd: list[str]) -> ProcProxy:

306

"""Create interactive process proxy.

307

308

Parameters

309

----------

310

cmd : list[str]

311

Command to execute

312

313

Returns

314

-------

315

ProcProxy

316

Process proxy for interaction

317

"""

318

from xonsh.procs.specs import SubprocSpec

319

spec = SubprocSpec(cmd, captured=False)

320

return ProcProxy(spec)

321

322

# Usage with interactive commands

323

# proc = create_interactive_process(['python', '-i'])

324

# proc.communicate(input=b"print('hello')\n")

325

```

326

327

## Script Execution

328

329

### File-Based Script Execution

330

```python { .api }

331

from xonsh.codecache import run_script_with_cache, run_code_with_cache

332

333

def run_script_with_cache(filename: str, glb: dict = None,

334

loc: dict = None) -> None:

335

"""Execute xonsh script file with caching.

336

337

Parameters

338

----------

339

filename : str

340

Path to xonsh script file

341

glb : dict, optional

342

Global namespace

343

loc : dict, optional

344

Local namespace

345

"""

346

347

def run_code_with_cache(code: str, filename: str = "<code>",

348

glb: dict = None, loc: dict = None) -> None:

349

"""Execute xonsh code with bytecode caching.

350

351

Parameters

352

----------

353

code : str

354

Code string to execute

355

filename : str, default "<code>"

356

Filename for caching and error reporting

357

glb : dict, optional

358

Global namespace

359

loc : dict, optional

360

Local namespace

361

"""

362

363

# Execute script files

364

run_script_with_cache('my_script.xsh')

365

run_script_with_cache('/path/to/script.py', glb=globals())

366

367

# Execute code with caching

368

script_code = """

369

echo "Starting process..."

370

files = $(ls *.py)

371

echo f"Found {len(files.split())} Python files"

372

"""

373

run_code_with_cache(script_code, filename="list_files.xsh")

374

```

375

376

### Dynamic Code Generation

377

```python { .api }

378

from xonsh.built_ins import XSH

379

380

def generate_and_execute_script(template: str, **kwargs) -> object:

381

"""Generate and execute xonsh script from template.

382

383

Parameters

384

----------

385

template : str

386

Script template with {variable} placeholders

387

**kwargs

388

Variables to substitute in template

389

390

Returns

391

-------

392

object

393

Execution result

394

"""

395

script = template.format(**kwargs)

396

return XSH.execer.eval(script)

397

398

# Template-based script generation

399

file_template = """

400

import os

401

target_dir = "{directory}"

402

if os.path.exists(target_dir):

403

files = $(ls {directory})

404

echo f"Directory {target_dir} contains: {{files}}"

405

else:

406

echo f"Directory {target_dir} does not exist"

407

"""

408

409

result = generate_and_execute_script(file_template, directory="/tmp")

410

```

411

412

## Advanced Scripting Features

413

414

### Error Handling in Scripts

415

```python { .api }

416

from xonsh.tools import XonshError, XonshCalledProcessError

417

418

def safe_execute(cmd: str) -> tuple[bool, str]:

419

"""Safely execute command with error handling.

420

421

Parameters

422

----------

423

cmd : str

424

Command to execute

425

426

Returns

427

-------

428

tuple[bool, str]

429

(success, output_or_error)

430

"""

431

try:

432

result = XSH.execer.eval(f"$({cmd})")

433

return True, result

434

except XonshCalledProcessError as e:

435

return False, f"Command failed: {e}"

436

except XonshError as e:

437

return False, f"Xonsh error: {e}"

438

except Exception as e:

439

return False, f"Unexpected error: {e}"

440

441

# Usage

442

success, output = safe_execute("git status")

443

if success:

444

print(f"Git status: {output}")

445

else:

446

print(f"Error: {output}")

447

```

448

449

### Environment-Aware Scripting

450

```python { .api }

451

from xonsh.built_ins import XSH

452

453

def conditional_execution():

454

"""Execute commands based on environment."""

455

env = XSH.env

456

457

# Platform-specific execution

458

if env.get('ON_WINDOWS'):

459

XSH.execer.exec('dir')

460

else:

461

XSH.execer.exec('ls -la')

462

463

# Conditional tool usage

464

if 'VIRTUAL_ENV' in env:

465

print("Running in virtual environment")

466

XSH.execer.exec('pip list')

467

else:

468

print("No virtual environment active")

469

470

# Configuration-based scripting

471

def load_config_and_execute():

472

"""Load configuration and execute based on settings."""

473

env = XSH.env

474

475

# Set defaults

476

env.setdefault('PROJECT_ROOT', '.')

477

env.setdefault('BUILD_TYPE', 'debug')

478

479

# Execute based on configuration

480

build_cmd = f"make {env['BUILD_TYPE']}"

481

XSH.execer.exec(f"cd {env['PROJECT_ROOT']} && {build_cmd}")

482

```

483

484

### Macro Integration

485

```python { .api }

486

from xonsh.built_ins import call_macro

487

488

def script_with_macros():

489

"""Integrate macros in scripting."""

490

491

# Define macro (would typically be in xonshrc)

492

macro_code = """

493

def backup_files(pattern):

494

files = $(find . -name @(pattern))

495

for f in files.split():

496

cp @(f) @(f + '.bak')

497

return f"Backed up {len(files.split())} files"

498

"""

499

500

XSH.execer.exec(macro_code)

501

502

# Use macro in script

503

result = call_macro('backup_files', '*.py')

504

print(result)

505

```

506

507

The scripting API provides powerful tools for automating tasks, integrating shell commands with Python logic, and creating sophisticated command-line applications that leverage both Python's capabilities and shell command efficiency.