or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-communication.mdconnection-management.mdindex.mdkernel-management.mdkernel-provisioning.mdkernel-specifications.mdsession-messaging.md

kernel-provisioning.mddocs/

0

# Kernel Provisioning

1

2

Pluggable kernel provisioning system for starting kernels in different environments. Supports local subprocess provisioning and extensible remote provisioning through a factory pattern and abstract base class system.

3

4

## Capabilities

5

6

### Kernel Provisioner Base

7

8

The `KernelProvisionerBase` abstract class defines the interface for kernel provisioners, enabling pluggable kernel launch strategies for different environments.

9

10

```python { .api }

11

class KernelProvisionerBase:

12

"""Abstract base class for kernel provisioners."""

13

14

@property

15

def has_process(self):

16

"""

17

Whether this provisioner manages a process.

18

19

Returns:

20

bool: True if provisioner manages a local process

21

"""

22

23

async def poll(self):

24

"""

25

Check if the kernel process is running.

26

27

Returns:

28

int | None: Process exit code or None if still running

29

"""

30

31

async def wait(self):

32

"""

33

Wait for the kernel process to terminate.

34

35

Returns:

36

int | None: Process exit code

37

"""

38

39

async def send_signal(self, signum):

40

"""

41

Send a signal to the kernel process.

42

43

Parameters:

44

- signum (int): Signal number to send

45

46

Returns:

47

None

48

"""

49

50

async def kill(self, restart=False):

51

"""

52

Kill the kernel process.

53

54

Parameters:

55

- restart (bool): Whether this is part of a restart

56

57

Returns:

58

None

59

"""

60

61

async def terminate(self, restart=False):

62

"""

63

Terminate the kernel process gracefully.

64

65

Parameters:

66

- restart (bool): Whether this is part of a restart

67

68

Returns:

69

None

70

"""

71

72

async def launch_kernel(self, cmd, **kwargs):

73

"""

74

Launch the kernel process.

75

76

Parameters:

77

- cmd (list): Command line arguments to execute

78

- **kwargs: Additional launch parameters

79

80

Returns:

81

dict: Connection information for the launched kernel

82

"""

83

84

# Optional override methods

85

86

async def cleanup(self, restart=False):

87

"""

88

Cleanup resources after kernel shutdown.

89

90

Parameters:

91

- restart (bool): Whether this is part of a restart

92

93

Returns:

94

None

95

"""

96

97

async def shutdown_requested(self, restart=False):

98

"""

99

Handle shutdown request from kernel manager.

100

101

Parameters:

102

- restart (bool): Whether this is part of a restart

103

104

Returns:

105

None

106

"""

107

108

async def pre_launch(self, **kwargs):

109

"""

110

Perform setup before kernel launch.

111

112

Parameters:

113

- **kwargs: Launch parameters

114

115

Returns:

116

dict: Updated launch parameters

117

"""

118

119

async def post_launch(self, **kwargs):

120

"""

121

Perform setup after kernel launch.

122

123

Parameters:

124

- **kwargs: Launch results

125

126

Returns:

127

None

128

"""

129

130

async def get_provisioner_info(self):

131

"""

132

Get current provisioner state information.

133

134

Returns:

135

dict: Provisioner state data

136

"""

137

138

async def load_provisioner_info(self, provisioner_info):

139

"""

140

Load provisioner state information.

141

142

Parameters:

143

- provisioner_info (dict): Previously saved state data

144

145

Returns:

146

None

147

"""

148

149

# Utility methods

150

151

def get_shutdown_wait_time(self, recommended=5.0):

152

"""

153

Get timeout for shutdown operations.

154

155

Parameters:

156

- recommended (float): Recommended timeout in seconds

157

158

Returns:

159

float: Timeout value to use

160

"""

161

162

def get_stable_start_time(self, recommended=10.0):

163

"""

164

Get timeout for kernel startup stability.

165

166

Parameters:

167

- recommended (float): Recommended timeout in seconds

168

169

Returns:

170

float: Timeout value to use

171

"""

172

```

173

174

### Local Provisioner

175

176

The `LocalProvisioner` provides a concrete implementation for running kernels as local subprocesses.

177

178

