Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1import re 

2 

3from sqlalchemy.types import NULLTYPE 

4 

5from . import schemaobj 

6from .base import BatchOperations 

7from .base import Operations 

8from .. import util 

9from ..util import sqla_compat 

10 

11 

12class MigrateOperation(object): 

13 """base class for migration command and organization objects. 

14 

15 This system is part of the operation extensibility API. 

16 

17 .. versionadded:: 0.8.0 

18 

19 .. seealso:: 

20 

21 :ref:`operation_objects` 

22 

23 :ref:`operation_plugins` 

24 

25 :ref:`customizing_revision` 

26 

27 """ 

28 

29 @util.memoized_property 

30 def info(self): 

31 """A dictionary that may be used to store arbitrary information 

32 along with this :class:`.MigrateOperation` object. 

33 

34 """ 

35 return {} 

36 

37 _mutations = frozenset() 

38 

39 

40class AddConstraintOp(MigrateOperation): 

41 """Represent an add constraint operation.""" 

42 

43 add_constraint_ops = util.Dispatcher() 

44 

45 @property 

46 def constraint_type(self): 

47 raise NotImplementedError() 

48 

49 @classmethod 

50 def register_add_constraint(cls, type_): 

51 def go(klass): 

52 cls.add_constraint_ops.dispatch_for(type_)(klass.from_constraint) 

53 return klass 

54 

55 return go 

56 

57 @classmethod 

58 def from_constraint(cls, constraint): 

59 return cls.add_constraint_ops.dispatch(constraint.__visit_name__)( 

60 constraint 

61 ) 

62 

63 def reverse(self): 

64 return DropConstraintOp.from_constraint(self.to_constraint()) 

65 

66 def to_diff_tuple(self): 

67 return ("add_constraint", self.to_constraint()) 

68 

69 

70@Operations.register_operation("drop_constraint") 

71@BatchOperations.register_operation("drop_constraint", "batch_drop_constraint") 

72class DropConstraintOp(MigrateOperation): 

73 """Represent a drop constraint operation.""" 

74 

75 def __init__( 

76 self, 

77 constraint_name, 

78 table_name, 

79 type_=None, 

80 schema=None, 

81 _orig_constraint=None, 

82 ): 

83 self.constraint_name = constraint_name 

84 self.table_name = table_name 

85 self.constraint_type = type_ 

86 self.schema = schema 

87 self._orig_constraint = _orig_constraint 

88 

89 def reverse(self): 

90 if self._orig_constraint is None: 

91 raise ValueError( 

92 "operation is not reversible; " 

93 "original constraint is not present" 

94 ) 

95 return AddConstraintOp.from_constraint(self._orig_constraint) 

96 

97 def to_diff_tuple(self): 

98 if self.constraint_type == "foreignkey": 

99 return ("remove_fk", self.to_constraint()) 

100 else: 

101 return ("remove_constraint", self.to_constraint()) 

102 

103 @classmethod 

104 def from_constraint(cls, constraint): 

105 types = { 

106 "unique_constraint": "unique", 

107 "foreign_key_constraint": "foreignkey", 

108 "primary_key_constraint": "primary", 

109 "check_constraint": "check", 

110 "column_check_constraint": "check", 

111 "table_or_column_check_constraint": "check", 

112 } 

113 

114 constraint_table = sqla_compat._table_for_constraint(constraint) 

115 return cls( 

116 constraint.name, 

117 constraint_table.name, 

118 schema=constraint_table.schema, 

119 type_=types[constraint.__visit_name__], 

120 _orig_constraint=constraint, 

121 ) 

122 

123 def to_constraint(self): 

124 if self._orig_constraint is not None: 

125 return self._orig_constraint 

126 else: 

127 raise ValueError( 

128 "constraint cannot be produced; " 

129 "original constraint is not present" 

130 ) 

131 

132 @classmethod 

133 @util._with_legacy_names([("type", "type_"), ("name", "constraint_name")]) 

134 def drop_constraint( 

135 cls, operations, constraint_name, table_name, type_=None, schema=None 

136 ): 

137 r"""Drop a constraint of the given name, typically via DROP CONSTRAINT. 

138 

139 :param constraint_name: name of the constraint. 

140 :param table_name: table name. 

141 :param type\_: optional, required on MySQL. can be 

142 'foreignkey', 'primary', 'unique', or 'check'. 

143 :param schema: Optional schema name to operate within. To control 

144 quoting of the schema outside of the default behavior, use 

145 the SQLAlchemy construct 

146 :class:`~sqlalchemy.sql.elements.quoted_name`. 

147 

148 .. versionadded:: 0.7.0 'schema' can now accept a 

149 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

150 

151 .. versionchanged:: 0.8.0 The following positional argument names 

152 have been changed: 

153 

154 * name -> constraint_name 

155 

156 """ 

157 

158 op = cls(constraint_name, table_name, type_=type_, schema=schema) 

159 return operations.invoke(op) 

160 

161 @classmethod 

162 def batch_drop_constraint(cls, operations, constraint_name, type_=None): 

163 """Issue a "drop constraint" instruction using the 

164 current batch migration context. 

165 

166 The batch form of this call omits the ``table_name`` and ``schema`` 

167 arguments from the call. 

168 

169 .. seealso:: 

170 

171 :meth:`.Operations.drop_constraint` 

172 

173 .. versionchanged:: 0.8.0 The following positional argument names 

174 have been changed: 

175 

176 * name -> constraint_name 

177 

178 """ 

179 op = cls( 

180 constraint_name, 

181 operations.impl.table_name, 

182 type_=type_, 

183 schema=operations.impl.schema, 

184 ) 

185 return operations.invoke(op) 

186 

187 

188@Operations.register_operation("create_primary_key") 

189@BatchOperations.register_operation( 

190 "create_primary_key", "batch_create_primary_key" 

191) 

192@AddConstraintOp.register_add_constraint("primary_key_constraint") 

193class CreatePrimaryKeyOp(AddConstraintOp): 

194 """Represent a create primary key operation.""" 

195 

196 constraint_type = "primarykey" 

197 

198 def __init__( 

199 self, 

200 constraint_name, 

201 table_name, 

202 columns, 

203 schema=None, 

204 _orig_constraint=None, 

205 **kw 

206 ): 

207 self.constraint_name = constraint_name 

208 self.table_name = table_name 

209 self.columns = columns 

210 self.schema = schema 

211 self._orig_constraint = _orig_constraint 

212 self.kw = kw 

213 

214 @classmethod 

215 def from_constraint(cls, constraint): 

216 constraint_table = sqla_compat._table_for_constraint(constraint) 

217 

218 return cls( 

219 constraint.name, 

220 constraint_table.name, 

221 constraint.columns, 

222 schema=constraint_table.schema, 

223 _orig_constraint=constraint, 

224 ) 

225 

226 def to_constraint(self, migration_context=None): 

227 if self._orig_constraint is not None: 

228 return self._orig_constraint 

229 

230 schema_obj = schemaobj.SchemaObjects(migration_context) 

231 return schema_obj.primary_key_constraint( 

232 self.constraint_name, 

233 self.table_name, 

234 self.columns, 

235 schema=self.schema, 

236 ) 

237 

238 @classmethod 

239 @util._with_legacy_names( 

240 [("name", "constraint_name"), ("cols", "columns")] 

241 ) 

242 def create_primary_key( 

243 cls, operations, constraint_name, table_name, columns, schema=None 

244 ): 

245 """Issue a "create primary key" instruction using the current 

246 migration context. 

247 

248 e.g.:: 

249 

250 from alembic import op 

251 op.create_primary_key( 

252 "pk_my_table", "my_table", 

253 ["id", "version"] 

254 ) 

255 

256 This internally generates a :class:`~sqlalchemy.schema.Table` object 

257 containing the necessary columns, then generates a new 

258 :class:`~sqlalchemy.schema.PrimaryKeyConstraint` 

259 object which it then associates with the 

260 :class:`~sqlalchemy.schema.Table`. 

261 Any event listeners associated with this action will be fired 

262 off normally. The :class:`~sqlalchemy.schema.AddConstraint` 

263 construct is ultimately used to generate the ALTER statement. 

264 

265 :param name: Name of the primary key constraint. The name is necessary 

266 so that an ALTER statement can be emitted. For setups that 

267 use an automated naming scheme such as that described at 

268 :ref:`sqla:constraint_naming_conventions` 

269 ``name`` here can be ``None``, as the event listener will 

270 apply the name to the constraint object when it is associated 

271 with the table. 

272 :param table_name: String name of the target table. 

273 :param columns: a list of string column names to be applied to the 

274 primary key constraint. 

275 :param schema: Optional schema name to operate within. To control 

276 quoting of the schema outside of the default behavior, use 

277 the SQLAlchemy construct 

278 :class:`~sqlalchemy.sql.elements.quoted_name`. 

279 

280 .. versionadded:: 0.7.0 'schema' can now accept a 

281 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

282 

283 .. versionchanged:: 0.8.0 The following positional argument names 

284 have been changed: 

285 

286 * name -> constraint_name 

287 * cols -> columns 

288 

289 """ 

290 op = cls(constraint_name, table_name, columns, schema) 

291 return operations.invoke(op) 

292 

293 @classmethod 

294 def batch_create_primary_key(cls, operations, constraint_name, columns): 

295 """Issue a "create primary key" instruction using the 

296 current batch migration context. 

297 

298 The batch form of this call omits the ``table_name`` and ``schema`` 

299 arguments from the call. 

300 

301 .. seealso:: 

302 

303 :meth:`.Operations.create_primary_key` 

304 

305 """ 

306 op = cls( 

307 constraint_name, 

308 operations.impl.table_name, 

309 columns, 

310 schema=operations.impl.schema, 

311 ) 

312 return operations.invoke(op) 

313 

314 

315@Operations.register_operation("create_unique_constraint") 

316@BatchOperations.register_operation( 

317 "create_unique_constraint", "batch_create_unique_constraint" 

318) 

319@AddConstraintOp.register_add_constraint("unique_constraint") 

320class CreateUniqueConstraintOp(AddConstraintOp): 

321 """Represent a create unique constraint operation.""" 

322 

323 constraint_type = "unique" 

324 

325 def __init__( 

326 self, 

327 constraint_name, 

328 table_name, 

329 columns, 

330 schema=None, 

331 _orig_constraint=None, 

332 **kw 

333 ): 

334 self.constraint_name = constraint_name 

335 self.table_name = table_name 

336 self.columns = columns 

337 self.schema = schema 

338 self._orig_constraint = _orig_constraint 

339 self.kw = kw 

340 

