or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

autogeneration.mdcli-commands.mdconfiguration.mdindex.mdmigration-context.mdmigration-operations.mdruntime.mdscript-management.md

script-management.mddocs/

0

# Script Management

1

2

Classes and utilities for managing migration scripts, revision tracking, and dependency graphs. The script management system handles migration file generation, versioning, and execution ordering.

3

4

## Core Imports

5

6

```python

7

from alembic.script import ScriptDirectory, Script

8

from alembic.script.revision import RevisionMap

9

```

10

11

## Capabilities

12

13

### Script Directory Management

14

15

Main class for managing the migration script directory and its contents.

16

17

```python { .api }

18

class ScriptDirectory:

19

def __init__(self, dir, file_template=None, truncate_slug_length=40, version_locations=None, sourceless=False, output_encoding='utf-8', timezone=None, hook=None, env_py_location=None):

20

"""

21

Initialize script directory manager.

22

23

Args:

24

dir (str): Path to script directory

25

file_template (str): Template for migration file names

26

truncate_slug_length (int): Maximum length for revision slugs

27

version_locations (list): Additional version file locations

28

sourceless (bool): Whether to support .pyc-only migrations

29

output_encoding (str): Encoding for generated files

30

timezone (str): Timezone for timestamps

31

hook (callable): Custom hook function

32

env_py_location (str): Path to env.py file

33

"""

34

35

@classmethod

36

def from_config(cls, config):

37

"""

38

Create ScriptDirectory from Alembic configuration.

39

40

Args:

41

config (Config): Alembic configuration object

42

43

Returns:

44

ScriptDirectory: Configured script directory

45

"""

46

47

def get_revision(self, id_):

48

"""

49

Get a revision by ID.

50

51

Args:

52

id_ (str): Revision identifier

53

54

Returns:

55

Script: Script object for the revision

56

"""

57

58

def get_revisions(self, id_):

59

"""

60

Get multiple revisions by ID pattern.

61

62

Args:

63

id_ (str): Revision identifier or pattern

64

65

Returns:

66

tuple: Tuple of Script objects

67

"""

68

69

def get_all_current(self, id_):

70

"""

71

Get all current head revisions.

72

73

Args:

74

id_ (str): Starting revision identifier

75

76

Returns:

77

tuple: Tuple of current head revisions

78

"""

79

80

def get_heads(self):

81

"""

82

Get all head revisions.

83

84

Returns:

85

tuple: Tuple of head revision identifiers

86

"""

87

88

def get_base(self):

89

"""

90

Get base revision identifier.

91

92

Returns:

93

str: Base revision identifier

94

"""

95

96

def walk_revisions(self, base='base', head='heads'):

97

"""

98

Walk through revisions from base to head.

99

100

Args:

101

base (str): Starting revision

102

head (str): Ending revision

103

104

Yields:

105

Script: Script objects in dependency order

106

"""

107

108

def get_current_head(self):

109

"""

110

Get the current single head revision.

111

112

Returns:

113

str: Head revision identifier

114

115

Raises:

116

CommandError: If multiple heads exist

117

"""

118

```

119

120

**Usage Examples**:

121

```python

122

from alembic.script import ScriptDirectory

123

from alembic.config import Config

124

125

# Create from configuration

126

config = Config('alembic.ini')

127

script_dir = ScriptDirectory.from_config(config)

128

129

# Get revision information

130

latest_rev = script_dir.get_current_head()

131

all_heads = script_dir.get_heads()

132

133

# Walk through revision history

134

for script in script_dir.walk_revisions():

135

print(f"Revision: {script.revision}, Message: {script.doc}")

136

137

# Get specific revision

138

rev_abc123 = script_dir.get_revision('abc123')

139

print(f"Down revision: {rev_abc123.down_revision}")

140

```

141

142

### Revision Generation

143

144

Generate new migration script files.

145

146

```python { .api }

147

class ScriptDirectory:

148

def generate_revision(self, revid, message, refresh=False, head='head', splice=False, branch_labels=None, version_path=None, depends_on=None, **kw):

149

"""

150

Generate a new revision script.

151

152

Args:

153

revid (str): Revision identifier

154

message (str): Revision message

155

refresh (bool): Refresh revision map

156

head (str): Head revision to base on

157

splice (bool): Allow revision to be spliced

158

branch_labels (list): Branch labels for revision

159

version_path (str): Path for version files

160

depends_on (list): Dependencies for revision

161

**kw: Additional template variables

162

163

Returns:

164

Script: Generated script object

165

"""

166

167

def run_env(self):

168

"""

169

Execute the env.py script.

170

171

Returns:

172

dict: Environment module's globals

173

"""

174

175

def get_upgrade_token(self):

176

"""

177

Get the upgrade token from env.py.

178

179

Returns:

180

str: Upgrade token identifier

181

"""

182

183

def get_downgrade_token(self):

184

"""

185

Get the downgrade token from env.py.

186

187

Returns:

188

str: Downgrade token identifier

189

"""

190

```

191

192

**Usage Examples**:

193

