environment.py 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. from __future__ import annotations
  2. from typing import Any
  3. from typing import Callable
  4. from typing import Collection
  5. from typing import Dict
  6. from typing import List
  7. from typing import Mapping
  8. from typing import MutableMapping
  9. from typing import Optional
  10. from typing import overload
  11. from typing import Sequence
  12. from typing import TextIO
  13. from typing import Tuple
  14. from typing import TYPE_CHECKING
  15. from typing import Union
  16. from sqlalchemy.sql.schema import Column
  17. from sqlalchemy.sql.schema import FetchedValue
  18. from typing_extensions import ContextManager
  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. @overload
  273. def get_x_argument(
  274. self, as_dictionary: Literal[True]
  275. ) -> Dict[str, str]: ...
  276. @overload
  277. def get_x_argument(
  278. self, as_dictionary: bool = ...
  279. ) -> Union[List[str], Dict[str, str]]: ...
  280. def get_x_argument(
  281. self, as_dictionary: bool = False
  282. ) -> Union[List[str], Dict[str, str]]:
  283. """Return the value(s) passed for the ``-x`` argument, if any.
  284. The ``-x`` argument is an open ended flag that allows any user-defined
  285. value or values to be passed on the command line, then available
  286. here for consumption by a custom ``env.py`` script.
  287. The return value is a list, returned directly from the ``argparse``
  288. structure. If ``as_dictionary=True`` is passed, the ``x`` arguments
  289. are parsed using ``key=value`` format into a dictionary that is
  290. then returned. If there is no ``=`` in the argument, value is an empty
  291. string.
  292. .. versionchanged:: 1.13.1 Support ``as_dictionary=True`` when
  293. arguments are passed without the ``=`` symbol.
  294. For example, to support passing a database URL on the command line,
  295. the standard ``env.py`` script can be modified like this::
  296. cmd_line_url = context.get_x_argument(
  297. as_dictionary=True).get('dbname')
  298. if cmd_line_url:
  299. engine = create_engine(cmd_line_url)
  300. else:
  301. engine = engine_from_config(
  302. config.get_section(config.config_ini_section),
  303. prefix='sqlalchemy.',
  304. poolclass=pool.NullPool)
  305. This then takes effect by running the ``alembic`` script as::
  306. alembic -x dbname=postgresql://user:pass@host/dbname upgrade head
  307. This function does not require that the :class:`.MigrationContext`
  308. has been configured.
  309. .. seealso::
  310. :meth:`.EnvironmentContext.get_tag_argument`
  311. :attr:`.Config.cmd_opts`
  312. """
  313. if self.config.cmd_opts is not None:
  314. value = self.config.cmd_opts.x or []
  315. else:
  316. value = []
  317. if as_dictionary:
  318. dict_value = {}
  319. for arg in value:
  320. x_key, _, x_value = arg.partition("=")
  321. dict_value[x_key] = x_value
  322. value = dict_value
  323. return value
  324. def configure(
  325. self,
  326. connection: Optional[Connection] = None,
  327. url: Optional[Union[str, URL]] = None,
  328. dialect_name: Optional[str] = None,
  329. dialect_opts: Optional[Dict[str, Any]] = None,
  330. transactional_ddl: Optional[bool] = None,
  331. transaction_per_migration: bool = False,
  332. output_buffer: Optional[TextIO] = None,
  333. starting_rev: Optional[str] = None,
  334. tag: Optional[str] = None,
  335. template_args: Optional[Dict[str, Any]] = None,
  336. render_as_batch: bool = False,
  337. target_metadata: Union[MetaData, Sequence[MetaData], None] = None,
  338. include_name: Optional[IncludeNameFn] = None,
  339. include_object: Optional[IncludeObjectFn] = None,
  340. include_schemas: bool = False,
  341. process_revision_directives: Optional[
  342. ProcessRevisionDirectiveFn
  343. ] = None,
  344. compare_type: Union[bool, CompareType] = True,
  345. compare_server_default: Union[bool, CompareServerDefault] = False,
  346. render_item: Optional[RenderItemFn] = None,
  347. literal_binds: bool = False,
  348. upgrade_token: str = "upgrades",
  349. downgrade_token: str = "downgrades",
  350. alembic_module_prefix: str = "op.",
  351. sqlalchemy_module_prefix: str = "sa.",
  352. user_module_prefix: Optional[str] = None,
  353. on_version_apply: Optional[OnVersionApplyFn] = None,
  354. **kw: Any,
  355. ) -> None:
  356. """Configure a :class:`.MigrationContext` within this
  357. :class:`.EnvironmentContext` which will provide database
  358. connectivity and other configuration to a series of
  359. migration scripts.
  360. Many methods on :class:`.EnvironmentContext` require that
  361. this method has been called in order to function, as they
  362. ultimately need to have database access or at least access
  363. to the dialect in use. Those which do are documented as such.
  364. The important thing needed by :meth:`.configure` is a
  365. means to determine what kind of database dialect is in use.
  366. An actual connection to that database is needed only if
  367. the :class:`.MigrationContext` is to be used in
  368. "online" mode.
  369. If the :meth:`.is_offline_mode` function returns ``True``,
  370. then no connection is needed here. Otherwise, the
  371. ``connection`` parameter should be present as an
  372. instance of :class:`sqlalchemy.engine.Connection`.
  373. This function is typically called from the ``env.py``
  374. script within a migration environment. It can be called
  375. multiple times for an invocation. The most recent
  376. :class:`~sqlalchemy.engine.Connection`
  377. for which it was called is the one that will be operated upon
  378. by the next call to :meth:`.run_migrations`.
  379. General parameters:
  380. :param connection: a :class:`~sqlalchemy.engine.Connection`
  381. to use
  382. for SQL execution in "online" mode. When present, is also
  383. used to determine the type of dialect in use.
  384. :param url: a string database url, or a
  385. :class:`sqlalchemy.engine.url.URL` object.
  386. The type of dialect to be used will be derived from this if
  387. ``connection`` is not passed.
  388. :param dialect_name: string name of a dialect, such as
  389. "postgresql", "mssql", etc.
  390. The type of dialect to be used will be derived from this if
  391. ``connection`` and ``url`` are not passed.
  392. :param dialect_opts: dictionary of options to be passed to dialect
  393. constructor.
  394. :param transactional_ddl: Force the usage of "transactional"
  395. DDL on or off;
  396. this otherwise defaults to whether or not the dialect in
  397. use supports it.
  398. :param transaction_per_migration: if True, nest each migration script
  399. in a transaction rather than the full series of migrations to
  400. run.
  401. :param output_buffer: a file-like object that will be used
  402. for textual output
  403. when the ``--sql`` option is used to generate SQL scripts.
  404. Defaults to
  405. ``sys.stdout`` if not passed here and also not present on
  406. the :class:`.Config`
  407. object. The value here overrides that of the :class:`.Config`
  408. object.
  409. :param output_encoding: when using ``--sql`` to generate SQL
  410. scripts, apply this encoding to the string output.
  411. :param literal_binds: when using ``--sql`` to generate SQL
  412. scripts, pass through the ``literal_binds`` flag to the compiler
  413. so that any literal values that would ordinarily be bound
  414. parameters are converted to plain strings.
  415. .. warning:: Dialects can typically only handle simple datatypes
  416. like strings and numbers for auto-literal generation. Datatypes
  417. like dates, intervals, and others may still require manual
  418. formatting, typically using :meth:`.Operations.inline_literal`.
  419. .. note:: the ``literal_binds`` flag is ignored on SQLAlchemy
  420. versions prior to 0.8 where this feature is not supported.
  421. .. seealso::
  422. :meth:`.Operations.inline_literal`
  423. :param starting_rev: Override the "starting revision" argument
  424. when using ``--sql`` mode.
  425. :param tag: a string tag for usage by custom ``env.py`` scripts.
  426. Set via the ``--tag`` option, can be overridden here.
  427. :param template_args: dictionary of template arguments which
  428. will be added to the template argument environment when
  429. running the "revision" command. Note that the script environment
  430. is only run within the "revision" command if the --autogenerate
  431. option is used, or if the option "revision_environment=true"
  432. is present in the alembic.ini file.
  433. :param version_table: The name of the Alembic version table.
  434. The default is ``'alembic_version'``.
  435. :param version_table_schema: Optional schema to place version
  436. table within.
  437. :param version_table_pk: boolean, whether the Alembic version table
  438. should use a primary key constraint for the "value" column; this
  439. only takes effect when the table is first created.
  440. Defaults to True; setting to False should not be necessary and is
  441. here for backwards compatibility reasons.
  442. :param on_version_apply: a callable or collection of callables to be
  443. run for each migration step.
  444. The callables will be run in the order they are given, once for
  445. each migration step, after the respective operation has been
  446. applied but before its transaction is finalized.
  447. Each callable accepts no positional arguments and the following
  448. keyword arguments:
  449. * ``ctx``: the :class:`.MigrationContext` running the migration,
  450. * ``step``: a :class:`.MigrationInfo` representing the
  451. step currently being applied,
  452. * ``heads``: a collection of version strings representing the
  453. current heads,
  454. * ``run_args``: the ``**kwargs`` passed to :meth:`.run_migrations`.
  455. Parameters specific to the autogenerate feature, when
  456. ``alembic revision`` is run with the ``--autogenerate`` feature:
  457. :param target_metadata: a :class:`sqlalchemy.schema.MetaData`
  458. object, or a sequence of :class:`~sqlalchemy.schema.MetaData`
  459. objects, that will be consulted during autogeneration.
  460. The tables present in each :class:`~sqlalchemy.schema.MetaData`
  461. will be compared against
  462. what is locally available on the target
  463. :class:`~sqlalchemy.engine.Connection`
  464. to produce candidate upgrade/downgrade operations.
  465. :param compare_type: Indicates type comparison behavior during
  466. an autogenerate
  467. operation. Defaults to ``True`` turning on type comparison, which
  468. has good accuracy on most backends. See :ref:`compare_types`
  469. for an example as well as information on other type
  470. comparison options. Set to ``False`` which disables type
  471. comparison. A callable can also be passed to provide custom type
  472. comparison, see :ref:`compare_types` for additional details.
  473. .. versionchanged:: 1.12.0 The default value of
  474. :paramref:`.EnvironmentContext.configure.compare_type` has been
  475. changed to ``True``.
  476. .. seealso::
  477. :ref:`compare_types`
  478. :paramref:`.EnvironmentContext.configure.compare_server_default`
  479. :param compare_server_default: Indicates server default comparison
  480. behavior during
  481. an autogenerate operation. Defaults to ``False`` which disables
  482. server default
  483. comparison. Set to ``True`` to turn on server default comparison,
  484. which has
  485. varied accuracy depending on backend.
  486. To customize server default comparison behavior, a callable may
  487. be specified
  488. which can filter server default comparisons during an
  489. autogenerate operation.
  490. defaults during an autogenerate operation. The format of this
  491. callable is::
  492. def my_compare_server_default(context, inspected_column,
  493. metadata_column, inspected_default, metadata_default,
  494. rendered_metadata_default):
  495. # return True if the defaults are different,
  496. # False if not, or None to allow the default implementation
  497. # to compare these defaults
  498. return None
  499. context.configure(
  500. # ...
  501. compare_server_default = my_compare_server_default
  502. )
  503. ``inspected_column`` is a dictionary structure as returned by
  504. :meth:`sqlalchemy.engine.reflection.Inspector.get_columns`, whereas
  505. ``metadata_column`` is a :class:`sqlalchemy.schema.Column` from
  506. the local model environment.
  507. A return value of ``None`` indicates to allow default server default
  508. comparison
  509. to proceed. Note that some backends such as Postgresql actually
  510. execute
  511. the two defaults on the database side to compare for equivalence.
  512. .. seealso::
  513. :paramref:`.EnvironmentContext.configure.compare_type`
  514. :param include_name: A callable function which is given
  515. the chance to return ``True`` or ``False`` for any database reflected
  516. object based on its name, including database schema names when
  517. the :paramref:`.EnvironmentContext.configure.include_schemas` flag
  518. is set to ``True``.
  519. The function accepts the following positional arguments:
  520. * ``name``: the name of the object, such as schema name or table name.
  521. Will be ``None`` when indicating the default schema name of the
  522. database connection.
  523. * ``type``: a string describing the type of object; currently
  524. ``"schema"``, ``"table"``, ``"column"``, ``"index"``,
  525. ``"unique_constraint"``, or ``"foreign_key_constraint"``
  526. * ``parent_names``: a dictionary of "parent" object names, that are
  527. relative to the name being given. Keys in this dictionary may
  528. include: ``"schema_name"``, ``"table_name"`` or
  529. ``"schema_qualified_table_name"``.
  530. E.g.::
  531. def include_name(name, type_, parent_names):
  532. if type_ == "schema":
  533. return name in ["schema_one", "schema_two"]
  534. else:
  535. return True
  536. context.configure(
  537. # ...
  538. include_schemas = True,
  539. include_name = include_name
  540. )
  541. .. seealso::
  542. :ref:`autogenerate_include_hooks`
  543. :paramref:`.EnvironmentContext.configure.include_object`
  544. :paramref:`.EnvironmentContext.configure.include_schemas`
  545. :param include_object: A callable function which is given
  546. the chance to return ``True`` or ``False`` for any object,
  547. indicating if the given object should be considered in the
  548. autogenerate sweep.
  549. The function accepts the following positional arguments:
  550. * ``object``: a :class:`~sqlalchemy.schema.SchemaItem` object such
  551. as a :class:`~sqlalchemy.schema.Table`,
  552. :class:`~sqlalchemy.schema.Column`,
  553. :class:`~sqlalchemy.schema.Index`
  554. :class:`~sqlalchemy.schema.UniqueConstraint`,
  555. or :class:`~sqlalchemy.schema.ForeignKeyConstraint` object
  556. * ``name``: the name of the object. This is typically available
  557. via ``object.name``.
  558. * ``type``: a string describing the type of object; currently
  559. ``"table"``, ``"column"``, ``"index"``, ``"unique_constraint"``,
  560. or ``"foreign_key_constraint"``
  561. * ``reflected``: ``True`` if the given object was produced based on
  562. table reflection, ``False`` if it's from a local :class:`.MetaData`
  563. object.
  564. * ``compare_to``: the object being compared against, if available,
  565. else ``None``.
  566. E.g.::
  567. def include_object(object, name, type_, reflected, compare_to):
  568. if (type_ == "column" and
  569. not reflected and
  570. object.info.get("skip_autogenerate", False)):
  571. return False
  572. else:
  573. return True
  574. context.configure(
  575. # ...
  576. include_object = include_object
  577. )
  578. For the use case of omitting specific schemas from a target database
  579. when :paramref:`.EnvironmentContext.configure.include_schemas` is
  580. set to ``True``, the :attr:`~sqlalchemy.schema.Table.schema`
  581. attribute can be checked for each :class:`~sqlalchemy.schema.Table`
  582. object passed to the hook, however it is much more efficient
  583. to filter on schemas before reflection of objects takes place
  584. using the :paramref:`.EnvironmentContext.configure.include_name`
  585. hook.
  586. .. seealso::
  587. :ref:`autogenerate_include_hooks`
  588. :paramref:`.EnvironmentContext.configure.include_name`
  589. :paramref:`.EnvironmentContext.configure.include_schemas`
  590. :param render_as_batch: if True, commands which alter elements
  591. within a table will be placed under a ``with batch_alter_table():``
  592. directive, so that batch migrations will take place.
  593. .. seealso::
  594. :ref:`batch_migrations`
  595. :param include_schemas: If True, autogenerate will scan across
  596. all schemas located by the SQLAlchemy
  597. :meth:`~sqlalchemy.engine.reflection.Inspector.get_schema_names`
  598. method, and include all differences in tables found across all
  599. those schemas. When using this option, you may want to also
  600. use the :paramref:`.EnvironmentContext.configure.include_name`
  601. parameter to specify a callable which
  602. can filter the tables/schemas that get included.
  603. .. seealso::
  604. :ref:`autogenerate_include_hooks`
  605. :paramref:`.EnvironmentContext.configure.include_name`
  606. :paramref:`.EnvironmentContext.configure.include_object`
  607. :param render_item: Callable that can be used to override how
  608. any schema item, i.e. column, constraint, type,
  609. etc., is rendered for autogenerate. The callable receives a
  610. string describing the type of object, the object, and
  611. the autogen context. If it returns False, the
  612. default rendering method will be used. If it returns None,
  613. the item will not be rendered in the context of a Table
  614. construct, that is, can be used to skip columns or constraints
  615. within op.create_table()::
  616. def my_render_column(type_, col, autogen_context):
  617. if type_ == "column" and isinstance(col, MySpecialCol):
  618. return repr(col)
  619. else:
  620. return False
  621. context.configure(
  622. # ...
  623. render_item = my_render_column
  624. )
  625. Available values for the type string include: ``"column"``,
  626. ``"primary_key"``, ``"foreign_key"``, ``"unique"``, ``"check"``,
  627. ``"type"``, ``"server_default"``.
  628. .. seealso::
  629. :ref:`autogen_render_types`
  630. :param upgrade_token: When autogenerate completes, the text of the
  631. candidate upgrade operations will be present in this template
  632. variable when ``script.py.mako`` is rendered. Defaults to
  633. ``upgrades``.
  634. :param downgrade_token: When autogenerate completes, the text of the
  635. candidate downgrade operations will be present in this
  636. template variable when ``script.py.mako`` is rendered. Defaults to
  637. ``downgrades``.
  638. :param alembic_module_prefix: When autogenerate refers to Alembic
  639. :mod:`alembic.operations` constructs, this prefix will be used
  640. (i.e. ``op.create_table``) Defaults to "``op.``".
  641. Can be ``None`` to indicate no prefix.
  642. :param sqlalchemy_module_prefix: When autogenerate refers to
  643. SQLAlchemy
  644. :class:`~sqlalchemy.schema.Column` or type classes, this prefix
  645. will be used
  646. (i.e. ``sa.Column("somename", sa.Integer)``) Defaults to "``sa.``".
  647. Can be ``None`` to indicate no prefix.
  648. Note that when dialect-specific types are rendered, autogenerate
  649. will render them using the dialect module name, i.e. ``mssql.BIT()``,
  650. ``postgresql.UUID()``.
  651. :param user_module_prefix: When autogenerate refers to a SQLAlchemy
  652. type (e.g. :class:`.TypeEngine`) where the module name is not
  653. under the ``sqlalchemy`` namespace, this prefix will be used
  654. within autogenerate. If left at its default of
  655. ``None``, the ``__module__`` attribute of the type is used to
  656. render the import module. It's a good practice to set this
  657. and to have all custom types be available from a fixed module space,
  658. in order to future-proof migration files against reorganizations
  659. in modules.
  660. .. seealso::
  661. :ref:`autogen_module_prefix`
  662. :param process_revision_directives: a callable function that will
  663. be passed a structure representing the end result of an autogenerate
  664. or plain "revision" operation, which can be manipulated to affect
  665. how the ``alembic revision`` command ultimately outputs new
  666. revision scripts. The structure of the callable is::
  667. def process_revision_directives(context, revision, directives):
  668. pass
  669. The ``directives`` parameter is a Python list containing
  670. a single :class:`.MigrationScript` directive, which represents
  671. the revision file to be generated. This list as well as its
  672. contents may be freely modified to produce any set of commands.
  673. The section :ref:`customizing_revision` shows an example of
  674. doing this. The ``context`` parameter is the
  675. :class:`.MigrationContext` in use,
  676. and ``revision`` is a tuple of revision identifiers representing the
  677. current revision of the database.
  678. The callable is invoked at all times when the ``--autogenerate``
  679. option is passed to ``alembic revision``. If ``--autogenerate``
  680. is not passed, the callable is invoked only if the
  681. ``revision_environment`` variable is set to True in the Alembic
  682. configuration, in which case the given ``directives`` collection
  683. will contain empty :class:`.UpgradeOps` and :class:`.DowngradeOps`
  684. collections for ``.upgrade_ops`` and ``.downgrade_ops``. The
  685. ``--autogenerate`` option itself can be inferred by inspecting
  686. ``context.config.cmd_opts.autogenerate``.
  687. The callable function may optionally be an instance of
  688. a :class:`.Rewriter` object. This is a helper object that
  689. assists in the production of autogenerate-stream rewriter functions.
  690. .. seealso::
  691. :ref:`customizing_revision`
  692. :ref:`autogen_rewriter`
  693. :paramref:`.command.revision.process_revision_directives`
  694. Parameters specific to individual backends:
  695. :param mssql_batch_separator: The "batch separator" which will
  696. be placed between each statement when generating offline SQL Server
  697. migrations. Defaults to ``GO``. Note this is in addition to the
  698. customary semicolon ``;`` at the end of each statement; SQL Server
  699. considers the "batch separator" to denote the end of an
  700. individual statement execution, and cannot group certain
  701. dependent operations in one step.
  702. :param oracle_batch_separator: The "batch separator" which will
  703. be placed between each statement when generating offline
  704. Oracle migrations. Defaults to ``/``. Oracle doesn't add a
  705. semicolon between statements like most other backends.
  706. """
  707. opts = self.context_opts
  708. if transactional_ddl is not None:
  709. opts["transactional_ddl"] = transactional_ddl
  710. if output_buffer is not None:
  711. opts["output_buffer"] = output_buffer
  712. elif self.config.output_buffer is not None:
  713. opts["output_buffer"] = self.config.output_buffer
  714. if starting_rev:
  715. opts["starting_rev"] = starting_rev
  716. if tag:
  717. opts["tag"] = tag
  718. if template_args and "template_args" in opts:
  719. opts["template_args"].update(template_args)
  720. opts["transaction_per_migration"] = transaction_per_migration
  721. opts["target_metadata"] = target_metadata
  722. opts["include_name"] = include_name
  723. opts["include_object"] = include_object
  724. opts["include_schemas"] = include_schemas
  725. opts["render_as_batch"] = render_as_batch
  726. opts["upgrade_token"] = upgrade_token
  727. opts["downgrade_token"] = downgrade_token
  728. opts["sqlalchemy_module_prefix"] = sqlalchemy_module_prefix
  729. opts["alembic_module_prefix"] = alembic_module_prefix
  730. opts["user_module_prefix"] = user_module_prefix
  731. opts["literal_binds"] = literal_binds
  732. opts["process_revision_directives"] = process_revision_directives
  733. opts["on_version_apply"] = util.to_tuple(on_version_apply, default=())
  734. if render_item is not None:
  735. opts["render_item"] = render_item
  736. opts["compare_type"] = compare_type
  737. if compare_server_default is not None:
  738. opts["compare_server_default"] = compare_server_default
  739. opts["script"] = self.script
  740. opts.update(kw)
  741. self._migration_context = MigrationContext.configure(
  742. connection=connection,
  743. url=url,
  744. dialect_name=dialect_name,
  745. environment_context=self,
  746. dialect_opts=dialect_opts,
  747. opts=opts,
  748. )
  749. def run_migrations(self, **kw: Any) -> None:
  750. """Run migrations as determined by the current command line
  751. configuration
  752. as well as versioning information present (or not) in the current
  753. database connection (if one is present).
  754. The function accepts optional ``**kw`` arguments. If these are
  755. passed, they are sent directly to the ``upgrade()`` and
  756. ``downgrade()``
  757. functions within each target revision file. By modifying the
  758. ``script.py.mako`` file so that the ``upgrade()`` and ``downgrade()``
  759. functions accept arguments, parameters can be passed here so that
  760. contextual information, usually information to identify a particular
  761. database in use, can be passed from a custom ``env.py`` script
  762. to the migration functions.
  763. This function requires that a :class:`.MigrationContext` has
  764. first been made available via :meth:`.configure`.
  765. """
  766. assert self._migration_context is not None
  767. with Operations.context(self._migration_context):
  768. self.get_context().run_migrations(**kw)
  769. def execute(
  770. self,
  771. sql: Union[Executable, str],
  772. execution_options: Optional[Dict[str, Any]] = None,
  773. ) -> None:
  774. """Execute the given SQL using the current change context.
  775. The behavior of :meth:`.execute` is the same
  776. as that of :meth:`.Operations.execute`. Please see that
  777. function's documentation for full detail including
  778. caveats and limitations.
  779. This function requires that a :class:`.MigrationContext` has
  780. first been made available via :meth:`.configure`.
  781. """
  782. self.get_context().execute(sql, execution_options=execution_options)
  783. def static_output(self, text: str) -> None:
  784. """Emit text directly to the "offline" SQL stream.
  785. Typically this is for emitting comments that
  786. start with --. The statement is not treated
  787. as a SQL execution, no ; or batch separator
  788. is added, etc.
  789. """
  790. self.get_context().impl.static_output(text)
  791. def begin_transaction(
  792. self,
  793. ) -> Union[_ProxyTransaction, ContextManager[None, Optional[bool]]]:
  794. """Return a context manager that will
  795. enclose an operation within a "transaction",
  796. as defined by the environment's offline
  797. and transactional DDL settings.
  798. e.g.::
  799. with context.begin_transaction():
  800. context.run_migrations()
  801. :meth:`.begin_transaction` is intended to
  802. "do the right thing" regardless of
  803. calling context:
  804. * If :meth:`.is_transactional_ddl` is ``False``,
  805. returns a "do nothing" context manager
  806. which otherwise produces no transactional
  807. state or directives.
  808. * If :meth:`.is_offline_mode` is ``True``,
  809. returns a context manager that will
  810. invoke the :meth:`.DefaultImpl.emit_begin`
  811. and :meth:`.DefaultImpl.emit_commit`
  812. methods, which will produce the string
  813. directives ``BEGIN`` and ``COMMIT`` on
  814. the output stream, as rendered by the
  815. target backend (e.g. SQL Server would
  816. emit ``BEGIN TRANSACTION``).
  817. * Otherwise, calls :meth:`sqlalchemy.engine.Connection.begin`
  818. on the current online connection, which
  819. returns a :class:`sqlalchemy.engine.Transaction`
  820. object. This object demarcates a real
  821. transaction and is itself a context manager,
  822. which will roll back if an exception
  823. is raised.
  824. Note that a custom ``env.py`` script which
  825. has more specific transactional needs can of course
  826. manipulate the :class:`~sqlalchemy.engine.Connection`
  827. directly to produce transactional state in "online"
  828. mode.
  829. """
  830. return self.get_context().begin_transaction()
  831. def get_context(self) -> MigrationContext:
  832. """Return the current :class:`.MigrationContext` object.
  833. If :meth:`.EnvironmentContext.configure` has not been
  834. called yet, raises an exception.
  835. """
  836. if self._migration_context is None:
  837. raise Exception("No context has been configured yet.")
  838. return self._migration_context
  839. def get_bind(self) -> Connection:
  840. """Return the current 'bind'.
  841. In "online" mode, this is the
  842. :class:`sqlalchemy.engine.Connection` currently being used
  843. to emit SQL to the database.
  844. This function requires that a :class:`.MigrationContext`
  845. has first been made available via :meth:`.configure`.
  846. """
  847. return self.get_context().bind # type: ignore[return-value]
  848. def get_impl(self) -> DefaultImpl:
  849. return self.get_context().impl