341 @classmethod 

342 def from_constraint(cls, constraint): 

343 constraint_table = sqla_compat._table_for_constraint(constraint) 

344 

345 kw = {} 

346 if constraint.deferrable: 

347 kw["deferrable"] = constraint.deferrable 

348 if constraint.initially: 

349 kw["initially"] = constraint.initially 

350 

351 return cls( 

352 constraint.name, 

353 constraint_table.name, 

354 [c.name for c in constraint.columns], 

355 schema=constraint_table.schema, 

356 _orig_constraint=constraint, 

357 **kw 

358 ) 

359 

360 def to_constraint(self, migration_context=None): 

361 if self._orig_constraint is not None: 

362 return self._orig_constraint 

363 

364 schema_obj = schemaobj.SchemaObjects(migration_context) 

365 return schema_obj.unique_constraint( 

366 self.constraint_name, 

367 self.table_name, 

368 self.columns, 

369 schema=self.schema, 

370 **self.kw 

371 ) 

372 

373 @classmethod 

374 @util._with_legacy_names( 

375 [ 

376 ("name", "constraint_name"), 

377 ("source", "table_name"), 

378 ("local_cols", "columns"), 

379 ] 

380 ) 

381 def create_unique_constraint( 

382 cls, 

383 operations, 

384 constraint_name, 

385 table_name, 

386 columns, 

387 schema=None, 

388 **kw 

389 ): 

390 """Issue a "create unique constraint" instruction using the 

391 current migration context. 

392 

393 e.g.:: 

394 

395 from alembic import op 

396 op.create_unique_constraint("uq_user_name", "user", ["name"]) 

397 

398 This internally generates a :class:`~sqlalchemy.schema.Table` object 

399 containing the necessary columns, then generates a new 

400 :class:`~sqlalchemy.schema.UniqueConstraint` 

401 object which it then associates with the 

402 :class:`~sqlalchemy.schema.Table`. 

403 Any event listeners associated with this action will be fired 

404 off normally. The :class:`~sqlalchemy.schema.AddConstraint` 

405 construct is ultimately used to generate the ALTER statement. 

406 

407 :param name: Name of the unique constraint. The name is necessary 

408 so that an ALTER statement can be emitted. For setups that 

409 use an automated naming scheme such as that described at 

410 :ref:`sqla:constraint_naming_conventions`, 

411 ``name`` here can be ``None``, as the event listener will 

412 apply the name to the constraint object when it is associated 

413 with the table. 

414 :param table_name: String name of the source table. 

415 :param columns: a list of string column names in the 

416 source table. 

417 :param deferrable: optional bool. If set, emit DEFERRABLE or 

418 NOT DEFERRABLE when issuing DDL for this constraint. 

419 :param initially: optional string. If set, emit INITIALLY <value> 

420 when issuing DDL for this constraint. 

421 :param schema: Optional schema name to operate within. To control 

422 quoting of the schema outside of the default behavior, use 

423 the SQLAlchemy construct 

424 :class:`~sqlalchemy.sql.elements.quoted_name`. 

425 

426 .. versionadded:: 0.7.0 'schema' can now accept a 

427 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

428 

429 .. versionchanged:: 0.8.0 The following positional argument names 

430 have been changed: 

431 

432 * name -> constraint_name 

433 * source -> table_name 

434 * local_cols -> columns 

435 

436 """ 

437 

438 op = cls(constraint_name, table_name, columns, schema=schema, **kw) 

439 return operations.invoke(op) 

440 

441 @classmethod 

442 @util._with_legacy_names([("name", "constraint_name")]) 

443 def batch_create_unique_constraint( 

444 cls, operations, constraint_name, columns, **kw 

445 ): 

446 """Issue a "create unique constraint" instruction using the 

447 current batch migration context. 

448 

449 The batch form of this call omits the ``source`` and ``schema`` 

450 arguments from the call. 

451 

452 .. seealso:: 

453 

454 :meth:`.Operations.create_unique_constraint` 

455 

456 .. versionchanged:: 0.8.0 The following positional argument names 

457 have been changed: 

458 

459 * name -> constraint_name 

460 

461 """ 

462 kw["schema"] = operations.impl.schema 

463 op = cls(constraint_name, operations.impl.table_name, columns, **kw) 

464 return operations.invoke(op) 

465 

466 

467@Operations.register_operation("create_foreign_key") 

468@BatchOperations.register_operation( 

469 "create_foreign_key", "batch_create_foreign_key" 

470) 

471@AddConstraintOp.register_add_constraint("foreign_key_constraint") 

472class CreateForeignKeyOp(AddConstraintOp): 

473 """Represent a create foreign key constraint operation.""" 

474 

475 constraint_type = "foreignkey" 

476 

477 def __init__( 

478 self, 

479 constraint_name, 

480 source_table, 

481 referent_table, 

482 local_cols, 

483 remote_cols, 

484 _orig_constraint=None, 

485 **kw 

486 ): 

487 self.constraint_name = constraint_name 

488 self.source_table = source_table 

489 self.referent_table = referent_table 

490 self.local_cols = local_cols 

491 self.remote_cols = remote_cols 

492 self._orig_constraint = _orig_constraint 

493 self.kw = kw 

494 

495 def to_diff_tuple(self): 

496 return ("add_fk", self.to_constraint()) 

497 

498 @classmethod 

499 def from_constraint(cls, constraint): 

500 kw = {} 

501 if constraint.onupdate: 

502 kw["onupdate"] = constraint.onupdate 

503 if constraint.ondelete: 

504 kw["ondelete"] = constraint.ondelete 

505 if constraint.initially: 

506 kw["initially"] = constraint.initially 

507 if constraint.deferrable: 

508 kw["deferrable"] = constraint.deferrable 

509 if constraint.use_alter: 

510 kw["use_alter"] = constraint.use_alter 

511 

512 ( 

513 source_schema, 

514 source_table, 

515 source_columns, 

516 target_schema, 

517 target_table, 

518 target_columns, 

519 onupdate, 

520 ondelete, 

521 deferrable, 

522 initially, 

523 ) = sqla_compat._fk_spec(constraint) 

524 

525 kw["source_schema"] = source_schema 

526 kw["referent_schema"] = target_schema 

527 

528 return cls( 

529 constraint.name, 

530 source_table, 

531 target_table, 

532 source_columns, 

533 target_columns, 

534 _orig_constraint=constraint, 

535 **kw 

536 ) 

537 

538 def to_constraint(self, migration_context=None): 

539 if self._orig_constraint is not None: 

540 return self._orig_constraint 

541 schema_obj = schemaobj.SchemaObjects(migration_context) 

542 return schema_obj.foreign_key_constraint( 

543 self.constraint_name, 

544 self.source_table, 

545 self.referent_table, 

546 self.local_cols, 

547 self.remote_cols, 

548 **self.kw 

549 ) 

550 

551 @classmethod 

552 @util._with_legacy_names( 

553 [ 

554 ("name", "constraint_name"), 

555 ("source", "source_table"), 

556 ("referent", "referent_table"), 

557 ] 

558 ) 

559 def create_foreign_key( 

560 cls, 

561 operations, 

562 constraint_name, 

563 source_table, 

564 referent_table, 

565 local_cols, 

566 remote_cols, 

567 onupdate=None, 

568 ondelete=None, 

569 deferrable=None, 

570 initially=None, 

571 match=None, 

572 source_schema=None, 

573 referent_schema=None, 

574 **dialect_kw 

575 ): 

576 """Issue a "create foreign key" instruction using the 

577 current migration context. 

578 

579 e.g.:: 

580 

581 from alembic import op 

582 op.create_foreign_key( 

583 "fk_user_address", "address", 

584 "user", ["user_id"], ["id"]) 

585 

586 This internally generates a :class:`~sqlalchemy.schema.Table` object 

587 containing the necessary columns, then generates a new 

588 :class:`~sqlalchemy.schema.ForeignKeyConstraint` 

589 object which it then associates with the 

590 :class:`~sqlalchemy.schema.Table`. 

591 Any event listeners associated with this action will be fired 

592 off normally. The :class:`~sqlalchemy.schema.AddConstraint` 

593 construct is ultimately used to generate the ALTER statement. 

594 

595 :param name: Name of the foreign key constraint. The name is necessary 

596 so that an ALTER statement can be emitted. For setups that 

597 use an automated naming scheme such as that described at 

598 :ref:`sqla:constraint_naming_conventions`, 

599 ``name`` here can be ``None``, as the event listener will 

600 apply the name to the constraint object when it is associated 

601 with the table. 

602 :param source_table: String name of the source table. 

603 :param referent_table: String name of the destination table. 

604 :param local_cols: a list of string column names in the 

605 source table. 

606 :param remote_cols: a list of string column names in the 

607 remote table. 

608 :param onupdate: Optional string. If set, emit ON UPDATE <value> when 

609 issuing DDL for this constraint. Typical values include CASCADE, 

610 DELETE and RESTRICT. 

611 :param ondelete: Optional string. If set, emit ON DELETE <value> when 

612 issuing DDL for this constraint. Typical values include CASCADE, 

613 DELETE and RESTRICT. 

614 :param deferrable: optional bool. If set, emit DEFERRABLE or NOT 

615 DEFERRABLE when issuing DDL for this constraint. 

616 :param source_schema: Optional schema name of the source table. 

617 :param referent_schema: Optional schema name of the destination table. 

618 

619 .. versionchanged:: 0.8.0 The following positional argument names 

620 have been changed: 

621 

622 * name -> constraint_name 

623 * source -> source_table 

624 * referent -> referent_table 

625 

626 """ 

627 

628 op = cls( 

629 constraint_name, 

630 source_table, 

631 referent_table, 

632 local_cols, 

633 remote_cols, 

634 onupdate=onupdate, 

635 ondelete=ondelete, 

636 deferrable=deferrable, 

637 source_schema=source_schema, 

638 referent_schema=referent_schema, 

639 initially=initially, 

640 match=match, 

641 **dialect_kw 

642 ) 

643 return operations.invoke(op) 

644 

645 @classmethod 

646 @util._with_legacy_names( 

647 [("name", "constraint_name"), ("referent", "referent_table")] 

648 ) 

649 def batch_create_foreign_key( 

650 cls, 

651 operations, 

652 constraint_name, 

653 referent_table, 

654 local_cols, 

655 remote_cols, 

656 referent_schema=None, 

657 onupdate=None, 

658 ondelete=None, 

659 deferrable=None, 

660 initially=None, 

661 match=None, 

662 **dialect_kw 

663 ): 

