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

autogeneration.mddocs/

0

# Autogeneration

1

2

Automatic migration generation by comparing database schema with SQLAlchemy model definitions. The autogeneration system includes customizable comparison and rendering systems for generating migration scripts.

3

4

## Core Imports

5

6

```python

7

from alembic.autogenerate import compare_metadata, produce_migrations, render_python_code

8

from alembic.autogenerate.api import RevisionContext, AutogenContext, _render_migration_diffs

9

from alembic.autogenerate.compare import _produce_net_changes, comparators

10

from alembic.autogenerate.render import render_op_text, renderers

11

```

12

13

## Capabilities

14

15

### Metadata Comparison

16

17

Compare target metadata against database schema to identify differences.

18

19

```python { .api }

20

def compare_metadata(context, metadata):

21

"""

22

Compare metadata against database and return differences.

23

24

Args:

25

context (MigrationContext): Migration context with database connection

26

metadata (MetaData): SQLAlchemy metadata to compare

27

28

Returns:

29

list: List of operation objects representing differences

30

"""

31

```

32

33

**Usage Example**:

34

```python

35

from alembic.autogenerate import compare_metadata

36

from alembic.runtime.migration import MigrationContext

37

from sqlalchemy import create_engine

38

39

engine = create_engine('postgresql://user:pass@localhost/db')

40

with engine.connect() as conn:

41

context = MigrationContext.configure(conn)

42

diffs = compare_metadata(context, target_metadata)

43

for diff in diffs:

44

print(diff)

45

```

46

47

### Migration Production

48

49

Generate migration operations from metadata comparison.

50

51

```python { .api }

52

def produce_migrations(context, metadata):

53

"""

54

Produce migration operations from metadata comparison.

55

56

Args:

57

context (MigrationContext): Migration context

58

metadata (MetaData): Target metadata

59

60

Returns:

61

UpgradeOps: Container of upgrade operations

62

"""

63

```

64

65

**Usage Example**:

66

```python

67

from alembic.autogenerate import produce_migrations

68

69

operations = produce_migrations(context, target_metadata)

70

for op in operations.ops:

71

print(f"Operation: {op}")

72

```

73

74

### Python Code Rendering

75

76

Render migration operations as Python code for migration scripts.

77

78

```python { .api }

79

def render_python_code(up_or_down_op, sqlalchemy_module_prefix='sa.', alembic_module_prefix='op.', render_as_batch=False, imports=None, render_item=None):

80

"""

81

Render operations as Python code.

82

83

Args:

84

up_or_down_op (OperationContainer): Operations to render

85

sqlalchemy_module_prefix (str): Prefix for SQLAlchemy imports

86

alembic_module_prefix (str): Prefix for Alembic operations

87

render_as_batch (bool): Render as batch operations

88

imports (set): Set to collect required imports

89

render_item (callable): Custom rendering function

90

91

Returns:

92

str: Python code representation

93

"""

94

```

95

96

**Usage Example**:

97

```python

98

from alembic.autogenerate import render_python_code

99

100

# Render upgrade operations

101

imports = set()

102

code = render_python_code(

103

operations,

104

sqlalchemy_module_prefix='sa.',

105

alembic_module_prefix='op.',

106

imports=imports

107

)

108

print("Required imports:", imports)

109

print("Migration code:")

110

print(code)

111

```

112

113

### Internal Rendering Functions

114

115

Internal functions for advanced migration rendering and processing.

116

117

```python { .api }

118

def _render_migration_diffs(autogen_context, template_args):

119

"""

120

Render migration differences for template generation.

121

122

Args:

123

autogen_context (AutogenContext): Autogeneration context

124

template_args (dict): Template arguments

125

126

Returns:

127

str: Rendered migration code

128

"""

129

130

def _produce_net_changes(autogen_context, metadata):

131

"""

132

Produce net changes from metadata comparison.

133

134

Args:

135

autogen_context (AutogenContext): Autogeneration context

136

metadata (MetaData): Target metadata

137

138

Returns:

139

UpgradeOps: Net change operations

140

"""

141

142

def render_op_text(autogen_context, op):

143

"""

144

Render operation as text representation.

145

146

Args:

147

autogen_context (AutogenContext): Autogeneration context

148

op (MigrateOperation): Operation to render

149

150

Returns:

151

str: Text representation of operation

152

"""

153

```

