base.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. from contextlib import contextmanager
  2. from .. import util
  3. from ..util import sqla_compat
  4. from . import batch
  5. from . import schemaobj
  6. from ..util.compat import exec_
  7. import textwrap
  8. import inspect
  9. __all__ = ('Operations', 'BatchOperations')
  10. try:
  11. from sqlalchemy.sql.naming import conv
  12. except:
  13. conv = None
  14. class Operations(util.ModuleClsProxy):
  15. """Define high level migration operations.
  16. Each operation corresponds to some schema migration operation,
  17. executed against a particular :class:`.MigrationContext`
  18. which in turn represents connectivity to a database,
  19. or a file output stream.
  20. While :class:`.Operations` is normally configured as
  21. part of the :meth:`.EnvironmentContext.run_migrations`
  22. method called from an ``env.py`` script, a standalone
  23. :class:`.Operations` instance can be
  24. made for use cases external to regular Alembic
  25. migrations by passing in a :class:`.MigrationContext`::
  26. from alembic.migration import MigrationContext
  27. from alembic.operations import Operations
  28. conn = myengine.connect()
  29. ctx = MigrationContext.configure(conn)
  30. op = Operations(ctx)
  31. op.alter_column("t", "c", nullable=True)
  32. Note that as of 0.8, most of the methods on this class are produced
  33. dynamically using the :meth:`.Operations.register_operation`
  34. method.
  35. """
  36. _to_impl = util.Dispatcher()
  37. def __init__(self, migration_context, impl=None):
  38. """Construct a new :class:`.Operations`
  39. :param migration_context: a :class:`.MigrationContext`
  40. instance.
  41. """
  42. self.migration_context = migration_context
  43. if impl is None:
  44. self.impl = migration_context.impl
  45. else:
  46. self.impl = impl
  47. self.schema_obj = schemaobj.SchemaObjects(migration_context)
  48. @classmethod
  49. def register_operation(cls, name, sourcename=None):
  50. """Register a new operation for this class.
  51. This method is normally used to add new operations
  52. to the :class:`.Operations` class, and possibly the
  53. :class:`.BatchOperations` class as well. All Alembic migration
  54. operations are implemented via this system, however the system
  55. is also available as a public API to facilitate adding custom
  56. operations.
  57. .. versionadded:: 0.8.0
  58. .. seealso::
  59. :ref:`operation_plugins`
  60. """
  61. def register(op_cls):
  62. if sourcename is None:
  63. fn = getattr(op_cls, name)
  64. source_name = fn.__name__
  65. else:
  66. fn = getattr(op_cls, sourcename)
  67. source_name = fn.__name__
  68. spec = inspect.getargspec(fn)
  69. name_args = spec[0]
  70. assert name_args[0:2] == ['cls', 'operations']
  71. name_args[0:2] = ['self']
  72. args = inspect.formatargspec(*spec)
  73. num_defaults = len(spec[3]) if spec[3] else 0
  74. if num_defaults:
  75. defaulted_vals = name_args[0 - num_defaults:]
  76. else:
  77. defaulted_vals = ()
  78. apply_kw = inspect.formatargspec(
  79. name_args, spec[1], spec[2],
  80. defaulted_vals,
  81. formatvalue=lambda x: '=' + x)
  82. func_text = textwrap.dedent("""\
  83. def %(name)s%(args)s:
  84. %(doc)r
  85. return op_cls.%(source_name)s%(apply_kw)s
  86. """ % {
  87. 'name': name,
  88. 'source_name': source_name,
  89. 'args': args,
  90. 'apply_kw': apply_kw,
  91. 'doc': fn.__doc__,
  92. 'meth': fn.__name__
  93. })
  94. globals_ = {'op_cls': op_cls}
  95. lcl = {}
  96. exec_(func_text, globals_, lcl)
  97. setattr(cls, name, lcl[name])
  98. fn.__func__.__doc__ = "This method is proxied on "\
  99. "the :class:`.%s` class, via the :meth:`.%s.%s` method." % (
  100. cls.__name__, cls.__name__, name
  101. )
  102. if hasattr(fn, '_legacy_translations'):
  103. lcl[name]._legacy_translations = fn._legacy_translations
  104. return op_cls
  105. return register
  106. @classmethod
  107. def implementation_for(cls, op_cls):
  108. """Register an implementation for a given :class:`.MigrateOperation`.
  109. This is part of the operation extensibility API.
  110. .. seealso::
  111. :ref:`operation_plugins` - example of use
  112. """
  113. def decorate(fn):
  114. cls._to_impl.dispatch_for(op_cls)(fn)
  115. return fn
  116. return decorate
  117. @classmethod
  118. @contextmanager
  119. def context(cls, migration_context):
  120. op = Operations(migration_context)
  121. op._install_proxy()
  122. yield op
  123. op._remove_proxy()
  124. @contextmanager
  125. def batch_alter_table(
  126. self, table_name, schema=None, recreate="auto", copy_from=None,
  127. table_args=(), table_kwargs=util.immutabledict(),
  128. reflect_args=(), reflect_kwargs=util.immutabledict(),
  129. naming_convention=None):
  130. """Invoke a series of per-table migrations in batch.
  131. Batch mode allows a series of operations specific to a table
  132. to be syntactically grouped together, and allows for alternate
  133. modes of table migration, in particular the "recreate" style of
  134. migration required by SQLite.
  135. "recreate" style is as follows:
  136. 1. A new table is created with the new specification, based on the
  137. migration directives within the batch, using a temporary name.
  138. 2. the data copied from the existing table to the new table.
  139. 3. the existing table is dropped.
  140. 4. the new table is renamed to the existing table name.
  141. The directive by default will only use "recreate" style on the
  142. SQLite backend, and only if directives are present which require
  143. this form, e.g. anything other than ``add_column()``. The batch
  144. operation on other backends will proceed using standard ALTER TABLE
  145. operations.
  146. The method is used as a context manager, which returns an instance
  147. of :class:`.BatchOperations`; this object is the same as
  148. :class:`.Operations` except that table names and schema names
  149. are omitted. E.g.::
  150. with op.batch_alter_table("some_table") as batch_op:
  151. batch_op.add_column(Column('foo', Integer))
  152. batch_op.drop_column('bar')
  153. The operations within the context manager are invoked at once
  154. when the context is ended. When run against SQLite, if the
  155. migrations include operations not supported by SQLite's ALTER TABLE,
  156. the entire table will be copied to a new one with the new
  157. specification, moving all data across as well.
  158. The copy operation by default uses reflection to retrieve the current
  159. structure of the table, and therefore :meth:`.batch_alter_table`
  160. in this mode requires that the migration is run in "online" mode.
  161. The ``copy_from`` parameter may be passed which refers to an existing
  162. :class:`.Table` object, which will bypass this reflection step.
  163. .. note:: The table copy operation will currently not copy
  164. CHECK constraints, and may not copy UNIQUE constraints that are
  165. unnamed, as is possible on SQLite. See the section
  166. :ref:`sqlite_batch_constraints` for workarounds.
  167. :param table_name: name of table
  168. :param schema: optional schema name.
  169. :param recreate: under what circumstances the table should be
  170. recreated. At its default of ``"auto"``, the SQLite dialect will
  171. recreate the table if any operations other than ``add_column()``,
  172. ``create_index()``, or ``drop_index()`` are
  173. present. Other options include ``"always"`` and ``"never"``.
  174. :param copy_from: optional :class:`~sqlalchemy.schema.Table` object
  175. that will act as the structure of the table being copied. If omitted,
  176. table reflection is used to retrieve the structure of the table.
  177. .. versionadded:: 0.7.6 Fully implemented the
  178. :paramref:`~.Operations.batch_alter_table.copy_from`
  179. parameter.
  180. .. seealso::
  181. :ref:`batch_offline_mode`
  182. :paramref:`~.Operations.batch_alter_table.reflect_args`
  183. :paramref:`~.Operations.batch_alter_table.reflect_kwargs`
  184. :param reflect_args: a sequence of additional positional arguments that
  185. will be applied to the table structure being reflected / copied;
  186. this may be used to pass column and constraint overrides to the
  187. table that will be reflected, in lieu of passing the whole
  188. :class:`~sqlalchemy.schema.Table` using
  189. :paramref:`~.Operations.batch_alter_table.copy_from`.
  190. .. versionadded:: 0.7.1
  191. :param reflect_kwargs: a dictionary of additional keyword arguments
  192. that will be applied to the table structure being copied; this may be
  193. used to pass additional table and reflection options to the table that
  194. will be reflected, in lieu of passing the whole
  195. :class:`~sqlalchemy.schema.Table` using
  196. :paramref:`~.Operations.batch_alter_table.copy_from`.
  197. .. versionadded:: 0.7.1
  198. :param table_args: a sequence of additional positional arguments that
  199. will be applied to the new :class:`~sqlalchemy.schema.Table` when
  200. created, in addition to those copied from the source table.
  201. This may be used to provide additional constraints such as CHECK
  202. constraints that may not be reflected.
  203. :param table_kwargs: a dictionary of additional keyword arguments
  204. that will be applied to the new :class:`~sqlalchemy.schema.Table`
  205. when created, in addition to those copied from the source table.
  206. This may be used to provide for additional table options that may
  207. not be reflected.
  208. .. versionadded:: 0.7.0
  209. :param naming_convention: a naming convention dictionary of the form
  210. described at :ref:`autogen_naming_conventions` which will be applied
  211. to the :class:`~sqlalchemy.schema.MetaData` during the reflection
  212. process. This is typically required if one wants to drop SQLite
  213. constraints, as these constraints will not have names when
  214. reflected on this backend. Requires SQLAlchemy **0.9.4** or greater.
  215. .. seealso::
  216. :ref:`dropping_sqlite_foreign_keys`
  217. .. versionadded:: 0.7.1
  218. .. note:: batch mode requires SQLAlchemy 0.8 or above.
  219. .. seealso::
  220. :ref:`batch_migrations`
  221. """
  222. impl = batch.BatchOperationsImpl(
  223. self, table_name, schema, recreate,
  224. copy_from, table_args, table_kwargs, reflect_args,
  225. reflect_kwargs, naming_convention)
  226. batch_op = BatchOperations(self.migration_context, impl=impl)
  227. yield batch_op
  228. impl.flush()
  229. def get_context(self):
  230. """Return the :class:`.MigrationContext` object that's
  231. currently in use.
  232. """
  233. return self.migration_context
  234. def invoke(self, operation):
  235. """Given a :class:`.MigrateOperation`, invoke it in terms of
  236. this :class:`.Operations` instance.
  237. .. versionadded:: 0.8.0
  238. """
  239. fn = self._to_impl.dispatch(
  240. operation, self.migration_context.impl.__dialect__)
  241. return fn(self, operation)
  242. def f(self, name):
  243. """Indicate a string name that has already had a naming convention
  244. applied to it.
  245. This feature combines with the SQLAlchemy ``naming_convention`` feature
  246. to disambiguate constraint names that have already had naming
  247. conventions applied to them, versus those that have not. This is
  248. necessary in the case that the ``"%(constraint_name)s"`` token
  249. is used within a naming convention, so that it can be identified
  250. that this particular name should remain fixed.
  251. If the :meth:`.Operations.f` is used on a constraint, the naming
  252. convention will not take effect::
  253. op.add_column('t', 'x', Boolean(name=op.f('ck_bool_t_x')))
  254. Above, the CHECK constraint generated will have the name
  255. ``ck_bool_t_x`` regardless of whether or not a naming convention is
  256. in use.
  257. Alternatively, if a naming convention is in use, and 'f' is not used,
  258. names will be converted along conventions. If the ``target_metadata``
  259. contains the naming convention
  260. ``{"ck": "ck_bool_%(table_name)s_%(constraint_name)s"}``, then the
  261. output of the following:
  262. op.add_column('t', 'x', Boolean(name='x'))
  263. will be::
  264. CONSTRAINT ck_bool_t_x CHECK (x in (1, 0)))
  265. The function is rendered in the output of autogenerate when
  266. a particular constraint name is already converted, for SQLAlchemy
  267. version **0.9.4 and greater only**. Even though ``naming_convention``
  268. was introduced in 0.9.2, the string disambiguation service is new
  269. as of 0.9.4.
  270. .. versionadded:: 0.6.4
  271. """
  272. if conv:
  273. return conv(name)
  274. else:
  275. raise NotImplementedError(
  276. "op.f() feature requires SQLAlchemy 0.9.4 or greater.")
  277. def inline_literal(self, value, type_=None):
  278. """Produce an 'inline literal' expression, suitable for
  279. using in an INSERT, UPDATE, or DELETE statement.
  280. When using Alembic in "offline" mode, CRUD operations
  281. aren't compatible with SQLAlchemy's default behavior surrounding
  282. literal values,
  283. which is that they are converted into bound values and passed
  284. separately into the ``execute()`` method of the DBAPI cursor.
  285. An offline SQL
  286. script needs to have these rendered inline. While it should
  287. always be noted that inline literal values are an **enormous**
  288. security hole in an application that handles untrusted input,
  289. a schema migration is not run in this context, so
  290. literals are safe to render inline, with the caveat that
  291. advanced types like dates may not be supported directly
  292. by SQLAlchemy.
  293. See :meth:`.execute` for an example usage of
  294. :meth:`.inline_literal`.
  295. The environment can also be configured to attempt to render
  296. "literal" values inline automatically, for those simple types
  297. that are supported by the dialect; see
  298. :paramref:`.EnvironmentContext.configure.literal_binds` for this
  299. more recently added feature.
  300. :param value: The value to render. Strings, integers, and simple
  301. numerics should be supported. Other types like boolean,
  302. dates, etc. may or may not be supported yet by various
  303. backends.
  304. :param type_: optional - a :class:`sqlalchemy.types.TypeEngine`
  305. subclass stating the type of this value. In SQLAlchemy
  306. expressions, this is usually derived automatically
  307. from the Python type of the value itself, as well as
  308. based on the context in which the value is used.
  309. .. seealso::
  310. :paramref:`.EnvironmentContext.configure.literal_binds`
  311. """
  312. return sqla_compat._literal_bindparam(None, value, type_=type_)
  313. def get_bind(self):
  314. """Return the current 'bind'.
  315. Under normal circumstances, this is the
  316. :class:`~sqlalchemy.engine.Connection` currently being used
  317. to emit SQL to the database.
  318. In a SQL script context, this value is ``None``. [TODO: verify this]
  319. """
  320. return self.migration_context.impl.bind
  321. class BatchOperations(Operations):
  322. """Modifies the interface :class:`.Operations` for batch mode.
  323. This basically omits the ``table_name`` and ``schema`` parameters
  324. from associated methods, as these are a given when running under batch
  325. mode.
  326. .. seealso::
  327. :meth:`.Operations.batch_alter_table`
  328. Note that as of 0.8, most of the methods on this class are produced
  329. dynamically using the :meth:`.Operations.register_operation`
  330. method.
  331. """
  332. def _noop(self, operation):
  333. raise NotImplementedError(
  334. "The %s method does not apply to a batch table alter operation."
  335. % operation)