664 """Issue a "create foreign key" instruction using the 

665 current batch migration context. 

666 

667 The batch form of this call omits the ``source`` and ``source_schema`` 

668 arguments from the call. 

669 

670 e.g.:: 

671 

672 with batch_alter_table("address") as batch_op: 

673 batch_op.create_foreign_key( 

674 "fk_user_address", 

675 "user", ["user_id"], ["id"]) 

676 

677 .. seealso:: 

678 

679 :meth:`.Operations.create_foreign_key` 

680 

681 .. versionchanged:: 0.8.0 The following positional argument names 

682 have been changed: 

683 

684 * name -> constraint_name 

685 * referent -> referent_table 

686 

687 """ 

688 op = cls( 

689 constraint_name, 

690 operations.impl.table_name, 

691 referent_table, 

692 local_cols, 

693 remote_cols, 

694 onupdate=onupdate, 

695 ondelete=ondelete, 

696 deferrable=deferrable, 

697 source_schema=operations.impl.schema, 

698 referent_schema=referent_schema, 

699 initially=initially, 

700 match=match, 

701 **dialect_kw 

702 ) 

703 return operations.invoke(op) 

704 

705 

706@Operations.register_operation("create_check_constraint") 

707@BatchOperations.register_operation( 

708 "create_check_constraint", "batch_create_check_constraint" 

709) 

710@AddConstraintOp.register_add_constraint("check_constraint") 

711@AddConstraintOp.register_add_constraint("table_or_column_check_constraint") 

712@AddConstraintOp.register_add_constraint("column_check_constraint") 

713class CreateCheckConstraintOp(AddConstraintOp): 

714 """Represent a create check constraint operation.""" 

715 

716 constraint_type = "check" 

717 

718 def __init__( 

719 self, 

720 constraint_name, 

721 table_name, 

722 condition, 

723 schema=None, 

724 _orig_constraint=None, 

725 **kw 

726 ): 

727 self.constraint_name = constraint_name 

728 self.table_name = table_name 

729 self.condition = condition 

730 self.schema = schema 

731 self._orig_constraint = _orig_constraint 

732 self.kw = kw 

733 

734 @classmethod 

735 def from_constraint(cls, constraint): 

736 constraint_table = sqla_compat._table_for_constraint(constraint) 

737 

738 return cls( 

739 constraint.name, 

740 constraint_table.name, 

741 constraint.sqltext, 

742 schema=constraint_table.schema, 

743 _orig_constraint=constraint, 

744 ) 

745 

746 def to_constraint(self, migration_context=None): 

747 if self._orig_constraint is not None: 

748 return self._orig_constraint 

749 schema_obj = schemaobj.SchemaObjects(migration_context) 

750 return schema_obj.check_constraint( 

751 self.constraint_name, 

752 self.table_name, 

753 self.condition, 

754 schema=self.schema, 

755 **self.kw 

756 ) 

757 

758 @classmethod 

759 @util._with_legacy_names( 

760 [("name", "constraint_name"), ("source", "table_name")] 

761 ) 

762 def create_check_constraint( 

763 cls, 

764 operations, 

765 constraint_name, 

766 table_name, 

767 condition, 

768 schema=None, 

769 **kw 

770 ): 

771 """Issue a "create check constraint" instruction using the 

772 current migration context. 

773 

774 e.g.:: 

775 

776 from alembic import op 

777 from sqlalchemy.sql import column, func 

778 

779 op.create_check_constraint( 

780 "ck_user_name_len", 

781 "user", 

782 func.len(column('name')) > 5 

783 ) 

784 

785 CHECK constraints are usually against a SQL expression, so ad-hoc 

786 table metadata is usually needed. The function will convert the given 

787 arguments into a :class:`sqlalchemy.schema.CheckConstraint` bound 

788 to an anonymous table in order to emit the CREATE statement. 

789 

790 :param name: Name of the check constraint. The name is necessary 

791 so that an ALTER statement can be emitted. For setups that 

792 use an automated naming scheme such as that described at 

793 :ref:`sqla:constraint_naming_conventions`, 

794 ``name`` here can be ``None``, as the event listener will 

795 apply the name to the constraint object when it is associated 

796 with the table. 

797 :param table_name: String name of the source table. 

798 :param condition: SQL expression that's the condition of the 

799 constraint. Can be a string or SQLAlchemy expression language 

800 structure. 

801 :param deferrable: optional bool. If set, emit DEFERRABLE or 

802 NOT DEFERRABLE when issuing DDL for this constraint. 

803 :param initially: optional string. If set, emit INITIALLY <value> 

804 when issuing DDL for this constraint. 

805 :param schema: Optional schema name to operate within. To control 

806 quoting of the schema outside of the default behavior, use 

807 the SQLAlchemy construct 

808 :class:`~sqlalchemy.sql.elements.quoted_name`. 

809 

810 .. versionadded:: 0.7.0 'schema' can now accept a 

811 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

812 

813 .. versionchanged:: 0.8.0 The following positional argument names 

814 have been changed: 

815 

816 * name -> constraint_name 

817 * source -> table_name 

818 

819 """ 

820 op = cls(constraint_name, table_name, condition, schema=schema, **kw) 

821 return operations.invoke(op) 

822 

823 @classmethod 

824 @util._with_legacy_names([("name", "constraint_name")]) 

825 def batch_create_check_constraint( 

826 cls, operations, constraint_name, condition, **kw 

827 ): 

828 """Issue a "create check constraint" instruction using the 

829 current batch migration context. 

830 

831 The batch form of this call omits the ``source`` and ``schema`` 

832 arguments from the call. 

833 

834 .. seealso:: 

835 

836 :meth:`.Operations.create_check_constraint` 

837 

838 .. versionchanged:: 0.8.0 The following positional argument names 

839 have been changed: 

840 

841 * name -> constraint_name 

842 

843 """ 

844 op = cls( 

845 constraint_name, 

846 operations.impl.table_name, 

847 condition, 

848 schema=operations.impl.schema, 

849 **kw 

850 ) 

851 return operations.invoke(op) 

852 

853 

854@Operations.register_operation("create_index") 

855@BatchOperations.register_operation("create_index", "batch_create_index") 

856class CreateIndexOp(MigrateOperation): 

857 """Represent a create index operation.""" 

858 

859 def __init__( 

860 self, 

861 index_name, 

862 table_name, 

863 columns, 

864 schema=None, 

865 unique=False, 

866 _orig_index=None, 

867 **kw 

868 ): 

869 self.index_name = index_name 

870 self.table_name = table_name 

871 self.columns = columns 

872 self.schema = schema 

873 self.unique = unique 

874 self.kw = kw 

875 self._orig_index = _orig_index 

876 

877 def reverse(self): 

878 return DropIndexOp.from_index(self.to_index()) 

879 

880 def to_diff_tuple(self): 

881 return ("add_index", self.to_index()) 

882 

883 @classmethod 

884 def from_index(cls, index): 

885 return cls( 

886 index.name, 

887 index.table.name, 

888 sqla_compat._get_index_expressions(index), 

889 schema=index.table.schema, 

890 unique=index.unique, 

891 _orig_index=index, 

892 **index.kwargs 

893 ) 

894 

895 def to_index(self, migration_context=None): 

896 if self._orig_index: 

897 return self._orig_index 

898 schema_obj = schemaobj.SchemaObjects(migration_context) 

899 return schema_obj.index( 

900 self.index_name, 

901 self.table_name, 

902 self.columns, 

903 schema=self.schema, 

904 unique=self.unique, 

905 **self.kw 

906 ) 

907 

908 @classmethod 

909 @util._with_legacy_names([("name", "index_name")]) 

910 def create_index( 

911 cls, 

912 operations, 

913 index_name, 

914 table_name, 

915 columns, 

916 schema=None, 

917 unique=False, 

918 **kw 

919 ): 

920 r"""Issue a "create index" instruction using the current 

921 migration context. 

922 

923 e.g.:: 

924 

925 from alembic import op 

926 op.create_index('ik_test', 't1', ['foo', 'bar']) 

927 

928 Functional indexes can be produced by using the 

929 :func:`sqlalchemy.sql.expression.text` construct:: 

930 

931 from alembic import op 

932 from sqlalchemy import text 

933 op.create_index('ik_test', 't1', [text('lower(foo)')]) 

934 

935 .. versionadded:: 0.6.7 support for making use of the 

936 :func:`~sqlalchemy.sql.expression.text` construct in 

937 conjunction with 

938 :meth:`.Operations.create_index` in 

939 order to produce functional expressions within CREATE INDEX. 

940 

941 :param index_name: name of the index. 

942 :param table_name: name of the owning table. 

943 :param columns: a list consisting of string column names and/or 

944 :func:`~sqlalchemy.sql.expression.text` constructs. 

945 :param schema: Optional schema name to operate within. To control 

946 quoting of the schema outside of the default behavior, use 

947 the SQLAlchemy construct 

948 :class:`~sqlalchemy.sql.elements.quoted_name`. 

949 

950 .. versionadded:: 0.7.0 'schema' can now accept a 

951 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

952 

953 :param unique: If True, create a unique index. 

954 

955 :param quote: 

956 Force quoting of this column's name on or off, corresponding 

957 to ``True`` or ``False``. When left at its default 

958 of ``None``, the column identifier will be quoted according to 

959 whether the name is case sensitive (identifiers with at least one 

960 upper case character are treated as case sensitive), or if it's a 

961 reserved word. This flag is only needed to force quoting of a 

962 reserved word which is not known by the SQLAlchemy dialect. 

963 

964 :param \**kw: Additional keyword arguments not mentioned above are 

965 dialect specific, and passed in the form 

966 ``<dialectname>_<argname>``. 

967 See the documentation regarding an individual dialect at 

968 :ref:`dialect_toplevel` for detail on documented arguments. 

969 

970 .. versionchanged:: 0.8.0 The following positional argument names 

971 have been changed: 

972 

973 * name -> index_name 

974 

975 """ 

976 op = cls( 

977 index_name, table_name, columns, schema=schema, unique=unique, **kw 

978 ) 

979 return operations.invoke(op) 

980 

981 @classmethod 

982 def batch_create_index(cls, operations, index_name, columns, **kw): 

983 """Issue a "create index" instruction using the 

984 current batch migration context. 

985 

986 .. seealso:: 

987 

988 :meth:`.Operations.create_index` 

989 

990 """ 

991 

992 op = cls( 

993 index_name, 

994 operations.impl.table_name, 

995 columns, 

996 schema=operations.impl.schema, 

997 **kw 

998 ) 

999 return operations.invoke(op) 

1000 

1001 

1002@Operations.register_operation("drop_index") 