```python

194

# Generate new revision

195

script = script_dir.generate_revision(

196

revid='abc123',

197

message='Create user table',

198

head='head',

199

branch_labels=['feature']

200

)

201

202

# Generate with dependencies

203

script = script_dir.generate_revision(

204

revid='def456',

205

message='Add indexes',

206

depends_on=['abc123']

207

)

208

209

# Generate with custom template variables

210

script = script_dir.generate_revision(

211

revid='ghi789',

212

message='Custom migration',

213

author='John Doe',

214

created_by='AutoGen'

215

)

216

```

217

218

### Script Objects

219

220

Individual migration script representation.

221

222

```python { .api }

223

class Script:

224

def __init__(self, module, rev_id, path):

225

"""

226

Initialize script object.

227

228

Args:

229

module: Python module containing the migration

230

rev_id (str): Revision identifier

231

path (str): File path to script

232

"""

233

234

# Properties

235

revision: str # Revision identifier

236

down_revision: Optional[str] # Previous revision

237

branch_labels: Optional[Set[str]] # Branch labels

238

depends_on: Optional[Set[str]] # Dependencies

239

path: str # File path

240

doc: str # Revision message

241

module: ModuleType # Python module

242

243

def get_path(self):

244

"""

245

Get the file path for this script.

246

247

Returns:

248

str: Path to script file

249

"""

250

251

def nextrev(self):

252

"""

253

Get the next revision in the chain.

254

255

Returns:

256

str: Next revision identifier

257

"""

258

259

def is_base(self):

260

"""

261

Check if this is a base revision.

262

263

Returns:

264

bool: True if base revision

265

"""

266

267

def is_head(self):

268

"""

269

Check if this is a head revision.

270

271

Returns:

272

bool: True if head revision

273

"""

274

275

def is_merge_point(self):

276

"""

277

Check if this is a merge point.

278

279

Returns:

280

bool: True if merge point

281

"""

282

283

def is_branch_point(self):

284

"""

285

Check if this is a branch point.

286

287

Returns:

288

bool: True if branch point

289

"""

290

```

291

292

**Usage Examples**:

293

```python

294

# Access script properties

295

script = script_dir.get_revision('abc123')

296

print(f"Revision: {script.revision}")

297

print(f"Message: {script.doc}")

298

print(f"Path: {script.path}")

299

print(f"Down revision: {script.down_revision}")

300

print(f"Branch labels: {script.branch_labels}")

301

302

# Check script status

303

if script.is_head():

304

print("This is a head revision")

305

if script.is_merge_point():

306

print("This is a merge point")

307

```

308

309

### Revision Maps

310

311

Manage revision dependency graphs and navigation.

312

313

```python { .api }

314

class RevisionMap:

315

def __init__(self, generator):

316

"""

317

Initialize revision map.

318

319

Args:

320

generator: Generator function yielding Script objects

321

"""

322

323

def get_revision(self, id_):

324

"""

325

Get revision by identifier.

326

327

Args:

328

id_ (str): Revision identifier

329

330

Returns:

331

Script: Script object

332

"""

333

334

def get_revisions(self, id_):

335

"""

336

Get multiple revisions by identifier.

337

338

Args:

339

id_ (str): Revision identifier pattern

340

341

Returns:

342

tuple: Tuple of Script objects

343

"""

344

345

def iterate_revisions(self, upper, lower):

346

"""

347

Iterate revisions between upper and lower bounds.

348

349

Args:

350

upper (str): Upper bound revision

351

lower (str): Lower bound revision

352

353

Yields:

354

Script: Script objects in order

355

"""

356

357

def get_heads(self):

358

"""

359

Get all head revision identifiers.

360

361

Returns:

362

tuple: Head revision identifiers

363

"""

364

365

def get_bases(self):

366

"""

367

Get all base revision identifiers.

368

369

Returns:

370

tuple: Base revision identifiers

371

"""

372

```

373

374

## Version Locations

375

376

Manage multiple locations for migration scripts.

377

378

```python

379

# Configure multiple version locations

380

script_dir = ScriptDirectory(

381

'migrations',

382

version_locations=[

383

'migrations/versions', # Default location

384

'migrations/feature', # Feature branch migrations

385

'migrations/hotfix' # Hotfix migrations

386

]

387

)

388

389

# Generate revision in specific location

390

script = script_dir.generate_revision(

391

revid='feature_001',

392

message='Feature migration',

393

version_path='migrations/feature'

394

)

395

```

396

397

## Branching and Merging

398

399

### Branch Management

400

401

```python

402

# Create branch revision

403

branch_script = script_dir.generate_revision(

404

revid='branch_001',

405

message='Start feature branch',

406

head='abc123', # Branch from this revision

407

branch_labels=['feature_x']

408

)

409

410

# Create merge revision

411

merge_script = script_dir.generate_revision(

412

revid='merge_001',

413

message='Merge feature branch',

414

head=['head', 'feature_x'] # Merge multiple heads

415

)

416

```

417

418

#### Dependency Management

419

420

