or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdcli-commands.mdconfiguration.mdenvironment-management.mdindex.mdplugin-system.mdproject-management.mdpython-management.md

environment-management.mddocs/

0

# Environment Management

1

2

Environment plugin system for creating, managing, and executing commands in isolated Python environments. Supports virtual environments, Docker containers, and custom environment types through plugins.

3

4

## Capabilities

5

6

### Environment Interface

7

8

Base interface for all environment plugins providing standardized operations for environment lifecycle management.

9

10

```python { .api }

11

class EnvironmentInterface:

12

"""

13

Base interface for environment plugins.

14

15

All environment plugins must inherit from this class and implement

16

the abstract methods to provide environment management capabilities.

17

"""

18

19

PLUGIN_NAME: str = '' # Must be set by plugin implementations

20

21

def __init__(self, root, metadata, name, config, matrix_variables, data_directory, platform, verbosity, app):

22

"""

23

Initialize environment interface.

24

25

Args:

26

root: Project root directory

27

metadata: Project metadata

28

name (str): Environment name

29

config (dict): Environment configuration

30

matrix_variables (dict): Matrix variables for environment

31

data_directory: Directory for environment data

32

platform: Platform utilities

33

verbosity (int): Verbosity level

34

app: Application instance

35

"""

36

37

@property

38

def root(self):

39

"""Project root directory."""

40

41

@property

42

def metadata(self):

43

"""Project metadata."""

44

45

@property

46

def name(self) -> str:

47

"""Environment name."""

48

49

@property

50

def config(self) -> dict:

51

"""Environment configuration."""

52

53

@property

54

def matrix_variables(self) -> dict:

55

"""Matrix variables for this environment."""

56

57

@property

58

def data_directory(self):

59

"""Directory for environment data storage."""

60

61

@property

62

def platform(self):

63

"""Platform utilities for command execution."""

64

65

@property

66

def app(self):

67

"""Application instance."""

68

69

@property

70

def env_vars(self) -> dict:

71

"""

72

Environment variables for this environment.

73

74

Returns:

75

Dict of environment variables to set during execution

76

"""

77

78

@property

79

def dependencies(self) -> list:

80

"""

81

List of dependencies for this environment.

82

83

Returns:

84

List of dependency specifications

85

"""

86

87

@property

88

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

89

"""

90

List of features enabled for this environment.

91

92

Returns:

93

List of feature names

94

"""

95

96

@property

97

def scripts(self) -> dict[str, str]:

98

"""

99

Scripts defined for this environment.

100

101

Returns:

102

Dict mapping script names to commands

103

"""

104

105

def exists(self) -> bool:

106

"""

107

Check if environment exists.

108

109

Returns:

110

True if environment exists and is ready for use

111

"""

112

113

def create(self) -> None:

114

"""

115

Create the environment.

116

117

This should create all necessary resources for the environment

118

including installing base dependencies.

119

"""

120

121

def remove(self) -> None:

122

"""

123

Remove the environment.

124

125

This should clean up all resources associated with the environment.

126

"""

127

128

def install_project(self) -> None:

129

"""

130

Install the project in the environment.

131

132

This should install the project package in the environment

133

without development mode.

134

"""

135

136

def install_project_dev_mode(self) -> None:

137

"""

138

Install the project in development mode.

139

140

This should install the project package in editable/development mode

141

so changes to source code are immediately reflected.

142

"""

143

144

def dependencies_in_sync(self) -> bool:

145

"""

146

Check if dependencies are synchronized with configuration.

147

148

Returns:

149

True if installed dependencies match configuration

150

"""

151

152

def sync_dependencies(self) -> None:

153

"""

154

Synchronize dependencies with configuration.

155

156

This should install, upgrade, or remove dependencies to match

157

the current environment configuration.

158

"""

159

160

def run_command(

161

self,

162

command: list[str],

163

*,

164

shell: bool = False,

165

env_vars: dict | None = None,

166

capture_output: bool = False

167

):

168

"""

169

Run command in the environment.

170

171

Args:

172

command (list[str]): Command and arguments to execute

173

shell (bool): Whether to use shell execution

174

env_vars (dict, optional): Additional environment variables

175

capture_output (bool): Whether to capture command output

176

177

Returns:

178

Command execution result

179

"""

180

181

def enter_shell(self, name: str, path: str, args: list[str]):

182

"""

183

Enter interactive shell in the environment.

184

185

Args:

186

name (str): Shell name

187

path (str): Shell executable path

188

args (list[str]): Shell arguments

189

"""

190

191

def build_environment(self, targets: list[str], env_vars: dict):

192

"""

193

Build artifacts in the environment.

194

195

Args:

196

targets (list[str]): Build targets

197

env_vars (dict): Environment variables for build

198

"""

199

200

def get_build_process(self, build_environment, **kwargs):

201

"""

202

Get build process for this environment.

203

204

Args:

205

build_environment: Build environment configuration

206

**kwargs: Additional build arguments

207

208

Returns:

209

Build process instance

210

"""

211

```