1003@BatchOperations.register_operation("drop_index", "batch_drop_index") 

1004class DropIndexOp(MigrateOperation): 

1005 """Represent a drop index operation.""" 

1006 

1007 def __init__( 

1008 self, index_name, table_name=None, schema=None, _orig_index=None, **kw 

1009 ): 

1010 self.index_name = index_name 

1011 self.table_name = table_name 

1012 self.schema = schema 

1013 self._orig_index = _orig_index 

1014 self.kw = kw 

1015 

1016 def to_diff_tuple(self): 

1017 return ("remove_index", self.to_index()) 

1018 

1019 def reverse(self): 

1020 if self._orig_index is None: 

1021 raise ValueError( 

1022 "operation is not reversible; " "original index is not present" 

1023 ) 

1024 return CreateIndexOp.from_index(self._orig_index) 

1025 

1026 @classmethod 

1027 def from_index(cls, index): 

1028 return cls( 

1029 index.name, 

1030 index.table.name, 

1031 schema=index.table.schema, 

1032 _orig_index=index, 

1033 **index.kwargs 

1034 ) 

1035 

1036 def to_index(self, migration_context=None): 

1037 if self._orig_index is not None: 

1038 return self._orig_index 

1039 

1040 schema_obj = schemaobj.SchemaObjects(migration_context) 

1041 

1042 # need a dummy column name here since SQLAlchemy 

1043 # 0.7.6 and further raises on Index with no columns 

1044 return schema_obj.index( 

1045 self.index_name, 

1046 self.table_name, 

1047 ["x"], 

1048 schema=self.schema, 

1049 **self.kw 

1050 ) 

1051 

1052 @classmethod 

1053 @util._with_legacy_names( 

1054 [("name", "index_name"), ("tablename", "table_name")] 

1055 ) 

1056 def drop_index( 

1057 cls, operations, index_name, table_name=None, schema=None, **kw 

1058 ): 

1059 r"""Issue a "drop index" instruction using the current 

1060 migration context. 

1061 

1062 e.g.:: 

1063 

1064 drop_index("accounts") 

1065 

1066 :param index_name: name of the index. 

1067 :param table_name: name of the owning table. Some 

1068 backends such as Microsoft SQL Server require this. 

1069 :param schema: Optional schema name to operate within. To control 

1070 quoting of the schema outside of the default behavior, use 

1071 the SQLAlchemy construct 

1072 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1073 

1074 .. versionadded:: 0.7.0 'schema' can now accept a 

1075 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1076 

1077 :param \**kw: Additional keyword arguments not mentioned above are 

1078 dialect specific, and passed in the form 

1079 ``<dialectname>_<argname>``. 

1080 See the documentation regarding an individual dialect at 

1081 :ref:`dialect_toplevel` for detail on documented arguments. 

1082 

1083 .. versionadded:: 0.9.5 Support for dialect-specific keyword 

1084 arguments for DROP INDEX 

1085 

1086 .. versionchanged:: 0.8.0 The following positional argument names 

1087 have been changed: 

1088 

1089 * name -> index_name 

1090 

1091 """ 

1092 op = cls(index_name, table_name=table_name, schema=schema, **kw) 

1093 return operations.invoke(op) 

1094 

1095 @classmethod 

1096 @util._with_legacy_names([("name", "index_name")]) 

1097 def batch_drop_index(cls, operations, index_name, **kw): 

1098 """Issue a "drop index" instruction using the 

1099 current batch migration context. 

1100 

1101 .. seealso:: 

1102 

1103 :meth:`.Operations.drop_index` 

1104 

1105 .. versionchanged:: 0.8.0 The following positional argument names 

1106 have been changed: 

1107 

1108 * name -> index_name 

1109 

1110 """ 

1111 

1112 op = cls( 

1113 index_name, 

1114 table_name=operations.impl.table_name, 

1115 schema=operations.impl.schema, 

1116 **kw 

1117 ) 

1118 return operations.invoke(op) 

1119 

1120 

1121@Operations.register_operation("create_table") 

1122class CreateTableOp(MigrateOperation): 

1123 """Represent a create table operation.""" 

1124 

1125 def __init__( 

1126 self, table_name, columns, schema=None, _orig_table=None, **kw 

1127 ): 

1128 self.table_name = table_name 

1129 self.columns = columns 

1130 self.schema = schema 

1131 self.kw = kw 

1132 self._orig_table = _orig_table 

1133 

1134 def reverse(self): 

1135 return DropTableOp.from_table(self.to_table()) 

1136 

1137 def to_diff_tuple(self): 

1138 return ("add_table", self.to_table()) 

1139 

1140 @classmethod 

1141 def from_table(cls, table): 

1142 return cls( 

1143 table.name, 

1144 list(table.c) + list(table.constraints), 

1145 schema=table.schema, 

1146 _orig_table=table, 

1147 **table.kwargs 

1148 ) 

1149 

1150 def to_table(self, migration_context=None): 

1151 if self._orig_table is not None: 

1152 return self._orig_table 

1153 schema_obj = schemaobj.SchemaObjects(migration_context) 

1154 

1155 return schema_obj.table( 

1156 self.table_name, *self.columns, schema=self.schema, **self.kw 

1157 ) 

1158 

1159 @classmethod 

1160 @util._with_legacy_names([("name", "table_name")]) 

1161 def create_table(cls, operations, table_name, *columns, **kw): 

1162 r"""Issue a "create table" instruction using the current migration 

1163 context. 

1164 

1165 This directive receives an argument list similar to that of the 

1166 traditional :class:`sqlalchemy.schema.Table` construct, but without the 

1167 metadata:: 

1168 

1169 from sqlalchemy import INTEGER, VARCHAR, NVARCHAR, Column 

1170 from alembic import op 

1171 

1172 op.create_table( 

1173 'account', 

1174 Column('id', INTEGER, primary_key=True), 

1175 Column('name', VARCHAR(50), nullable=False), 

1176 Column('description', NVARCHAR(200)), 

1177 Column('timestamp', TIMESTAMP, server_default=func.now()) 

1178 ) 

1179 

1180 Note that :meth:`.create_table` accepts 

1181 :class:`~sqlalchemy.schema.Column` 

1182 constructs directly from the SQLAlchemy library. In particular, 

1183 default values to be created on the database side are 

1184 specified using the ``server_default`` parameter, and not 

1185 ``default`` which only specifies Python-side defaults:: 

1186 

1187 from alembic import op 

1188 from sqlalchemy import Column, TIMESTAMP, func 

1189 

1190 # specify "DEFAULT NOW" along with the "timestamp" column 

1191 op.create_table('account', 

1192 Column('id', INTEGER, primary_key=True), 

1193 Column('timestamp', TIMESTAMP, server_default=func.now()) 

1194 ) 

1195 

1196 The function also returns a newly created 

1197 :class:`~sqlalchemy.schema.Table` object, corresponding to the table 

1198 specification given, which is suitable for 

1199 immediate SQL operations, in particular 

1200 :meth:`.Operations.bulk_insert`:: 

1201 

1202 from sqlalchemy import INTEGER, VARCHAR, NVARCHAR, Column 

1203 from alembic import op 

1204 

1205 account_table = op.create_table( 

1206 'account', 

1207 Column('id', INTEGER, primary_key=True), 

1208 Column('name', VARCHAR(50), nullable=False), 

1209 Column('description', NVARCHAR(200)), 

1210 Column('timestamp', TIMESTAMP, server_default=func.now()) 

1211 ) 

1212 

1213 op.bulk_insert( 

1214 account_table, 

1215 [ 

1216 {"name": "A1", "description": "account 1"}, 

1217 {"name": "A2", "description": "account 2"}, 

1218 ] 

1219 ) 

1220 

1221 .. versionadded:: 0.7.0 

1222 

1223 :param table_name: Name of the table 

1224 :param \*columns: collection of :class:`~sqlalchemy.schema.Column` 

1225 objects within 

1226 the table, as well as optional :class:`~sqlalchemy.schema.Constraint` 

1227 objects 

1228 and :class:`~.sqlalchemy.schema.Index` objects. 

1229 :param schema: Optional schema name to operate within. To control 

1230 quoting of the schema outside of the default behavior, use 

1231 the SQLAlchemy construct 

1232 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1233 

1234 .. versionadded:: 0.7.0 'schema' can now accept a 

1235 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1236 :param \**kw: Other keyword arguments are passed to the underlying 

1237 :class:`sqlalchemy.schema.Table` object created for the command. 

1238 

1239 :return: the :class:`~sqlalchemy.schema.Table` object corresponding 

1240 to the parameters given. 

1241 

1242 .. versionadded:: 0.7.0 - the :class:`~sqlalchemy.schema.Table` 

1243 object is returned. 

1244 

1245 .. versionchanged:: 0.8.0 The following positional argument names 

1246 have been changed: 

1247 

1248 * name -> table_name 

1249 

1250 """ 

1251 op = cls(table_name, columns, **kw) 

1252 return operations.invoke(op) 

1253 

1254 

1255@Operations.register_operation("drop_table") 

1256class DropTableOp(MigrateOperation): 

1257 """Represent a drop table operation.""" 

1258 

1259 def __init__( 

1260 self, table_name, schema=None, table_kw=None, _orig_table=None 

1261 ): 

1262 self.table_name = table_name 

1263 self.schema = schema 

1264 self.table_kw = table_kw or {} 

1265 self._orig_table = _orig_table 

1266 

1267 def to_diff_tuple(self): 

1268 return ("remove_table", self.to_table()) 

1269 

1270 def reverse(self): 

1271 if self._orig_table is None: 

1272 raise ValueError( 

1273 "operation is not reversible; " "original table is not present" 

1274 ) 

1275 return CreateTableOp.from_table(self._orig_table) 

1276 

1277 @classmethod 

1278 def from_table(cls, table): 

1279 return cls(table.name, schema=table.schema, _orig_table=table) 

1280 

1281 def to_table(self, migration_context=None): 

1282 if self._orig_table is not None: 

1283 return self._orig_table 

1284 schema_obj = schemaobj.SchemaObjects(migration_context) 

1285 return schema_obj.table( 

1286 self.table_name, schema=self.schema, **self.table_kw 

1287 ) 

1288 

1289 @classmethod 

1290 @util._with_legacy_names([("name", "table_name")]) 

1291 def drop_table(cls, operations, table_name, schema=None, **kw): 