154

155

### Revision Context

156

157

Context manager for revision generation with autogeneration support.

158

159

```python { .api }

160

class RevisionContext:

161

def __init__(self, config, script_directory, command_args, process_revision_directives=None):

162

"""

163

Context for revision generation.

164

165

Args:

166

config (Config): Alembic configuration

167

script_directory (ScriptDirectory): Script directory

168

command_args (dict): Command arguments

169

process_revision_directives (callable): Custom directive processing

170

"""

171

172

def run_autogenerate(self, rev_id, context):

173

"""

174

Run autogeneration process.

175

176

Args:

177

rev_id (str): Revision identifier

178

context (MigrationContext): Migration context

179

180

Returns:

181

Script: Generated script object

182

"""

183

184

def run_no_autogenerate(self, rev_id, context):

185

"""

186

Create empty revision without autogeneration.

187

188

Args:

189

rev_id (str): Revision identifier

190

context (MigrationContext): Migration context

191

192

Returns:

193

Script: Generated script object

194

"""

195

```

196

197

### Autogeneration Context

198

199

Context object containing autogeneration configuration and state.

200

201

```python { .api }

202

class AutogenContext:

203

def __init__(self, migration_context, metadata=None, opts=None, autogenerate=True):

204

"""

205

Context for autogeneration operations.

206

207

Args:

208

migration_context (MigrationContext): Migration context

209

metadata (MetaData): Target metadata

210

opts (dict): Configuration options

211

autogenerate (bool): Enable autogeneration

212

"""

213

214

# Properties and methods available on AutogenContext

215

migration_context: MigrationContext

216

metadata: MetaData

217

connection: Connection

218

dialect: Dialect

219

imports: Set[str]

220

```

221

222

## Comparison Customization

223

224

### Custom Comparators

225

226

Register custom comparison functions for specific object types.

227

228

```python { .api }

229

from alembic.autogenerate import comparators

230

231

@comparators.dispatch_for("schema")

232

def compare_schema(autogen_context, upgrade_ops, schemas):

233

"""

234

Custom schema comparison.

235

236

Args:

237

autogen_context (AutogenContext): Autogeneration context

238

upgrade_ops (UpgradeOps): Container for upgrade operations

239

schemas (set): Set of schema names

240

"""

241

242

@comparators.dispatch_for("table")

243

def compare_table(autogen_context, upgrade_ops, schema, table_name, conn_table, metadata_table):

244

"""

245

Custom table comparison.

246

247

Args:

248

autogen_context (AutogenContext): Autogeneration context

249

upgrade_ops (UpgradeOps): Container for upgrade operations

250

schema (str): Schema name

251

table_name (str): Table name

252

conn_table (Table): Database table reflection

253

metadata_table (Table): Metadata table definition

254

"""

255

```

256

257

**Example Usage**:

258

```python

259

@comparators.dispatch_for("table")

260

def ignore_temp_tables(autogen_context, upgrade_ops, schema, table_name, conn_table, metadata_table):

261

"""Ignore temporary tables during comparison."""

262

if table_name.startswith('temp_'):

263

return

264

# Continue with default comparison

265

return comparators.dispatch("table")(autogen_context, upgrade_ops, schema, table_name, conn_table, metadata_table)

266

```

267

268

### Type Comparison

269

270

Customize how column types are compared during autogeneration.

271

272