212

213

### Virtual Environment Plugin

214

215

Built-in virtual environment plugin providing standard Python virtual environment support.

216

217

```python { .api }

218

class VirtualEnvironment(EnvironmentInterface):

219

"""

220

Virtual environment plugin using Python's venv module.

221

222

Provides isolated Python environments with dependency management

223

and project installation support.

224

"""

225

226

PLUGIN_NAME = 'virtual'

227

228

@property

229

def python_info(self) -> dict:

230

"""Information about Python installation in environment."""

231

232

@property

233

def python_path(self) -> str:

234

"""Path to Python executable in environment."""

235

236

@property

237

def site_packages_path(self) -> str:

238

"""Path to site-packages directory in environment."""

239

240

@property

241

def scripts_path(self) -> str:

242

"""Path to scripts/bin directory in environment."""

243

244

def activate_environment(self) -> dict[str, str]:

245

"""

246

Get environment variables for activating virtual environment.

247

248

Returns:

249

Dict of environment variables to set for activation

250

"""

251

252

def deactivate_environment(self) -> dict[str, str]:

253

"""

254

Get environment variables for deactivating virtual environment.

255

256

Returns:

257

Dict of environment variables to unset for deactivation

258

"""

259

260

def install_packages(self, packages: list[str], *, dev: bool = False) -> None:

261

"""

262

Install packages in the virtual environment.

263

264

Args:

265

packages (list[str]): Package specifications to install

266

dev (bool): Whether to install development dependencies

267

"""

268

269

def uninstall_packages(self, packages: list[str]) -> None:

270

"""

271

Uninstall packages from the virtual environment.

272

273

Args:

274

packages (list[str]): Package names to uninstall

275

"""

276

277

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

278

"""

279

List installed packages in the environment.

280

281

Returns:

282

List of installed package specifications

283

"""

284

```

285

286

### Environment Configuration

287

288

Configuration system for defining environments including dependencies, scripts, environment variables, and plugin settings.

289

290

```python { .api }

291

class EnvironmentConfig:

292

"""Configuration for a single environment."""

293

294

@property

295

def type(self) -> str:

296

"""Environment type/plugin name."""

297

298

@property

299

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

300

"""List of dependencies for this environment."""

301

302

@property

303

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

304

"""Extra dependencies beyond project dependencies."""

305

306

@property

307

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

308

"""Project features to install."""

309

310

@property

311

def dev_mode(self) -> bool:

312

"""Whether to install project in development mode."""

313

314

@property

315

def skip_install(self) -> bool:

316

"""Whether to skip project installation."""

317

318

@property

319

def python(self) -> str:

320

"""Python version or path for this environment."""

321

322

@property

323

def matrix(self) -> dict:

324

"""Matrix variables for environment variants."""

325

326

@property

327

def env_vars(self) -> dict[str, str]:

328

"""Environment variables to set."""

329

330

@property

331

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

332

"""Environment variables to include from host."""

333

334

@property

335

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

336

"""Environment variables to exclude."""

337

338

@property

339

def scripts(self) -> dict[str, str]:

340

"""Scripts defined for this environment."""

341

342

@property

343

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

344

"""Commands to run before installing dependencies."""

345

346

@property

347

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

348

"""Commands to run after installing dependencies."""

349

350

@property

351

def template(self) -> str:

352

"""Template environment to inherit from."""

353

```

354

355

### Environment Discovery

356

357

Utilities for discovering, validating, and collecting environment configurations from various sources.

358

359

```python { .api }

360

def discover_environments(project) -> dict[str, EnvironmentConfig]:

361

"""

362

Discover environment configurations from project.

363

364

Args:

365

project: Project instance

366

367

Returns:

368

Dict mapping environment names to configurations

369

"""

370

371

def validate_environment_config(config: dict) -> list[str]:

372

"""

373

Validate environment configuration.

374

375

Args:

376

config (dict): Environment configuration to validate

377

378

Returns:

379

List of validation errors (empty if valid)

380

"""

381

382

def resolve_environment_dependencies(

383

base_dependencies: list[str],

384

env_config: EnvironmentConfig,

385

features: list[str]

386

) -> list[str]:

387

"""

388

Resolve final dependency list for environment.

389

390

Args:

391

base_dependencies (list[str]): Project base dependencies

392

env_config (EnvironmentConfig): Environment configuration

393

features (list[str]): Enabled features

394

395

Returns:

396

Final list of dependencies to install

397

"""

398

399

def expand_environment_matrix(

400

env_config: EnvironmentConfig

401

) -> list[tuple[str, dict]]:

402

"""

403

Expand environment matrix into individual configurations.

404

405

Args:

406

env_config (EnvironmentConfig): Environment with matrix

407

408

Returns:

409

List of (environment_name, matrix_variables) tuples

410

"""

411

```

412

413

### Environment Operations

414

415

High-level operations for managing environments including creation, synchronization, cleanup, and status reporting.

416

417