1292 r"""Issue a "drop table" instruction using the current 

1293 migration context. 

1294 

1295 

1296 e.g.:: 

1297 

1298 drop_table("accounts") 

1299 

1300 :param table_name: Name of the table 

1301 :param schema: Optional schema name to operate within. To control 

1302 quoting of the schema outside of the default behavior, use 

1303 the SQLAlchemy construct 

1304 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1305 

1306 .. versionadded:: 0.7.0 'schema' can now accept a 

1307 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1308 

1309 :param \**kw: Other keyword arguments are passed to the underlying 

1310 :class:`sqlalchemy.schema.Table` object created for the command. 

1311 

1312 .. versionchanged:: 0.8.0 The following positional argument names 

1313 have been changed: 

1314 

1315 * name -> table_name 

1316 

1317 """ 

1318 op = cls(table_name, schema=schema, table_kw=kw) 

1319 operations.invoke(op) 

1320 

1321 

1322class AlterTableOp(MigrateOperation): 

1323 """Represent an alter table operation.""" 

1324 

1325 def __init__(self, table_name, schema=None): 

1326 self.table_name = table_name 

1327 self.schema = schema 

1328 

1329 

1330@Operations.register_operation("rename_table") 

1331class RenameTableOp(AlterTableOp): 

1332 """Represent a rename table operation.""" 

1333 

1334 def __init__(self, old_table_name, new_table_name, schema=None): 

1335 super(RenameTableOp, self).__init__(old_table_name, schema=schema) 

1336 self.new_table_name = new_table_name 

1337 

1338 @classmethod 

1339 def rename_table( 

1340 cls, operations, old_table_name, new_table_name, schema=None 

1341 ): 

1342 """Emit an ALTER TABLE to rename a table. 

1343 

1344 :param old_table_name: old name. 

1345 :param new_table_name: new name. 

1346 :param schema: Optional schema name to operate within. To control 

1347 quoting of the schema outside of the default behavior, use 

1348 the SQLAlchemy construct 

1349 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1350 

1351 .. versionadded:: 0.7.0 'schema' can now accept a 

1352 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1353 

1354 """ 

1355 op = cls(old_table_name, new_table_name, schema=schema) 

1356 return operations.invoke(op) 

1357 

1358 

1359@Operations.register_operation("create_table_comment") 

1360class CreateTableCommentOp(AlterTableOp): 

1361 """Represent a COMMENT ON `table` operation. 

1362 """ 

1363 

1364 def __init__( 

1365 self, table_name, comment, schema=None, existing_comment=None 

1366 ): 

1367 self.table_name = table_name 

1368 self.comment = comment 

1369 self.existing_comment = existing_comment 

1370 self.schema = schema 

1371 

1372 @classmethod 

1373 def create_table_comment( 

1374 cls, 

1375 operations, 

1376 table_name, 

1377 comment, 

1378 existing_comment=None, 

1379 schema=None, 

1380 ): 

1381 """Emit a COMMENT ON operation to set the comment for a table. 

1382 

1383 .. versionadded:: 1.0.6 

1384 

1385 :param table_name: string name of the target table. 

1386 :param comment: string value of the comment being registered against 

1387 the specified table. 

1388 :param existing_comment: String value of a comment 

1389 already registered on the specified table, used within autogenerate 

1390 so that the operation is reversible, but not required for direct 

1391 use. 

1392 

1393 .. seealso:: 

1394 

1395 :meth:`.Operations.drop_table_comment` 

1396 

1397 :paramref:`.Operations.alter_column.comment` 

1398 

1399 """ 

1400 

1401 op = cls( 

1402 table_name, 

1403 comment, 

1404 existing_comment=existing_comment, 

1405 schema=schema, 

1406 ) 

1407 return operations.invoke(op) 

1408 

1409 def reverse(self): 

1410 """Reverses the COMMENT ON operation against a table. 

1411 """ 

1412 if self.existing_comment is None: 

1413 return DropTableCommentOp( 

1414 self.table_name, 

1415 existing_comment=self.comment, 

1416 schema=self.schema, 

1417 ) 

1418 else: 

1419 return CreateTableCommentOp( 

1420 self.table_name, 

1421 self.existing_comment, 

1422 existing_comment=self.comment, 

1423 schema=self.schema, 

1424 ) 

1425 

1426 def to_table(self, migration_context=None): 

1427 schema_obj = schemaobj.SchemaObjects(migration_context) 

1428 

1429 return schema_obj.table( 

1430 self.table_name, schema=self.schema, comment=self.comment 

1431 ) 

1432 

1433 def to_diff_tuple(self): 

1434 return ("add_table_comment", self.to_table(), self.existing_comment) 

1435 

1436 

1437@Operations.register_operation("drop_table_comment") 

1438class DropTableCommentOp(AlterTableOp): 

1439 """Represent an operation to remove the comment from a table. 

1440 """ 

1441 

1442 def __init__(self, table_name, schema=None, existing_comment=None): 

1443 self.table_name = table_name 

1444 self.existing_comment = existing_comment 

1445 self.schema = schema 

1446 

1447 @classmethod 

1448 def drop_table_comment( 

1449 cls, operations, table_name, existing_comment=None, schema=None 

1450 ): 

1451 """Issue a "drop table comment" operation to 

1452 remove an existing comment set on a table. 

1453 

1454 .. versionadded:: 1.0.6 

1455 

1456 :param table_name: string name of the target table. 

1457 :param existing_comment: An optional string value of a comment already 

1458 registered on the specified table. 

1459 

1460 .. seealso:: 

1461 

1462 :meth:`.Operations.create_table_comment` 

1463 

1464 :paramref:`.Operations.alter_column.comment` 

1465 

1466 """ 

1467 

1468 op = cls(table_name, existing_comment=existing_comment, schema=schema) 

1469 return operations.invoke(op) 

1470 

1471 def reverse(self): 

1472 """Reverses the COMMENT ON operation against a table. 

1473 """ 

1474 return CreateTableCommentOp( 

1475 self.table_name, self.existing_comment, schema=self.schema 

1476 ) 

1477 

1478 def to_table(self, migration_context=None): 

1479 schema_obj = schemaobj.SchemaObjects(migration_context) 

1480 

1481 return schema_obj.table(self.table_name, schema=self.schema) 

1482 

1483 def to_diff_tuple(self): 

1484 return ("remove_table_comment", self.to_table()) 

1485 

1486 

1487@Operations.register_operation("alter_column") 

1488@BatchOperations.register_operation("alter_column", "batch_alter_column") 

1489class AlterColumnOp(AlterTableOp): 

1490 """Represent an alter column operation.""" 

1491 

1492 def __init__( 

1493 self, 

1494 table_name, 

1495 column_name, 

1496 schema=None, 

1497 existing_type=None, 

1498 existing_server_default=False, 

1499 existing_nullable=None, 

1500 existing_comment=None, 

1501 modify_nullable=None, 

1502 modify_comment=False, 

1503 modify_server_default=False, 

1504 modify_name=None, 

1505 modify_type=None, 

1506 **kw 

1507 ): 

1508 super(AlterColumnOp, self).__init__(table_name, schema=schema) 

1509 self.column_name = column_name 

1510 self.existing_type = existing_type 

1511 self.existing_server_default = existing_server_default 

1512 self.existing_nullable = existing_nullable 

1513 self.existing_comment = existing_comment 

1514 self.modify_nullable = modify_nullable 

1515 self.modify_comment = modify_comment 

1516 self.modify_server_default = modify_server_default 

1517 self.modify_name = modify_name 

1518 self.modify_type = modify_type 

1519 self.kw = kw 

1520 

1521 def to_diff_tuple(self): 

1522 col_diff = [] 

1523 schema, tname, cname = self.schema, self.table_name, self.column_name 

1524 

1525 if self.modify_type is not None: 

1526 col_diff.append( 

1527 ( 

1528 "modify_type", 

1529 schema, 

1530 tname, 

1531 cname, 

1532 { 

1533 "existing_nullable": self.existing_nullable, 

1534 "existing_server_default": ( 

1535 self.existing_server_default 

1536 ), 

1537 "existing_comment": self.existing_comment, 

1538 }, 

1539 self.existing_type, 

1540 self.modify_type, 

1541 ) 

1542 ) 

1543 

1544 if self.modify_nullable is not None: 

1545 col_diff.append( 

1546 ( 

1547 "modify_nullable", 

1548 schema, 

1549 tname, 

1550 cname, 

1551 { 

1552 "existing_type": self.existing_type, 

1553 "existing_server_default": ( 

1554 self.existing_server_default 

1555 ), 

1556 "existing_comment": self.existing_comment, 

1557 }, 

1558 self.existing_nullable, 

1559 self.modify_nullable, 

1560 ) 

1561 ) 

1562 

1563 if self.modify_server_default is not False: 

1564 col_diff.append( 

1565 ( 

1566 "modify_default", 

1567 schema, 

1568 tname, 

1569 cname, 

1570 { 

1571 "existing_nullable": self.existing_nullable, 

1572 "existing_type": self.existing_type, 

1573 "existing_comment": self.existing_comment, 

1574 }, 

1575 self.existing_server_default, 

1576 self.modify_server_default, 

1577 ) 

1578 ) 

1579 

1580 if self.modify_comment is not False: 

1581 col_diff.append( 

1582 ( 

1583 "modify_comment", 

1584 schema, 

1585 tname, 

1586 cname, 

1587 { 

1588 "existing_nullable": self.existing_nullable, 

1589 "existing_type": self.existing_type, 

1590 "existing_server_default": ( 

1591 self.existing_server_default 

1592 ), 

1593 }, 

1594 self.existing_comment, 

1595 self.modify_comment, 

1596 ) 

1597 ) 

1598 

1599 return col_diff 

1600 

1601 def has_changes(self): 

1602 hc1 = ( 

1603 self.modify_nullable is not None 

1604 or self.modify_server_default is not False 

1605 or self.modify_type is not None 

1606 or self.modify_comment is not False 

1607 ) 

1608 if hc1: 

1609 return True 

1610 for kw in self.kw: 

1611 if kw.startswith("modify_"): 

1612 return True 

1613 else: 

1614 return False 

1615 

1616 def reverse(self): 

1617 

1618 kw = self.kw.copy() 

1619 kw["existing_type"] = self.existing_type 

1620 kw["existing_nullable"] = self.existing_nullable 

1621 kw["existing_server_default"] = self.existing_server_default 

1622 kw["existing_comment"] = self.existing_comment 

1623 if self.modify_type is not None: 

1624 kw["modify_type"] = self.modify_type 

1625 if self.modify_nullable is not None: 

1626 kw["modify_nullable"] = self.modify_nullable 

1627 if self.modify_server_default is not False: 

1628 kw["modify_server_default"] = self.modify_server_default 

1629 if self.modify_comment is not False: 