```python

421

# Create revision with dependencies

422

dependent_script = script_dir.generate_revision(

423

revid='dep_001',

424

message='Migration with dependencies',

425

depends_on=['abc123', 'def456'] # Depends on these revisions

426

)

427

428

# Check dependencies

429

for dep in dependent_script.depends_on:

430

dep_script = script_dir.get_revision(dep)

431

print(f"Depends on: {dep_script.doc}")

432

```

433

434

## Template Customization

435

436

### Custom File Templates

437

438

```python

439

# Custom template with additional variables

440

custom_template = '''"""${message}

441

442

Revision ID: ${up_revision}

443

Revises: ${down_revision | comma,n}

444

Create Date: ${create_date}

445

Author: ${author}

446

Branch: ${branch_name}

447

"""

448

449

from alembic import op

450

import sqlalchemy as sa

451

${imports if imports else ""}

452

453

# revision identifiers, used by Alembic.

454

revision = ${repr(up_revision)}

455

down_revision = ${repr(down_revision)}

456

branch_labels = ${repr(branch_labels)}

457

depends_on = ${repr(depends_on)}

458

459

def upgrade():

460

${upgrades if upgrades else "pass"}

461

462

def downgrade():

463

${downgrades if downgrades else "pass"}

464

'''

465

466

# Use custom template

467

script_dir = ScriptDirectory(

468

'migrations',

469

file_template=custom_template

470

)

471

```

472

473

### Template Variables

474

475

Available variables in migration templates:

476

477

- `${message}`: Revision message

478

- `${up_revision}`: Revision identifier

479

- `${down_revision}`: Previous revision identifier

480

- `${create_date}`: Creation timestamp

481

- `${branch_labels}`: Branch labels

482

- `${depends_on}`: Dependencies

483

- `${upgrades}`: Upgrade operations (autogenerate)

484

- `${downgrades}`: Downgrade operations (autogenerate)

485

- `${imports}`: Required imports (autogenerate)

486

487

## Advanced Features

488

489

### Sourceless Migrations

490

491

Run migrations from compiled .pyc files without .py sources.

492

493

```python

494

# Configure sourceless mode

495

script_dir = ScriptDirectory(

496

'migrations',

497

sourceless=True # Support .pyc-only migrations

498

)

499

```

500

501

### Custom Hook Functions

502

503

Execute custom logic during script operations.

504

505

```python

506

def custom_hook(rev, context):

507

"""Custom hook function."""

508

print(f"Processing revision: {rev}")

509

# Custom validation or processing logic

510

511

script_dir = ScriptDirectory(

512

'migrations',

513

hook=custom_hook

514

)

515

```

516

517

### Environment Integration

518

519

```python

520

# Custom env.py location

521

script_dir = ScriptDirectory(

522

'migrations',

523

env_py_location='custom/env.py'

524

)

525

526

# Execute environment script

527

env_globals = script_dir.run_env()

528

target_metadata = env_globals.get('target_metadata')

529

```

530

531

## Error Handling

532

533

Script management operations may raise:

534

- `RevisionError`: Revision identifier conflicts or invalid references

535

- `MultipleHeads`: Multiple head revisions when single expected

536

- `CommandError`: General script management errors

537

- `FileNotFoundError`: Missing script files or directories

538

539

## Integration Examples

540

541

### Web Application Integration

542

543

```python

544

from alembic.script import ScriptDirectory

545

from alembic.config import Config

546

547

class MigrationManager:

548

def __init__(self, config_path):

549

self.config = Config(config_path)

550

self.script_dir = ScriptDirectory.from_config(self.config)

551

552

def get_migration_status(self):

553

"""Get current migration status."""

554

current_heads = self.script_dir.get_heads()

555

return {

556

'heads': current_heads,

557

'is_current': len(current_heads) == 1

558

}

559

560

def list_migrations(self):

561

"""List all migrations."""

562

migrations = []

563

for script in self.script_dir.walk_revisions():

564

migrations.append({

565

'revision': script.revision,

566

'message': script.doc,

567

'down_revision': script.down_revision

568

})

569

return migrations

570

```

571

572

### Automated Migration Generation

573

574

```python

575

def auto_generate_migration(app_metadata, message):

576

"""Generate migration automatically."""

577

config = Config('alembic.ini')

578

script_dir = ScriptDirectory.from_config(config)

579

580

# Generate unique revision ID

581

import uuid

582

rev_id = str(uuid.uuid4())[:12]

583

584

# Generate migration script

585

script = script_dir.generate_revision(

586

revid=rev_id,

587

message=message,

588

autogenerate=True,

589

target_metadata=app_metadata

590

)

591

592

return script

593

```

594

595

## Types

596

597

```python { .api }

598

# Script management types

599

class Script:

600

revision: str

601

down_revision: Optional[str]

602

branch_labels: Optional[Set[str]]

603

depends_on: Optional[Set[str]]

604

path: str

605

doc: str

606

module: ModuleType

607

608

class ScriptDirectory:

609

dir: str

610

file_template: str

611

truncate_slug_length: int

612

version_locations: Optional[List[str]]

613

614

class RevisionMap:

615

map: Dict[str, Script]

616

617

# Hook function type

618

HookFunc = Callable[[str, Any], None]

619

```