```python

273

def compare_type(context, inspected_column, metadata_column, inspected_type, metadata_type):

274

"""

275

Compare column types for differences.

276

277

Args:

278

context (MigrationContext): Migration context

279

inspected_column (dict): Database column information

280

metadata_column (Column): Metadata column

281

inspected_type (TypeEngine): Database column type

282

metadata_type (TypeEngine): Metadata column type

283

284

Returns:

285

bool: True if types are different

286

"""

287

# Custom type comparison logic

288

if isinstance(metadata_type, sa.String) and isinstance(inspected_type, sa.Text):

289

return False # Consider String and Text as equivalent

290

return None # Use default comparison

291

292

# Configure in context.configure()

293

context.configure(

294

connection=connection,

295

target_metadata=target_metadata,

296

compare_type=compare_type

297

)

298

```

299

300

### Server Default Comparison

301

302

Customize server default comparison logic.

303

304

```python

305

def compare_server_default(context, inspected_column, metadata_column, inspected_default, metadata_default, rendered_metadata_default):

306

"""

307

Compare server defaults for differences.

308

309

Args:

310

context (MigrationContext): Migration context

311

inspected_column (dict): Database column information

312

metadata_column (Column): Metadata column

313

inspected_default (str): Database default value

314

metadata_default: Metadata default value

315

rendered_metadata_default (str): Rendered metadata default

316

317

Returns:

318

bool: True if defaults are different

319

"""

320

# Custom server default comparison

321

if inspected_default == "''" and metadata_default is None:

322

return False # Empty string equals NULL

323

return None # Use default comparison

324

325

context.configure(

326

connection=connection,

327

target_metadata=target_metadata,

328

compare_server_default=compare_server_default

329

)

330

```

331

332

## Rendering Customization

333

334

### Custom Renderers

335

336

Register custom rendering functions for specific operations.

337

338

```python { .api }

339

from alembic.autogenerate import renderers

340

341

@renderers.dispatch_for(CreateTableOp)

342

def render_create_table(autogen_context, op):

343

"""

344

Custom rendering for CREATE TABLE operations.

345

346

Args:

347

autogen_context (AutogenContext): Autogeneration context

348

op (CreateTableOp): Create table operation

349

350

Returns:

351

str: Python code for the operation

352

"""

353

return f"op.create_table({op.table_name!r}, ...)"

354

```

355

356

### Include/Exclude Filtering

357

358

Filter objects during autogeneration.

359

360

```python

361

def include_object(object, name, type_, reflected, compare_to):

362

"""

363

Determine whether to include an object in autogeneration.

364

365

Args:

366

object: Database object

367

name (str): Object name

368

type_ (str): Object type ('table', 'column', 'index', etc.)

369

reflected (bool): True if object was reflected from database

370

compare_to: Corresponding metadata object

371

372

Returns:

373

bool: True to include object in comparison

374

"""

375

# Skip temporary tables

376

if type_ == "table" and name.startswith("temp_"):

377

return False

378

379

# Skip certain indexes

380

if type_ == "index" and name.startswith("_"):

381

return False

382

383

return True

384

385

def include_name(name, type_, parent_names):

386

"""

387

Filter object names during reflection.

388

389

Args:

390

name (str): Object name

391

type_ (str): Object type

392

parent_names (dict): Parent object names

393

394

Returns:

395

bool: True to include object

396

"""

397

# Skip system schemas

398

if type_ == "schema" and name.startswith("information_"):

399

return False

400

return True

401

402

# Configure filtering

403

context.configure(

404

connection=connection,

405

target_metadata=target_metadata,

406

include_object=include_object,

407

include_name=include_name

408

)

409

```

410

411

## Advanced Features

412

413

### Process Revision Directives

414

415

Customize the revision generation process.

416

417

```python

418

def process_revision_directives(context, revision, directives):

419

"""

420

Process and modify revision directives.

421

422

Args:

423

context (MigrationContext): Migration context

424

revision (tuple): Revision information

425

directives (list): List of MigrationScript directives

426

"""

427

# Skip empty migrations

428

script = directives[0]

429

if script.upgrade_ops.is_empty():

430

directives[:] = []

431

print("Skipping empty migration")

432

return

433

434

# Add custom header comment

435

script.upgrade_ops.ops.insert(0,

436

ExecuteSQLOp("-- Auto-generated migration"))

437

438

# Use in context configuration

439

context.configure(

440

connection=connection,

441

target_metadata=target_metadata,

442

process_revision_directives=process_revision_directives

443

)

444

```