1630 kw["modify_comment"] = self.modify_comment 

1631 

1632 # TODO: make this a little simpler 

1633 all_keys = set( 

1634 m.group(1) 

1635 for m in [re.match(r"^(?:existing_|modify_)(.+)$", k) for k in kw] 

1636 if m 

1637 ) 

1638 

1639 for k in all_keys: 

1640 if "modify_%s" % k in kw: 

1641 swap = kw["existing_%s" % k] 

1642 kw["existing_%s" % k] = kw["modify_%s" % k] 

1643 kw["modify_%s" % k] = swap 

1644 

1645 return self.__class__( 

1646 self.table_name, self.column_name, schema=self.schema, **kw 

1647 ) 

1648 

1649 @classmethod 

1650 @util._with_legacy_names([("name", "new_column_name")]) 

1651 def alter_column( 

1652 cls, 

1653 operations, 

1654 table_name, 

1655 column_name, 

1656 nullable=None, 

1657 comment=False, 

1658 server_default=False, 

1659 new_column_name=None, 

1660 type_=None, 

1661 existing_type=None, 

1662 existing_server_default=False, 

1663 existing_nullable=None, 

1664 existing_comment=None, 

1665 schema=None, 

1666 **kw 

1667 ): 

1668 r"""Issue an "alter column" instruction using the 

1669 current migration context. 

1670 

1671 Generally, only that aspect of the column which 

1672 is being changed, i.e. name, type, nullability, 

1673 default, needs to be specified. Multiple changes 

1674 can also be specified at once and the backend should 

1675 "do the right thing", emitting each change either 

1676 separately or together as the backend allows. 

1677 

1678 MySQL has special requirements here, since MySQL 

1679 cannot ALTER a column without a full specification. 

1680 When producing MySQL-compatible migration files, 

1681 it is recommended that the ``existing_type``, 

1682 ``existing_server_default``, and ``existing_nullable`` 

1683 parameters be present, if not being altered. 

1684 

1685 Type changes which are against the SQLAlchemy 

1686 "schema" types :class:`~sqlalchemy.types.Boolean` 

1687 and :class:`~sqlalchemy.types.Enum` may also 

1688 add or drop constraints which accompany those 

1689 types on backends that don't support them natively. 

1690 The ``existing_type`` argument is 

1691 used in this case to identify and remove a previous 

1692 constraint that was bound to the type object. 

1693 

1694 :param table_name: string name of the target table. 

1695 :param column_name: string name of the target column, 

1696 as it exists before the operation begins. 

1697 :param nullable: Optional; specify ``True`` or ``False`` 

1698 to alter the column's nullability. 

1699 :param server_default: Optional; specify a string 

1700 SQL expression, :func:`~sqlalchemy.sql.expression.text`, 

1701 or :class:`~sqlalchemy.schema.DefaultClause` to indicate 

1702 an alteration to the column's default value. 

1703 Set to ``None`` to have the default removed. 

1704 :param comment: optional string text of a new comment to add to the 

1705 column. 

1706 

1707 .. versionadded:: 1.0.6 

1708 

1709 :param new_column_name: Optional; specify a string name here to 

1710 indicate the new name within a column rename operation. 

1711 :param type\_: Optional; a :class:`~sqlalchemy.types.TypeEngine` 

1712 type object to specify a change to the column's type. 

1713 For SQLAlchemy types that also indicate a constraint (i.e. 

1714 :class:`~sqlalchemy.types.Boolean`, :class:`~sqlalchemy.types.Enum`), 

1715 the constraint is also generated. 

1716 :param autoincrement: set the ``AUTO_INCREMENT`` flag of the column; 

1717 currently understood by the MySQL dialect. 

1718 :param existing_type: Optional; a 

1719 :class:`~sqlalchemy.types.TypeEngine` 

1720 type object to specify the previous type. This 

1721 is required for all MySQL column alter operations that 

1722 don't otherwise specify a new type, as well as for 

1723 when nullability is being changed on a SQL Server 

1724 column. It is also used if the type is a so-called 

1725 SQLlchemy "schema" type which may define a constraint (i.e. 

1726 :class:`~sqlalchemy.types.Boolean`, 

1727 :class:`~sqlalchemy.types.Enum`), 

1728 so that the constraint can be dropped. 

1729 :param existing_server_default: Optional; The existing 

1730 default value of the column. Required on MySQL if 

1731 an existing default is not being changed; else MySQL 

1732 removes the default. 

1733 :param existing_nullable: Optional; the existing nullability 

1734 of the column. Required on MySQL if the existing nullability 

1735 is not being changed; else MySQL sets this to NULL. 

1736 :param existing_autoincrement: Optional; the existing autoincrement 

1737 of the column. Used for MySQL's system of altering a column 

1738 that specifies ``AUTO_INCREMENT``. 

1739 :param existing_comment: string text of the existing comment on the 

1740 column to be maintained. Required on MySQL if the existing comment 

1741 on the column is not being changed. 

1742 

1743 .. versionadded:: 1.0.6 

1744 

1745 :param schema: Optional schema name to operate within. To control 

1746 quoting of the schema outside of the default behavior, use 

1747 the SQLAlchemy construct 

1748 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1749 

1750 .. versionadded:: 0.7.0 'schema' can now accept a 

1751 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1752 

1753 :param postgresql_using: String argument which will indicate a 

1754 SQL expression to render within the Postgresql-specific USING clause 

1755 within ALTER COLUMN. This string is taken directly as raw SQL which 

1756 must explicitly include any necessary quoting or escaping of tokens 

1757 within the expression. 

1758 

1759 .. versionadded:: 0.8.8 

1760 

1761 """ 

1762 

1763 alt = cls( 

1764 table_name, 

1765 column_name, 

1766 schema=schema, 

1767 existing_type=existing_type, 

1768 existing_server_default=existing_server_default, 

1769 existing_nullable=existing_nullable, 

1770 existing_comment=existing_comment, 

1771 modify_name=new_column_name, 

1772 modify_type=type_, 

1773 modify_server_default=server_default, 

1774 modify_nullable=nullable, 

1775 modify_comment=comment, 

1776 **kw 

1777 ) 

1778 

1779 return operations.invoke(alt) 

1780 

1781 @classmethod 

1782 def batch_alter_column( 

1783 cls, 

1784 operations, 

1785 column_name, 

1786 nullable=None, 

1787 comment=False, 

1788 server_default=False, 

1789 new_column_name=None, 

1790 type_=None, 

1791 existing_type=None, 

1792 existing_server_default=False, 

1793 existing_nullable=None, 

1794 existing_comment=None, 

1795 insert_before=None, 

1796 insert_after=None, 

1797 **kw 

1798 ): 

1799 """Issue an "alter column" instruction using the current 

1800 batch migration context. 

1801 

1802 Parameters are the same as that of :meth:`.Operations.alter_column`, 

1803 as well as the following option(s): 

1804 

1805 :param insert_before: String name of an existing column which this 

1806 column should be placed before, when creating the new table. 

1807 

1808 .. versionadded:: 1.4.0 

1809 

1810 :param insert_before: String name of an existing column which this 

1811 column should be placed after, when creating the new table. If 

1812 both :paramref:`.BatchOperations.alter_column.insert_before` 

1813 and :paramref:`.BatchOperations.alter_column.insert_after` are 

1814 omitted, the column is inserted after the last existing column 

1815 in the table. 

1816 

1817 .. versionadded:: 1.4.0 

1818 

1819 .. seealso:: 

1820 

1821 :meth:`.Operations.alter_column` 

1822 

1823 

1824 """ 

1825 alt = cls( 

1826 operations.impl.table_name, 

1827 column_name, 

1828 schema=operations.impl.schema, 

1829 existing_type=existing_type, 

1830 existing_server_default=existing_server_default, 

1831 existing_nullable=existing_nullable, 

1832 existing_comment=existing_comment, 

1833 modify_name=new_column_name, 

1834 modify_type=type_, 

1835 modify_server_default=server_default, 

1836 modify_nullable=nullable, 

1837 modify_comment=comment, 

1838 **kw 

1839 ) 

1840 

1841 return operations.invoke(alt) 

1842 

1843 

1844@Operations.register_operation("add_column") 

1845@BatchOperations.register_operation("add_column", "batch_add_column") 

1846class AddColumnOp(AlterTableOp): 

1847 """Represent an add column operation.""" 

1848 

1849 def __init__(self, table_name, column, schema=None, **kw): 

1850 super(AddColumnOp, self).__init__(table_name, schema=schema) 

1851 self.column = column 

1852 self.kw = kw 

1853 

1854 def reverse(self): 

1855 return DropColumnOp.from_column_and_tablename( 

1856 self.schema, self.table_name, self.column 

1857 ) 

1858 

1859 def to_diff_tuple(self): 

1860 return ("add_column", self.schema, self.table_name, self.column) 

1861 

1862 def to_column(self): 

1863 return self.column 

1864 

1865 @classmethod 

1866 def from_column(cls, col): 

1867 return cls(col.table.name, col, schema=col.table.schema) 

1868 

1869 @classmethod 

1870 def from_column_and_tablename(cls, schema, tname, col): 

1871 return cls(tname, col, schema=schema) 

1872 

1873 @classmethod 

1874 def add_column(cls, operations, table_name, column, schema=None): 

1875 """Issue an "add column" instruction using the current 

1876 migration context. 

1877 

1878 e.g.:: 

1879 

1880 from alembic import op 

1881 from sqlalchemy import Column, String 

1882 

1883 op.add_column('organization', 

1884 Column('name', String()) 

1885 ) 

1886 

1887 The provided :class:`~sqlalchemy.schema.Column` object can also 

1888 specify a :class:`~sqlalchemy.schema.ForeignKey`, referencing 

1889 a remote table name. Alembic will automatically generate a stub 

1890 "referenced" table and emit a second ALTER statement in order 

1891 to add the constraint separately:: 

1892 

1893 from alembic import op 

1894 from sqlalchemy import Column, INTEGER, ForeignKey 

1895 

1896 op.add_column('organization', 

1897 Column('account_id', INTEGER, ForeignKey('accounts.id')) 

1898 ) 

1899 

1900 Note that this statement uses the :class:`~sqlalchemy.schema.Column` 

1901 construct as is from the SQLAlchemy library. In particular, 

1902 default values to be created on the database side are 

1903 specified using the ``server_default`` parameter, and not 

1904 ``default`` which only specifies Python-side defaults:: 

1905 

1906 from alembic import op 

1907 from sqlalchemy import Column, TIMESTAMP, func 

1908 

1909 # specify "DEFAULT NOW" along with the column add 

1910 op.add_column('account', 

1911 Column('timestamp', TIMESTAMP, server_default=func.now()) 

1912 ) 

1913 

1914 :param table_name: String name of the parent table. 

1915 :param column: a :class:`sqlalchemy.schema.Column` object 

1916 representing the new column. 

1917 :param schema: Optional schema name to operate within. To control 

1918 quoting of the schema outside of the default behavior, use 

1919 the SQLAlchemy construct 

1920 :class:`~sqlalchemy.sql.elements.quoted_name`. 

1921 

1922 .. versionadded:: 0.7.0 'schema' can now accept a 

1923 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

1924 

1925 

1926 """ 

