environment.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053
  1. from __future__ import annotations
  2. from typing import Any
  3. from typing import Callable
  4. from typing import Collection
  5. from typing import ContextManager
  6. from typing import Dict
  7. from typing import List
  8. from typing import Mapping
  9. from typing import MutableMapping
  10. from typing import Optional
  11. from typing import overload
  12. from typing import Sequence
  13. from typing import TextIO
  14. from typing import Tuple
  15. from typing import TYPE_CHECKING
  16. from typing import Union
  17. from sqlalchemy.sql.schema import Column
  18. from sqlalchemy.sql.schema import FetchedValue
  19. from typing_extensions import Literal
  20. from .migration import _ProxyTransaction
  21. from .migration import MigrationContext
  22. from .. import util
  23. from ..operations import Operations
  24. from ..script.revision import _GetRevArg
  25. if TYPE_CHECKING:
  26. from sqlalchemy.engine import URL
  27. from sqlalchemy.engine.base import Connection
  28. from sqlalchemy.sql import Executable
  29. from sqlalchemy.sql.schema import MetaData
  30. from sqlalchemy.sql.schema import SchemaItem
  31. from sqlalchemy.sql.type_api import TypeEngine
  32. from .migration import MigrationInfo
  33. from ..autogenerate.api import AutogenContext
  34. from ..config import Config
  35. from ..ddl import DefaultImpl
  36. from ..operations.ops import MigrationScript
  37. from ..script.base import ScriptDirectory
  38. _RevNumber = Optional[Union[str, Tuple[str, ...]]]
  39. ProcessRevisionDirectiveFn = Callable[
  40. [MigrationContext, _GetRevArg, List["MigrationScript"]], None
  41. ]
  42. RenderItemFn = Callable[
  43. [str, Any, "AutogenContext"], Union[str, Literal[False]]
  44. ]
  45. NameFilterType = Literal[
  46. "schema",
  47. "table",
  48. "column",
  49. "index",
  50. "unique_constraint",
  51. "foreign_key_constraint",
  52. ]
  53. NameFilterParentNames = MutableMapping[
  54. Literal["schema_name", "table_name", "schema_qualified_table_name"],
  55. Optional[str],
  56. ]
  57. IncludeNameFn = Callable[
  58. [Optional[str], NameFilterType, NameFilterParentNames], bool
  59. ]
  60. IncludeObjectFn = Callable[
  61. [
  62. "SchemaItem",
  63. Optional[str],
  64. NameFilterType,
  65. bool,
  66. Optional["SchemaItem"],
  67. ],
  68. bool,
  69. ]
  70. OnVersionApplyFn = Callable[
  71. [MigrationContext, "MigrationInfo", Collection[Any], Mapping[str, Any]],
  72. None,
  73. ]
  74. CompareServerDefault = Callable[
  75. [
  76. MigrationContext,
  77. "Column[Any]",
  78. "Column[Any]",
  79. Optional[str],
  80. Optional[FetchedValue],
  81. Optional[str],
  82. ],
  83. Optional[bool],
  84. ]
  85. CompareType = Callable[
  86. [
  87. MigrationContext,
  88. "Column[Any]",
  89. "Column[Any]",
  90. "TypeEngine[Any]",
  91. "TypeEngine[Any]",
  92. ],
  93. Optional[bool],
  94. ]
  95. class EnvironmentContext(util.ModuleClsProxy):
  96. """A configurational facade made available in an ``env.py`` script.
  97. The :class:`.EnvironmentContext` acts as a *facade* to the more
  98. nuts-and-bolts objects of :class:`.MigrationContext` as well as certain
  99. aspects of :class:`.Config`,
  100. within the context of the ``env.py`` script that is invoked by
  101. most Alembic commands.
  102. :class:`.EnvironmentContext` is normally instantiated
  103. when a command in :mod:`alembic.command` is run. It then makes
  104. itself available in the ``alembic.context`` module for the scope
  105. of the command. From within an ``env.py`` script, the current
  106. :class:`.EnvironmentContext` is available by importing this module.
  107. :class:`.EnvironmentContext` also supports programmatic usage.
  108. At this level, it acts as a Python context manager, that is, is
  109. intended to be used using the
  110. ``with:`` statement. A typical use of :class:`.EnvironmentContext`::
  111. from alembic.config import Config
  112. from alembic.script import ScriptDirectory
  113. config = Config()
  114. config.set_main_option("script_location", "myapp:migrations")
  115. script = ScriptDirectory.from_config(config)
  116. def my_function(rev, context):
  117. '''do something with revision "rev", which
  118. will be the current database revision,
  119. and "context", which is the MigrationContext
  120. that the env.py will create'''
  121. with EnvironmentContext(
  122. config,
  123. script,
  124. fn=my_function,
  125. as_sql=False,
  126. starting_rev="base",
  127. destination_rev="head",
  128. tag="sometag",
  129. ):
  130. script.run_env()
  131. The above script will invoke the ``env.py`` script
  132. within the migration environment. If and when ``env.py``
  133. calls :meth:`.MigrationContext.run_migrations`, the
  134. ``my_function()`` function above will be called
  135. by the :class:`.MigrationContext`, given the context
  136. itself as well as the current revision in the database.
  137. .. note::
  138. For most API usages other than full blown
  139. invocation of migration scripts, the :class:`.MigrationContext`
  140. and :class:`.ScriptDirectory` objects can be created and
  141. used directly. The :class:`.EnvironmentContext` object
  142. is *only* needed when you need to actually invoke the
  143. ``env.py`` module present in the migration environment.
  144. """
  145. _migration_context: Optional[MigrationContext] = None
  146. config: Config = None # type:ignore[assignment]
  147. """An instance of :class:`.Config` representing the
  148. configuration file contents as well as other variables
  149. set programmatically within it."""
  150. script: ScriptDirectory = None # type:ignore[assignment]
  151. """An instance of :class:`.ScriptDirectory` which provides
  152. programmatic access to version files within the ``versions/``
  153. directory.
  154. """
  155. def __init__(
  156. self, config: Config, script: ScriptDirectory, **kw: Any
  157. ) -> None:
  158. r"""Construct a new :class:`.EnvironmentContext`.
  159. :param config: a :class:`.Config` instance.
  160. :param script: a :class:`.ScriptDirectory` instance.
  161. :param \**kw: keyword options that will be ultimately
  162. passed along to the :class:`.MigrationContext` when
  163. :meth:`.EnvironmentContext.configure` is called.
  164. """
  165. self.config = config
  166. self.script = script
  167. self.context_opts = kw
  168. def __enter__(self) -> EnvironmentContext:
  169. """Establish a context which provides a
  170. :class:`.EnvironmentContext` object to
  171. env.py scripts.
  172. The :class:`.EnvironmentContext` will
  173. be made available as ``from alembic import context``.
  174. """
  175. self._install_proxy()
  176. return self
  177. def __exit__(self, *arg: Any, **kw: Any) -> None:
  178. self._remove_proxy()
  179. def is_offline_mode(self) -> bool:
  180. """Return True if the current migrations environment
  181. is running in "offline mode".
  182. This is ``True`` or ``False`` depending
  183. on the ``--sql`` flag passed.
  184. This function does not require that the :class:`.MigrationContext`
  185. has been configured.
  186. """
  187. return self.context_opts.get("as_sql", False) # type: ignore[no-any-return] # noqa: E501
  188. def is_transactional_ddl(self) -> bool:
  189. """Return True if the context is configured to expect a
  190. transactional DDL capable backend.
  191. This defaults to the type of database in use, and
  192. can be overridden by the ``transactional_ddl`` argument
  193. to :meth:`.configure`
  194. This function requires that a :class:`.MigrationContext`
  195. has first been made available via :meth:`.configure`.
  196. """
  197. return self.get_context().impl.transactional_ddl
  198. def requires_connection(self) -> bool:
  199. return not self.is_offline_mode()
  200. def get_head_revision(self) -> _RevNumber:
  201. """Return the hex identifier of the 'head' script revision.
  202. If the script directory has multiple heads, this
  203. method raises a :class:`.CommandError`;
  204. :meth:`.EnvironmentContext.get_head_revisions` should be preferred.
  205. This function does not require that the :class:`.MigrationContext`
  206. has been configured.
  207. .. seealso:: :meth:`.EnvironmentContext.get_head_revisions`
  208. """
  209. return self.script.as_revision_number("head")
  210. def get_head_revisions(self) -> _RevNumber:
  211. """Return the hex identifier of the 'heads' script revision(s).
  212. This returns a tuple containing the version number of all
  213. heads in the script directory.
  214. This function does not require that the :class:`.MigrationContext`
  215. has been configured.
  216. """
  217. return self.script.as_revision_number("heads")
  218. def get_starting_revision_argument(self) -> _RevNumber:
  219. """Return the 'starting revision' argument,
  220. if the revision was passed using ``start:end``.
  221. This is only meaningful in "offline" mode.
  222. Returns ``None`` if no value is available
  223. or was configured.
  224. This function does not require that the :class:`.MigrationContext`
  225. has been configured.
  226. """
  227. if self._migration_context is not None:
  228. return self.script.as_revision_number(
  229. self.get_context()._start_from_rev
  230. )
  231. elif "starting_rev" in self.context_opts:
  232. return self.script.as_revision_number(
  233. self.context_opts["starting_rev"]
  234. )
  235. else:
  236. # this should raise only in the case that a command
  237. # is being run where the "starting rev" is never applicable;
  238. # this is to catch scripts which rely upon this in
  239. # non-sql mode or similar
  240. raise util.CommandError(
  241. "No starting revision argument is available."
  242. )
  243. def get_revision_argument(self) -> _RevNumber:
  244. """Get the 'destination' revision argument.
  245. This is typically the argument passed to the
  246. ``upgrade`` or ``downgrade`` command.
  247. If it was specified as ``head``, the actual
  248. version number is returned; if specified
  249. as ``base``, ``None`` is returned.
  250. This function does not require that the :class:`.MigrationContext`
  251. has been configured.
  252. """
  253. return self.script.as_revision_number(
  254. self.context_opts["destination_rev"]
  255. )
  256. def get_tag_argument(self) -> Optional[str]:
  257. """Return the value passed for the ``--tag`` argument, if any.
  258. The ``--tag`` argument is not used directly by Alembic,
  259. but is available for custom ``env.py`` configurations that
  260. wish to use it; particularly for offline generation scripts
  261. that wish to generate tagged filenames.
  262. This function does not require that the :class:`.MigrationContext`
  263. has been configured.
  264. .. seealso::
  265. :meth:`.EnvironmentContext.get_x_argument` - a newer and more
  266. open ended system of extending ``env.py`` scripts via the command
  267. line.
  268. """
  269. return self.context_opts.get("tag", None) # type: ignore[no-any-return] # noqa: E501
  270. @overload
  271. def get_x_argument(self, as_dictionary: Literal[False]) -> List[str]:
  272. ...
  273. @overload
  274. def get_x_argument(self, as_dictionary: Literal[True]) -> Dict[str, str]:
  275. ...
  276. @overload
  277. def get_x_argument(
  278. self, as_dictionary: bool = ...
  279. ) -> Union[List[str], Dict[str, str]]:
  280. ...
  281. def get_x_argument(
  282. self, as_dictionary: bool = False
  283. ) -> Union[List[str], Dict[str, str]]:
  284. """Return the value(s) passed for the ``-x`` argument, if any.
  285. The ``-x`` argument is an open ended flag that allows any user-defined
  286. value or values to be passed on the command line, then available
  287. here for consumption by a custom ``env.py`` script.
  288. The return value is a list, returned directly from the ``argparse``
  289. structure. If ``as_dictionary=True`` is passed, the ``x`` arguments
  290. are parsed using ``key=value`` format into a dictionary that is
  291. then returned. If there is no ``=`` in the argument, value is an empty
  292. string.
  293. .. versionchanged:: 1.13.1 Support ``as_dictionary=True`` when
  294. arguments are passed without the ``=`` symbol.
  295. For example, to support passing a database URL on the command line,
  296. the standard ``env.py`` script can be modified like this::
  297. cmd_line_url = context.get_x_argument(
  298. as_dictionary=True).get('dbname')
  299. if cmd_line_url:
  300. engine = create_engine(cmd_line_url)
  301. else:
  302. engine = engine_from_config(
  303. config.get_section(config.config_ini_section),
  304. prefix='sqlalchemy.',
  305. poolclass=pool.NullPool)
  306. This then takes effect by running the ``alembic`` script as::
  307. alembic -x dbname=postgresql://user:pass@host/dbname upgrade head
  308. This function does not require that the :class:`.MigrationContext`
  309. has been configured.
  310. .. seealso::
  311. :meth:`.EnvironmentContext.get_tag_argument`
  312. :attr:`.Config.cmd_opts`
  313. """
  314. if self.config.cmd_opts is not None:
  315. value = self.config.cmd_opts.x or []
  316. else:
  317. value = []
  318. if as_dictionary:
  319. dict_value = {}
  320. for arg in value:
  321. x_key, _, x_value = arg.partition("=")
  322. dict_value[x_key] = x_value
  323. value = dict_value
  324. return value
  325. def configure(
  326. self,
  327. connection: Optional[Connection] = None,
  328. url: Optional[Union[str, URL]] = None,
  329. dialect_name: Optional[str] = None,
  330. dialect_opts: Optional[Dict[str, Any]] = None,
  331. transactional_ddl: Optional[bool] = None,
  332. transaction_per_migration: bool = False,
  333. output_buffer: Optional[TextIO] = None,
  334. starting_rev: Optional[str] = None,
  335. tag: Optional[str] = None,
  336. template_args: Optional[Dict[str, Any]] = None,
  337. render_as_batch: bool = False,
  338. target_metadata: Union[MetaData, Sequence[MetaData], None] = None,
  339. include_name: Optional[IncludeNameFn] = None,
  340. include_object: Optional[IncludeObjectFn] = None,
  341. include_schemas: bool = False,
  342. process_revision_directives: Optional[
  343. ProcessRevisionDirectiveFn
  344. ] = None,
  345. compare_type: Union[bool, CompareType] = True,
  346. compare_server_default: Union[bool, CompareServerDefault] = False,
  347. render_item: Optional[RenderItemFn] = None,
  348. literal_binds: bool = False,
  349. upgrade_token: str = "upgrades",
  350. downgrade_token: str = "downgrades",
  351. alembic_module_prefix: str = "op.",
  352. sqlalchemy_module_prefix: str = "sa.",
  353. user_module_prefix: Optional[str] = None,
  354. on_version_apply: Optional[OnVersionApplyFn] = None,
  355. **kw: Any,
  356. ) -> None:
  357. """Configure a :class:`.MigrationContext` within this
  358. :class:`.EnvironmentContext` which will provide database
  359. connectivity and other configuration to a series of
  360. migration scripts.
  361. Many methods on :class:`.EnvironmentContext` require that
  362. this method has been called in order to function, as they
  363. ultimately need to have database access or at least access
  364. to the dialect in use. Those which do are documented as such.
  365. The important thing needed by :meth:`.configure` is a
  366. means to determine what kind of database dialect is in use.
  367. An actual connection to that database is needed only if
  368. the :class:`.MigrationContext` is to be used in
  369. "online" mode.
  370. If the :meth:`.is_offline_mode` function returns ``True``,
  371. then no connection is needed here. Otherwise, the
  372. ``connection`` parameter should be present as an
  373. instance of :class:`sqlalchemy.engine.Connection`.
  374. This function is typically called from the ``env.py``
  375. script within a migration environment. It can be called
  376. multiple times for an invocation. The most recent
  377. :class:`~sqlalchemy.engine.Connection`
  378. for which it was called is the one that will be operated upon
  379. by the next call to :meth:`.run_migrations`.
  380. General parameters:
  381. :param connection: a :class:`~sqlalchemy.engine.Connection`
  382. to use
  383. for SQL execution in "online" mode. When present, is also
  384. used to determine the type of dialect in use.
  385. :param url: a string database url, or a
  386. :class:`sqlalchemy.engine.url.URL` object.
  387. The type of dialect to be used will be derived from this if
  388. ``connection`` is not passed.
  389. :param dialect_name: string name of a dialect, such as
  390. "postgresql", "mssql", etc.
  391. The type of dialect to be used will be derived from this if
  392. ``connection`` and ``url`` are not passed.
  393. :param dialect_opts: dictionary of options to be passed to dialect
  394. constructor.
  395. :param transactional_ddl: Force the usage of "transactional"
  396. DDL on or off;
  397. this otherwise defaults to whether or not the dialect in
  398. use supports it.
  399. :param transaction_per_migration: if True, nest each migration script
  400. in a transaction rather than the full series of migrations to
  401. run.
  402. :param output_buffer: a file-like object that will be used
  403. for textual output
  404. when the ``--sql`` option is used to generate SQL scripts.
  405. Defaults to
  406. ``sys.stdout`` if not passed here and also not present on
  407. the :class:`.Config`
  408. object. The value here overrides that of the :class:`.Config`
  409. object.
  410. :param output_encoding: when using ``--sql`` to generate SQL
  411. scripts, apply this encoding to the string output.
  412. :param literal_binds: when using ``--sql`` to generate SQL
  413. scripts, pass through the ``literal_binds`` flag to the compiler
  414. so that any literal values that would ordinarily be bound
  415. parameters are converted to plain strings.
  416. .. warning:: Dialects can typically only handle simple datatypes
  417. like strings and numbers for auto-literal generation. Datatypes
  418. like dates, intervals, and others may still require manual
  419. formatting, typically using :meth:`.Operations.inline_literal`.
  420. .. note:: the ``literal_binds`` flag is ignored on SQLAlchemy
  421. versions prior to 0.8 where this feature is not supported.
  422. .. seealso::
  423. :meth:`.Operations.inline_literal`
  424. :param starting_rev: Override the "starting revision" argument
  425. when using ``--sql`` mode.
  426. :param tag: a string tag for usage by custom ``env.py`` scripts.
  427. Set via the ``--tag`` option, can be overridden here.
  428. :param template_args: dictionary of template arguments which
  429. will be added to the template argument environment when
  430. running the "revision" command. Note that the script environment
  431. is only run within the "revision" command if the --autogenerate
  432. option is used, or if the option "revision_environment=true"
  433. is present in the alembic.ini file.
  434. :param version_table: The name of the Alembic version table.
  435. The default is ``'alembic_version'``.
  436. :param version_table_schema: Optional schema to place version
  437. table within.
  438. :param version_table_pk: boolean, whether the Alembic version table
  439. should use a primary key constraint for the "value" column; this
  440. only takes effect when the table is first created.
  441. Defaults to True; setting to False should not be necessary and is
  442. here for backwards compatibility reasons.
  443. :param on_version_apply: a callable or collection of callables to be
  444. run for each migration step.
  445. The callables will be run in the order they are given, once for
  446. each migration step, after the respective operation has been
  447. applied but before its transaction is finalized.
  448. Each callable accepts no positional arguments and the following
  449. keyword arguments:
  450. * ``ctx``: the :class:`.MigrationContext` running the migration,
  451. * ``step``: a :class:`.MigrationInfo` representing the
  452. step currently being applied,
  453. * ``heads``: a collection of version strings representing the
  454. current heads,
  455. * ``run_args``: the ``**kwargs`` passed to :meth:`.run_migrations`.
  456. Parameters specific to the autogenerate feature, when
  457. ``alembic revision`` is run with the ``--autogenerate`` feature:
  458. :param target_metadata: a :class:`sqlalchemy.schema.MetaData`
  459. object, or a sequence of :class:`~sqlalchemy.schema.MetaData`
  460. objects, that will be consulted during autogeneration.
  461. The tables present in each :class:`~sqlalchemy.schema.MetaData`
  462. will be compared against
  463. what is locally available on the target
  464. :class:`~sqlalchemy.engine.Connection`
  465. to produce candidate upgrade/downgrade operations.
  466. :param compare_type: Indicates type comparison behavior during
  467. an autogenerate
  468. operation. Defaults to ``True`` turning on type comparison, which
  469. has good accuracy on most backends. See :ref:`compare_types`
  470. for an example as well as information on other type
  471. comparison options. Set to ``False`` which disables type
  472. comparison. A callable can also be passed to provide custom type
  473. comparison, see :ref:`compare_types` for additional details.
  474. .. versionchanged:: 1.12.0 The default value of
  475. :paramref:`.EnvironmentContext.configure.compare_type` has been
  476. changed to ``True``.
  477. .. seealso::
  478. :ref:`compare_types`
  479. :paramref:`.EnvironmentContext.configure.compare_server_default`
  480. :param compare_server_default: Indicates server default comparison
  481. behavior during
  482. an autogenerate operation. Defaults to ``False`` which disables
  483. server default
  484. comparison. Set to ``True`` to turn on server default comparison,
  485. which has
  486. varied accuracy depending on backend.
  487. To customize server default comparison behavior, a callable may
  488. be specified
  489. which can filter server default comparisons during an
  490. autogenerate operation.
  491. defaults during an autogenerate operation. The format of this
  492. callable is::
  493. def my_compare_server_default(context, inspected_column,
  494. metadata_column, inspected_default, metadata_default,
  495. rendered_metadata_default):
  496. # return True if the defaults are different,
  497. # False if not, or None to allow the default implementation
  498. # to compare these defaults
  499. return None
  500. context.configure(
  501. # ...
  502. compare_server_default = my_compare_server_default
  503. )
  504. ``inspected_column`` is a dictionary structure as returned by
  505. :meth:`sqlalchemy.engine.reflection.Inspector.get_columns`, whereas
  506. ``metadata_column`` is a :class:`sqlalchemy.schema.Column` from
  507. the local model environment.
  508. A return value of ``None`` indicates to allow default server default
  509. comparison
  510. to proceed. Note that some backends such as Postgresql actually
  511. execute
  512. the two defaults on the database side to compare for equivalence.
  513. .. seealso::
  514. :paramref:`.EnvironmentContext.configure.compare_type`
  515. :param include_name: A callable function which is given
  516. the chance to return ``True`` or ``False`` for any database reflected
  517. object based on its name, including database schema names when
  518. the :paramref:`.EnvironmentContext.configure.include_schemas` flag
  519. is set to ``True``.
  520. The function accepts the following positional arguments:
  521. * ``name``: the name of the object, such as schema name or table name.
  522. Will be ``None`` when indicating the default schema name of the
  523. database connection.
  524. * ``type``: a string describing the type of object; currently
  525. ``"schema"``, ``"table"``, ``"column"``, ``"index"``,
  526. ``"unique_constraint"``, or ``"foreign_key_constraint"``
  527. * ``parent_names``: a dictionary of "parent" object names, that are
  528. relative to the name being given. Keys in this dictionary may
  529. include: ``"schema_name"``, ``"table_name"`` or
  530. ``"schema_qualified_table_name"``.
  531. E.g.::
  532. def include_name(name, type_, parent_names):
  533. if type_ == "schema":
  534. return name in ["schema_one", "schema_two"]
  535. else:
  536. return True
  537. context.configure(
  538. # ...
  539. include_schemas = True,
  540. include_name = include_name
  541. )
  542. .. seealso::
  543. :ref:`autogenerate_include_hooks`
  544. :paramref:`.EnvironmentContext.configure.include_object`
  545. :paramref:`.EnvironmentContext.configure.include_schemas`
  546. :param include_object: A callable function which is given
  547. the chance to return ``True`` or ``False`` for any object,
  548. indicating if the given object should be considered in the
  549. autogenerate sweep.
  550. The function accepts the following positional arguments:
  551. * ``object``: a :class:`~sqlalchemy.schema.SchemaItem` object such
  552. as a :class:`~sqlalchemy.schema.Table`,
  553. :class:`~sqlalchemy.schema.Column`,
  554. :class:`~sqlalchemy.schema.Index`
  555. :class:`~sqlalchemy.schema.UniqueConstraint`,
  556. or :class:`~sqlalchemy.schema.ForeignKeyConstraint` object
  557. * ``name``: the name of the object. This is typically available
  558. via ``object.name``.
  559. * ``type``: a string describing the type of object; currently
  560. ``"table"``, ``"column"``, ``"index"``, ``"unique_constraint"``,
  561. or ``"foreign_key_constraint"``
  562. * ``reflected``: ``True`` if the given object was produced based on
  563. table reflection, ``False`` if it's from a local :class:`.MetaData`
  564. object.
  565. * ``compare_to``: the object being compared against, if available,
  566. else ``None``.
  567. E.g.::
  568. def include_object(object, name, type_, reflected, compare_to):
  569. if (type_ == "column" and
  570. not reflected and
  571. object.info.get("skip_autogenerate", False)):
  572. return False
  573. else:
  574. return True
  575. context.configure(
  576. # ...
  577. include_object = include_object
  578. )
  579. For the use case of omitting specific schemas from a target database
  580. when :paramref:`.EnvironmentContext.configure.include_schemas` is
  581. set to ``True``, the :attr:`~sqlalchemy.schema.Table.schema`
  582. attribute can be checked for each :class:`~sqlalchemy.schema.Table`
  583. object passed to the hook, however it is much more efficient
  584. to filter on schemas before reflection of objects takes place
  585. using the :paramref:`.EnvironmentContext.configure.include_name`
  586. hook.
  587. .. seealso::
  588. :ref:`autogenerate_include_hooks`
  589. :paramref:`.EnvironmentContext.configure.include_name`
  590. :paramref:`.EnvironmentContext.configure.include_schemas`
  591. :param render_as_batch: if True, commands which alter elements
  592. within a table will be placed under a ``with batch_alter_table():``
  593. directive, so that batch migrations will take place.
  594. .. seealso::
  595. :ref:`batch_migrations`
  596. :param include_schemas: If True, autogenerate will scan across
  597. all schemas located by the SQLAlchemy
  598. :meth:`~sqlalchemy.engine.reflection.Inspector.get_schema_names`
  599. method, and include all differences in tables found across all
  600. those schemas. When using this option, you may want to also
  601. use the :paramref:`.EnvironmentContext.configure.include_name`
  602. parameter to specify a callable which
  603. can filter the tables/schemas that get included.
  604. .. seealso::
  605. :ref:`autogenerate_include_hooks`
  606. :paramref:`.EnvironmentContext.configure.include_name`
  607. :paramref:`.EnvironmentContext.configure.include_object`
  608. :param render_item: Callable that can be used to override how
  609. any schema item, i.e. column, constraint, type,
  610. etc., is rendered for autogenerate. The callable receives a
  611. string describing the type of object, the object, and
  612. the autogen context. If it returns False, the
  613. default rendering method will be used. If it returns None,
  614. the item will not be rendered in the context of a Table
  615. construct, that is, can be used to skip columns or constraints
  616. within op.create_table()::
  617. def my_render_column(type_, col, autogen_context):
  618. if type_ == "column" and isinstance(col, MySpecialCol):
  619. return repr(col)
  620. else:
  621. return False
  622. context.configure(
  623. # ...
  624. render_item = my_render_column
  625. )
  626. Available values for the type string include: ``"column"``,
  627. ``"primary_key"``, ``"foreign_key"``, ``"unique"``, ``"check"``,
  628. ``"type"``, ``"server_default"``.
  629. .. seealso::
  630. :ref:`autogen_render_types`
  631. :param upgrade_token: When autogenerate completes, the text of the
  632. candidate upgrade operations will be present in this template
  633. variable when ``script.py.mako`` is rendered. Defaults to
  634. ``upgrades``.
  635. :param downgrade_token: When autogenerate completes, the text of the
  636. candidate downgrade operations will be present in this
  637. template variable when ``script.py.mako`` is rendered. Defaults to
  638. ``downgrades``.
  639. :param alembic_module_prefix: When autogenerate refers to Alembic
  640. :mod:`alembic.operations` constructs, this prefix will be used
  641. (i.e. ``op.create_table``) Defaults to "``op.``".
  642. Can be ``None`` to indicate no prefix.
  643. :param sqlalchemy_module_prefix: When autogenerate refers to
  644. SQLAlchemy
  645. :class:`~sqlalchemy.schema.Column` or type classes, this prefix
  646. will be used
  647. (i.e. ``sa.Column("somename", sa.Integer)``) Defaults to "``sa.``".
  648. Can be ``None`` to indicate no prefix.
  649. Note that when dialect-specific types are rendered, autogenerate
  650. will render them using the dialect module name, i.e. ``mssql.BIT()``,
  651. ``postgresql.UUID()``.
  652. :param user_module_prefix: When autogenerate refers to a SQLAlchemy
  653. type (e.g. :class:`.TypeEngine`) where the module name is not
  654. under the ``sqlalchemy`` namespace, this prefix will be used
  655. within autogenerate. If left at its default of
  656. ``None``, the ``__module__`` attribute of the type is used to
  657. render the import module. It's a good practice to set this
  658. and to have all custom types be available from a fixed module space,
  659. in order to future-proof migration files against reorganizations
  660. in modules.
  661. .. seealso::
  662. :ref:`autogen_module_prefix`
  663. :param process_revision_directives: a callable function that will
  664. be passed a structure representing the end result of an autogenerate
  665. or plain "revision" operation, which can be manipulated to affect
  666. how the ``alembic revision`` command ultimately outputs new
  667. revision scripts. The structure of the callable is::
  668. def process_revision_directives(context, revision, directives):
  669. pass
  670. The ``directives`` parameter is a Python list containing
  671. a single :class:`.MigrationScript` directive, which represents
  672. the revision file to be generated. This list as well as its
  673. contents may be freely modified to produce any set of commands.
  674. The section :ref:`customizing_revision` shows an example of
  675. doing this. The ``context`` parameter is the
  676. :class:`.MigrationContext` in use,
  677. and ``revision`` is a tuple of revision identifiers representing the
  678. current revision of the database.
  679. The callable is invoked at all times when the ``--autogenerate``
  680. option is passed to ``alembic revision``. If ``--autogenerate``
  681. is not passed, the callable is invoked only if the
  682. ``revision_environment`` variable is set to True in the Alembic
  683. configuration, in which case the given ``directives`` collection
  684. will contain empty :class:`.UpgradeOps` and :class:`.DowngradeOps`
  685. collections for ``.upgrade_ops`` and ``.downgrade_ops``. The
  686. ``--autogenerate`` option itself can be inferred by inspecting
  687. ``context.config.cmd_opts.autogenerate``.
  688. The callable function may optionally be an instance of
  689. a :class:`.Rewriter` object. This is a helper object that
  690. assists in the production of autogenerate-stream rewriter functions.
  691. .. seealso::
  692. :ref:`customizing_revision`
  693. :ref:`autogen_rewriter`
  694. :paramref:`.command.revision.process_revision_directives`
  695. Parameters specific to individual backends:
  696. :param mssql_batch_separator: The "batch separator" which will
  697. be placed between each statement when generating offline SQL Server
  698. migrations. Defaults to ``GO``. Note this is in addition to the
  699. customary semicolon ``;`` at the end of each statement; SQL Server
  700. considers the "batch separator" to denote the end of an
  701. individual statement execution, and cannot group certain
  702. dependent operations in one step.
  703. :param oracle_batch_separator: The "batch separator" which will
  704. be placed between each statement when generating offline
  705. Oracle migrations. Defaults to ``/``. Oracle doesn't add a
  706. semicolon between statements like most other backends.
  707. """
  708. opts = self.context_opts
  709. if transactional_ddl is not None:
  710. opts["transactional_ddl"] = transactional_ddl
  711. if output_buffer is not None:
  712. opts["output_buffer"] = output_buffer
  713. elif self.config.output_buffer is not None:
  714. opts["output_buffer"] = self.config.output_buffer
  715. if starting_rev:
  716. opts["starting_rev"] = starting_rev
  717. if tag:
  718. opts["tag"] = tag
  719. if template_args and "template_args" in opts:
  720. opts["template_args"].update(template_args)
  721. opts["transaction_per_migration"] = transaction_per_migration
  722. opts["target_metadata"] = target_metadata
  723. opts["include_name"] = include_name
  724. opts["include_object"] = include_object
  725. opts["include_schemas"] = include_schemas
  726. opts["render_as_batch"] = render_as_batch
  727. opts["upgrade_token"] = upgrade_token
  728. opts["downgrade_token"] = downgrade_token
  729. opts["sqlalchemy_module_prefix"] = sqlalchemy_module_prefix
  730. opts["alembic_module_prefix"] = alembic_module_prefix
  731. opts["user_module_prefix"] = user_module_prefix
  732. opts["literal_binds"] = literal_binds
  733. opts["process_revision_directives"] = process_revision_directives
  734. opts["on_version_apply"] = util.to_tuple(on_version_apply, default=())
  735. if render_item is not None:
  736. opts["render_item"] = render_item
  737. opts["compare_type"] = compare_type
  738. if compare_server_default is not None:
  739. opts["compare_server_default"] = compare_server_default
  740. opts["script"] = self.script
  741. opts.update(kw)
  742. self._migration_context = MigrationContext.configure(
  743. connection=connection,
  744. url=url,
  745. dialect_name=dialect_name,
  746. environment_context=self,
  747. dialect_opts=dialect_opts,
  748. opts=opts,
  749. )
  750. def run_migrations(self, **kw: Any) -> None:
  751. """Run migrations as determined by the current command line
  752. configuration
  753. as well as versioning information present (or not) in the current
  754. database connection (if one is present).
  755. The function accepts optional ``**kw`` arguments. If these are
  756. passed, they are sent directly to the ``upgrade()`` and
  757. ``downgrade()``
  758. functions within each target revision file. By modifying the
  759. ``script.py.mako`` file so that the ``upgrade()`` and ``downgrade()``
  760. functions accept arguments, parameters can be passed here so that
  761. contextual information, usually information to identify a particular
  762. database in use, can be passed from a custom ``env.py`` script
  763. to the migration functions.
  764. This function requires that a :class:`.MigrationContext` has
  765. first been made available via :meth:`.configure`.
  766. """
  767. assert self._migration_context is not None
  768. with Operations.context(self._migration_context):
  769. self.get_context().run_migrations(**kw)
  770. def execute(
  771. self,
  772. sql: Union[Executable, str],
  773. execution_options: Optional[Dict[str, Any]] = None,
  774. ) -> None:
  775. """Execute the given SQL using the current change context.
  776. The behavior of :meth:`.execute` is the same
  777. as that of :meth:`.Operations.execute`. Please see that
  778. function's documentation for full detail including
  779. caveats and limitations.
  780. This function requires that a :class:`.MigrationContext` has
  781. first been made available via :meth:`.configure`.
  782. """
  783. self.get_context().execute(sql, execution_options=execution_options)
  784. def static_output(self, text: str) -> None:
  785. """Emit text directly to the "offline" SQL stream.
  786. Typically this is for emitting comments that
  787. start with --. The statement is not treated
  788. as a SQL execution, no ; or batch separator
  789. is added, etc.
  790. """
  791. self.get_context().impl.static_output(text)
  792. def begin_transaction(
  793. self,
  794. ) -> Union[_ProxyTransaction, ContextManager[None]]:
  795. """Return a context manager that will
  796. enclose an operation within a "transaction",
  797. as defined by the environment's offline
  798. and transactional DDL settings.
  799. e.g.::
  800. with context.begin_transaction():
  801. context.run_migrations()
  802. :meth:`.begin_transaction` is intended to
  803. "do the right thing" regardless of
  804. calling context:
  805. * If :meth:`.is_transactional_ddl` is ``False``,
  806. returns a "do nothing" context manager
  807. which otherwise produces no transactional
  808. state or directives.
  809. * If :meth:`.is_offline_mode` is ``True``,
  810. returns a context manager that will
  811. invoke the :meth:`.DefaultImpl.emit_begin`
  812. and :meth:`.DefaultImpl.emit_commit`
  813. methods, which will produce the string
  814. directives ``BEGIN`` and ``COMMIT`` on
  815. the output stream, as rendered by the
  816. target backend (e.g. SQL Server would
  817. emit ``BEGIN TRANSACTION``).
  818. * Otherwise, calls :meth:`sqlalchemy.engine.Connection.begin`
  819. on the current online connection, which
  820. returns a :class:`sqlalchemy.engine.Transaction`
  821. object. This object demarcates a real
  822. transaction and is itself a context manager,
  823. which will roll back if an exception
  824. is raised.
  825. Note that a custom ``env.py`` script which
  826. has more specific transactional needs can of course
  827. manipulate the :class:`~sqlalchemy.engine.Connection`
  828. directly to produce transactional state in "online"
  829. mode.
  830. """
  831. return self.get_context().begin_transaction()
  832. def get_context(self) -> MigrationContext:
  833. """Return the current :class:`.MigrationContext` object.
  834. If :meth:`.EnvironmentContext.configure` has not been
  835. called yet, raises an exception.
  836. """
  837. if self._migration_context is None:
  838. raise Exception("No context has been configured yet.")
  839. return self._migration_context
  840. def get_bind(self) -> Connection:
  841. """Return the current 'bind'.
  842. In "online" mode, this is the
  843. :class:`sqlalchemy.engine.Connection` currently being used
  844. to emit SQL to the database.
  845. This function requires that a :class:`.MigrationContext`
  846. has first been made available via :meth:`.configure`.
  847. """
  848. return self.get_context().bind # type: ignore[return-value]
  849. def get_impl(self) -> DefaultImpl:
  850. return self.get_context().impl