```python { .api }

179

class LocalProvisioner(KernelProvisionerBase):

180

"""Provisions kernels locally using subprocess."""

181

182

@property

183

def has_process(self):

184

"""

185

Always returns True for local provisioner.

186

187

Returns:

188

bool: True

189

"""

190

191

async def poll(self):

192

"""

193

Poll the local subprocess status.

194

195

Returns:

196

int | None: Process exit code or None if running

197

"""

198

199

async def wait(self):

200

"""

201

Wait for local subprocess to terminate.

202

203

Returns:

204

int | None: Process exit code

205

"""

206

207

async def send_signal(self, signum):

208

"""

209

Send signal to local subprocess.

210

211

Parameters:

212

- signum (int): Signal number

213

214

Returns:

215

None

216

"""

217

218

async def kill(self, restart=False):

219

"""

220

Kill local subprocess.

221

222

Parameters:

223

- restart (bool): Whether part of restart

224

225

Returns:

226

None

227

"""

228

229

async def terminate(self, restart=False):

230

"""

231

Terminate local subprocess gracefully.

232

233

Parameters:

234

- restart (bool): Whether part of restart

235

236

Returns:

237

None

238

"""

239

240

async def launch_kernel(self, cmd, **kwargs):

241

"""

242

Launch kernel as local subprocess.

243

244

Parameters:

245

- cmd (list): Command to execute

246

- **kwargs: Additional subprocess parameters

247

248

Returns:

249

dict: Connection information

250

"""

251

252

async def pre_launch(self, **kwargs):

253

"""

254

Setup local environment before launch.

255

256

Parameters:

257

- **kwargs: Launch parameters

258

259

Returns:

260

dict: Updated launch parameters

261

"""

262

263

async def cleanup(self, restart=False):

264

"""

265

Cleanup local resources.

266

267

Parameters:

268

- restart (bool): Whether part of restart

269

270

Returns:

271

None

272

"""

273

```

274

275

### Provisioner Factory

276

277

The `KernelProvisionerFactory` manages the creation of provisioner instances and discovery of available provisioners.

278

279

```python { .api }

280

class KernelProvisionerFactory:

281

"""Factory for creating kernel provisioner instances."""

282

283

def is_provisioner_available(self, kernel_spec):

284

"""

285

Check if a provisioner is available for the kernel spec.

286

287

Parameters:

288

- kernel_spec (KernelSpec): Kernel specification

289

290

Returns:

291

bool: True if provisioner is available

292

"""

293

294

def create_provisioner_instance(self, kernel_id, kernel_spec, parent):

295

"""

296

Create a provisioner instance for the kernel.

297

298

Parameters:

299

- kernel_id (str): Unique kernel identifier

300

- kernel_spec (KernelSpec): Kernel specification

301

- parent: Parent configurable object

302

303

Returns:

304

KernelProvisionerBase: Provisioner instance

305

"""

306

307

def get_provisioner_entries(self):

308

"""

309

Get all available provisioner entry points.

310

311

Returns:

312

dict: Mapping of provisioner names to entry points

313

"""

314

```

315

316

### Kernel Launcher

317

318

Utility function for launching kernel processes directly.

319

320

```python { .api }

321

def launch_kernel(cmd, stdin=None, stdout=None, stderr=None,

322

env=None, independent=False, cwd=None, **kw):

323

"""

324

Launch a kernel process.

325

326

Parameters:

327

- cmd (list): Command line arguments to execute

328

- stdin (int): Standard input file descriptor

329

- stdout (int): Standard output file descriptor

330

- stderr (int): Standard error file descriptor

331

- env (dict): Environment variables

332

- independent (bool): Whether kernel survives parent death

333

- cwd (str): Working directory for kernel process

334

- **kw: Additional Popen arguments

335

336

Returns:

337

subprocess.Popen: Process object for the kernel

338

"""

339

```

340

341

## Usage Examples

342

343

### Using Default Local Provisioner

344

345

```python

346

from jupyter_client import KernelManager

347

348

# KernelManager uses LocalProvisioner by default

349

km = KernelManager(kernel_name='python3')

350

km.start_kernel()

351

352

# The provisioner is accessible

353

provisioner = km.provisioner

354

print(f"Provisioner type: {type(provisioner)}")

355

print(f"Has process: {provisioner.has_process}")

356

357

# Check if kernel is running

358

if await provisioner.poll() is None:

359

print("Kernel is running")

360

361

km.shutdown_kernel()

362

```

363

364

### Creating Custom Provisioner

365

366