1927 

1928 op = cls(table_name, column, schema=schema) 

1929 return operations.invoke(op) 

1930 

1931 @classmethod 

1932 def batch_add_column( 

1933 cls, operations, column, insert_before=None, insert_after=None 

1934 ): 

1935 """Issue an "add column" instruction using the current 

1936 batch migration context. 

1937 

1938 .. seealso:: 

1939 

1940 :meth:`.Operations.add_column` 

1941 

1942 """ 

1943 

1944 kw = {} 

1945 if insert_before: 

1946 kw["insert_before"] = insert_before 

1947 if insert_after: 

1948 kw["insert_after"] = insert_after 

1949 

1950 op = cls( 

1951 operations.impl.table_name, 

1952 column, 

1953 schema=operations.impl.schema, 

1954 **kw 

1955 ) 

1956 return operations.invoke(op) 

1957 

1958 

1959@Operations.register_operation("drop_column") 

1960@BatchOperations.register_operation("drop_column", "batch_drop_column") 

1961class DropColumnOp(AlterTableOp): 

1962 """Represent a drop column operation.""" 

1963 

1964 def __init__( 

1965 self, table_name, column_name, schema=None, _orig_column=None, **kw 

1966 ): 

1967 super(DropColumnOp, self).__init__(table_name, schema=schema) 

1968 self.column_name = column_name 

1969 self.kw = kw 

1970 self._orig_column = _orig_column 

1971 

1972 def to_diff_tuple(self): 

1973 return ( 

1974 "remove_column", 

1975 self.schema, 

1976 self.table_name, 

1977 self.to_column(), 

1978 ) 

1979 

1980 def reverse(self): 

1981 if self._orig_column is None: 

1982 raise ValueError( 

1983 "operation is not reversible; " 

1984 "original column is not present" 

1985 ) 

1986 

1987 return AddColumnOp.from_column_and_tablename( 

1988 self.schema, self.table_name, self._orig_column 

1989 ) 

1990 

1991 @classmethod 

1992 def from_column_and_tablename(cls, schema, tname, col): 

1993 return cls(tname, col.name, schema=schema, _orig_column=col) 

1994 

1995 def to_column(self, migration_context=None): 

1996 if self._orig_column is not None: 

1997 return self._orig_column 

1998 schema_obj = schemaobj.SchemaObjects(migration_context) 

1999 return schema_obj.column(self.column_name, NULLTYPE) 

2000 

2001 @classmethod 

2002 def drop_column( 

2003 cls, operations, table_name, column_name, schema=None, **kw 

2004 ): 

2005 """Issue a "drop column" instruction using the current 

2006 migration context. 

2007 

2008 e.g.:: 

2009 

2010 drop_column('organization', 'account_id') 

2011 

2012 :param table_name: name of table 

2013 :param column_name: name of column 

2014 :param schema: Optional schema name to operate within. To control 

2015 quoting of the schema outside of the default behavior, use 

2016 the SQLAlchemy construct 

2017 :class:`~sqlalchemy.sql.elements.quoted_name`. 

2018 

2019 .. versionadded:: 0.7.0 'schema' can now accept a 

2020 :class:`~sqlalchemy.sql.elements.quoted_name` construct. 

2021 

2022 :param mssql_drop_check: Optional boolean. When ``True``, on 

2023 Microsoft SQL Server only, first 

2024 drop the CHECK constraint on the column using a 

2025 SQL-script-compatible 

2026 block that selects into a @variable from sys.check_constraints, 

2027 then exec's a separate DROP CONSTRAINT for that constraint. 

2028 :param mssql_drop_default: Optional boolean. When ``True``, on 

2029 Microsoft SQL Server only, first 

2030 drop the DEFAULT constraint on the column using a 

2031 SQL-script-compatible 

2032 block that selects into a @variable from sys.default_constraints, 

2033 then exec's a separate DROP CONSTRAINT for that default. 

2034 :param mssql_drop_foreign_key: Optional boolean. When ``True``, on 

2035 Microsoft SQL Server only, first 

2036 drop a single FOREIGN KEY constraint on the column using a 

2037 SQL-script-compatible 

2038 block that selects into a @variable from 

2039 sys.foreign_keys/sys.foreign_key_columns, 

2040 then exec's a separate DROP CONSTRAINT for that default. Only 

2041 works if the column has exactly one FK constraint which refers to 

2042 it, at the moment. 

2043 

2044 .. versionadded:: 0.6.2 

2045 

2046 """ 

2047 

2048 op = cls(table_name, column_name, schema=schema, **kw) 

2049 return operations.invoke(op) 

2050 

2051 @classmethod 

2052 def batch_drop_column(cls, operations, column_name, **kw): 

2053 """Issue a "drop column" instruction using the current 

2054 batch migration context. 

2055 

2056 .. seealso:: 

2057 

2058 :meth:`.Operations.drop_column` 

2059 

2060 """ 

2061 op = cls( 

2062 operations.impl.table_name, 

2063 column_name, 

2064 schema=operations.impl.schema, 

2065 **kw 

2066 ) 

2067 return operations.invoke(op) 

2068 

2069 

2070@Operations.register_operation("bulk_insert") 

2071class BulkInsertOp(MigrateOperation): 

2072 """Represent a bulk insert operation.""" 

2073 

2074 def __init__(self, table, rows, multiinsert=True): 

2075 self.table = table 

2076 self.rows = rows 

2077 self.multiinsert = multiinsert 

2078 

2079 @classmethod 

2080 def bulk_insert(cls, operations, table, rows, multiinsert=True): 

2081 """Issue a "bulk insert" operation using the current 

2082 migration context. 

2083 

2084 This provides a means of representing an INSERT of multiple rows 

2085 which works equally well in the context of executing on a live 

2086 connection as well as that of generating a SQL script. In the 

2087 case of a SQL script, the values are rendered inline into the 

2088 statement. 

2089 

2090 e.g.:: 

2091 

2092 from alembic import op 

2093 from datetime import date 

2094 from sqlalchemy.sql import table, column 

2095 from sqlalchemy import String, Integer, Date 

2096 

2097 # Create an ad-hoc table to use for the insert statement. 

2098 accounts_table = table('account', 

2099 column('id', Integer), 

2100 column('name', String), 

2101 column('create_date', Date) 

2102 ) 

2103 

2104 op.bulk_insert(accounts_table, 

2105 [ 

2106 {'id':1, 'name':'John Smith', 

2107 'create_date':date(2010, 10, 5)}, 

2108 {'id':2, 'name':'Ed Williams', 

2109 'create_date':date(2007, 5, 27)}, 

2110 {'id':3, 'name':'Wendy Jones', 

2111 'create_date':date(2008, 8, 15)}, 

2112 ] 

2113 ) 

2114 

2115 When using --sql mode, some datatypes may not render inline 

2116 automatically, such as dates and other special types. When this 

2117 issue is present, :meth:`.Operations.inline_literal` may be used:: 

2118 

2119 op.bulk_insert(accounts_table, 

2120 [ 

2121 {'id':1, 'name':'John Smith', 

2122 'create_date':op.inline_literal("2010-10-05")}, 

2123 {'id':2, 'name':'Ed Williams', 

2124 'create_date':op.inline_literal("2007-05-27")}, 

2125 {'id':3, 'name':'Wendy Jones', 

2126 'create_date':op.inline_literal("2008-08-15")}, 

2127 ], 

2128 multiinsert=False 

2129 ) 

2130 

2131 When using :meth:`.Operations.inline_literal` in conjunction with 

2132 :meth:`.Operations.bulk_insert`, in order for the statement to work 

2133 in "online" (e.g. non --sql) mode, the 

2134 :paramref:`~.Operations.bulk_insert.multiinsert` 

2135 flag should be set to ``False``, which will have the effect of 

2136 individual INSERT statements being emitted to the database, each 

2137 with a distinct VALUES clause, so that the "inline" values can 

2138 still be rendered, rather than attempting to pass the values 

2139 as bound parameters. 

2140 

2141 .. versionadded:: 0.6.4 :meth:`.Operations.inline_literal` can now 

2142 be used with :meth:`.Operations.bulk_insert`, and the 

2143 :paramref:`~.Operations.bulk_insert.multiinsert` flag has 

2144 been added to assist in this usage when running in "online" 

2145 mode. 

2146 

2147 :param table: a table object which represents the target of the INSERT. 

2148 

2149 :param rows: a list of dictionaries indicating rows. 

2150 

2151 :param multiinsert: when at its default of True and --sql mode is not 

2152 enabled, the INSERT statement will be executed using 

2153 "executemany()" style, where all elements in the list of 

2154 dictionaries are passed as bound parameters in a single 

2155 list. Setting this to False results in individual INSERT 

2156 statements being emitted per parameter set, and is needed 

2157 in those cases where non-literal values are present in the 

2158 parameter sets. 

2159 

2160 .. versionadded:: 0.6.4 

2161 

2162 """ 

2163 

2164 op = cls(table, rows, multiinsert=multiinsert) 

2165 operations.invoke(op) 

2166 

2167 

2168@Operations.register_operation("execute") 

2169class ExecuteSQLOp(MigrateOperation): 

2170 """Represent an execute SQL operation.""" 

2171 

2172 def __init__(self, sqltext, execution_options=None): 

2173 self.sqltext = sqltext 

2174 self.execution_options = execution_options 

2175 

2176 @classmethod 

2177 def execute(cls, operations, sqltext, execution_options=None): 