```python { .api }

418

def create_environment(app, env_name: str) -> None:

419

"""

420

Create named environment.

421

422

Args:

423

app: Application instance

424

env_name (str): Environment name to create

425

"""

426

427

def remove_environment(app, env_name: str) -> None:

428

"""

429

Remove named environment.

430

431

Args:

432

app: Application instance

433

env_name (str): Environment name to remove

434

"""

435

436

def sync_environment(app, env_name: str) -> None:

437

"""

438

Synchronize environment dependencies.

439

440

Args:

441

app: Application instance

442

env_name (str): Environment name to synchronize

443

"""

444

445

def prune_environments(app) -> list[str]:

446

"""

447

Remove unused environments.

448

449

Args:

450

app: Application instance

451

452

Returns:

453

List of removed environment names

454

"""

455

456

def show_environment_info(app, env_name: str) -> dict:

457

"""

458

Get environment information.

459

460

Args:

461

app: Application instance

462

env_name (str): Environment name

463

464

Returns:

465

Dict with environment information

466

"""

467

468

def find_environment_path(app, env_name: str) -> str | None:

469

"""

470

Find path to environment directory.

471

472

Args:

473

app: Application instance

474

env_name (str): Environment name

475

476

Returns:

477

Path to environment or None if not found

478

"""

479

```

480

481

## Usage Examples

482

483

### Creating and Using Environments

484

485

```python

486

from hatch.cli.application import Application

487

from hatch.env.plugin.interface import EnvironmentInterface

488

489

app = Application(lambda code: exit(code))

490

491

# Get environment interface

492

env = app.get_environment("test")

493

494

# Create environment if it doesn't exist

495

if not env.exists():

496

print("Creating test environment...")

497

env.create()

498

499

# Install project in development mode

500

env.install_project_dev_mode()

501

502

# Synchronize dependencies

503

if not env.dependencies_in_sync():

504

print("Synchronizing dependencies...")

505

env.sync_dependencies()

506

507

# Run command in environment

508

result = env.run_command(

509

["python", "-m", "pytest", "tests/"],

510

capture_output=True

511

)

512

print(f"Test result: {result.returncode}")

513

```

514

515

### Environment Configuration

516

517

```python

518

from hatch.env import discover_environments

519

520

# Discover environments from project

521

project = app.project

522

environments = discover_environments(project)

523

524

# Access environment configuration

525

test_env_config = environments.get("test")

526

if test_env_config:

527

print(f"Test dependencies: {test_env_config.dependencies}")

528

print(f"Test scripts: {test_env_config.scripts}")

529

print(f"Python version: {test_env_config.python}")

530

531

# Validate configuration

532

errors = validate_environment_config(test_env_config.__dict__)

533

if errors:

534

print(f"Configuration errors: {errors}")

535

```

536

537

### Custom Environment Plugin

538

539

```python

540

from hatch.env.plugin.interface import EnvironmentInterface

541

542

class DockerEnvironment(EnvironmentInterface):

543

"""Custom Docker-based environment plugin."""

544

545

PLUGIN_NAME = 'docker'

546

547

def exists(self) -> bool:

548

# Check if Docker container exists

549

result = self.platform.run_command([

550

'docker', 'inspect', self.container_name

551

], capture_output=True)

552

return result.returncode == 0

553

554

def create(self) -> None:

555

# Create Docker container

556

self.platform.run_command([

557

'docker', 'create',

558

'--name', self.container_name,

559

'--volume', f'{self.root}:/workspace',

560

self.config.get('image', 'python:3.11'),

561

'sleep', 'infinity'

562

])

563

564

# Start container

565

self.platform.run_command([

566

'docker', 'start', self.container_name

567

])

568

569

def remove(self) -> None:

570

# Remove Docker container

571

self.platform.run_command([

572

'docker', 'rm', '-f', self.container_name

573

])

574

575

@property

576

def container_name(self) -> str:

577

return f'hatch-{self.name}-{self.root.name}'

578

579

def run_command(self, command: list[str], **kwargs):

580

# Execute command in Docker container

581

docker_cmd = [

582

'docker', 'exec',

583

'-w', '/workspace',

584

self.container_name

585

] + command

586

587

return self.platform.run_command(docker_cmd, **kwargs)

588

```

589

590

### Environment Matrix

591

592

```python

593

from hatch.env import expand_environment_matrix

594

595

# Environment configuration with matrix

596

config = EnvironmentConfig({

597

'matrix': {

598

'python': ['3.9', '3.10', '3.11'],

599

'django': ['3.2', '4.0', '4.1']

600

},

601

'dependencies': [

602

'django=={matrix:django}'

603

]

604

})

605

606

# Expand matrix into individual environments

607

environments = expand_environment_matrix(config)

608

609

for env_name, matrix_vars in environments:

610

print(f"Environment: {env_name}")

611

print(f"Variables: {matrix_vars}")

612

# Result: test-py3.9-django3.2, test-py3.10-django4.0, etc.

613

```