445

446

### Template Arguments

447

448

Pass custom variables to migration templates.

449

450

```python

451

def process_revision_directives(context, revision, directives):

452

"""Add custom template variables."""

453

script = directives[0]

454

script.template_args = {

455

'author': 'AutoGen System',

456

'created_at': datetime.now().isoformat()

457

}

458

459

# In migration template

460

"""${message}

461

462

Revision ID: ${up_revision}

463

Revises: ${down_revision | comma,n}

464

Create Date: ${create_date}

465

Author: ${author}

466

Created At: ${created_at}

467

"""

468

```

469

470

### Batch Rendering

471

472

Render operations suitable for SQLite batch mode.

473

474

```python

475

# Configure batch rendering

476

context.configure(

477

connection=connection,

478

target_metadata=target_metadata,

479

render_as_batch=True # Use batch operations

480

)

481

482

# Or in rendering

483

code = render_python_code(

484

operations,

485

render_as_batch=True

486

)

487

```

488

489

## Integration Examples

490

491

### Flask-SQLAlchemy Integration

492

493

```python

494

from flask import current_app

495

from alembic import context

496

from flask_sqlalchemy import SQLAlchemy

497

498

def get_metadata():

499

"""Get metadata from Flask-SQLAlchemy."""

500

with current_app.app_context():

501

return current_app.extensions['sqlalchemy'].db.metadata

502

503

def run_migrations_online():

504

"""Run migrations with Flask app context."""

505

connectable = engine_from_config(

506

config.get_section(config.config_ini_section),

507

prefix='sqlalchemy.',

508

poolclass=pool.NullPool,

509

)

510

511

with connectable.connect() as connection:

512

context.configure(

513

connection=connection,

514

target_metadata=get_metadata(),

515

include_object=include_object,

516

compare_type=True,

517

compare_server_default=True

518

)

519

520

with context.begin_transaction():

521

context.run_migrations()

522

```

523

524

### Django Integration

525

526

```python

527

def run_autogenerate_with_django():

528

"""Run autogeneration with Django models."""

529

import django

530

from django.conf import settings

531

532

django.setup()

533

534

# Convert Django models to SQLAlchemy metadata

535

metadata = convert_django_models_to_sqlalchemy()

536

537

engine = create_engine(get_database_url())

538

with engine.connect() as connection:

539

context = MigrationContext.configure(

540

connection,

541

opts={

542

'target_metadata': metadata,

543

'compare_type': True,

544

'include_object': include_object

545

}

546

)

547

548

diffs = compare_metadata(context, metadata)

549

return diffs

550

```

551

552

## Types

553

554

```python { .api }

555

# Autogeneration context types

556

class AutogenContext:

557

migration_context: MigrationContext

558

metadata: Optional[MetaData]

559

connection: Connection

560

dialect: Dialect

561

imports: Set[str]

562

563

class RevisionContext:

564

config: Config

565

script_directory: ScriptDirectory

566

command_args: Dict[str, Any]

567

568

# Operation containers

569

class UpgradeOps:

570

ops: List[MigrateOperation]

571

572

class DowngradeOps:

573

ops: List[MigrateOperation]

574

575

# Comparison function types

576

CompareTypeFunc = Callable[[MigrationContext, Column, Column, TypeEngine, TypeEngine], Optional[bool]]

577

CompareServerDefaultFunc = Callable[[MigrationContext, Column, Column, Any, Any, str], Optional[bool]]

578

IncludeObjectFunc = Callable[[Any, str, str, bool, Any], bool]

579

ProcessRevisionDirectivesFunc = Callable[[MigrationContext, Tuple, List], None]

580

```