2178 r"""Execute the given SQL using the current migration context. 

2179 

2180 The given SQL can be a plain string, e.g.:: 

2181 

2182 op.execute("INSERT INTO table (foo) VALUES ('some value')") 

2183 

2184 Or it can be any kind of Core SQL Expression construct, such as 

2185 below where we use an update construct:: 

2186 

2187 from sqlalchemy.sql import table, column 

2188 from sqlalchemy import String 

2189 from alembic import op 

2190 

2191 account = table('account', 

2192 column('name', String) 

2193 ) 

2194 op.execute( 

2195 account.update().\\ 

2196 where(account.c.name==op.inline_literal('account 1')).\\ 

2197 values({'name':op.inline_literal('account 2')}) 

2198 ) 

2199 

2200 Above, we made use of the SQLAlchemy 

2201 :func:`sqlalchemy.sql.expression.table` and 

2202 :func:`sqlalchemy.sql.expression.column` constructs to make a brief, 

2203 ad-hoc table construct just for our UPDATE statement. A full 

2204 :class:`~sqlalchemy.schema.Table` construct of course works perfectly 

2205 fine as well, though note it's a recommended practice to at least 

2206 ensure the definition of a table is self-contained within the migration 

2207 script, rather than imported from a module that may break compatibility 

2208 with older migrations. 

2209 

2210 In a SQL script context, the statement is emitted directly to the 

2211 output stream. There is *no* return result, however, as this 

2212 function is oriented towards generating a change script 

2213 that can run in "offline" mode. Additionally, parameterized 

2214 statements are discouraged here, as they *will not work* in offline 

2215 mode. Above, we use :meth:`.inline_literal` where parameters are 

2216 to be used. 

2217 

2218 For full interaction with a connected database where parameters can 

2219 also be used normally, use the "bind" available from the context:: 

2220 

2221 from alembic import op 

2222 connection = op.get_bind() 

2223 

2224 connection.execute( 

2225 account.update().where(account.c.name=='account 1'). 

2226 values({"name": "account 2"}) 

2227 ) 

2228 

2229 Additionally, when passing the statement as a plain string, it is first 

2230 coerceed into a :func:`sqlalchemy.sql.expression.text` construct 

2231 before being passed along. In the less likely case that the 

2232 literal SQL string contains a colon, it must be escaped with a 

2233 backslash, as:: 

2234 

2235 op.execute("INSERT INTO table (foo) VALUES ('\:colon_value')") 

2236 

2237 

2238 :param sql: Any legal SQLAlchemy expression, including: 

2239 

2240 * a string 

2241 * a :func:`sqlalchemy.sql.expression.text` construct. 

2242 * a :func:`sqlalchemy.sql.expression.insert` construct. 

2243 * a :func:`sqlalchemy.sql.expression.update`, 

2244 :func:`sqlalchemy.sql.expression.insert`, 

2245 or :func:`sqlalchemy.sql.expression.delete` construct. 

2246 * Pretty much anything that's "executable" as described 

2247 in :ref:`sqlexpression_toplevel`. 

2248 

2249 .. note:: when passing a plain string, the statement is coerced into 

2250 a :func:`sqlalchemy.sql.expression.text` construct. This construct 

2251 considers symbols with colons, e.g. ``:foo`` to be bound parameters. 

2252 To avoid this, ensure that colon symbols are escaped, e.g. 

2253 ``\:foo``. 

2254 

2255 :param execution_options: Optional dictionary of 

2256 execution options, will be passed to 

2257 :meth:`sqlalchemy.engine.Connection.execution_options`. 

2258 """ 

2259 op = cls(sqltext, execution_options=execution_options) 

2260 return operations.invoke(op) 

2261 

2262 

2263class OpContainer(MigrateOperation): 

2264 """Represent a sequence of operations operation.""" 

2265 

2266 def __init__(self, ops=()): 

2267 self.ops = ops 

2268 

2269 def is_empty(self): 

2270 return not self.ops 

2271 

2272 def as_diffs(self): 

2273 return list(OpContainer._ops_as_diffs(self)) 

2274 

2275 @classmethod 

2276 def _ops_as_diffs(cls, migrations): 

2277 for op in migrations.ops: 

2278 if hasattr(op, "ops"): 

2279 for sub_op in cls._ops_as_diffs(op): 

2280 yield sub_op 

2281 else: 

2282 yield op.to_diff_tuple() 

2283 

2284 

2285class ModifyTableOps(OpContainer): 

2286 """Contains a sequence of operations that all apply to a single Table.""" 

2287 

2288 def __init__(self, table_name, ops, schema=None): 

2289 super(ModifyTableOps, self).__init__(ops) 

2290 self.table_name = table_name 

2291 self.schema = schema 

2292 

2293 def reverse(self): 

2294 return ModifyTableOps( 

2295 self.table_name, 

2296 ops=list(reversed([op.reverse() for op in self.ops])), 

2297 schema=self.schema, 

2298 ) 

2299 

2300 

2301class UpgradeOps(OpContainer): 

2302 """contains a sequence of operations that would apply to the 

2303 'upgrade' stream of a script. 

2304 

2305 .. seealso:: 

2306 

2307 :ref:`customizing_revision` 

2308 

2309 """ 

2310 

2311 def __init__(self, ops=(), upgrade_token="upgrades"): 

2312 super(UpgradeOps, self).__init__(ops=ops) 

2313 self.upgrade_token = upgrade_token 

2314 

2315 def reverse_into(self, downgrade_ops): 

2316 downgrade_ops.ops[:] = list( 

2317 reversed([op.reverse() for op in self.ops]) 

2318 ) 

2319 return downgrade_ops 

2320 

2321 def reverse(self): 

2322 return self.reverse_into(DowngradeOps(ops=[])) 

2323 

2324 

2325class DowngradeOps(OpContainer): 

2326 """contains a sequence of operations that would apply to the 

2327 'downgrade' stream of a script. 

2328 

2329 .. seealso:: 

2330 

2331 :ref:`customizing_revision` 

2332 

2333 """ 

2334 

2335 def __init__(self, ops=(), downgrade_token="downgrades"): 

2336 super(DowngradeOps, self).__init__(ops=ops) 

2337 self.downgrade_token = downgrade_token 

2338 

2339 def reverse(self): 

2340 return UpgradeOps( 

2341 ops=list(reversed([op.reverse() for op in self.ops])) 

2342 ) 

2343 

2344 

2345class MigrationScript(MigrateOperation): 

2346 """represents a migration script. 

2347 

2348 E.g. when autogenerate encounters this object, this corresponds to the 

2349 production of an actual script file. 

2350 

2351 A normal :class:`.MigrationScript` object would contain a single 

2352 :class:`.UpgradeOps` and a single :class:`.DowngradeOps` directive. 

2353 These are accessible via the ``.upgrade_ops`` and ``.downgrade_ops`` 

2354 attributes. 

2355 

2356 In the case of an autogenerate operation that runs multiple times, 

2357 such as the multiple database example in the "multidb" template, 

2358 the ``.upgrade_ops`` and ``.downgrade_ops`` attributes are disabled, 

2359 and instead these objects should be accessed via the ``.upgrade_ops_list`` 

2360 and ``.downgrade_ops_list`` list-based attributes. These latter 

2361 attributes are always available at the very least as single-element lists. 

2362 

2363 .. versionchanged:: 0.8.1 the ``.upgrade_ops`` and ``.downgrade_ops`` 

2364 attributes should be accessed via the ``.upgrade_ops_list`` 

2365 and ``.downgrade_ops_list`` attributes if multiple autogenerate 

2366 passes proceed on the same :class:`.MigrationScript` object. 

2367 

2368 .. seealso:: 

2369 

2370 :ref:`customizing_revision` 

2371 

2372 """ 

2373 

2374 def __init__( 

2375 self, 

2376 rev_id, 

2377 upgrade_ops, 

2378 downgrade_ops, 

2379 message=None, 

2380 imports=set(), 

2381 head=None, 

2382 splice=None, 

2383 branch_label=None, 

2384 version_path=None, 

2385 depends_on=None, 

2386 ): 

2387 self.rev_id = rev_id 

2388 self.message = message 

2389 self.imports = imports 

2390 self.head = head 

2391 self.splice = splice 

2392 self.branch_label = branch_label 

2393 self.version_path = version_path 

2394 self.depends_on = depends_on 

2395 self.upgrade_ops = upgrade_ops 

2396 self.downgrade_ops = downgrade_ops 

2397 

2398 @property 

2399 def upgrade_ops(self): 

2400 """An instance of :class:`.UpgradeOps`. 

2401 

2402 .. seealso:: 

2403 

2404 :attr:`.MigrationScript.upgrade_ops_list` 

2405 """ 

2406 if len(self._upgrade_ops) > 1: 

2407 raise ValueError( 

2408 "This MigrationScript instance has a multiple-entry " 

2409 "list for UpgradeOps; please use the " 

2410 "upgrade_ops_list attribute." 

2411 ) 

2412 elif not self._upgrade_ops: 

2413 return None 

2414 else: 

2415 return self._upgrade_ops[0] 

2416 

2417 @upgrade_ops.setter 

2418 def upgrade_ops(self, upgrade_ops): 

2419 self._upgrade_ops = util.to_list(upgrade_ops) 

2420 for elem in self._upgrade_ops: 

2421 assert isinstance(elem, UpgradeOps) 

2422 

2423 @property 

2424 def downgrade_ops(self): 

2425 """An instance of :class:`.DowngradeOps`. 

2426 

2427 .. seealso:: 

2428 

2429 :attr:`.MigrationScript.downgrade_ops_list` 

2430 """ 

2431 if len(self._downgrade_ops) > 1: 

2432 raise ValueError( 

2433 "This MigrationScript instance has a multiple-entry " 

2434 "list for DowngradeOps; please use the " 

2435 "downgrade_ops_list attribute." 

2436 ) 

2437 elif not self._downgrade_ops: 

2438 return None 

2439 else: 

2440 return self._downgrade_ops[0] 

2441 

2442 @downgrade_ops.setter 

2443 def downgrade_ops(self, downgrade_ops): 

2444 self._downgrade_ops = util.to_list(downgrade_ops) 

2445 for elem in self._downgrade_ops: 

2446 assert isinstance(elem, DowngradeOps) 

2447 

2448 @property 

2449 def upgrade_ops_list(self): 

2450 """A list of :class:`.UpgradeOps` instances. 

2451 

2452 This is used in place of the :attr:`.MigrationScript.upgrade_ops` 

2453 attribute when dealing with a revision operation that does 

2454 multiple autogenerate passes. 

2455 

2456 .. versionadded:: 0.8.1 

2457 

2458 """ 

2459 return self._upgrade_ops 

2460 

2461 @property 

2462 def downgrade_ops_list(self): 

2463 """A list of :class:`.DowngradeOps` instances. 

2464 

2465 This is used in place of the :attr:`.MigrationScript.downgrade_ops` 

2466 attribute when dealing with a revision operation that does 

2467 multiple autogenerate passes. 

2468 

2469 .. versionadded:: 0.8.1 

2470 

2471 """ 

2472 return self._downgrade_ops