```python

367

from jupyter_client.provisioning import KernelProvisionerBase

368

import asyncio

369

import subprocess

370

371

class CustomProvisioner(KernelProvisionerBase):

372

"""Custom provisioner example."""

373

374

def __init__(self, **kwargs):

375

super().__init__(**kwargs)

376

self.process = None

377

378

@property

379

def has_process(self):

380

return True

381

382

async def launch_kernel(self, cmd, **kwargs):

383

"""Launch kernel with custom logic."""

384

# Custom environment setup

385

custom_env = kwargs.get('env', {}).copy()

386

custom_env['CUSTOM_VAR'] = 'custom_value'

387

388

# Launch process

389

self.process = subprocess.Popen(

390

cmd,

391

env=custom_env,

392

cwd=kwargs.get('cwd'),

393

stdout=subprocess.PIPE,

394

stderr=subprocess.PIPE

395

)

396

397

# Return connection info (would be real in practice)

398

return {

399

'shell_port': 50001,

400

'iopub_port': 50002,

401

'stdin_port': 50003,

402

'hb_port': 50004,

403

'control_port': 50005,

404

'ip': '127.0.0.1',

405

'transport': 'tcp'

406

}

407

408

async def poll(self):

409

if self.process:

410

return self.process.poll()

411

return None

412

413

async def kill(self, restart=False):

414

if self.process:

415

self.process.kill()

416

417

async def terminate(self, restart=False):

418

if self.process:

419

self.process.terminate()

420

421

async def send_signal(self, signum):

422

if self.process:

423

self.process.send_signal(signum)

424

425

async def wait(self):

426

if self.process:

427

return self.process.wait()

428

return None

429

430

# Use custom provisioner

431

from jupyter_client import KernelManager

432

km = KernelManager()

433

km.provisioner = CustomProvisioner(parent=km)

434

```

435

436

### Working with Provisioner Factory

437

438

```python

439

from jupyter_client.provisioning import KernelProvisionerFactory

440

from jupyter_client import get_kernel_spec

441

442

# Get factory instance

443

factory = KernelProvisionerFactory.instance()

444

445

# Get available provisioners

446

provisioners = factory.get_provisioner_entries()

447

print(f"Available provisioners: {list(provisioners.keys())}")

448

449

# Check if provisioner is available for a kernel spec

450

kernel_spec = get_kernel_spec('python3')

451

if factory.is_provisioner_available(kernel_spec):

452

print("Provisioner available for python3")

453

454

# Create provisioner instance

455

provisioner = factory.create_provisioner_instance(

456

kernel_id='test-kernel',

457

kernel_spec=kernel_spec,

458

parent=None

459

)

460

print(f"Created provisioner: {type(provisioner)}")

461

```

462

463

### Async Provisioner Operations

464

465

```python

466

import asyncio

467

from jupyter_client import AsyncKernelManager

468

469

async def manage_kernel_with_provisioner():

470

km = AsyncKernelManager()

471

await km.start_kernel()

472

473

provisioner = km.provisioner

474

475

# Check provisioner state

476

if provisioner.has_process:

477

status = await provisioner.poll()

478

if status is None:

479

print("Kernel process is running")

480

481

# Get provisioner info

482

info = await provisioner.get_provisioner_info()

483

print(f"Provisioner info: {info}")

484

485

# Graceful shutdown

486

await provisioner.terminate()

487

await provisioner.wait()

488

489

# Cleanup

490

await provisioner.cleanup()

491

492

await km.shutdown_kernel()

493

494

# Run async example

495

asyncio.run(manage_kernel_with_provisioner())

496

```

497

498

### Direct Kernel Launch

499

500

```python

501

from jupyter_client.launcher import launch_kernel

502

import tempfile

503

import os

504

505

# Prepare kernel command

506

cmd = ['python', '-m', 'ipykernel_launcher', '-f', 'connection.json']

507

508

# Create temporary directory for kernel

509

with tempfile.TemporaryDirectory() as temp_dir:

510

conn_file = os.path.join(temp_dir, 'connection.json')

511

512

# Write connection file

513

from jupyter_client import write_connection_file

514

write_connection_file(conn_file)

515

516

# Launch kernel directly

517

process = launch_kernel(

518

cmd,

519

cwd=temp_dir,

520

independent=True

521

)

522

523

print(f"Launched kernel with PID: {process.pid}")

524

525

# Use kernel...

526

527

# Clean up

528

process.terminate()

529

process.wait()

530

```

531

532

### Custom Environment Provisioner

533

534

```python

535

from jupyter_client.provisioning import LocalProvisioner

536

537

class ContainerProvisioner(LocalProvisioner):

538

"""Example provisioner that runs kernels in containers."""

539

540

async def pre_launch(self, **kwargs):

541

"""Modify command to run in container."""

542

cmd = kwargs.get('cmd', [])

543

544

# Wrap command with container runtime

545

container_cmd = [

546

'docker', 'run', '--rm', '-i',

547

'--name', f'kernel-{self.kernel_id}',

548

'jupyter/scipy-notebook'

549

] + cmd

550

551

kwargs['cmd'] = container_cmd

552

return kwargs

553

554

async def kill(self, restart=False):

555

"""Kill container instead of process."""

556

import subprocess

557

try:

558

subprocess.run([

559

'docker', 'kill', f'kernel-{self.kernel_id}'

560

], check=True)

561

except subprocess.CalledProcessError:

562

pass # Container might already be stopped

563

564

# Use container provisioner

565

from jupyter_client import KernelManager

566

km = KernelManager()

567

km.provisioner_class = ContainerProvisioner

568

km.start_kernel()

569

```