alembic 1.13.2__tar.gz → 1.13.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. {alembic-1.13.2/alembic.egg-info → alembic-1.13.3}/PKG-INFO +1 -1
  2. {alembic-1.13.2 → alembic-1.13.3}/alembic/__init__.py +1 -1
  3. {alembic-1.13.2 → alembic-1.13.3}/alembic/autogenerate/render.py +11 -0
  4. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/impl.py +4 -4
  5. {alembic-1.13.2 → alembic-1.13.3}/alembic/op.pyi +19 -2
  6. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/base.py +19 -2
  7. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/ops.py +16 -2
  8. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/toimpl.py +14 -2
  9. {alembic-1.13.2 → alembic-1.13.3}/alembic/script/base.py +6 -2
  10. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/async/alembic.ini.mako +1 -0
  11. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/generic/alembic.ini.mako +1 -0
  12. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/multidb/alembic.ini.mako +1 -0
  13. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/assertions.py +13 -4
  14. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/sqla_compat.py +1 -1
  15. {alembic-1.13.2 → alembic-1.13.3/alembic.egg-info}/PKG-INFO +1 -1
  16. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/SOURCES.txt +35 -21
  17. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/changelog.rst +47 -0
  18. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/cookbook.rst +36 -17
  19. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/tutorial.rst +1 -0
  20. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/basic.css +1 -1
  21. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/documentation_options.js +2 -2
  22. alembic-1.13.3/docs/_static/images/logo_colab.png +0 -0
  23. alembic-1.13.3/docs/_static/pygments.css +152 -0
  24. alembic-1.13.3/docs/_static/sbt-webpack-macros.html +11 -0
  25. alembic-1.13.3/docs/_static/scripts/bootstrap.js +3 -0
  26. alembic-1.13.3/docs/_static/scripts/bootstrap.js.LICENSE.txt +5 -0
  27. alembic-1.13.3/docs/_static/scripts/pydata-sphinx-theme.js +2 -0
  28. alembic-1.13.3/docs/_static/scripts/sphinx-book-theme.js +2 -0
  29. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/searchtools.js +4 -3
  30. alembic-1.13.3/docs/_static/styles/bootstrap.css +6 -0
  31. alembic-1.13.3/docs/_static/styles/pydata-sphinx-theme.css +2 -0
  32. alembic-1.13.3/docs/_static/styles/sphinx-book-theme.css +9 -0
  33. alembic-1.13.3/docs/_static/styles/theme.css +2 -0
  34. alembic-1.13.3/docs/_static/vendor/fontawesome/6.5.2/LICENSE.txt +165 -0
  35. alembic-1.13.3/docs/_static/vendor/fontawesome/6.5.2/css/all.min.css +5 -0
  36. alembic-1.13.3/docs/_static/vendor/fontawesome/6.5.2/js/all.min.js +2 -0
  37. alembic-1.13.3/docs/_static/vendor/fontawesome/6.5.2/js/all.min.js.LICENSE.txt +5 -0
  38. alembic-1.13.3/docs/_static/webpack-macros.html +31 -0
  39. {alembic-1.13.2 → alembic-1.13.3}/docs/api/autogenerate.html +528 -140
  40. {alembic-1.13.2 → alembic-1.13.3}/docs/api/commands.html +481 -118
  41. {alembic-1.13.2 → alembic-1.13.3}/docs/api/config.html +486 -120
  42. {alembic-1.13.2 → alembic-1.13.3}/docs/api/ddl.html +922 -396
  43. {alembic-1.13.2 → alembic-1.13.3}/docs/api/index.html +416 -80
  44. {alembic-1.13.2 → alembic-1.13.3}/docs/api/operations.html +668 -216
  45. alembic-1.13.3/docs/api/overview.html +497 -0
  46. {alembic-1.13.2 → alembic-1.13.3}/docs/api/runtime.html +537 -150
  47. {alembic-1.13.2 → alembic-1.13.3}/docs/api/script.html +589 -182
  48. {alembic-1.13.2 → alembic-1.13.3}/docs/autogenerate.html +489 -116
  49. {alembic-1.13.2 → alembic-1.13.3}/docs/batch.html +465 -104
  50. {alembic-1.13.2 → alembic-1.13.3}/docs/branches.html +473 -108
  51. {alembic-1.13.2 → alembic-1.13.3}/docs/build/Makefile +1 -1
  52. alembic-1.13.2/docs/_sources/changelog.rst.txt → alembic-1.13.3/docs/build/changelog.rst +47 -0
  53. {alembic-1.13.2 → alembic-1.13.3}/docs/build/conf.py +30 -9
  54. alembic-1.13.2/docs/_sources/cookbook.rst.txt → alembic-1.13.3/docs/build/cookbook.rst +36 -17
  55. {alembic-1.13.2 → alembic-1.13.3}/docs/build/requirements.txt +3 -0
  56. alembic-1.13.2/docs/_sources/tutorial.rst.txt → alembic-1.13.3/docs/build/tutorial.rst +1 -0
  57. {alembic-1.13.2 → alembic-1.13.3}/docs/changelog.html +1687 -720
  58. {alembic-1.13.2 → alembic-1.13.3}/docs/cookbook.html +548 -151
  59. alembic-1.13.3/docs/front.html +583 -0
  60. {alembic-1.13.2 → alembic-1.13.3}/docs/genindex.html +367 -63
  61. {alembic-1.13.2 → alembic-1.13.3}/docs/index.html +439 -79
  62. {alembic-1.13.2 → alembic-1.13.3}/docs/naming.html +442 -90
  63. {alembic-1.13.2 → alembic-1.13.3}/docs/offline.html +445 -92
  64. {alembic-1.13.2 → alembic-1.13.3}/docs/ops.html +586 -174
  65. alembic-1.13.3/docs/py-modindex.html +475 -0
  66. alembic-1.13.3/docs/search.html +392 -0
  67. alembic-1.13.3/docs/searchindex.js +1 -0
  68. {alembic-1.13.2 → alembic-1.13.3}/docs/tutorial.html +475 -110
  69. {alembic-1.13.2 → alembic-1.13.3}/pyproject.toml +11 -3
  70. {alembic-1.13.2 → alembic-1.13.3}/setup.cfg +0 -8
  71. {alembic-1.13.2 → alembic-1.13.3}/tests/test_autogen_render.py +62 -0
  72. {alembic-1.13.2 → alembic-1.13.3}/tests/test_config.py +9 -2
  73. {alembic-1.13.2 → alembic-1.13.3}/tests/test_op.py +20 -0
  74. {alembic-1.13.2 → alembic-1.13.3}/tox.ini +0 -1
  75. alembic-1.13.2/docs/_static/nature.css +0 -252
  76. alembic-1.13.2/docs/_static/pygments.css +0 -75
  77. alembic-1.13.2/docs/api/overview.html +0 -163
  78. alembic-1.13.2/docs/front.html +0 -225
  79. alembic-1.13.2/docs/py-modindex.html +0 -181
  80. alembic-1.13.2/docs/search.html +0 -103
  81. alembic-1.13.2/docs/searchindex.js +0 -1
  82. {alembic-1.13.2 → alembic-1.13.3}/CHANGES +0 -0
  83. {alembic-1.13.2 → alembic-1.13.3}/LICENSE +0 -0
  84. {alembic-1.13.2 → alembic-1.13.3}/MANIFEST.in +0 -0
  85. {alembic-1.13.2 → alembic-1.13.3}/README.rst +0 -0
  86. {alembic-1.13.2 → alembic-1.13.3}/README.unittests.rst +0 -0
  87. {alembic-1.13.2 → alembic-1.13.3}/alembic/__main__.py +0 -0
  88. {alembic-1.13.2 → alembic-1.13.3}/alembic/autogenerate/__init__.py +0 -0
  89. {alembic-1.13.2 → alembic-1.13.3}/alembic/autogenerate/api.py +0 -0
  90. {alembic-1.13.2 → alembic-1.13.3}/alembic/autogenerate/compare.py +0 -0
  91. {alembic-1.13.2 → alembic-1.13.3}/alembic/autogenerate/rewriter.py +0 -0
  92. {alembic-1.13.2 → alembic-1.13.3}/alembic/command.py +0 -0
  93. {alembic-1.13.2 → alembic-1.13.3}/alembic/config.py +0 -0
  94. {alembic-1.13.2 → alembic-1.13.3}/alembic/context.py +0 -0
  95. {alembic-1.13.2 → alembic-1.13.3}/alembic/context.pyi +0 -0
  96. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/__init__.py +0 -0
  97. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/_autogen.py +0 -0
  98. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/base.py +0 -0
  99. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/mssql.py +0 -0
  100. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/mysql.py +0 -0
  101. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/oracle.py +0 -0
  102. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/postgresql.py +0 -0
  103. {alembic-1.13.2 → alembic-1.13.3}/alembic/ddl/sqlite.py +0 -0
  104. {alembic-1.13.2 → alembic-1.13.3}/alembic/environment.py +0 -0
  105. {alembic-1.13.2 → alembic-1.13.3}/alembic/migration.py +0 -0
  106. {alembic-1.13.2 → alembic-1.13.3}/alembic/op.py +0 -0
  107. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/__init__.py +0 -0
  108. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/batch.py +0 -0
  109. {alembic-1.13.2 → alembic-1.13.3}/alembic/operations/schemaobj.py +0 -0
  110. {alembic-1.13.2 → alembic-1.13.3}/alembic/py.typed +0 -0
  111. {alembic-1.13.2 → alembic-1.13.3}/alembic/runtime/__init__.py +0 -0
  112. {alembic-1.13.2 → alembic-1.13.3}/alembic/runtime/environment.py +0 -0
  113. {alembic-1.13.2 → alembic-1.13.3}/alembic/runtime/migration.py +0 -0
  114. {alembic-1.13.2 → alembic-1.13.3}/alembic/script/__init__.py +0 -0
  115. {alembic-1.13.2 → alembic-1.13.3}/alembic/script/revision.py +0 -0
  116. {alembic-1.13.2 → alembic-1.13.3}/alembic/script/write_hooks.py +0 -0
  117. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/async/README +0 -0
  118. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/async/env.py +0 -0
  119. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/async/script.py.mako +0 -0
  120. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/generic/README +0 -0
  121. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/generic/env.py +0 -0
  122. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/generic/script.py.mako +0 -0
  123. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/multidb/README +0 -0
  124. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/multidb/env.py +0 -0
  125. {alembic-1.13.2 → alembic-1.13.3}/alembic/templates/multidb/script.py.mako +0 -0
  126. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/__init__.py +0 -0
  127. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/env.py +0 -0
  128. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/fixtures.py +0 -0
  129. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/plugin/__init__.py +0 -0
  130. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/plugin/bootstrap.py +0 -0
  131. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/requirements.py +0 -0
  132. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/schemacompare.py +0 -0
  133. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/__init__.py +0 -0
  134. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/_autogen_fixtures.py +0 -0
  135. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_autogen_comments.py +0 -0
  136. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_autogen_computed.py +0 -0
  137. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_autogen_diffs.py +0 -0
  138. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_autogen_fks.py +0 -0
  139. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_autogen_identity.py +0 -0
  140. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_environment.py +0 -0
  141. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/suite/test_op.py +0 -0
  142. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/util.py +0 -0
  143. {alembic-1.13.2 → alembic-1.13.3}/alembic/testing/warnings.py +0 -0
  144. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/__init__.py +0 -0
  145. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/compat.py +0 -0
  146. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/editor.py +0 -0
  147. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/exc.py +0 -0
  148. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/langhelpers.py +0 -0
  149. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/messaging.py +0 -0
  150. {alembic-1.13.2 → alembic-1.13.3}/alembic/util/pyfiles.py +0 -0
  151. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/dependency_links.txt +0 -0
  152. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/entry_points.txt +0 -0
  153. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/not-zip-safe +0 -0
  154. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/requires.txt +0 -0
  155. {alembic-1.13.2 → alembic-1.13.3}/alembic.egg-info/top_level.txt +0 -0
  156. {alembic-1.13.2 → alembic-1.13.3}/docs/_images/api_overview.png +0 -0
  157. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/autogenerate.rst +0 -0
  158. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/commands.rst +0 -0
  159. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/config.rst +0 -0
  160. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/ddl.rst +0 -0
  161. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/index.rst +0 -0
  162. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/operations.rst +0 -0
  163. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/overview.rst +0 -0
  164. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/runtime.rst +0 -0
  165. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/api/script.rst +0 -0
  166. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/autogenerate.rst +0 -0
  167. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/batch.rst +0 -0
  168. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/branches.rst +0 -0
  169. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/front.rst +0 -0
  170. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/index.rst +0 -0
  171. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/naming.rst +0 -0
  172. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/offline.rst +0 -0
  173. {alembic-1.13.2/docs/build → alembic-1.13.3/docs/_sources}/ops.rst +0 -0
  174. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/changelog.css +0 -0
  175. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/clipboard.min.js +0 -0
  176. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/copybutton.css +0 -0
  177. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/copybutton.js +0 -0
  178. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/copybutton_funcs.js +0 -0
  179. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/doctools.js +0 -0
  180. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/file.png +0 -0
  181. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/language_data.js +0 -0
  182. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/minus.png +0 -0
  183. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/nature_override.css +0 -0
  184. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/plus.png +0 -0
  185. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/site_custom_css.css +0 -0
  186. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/sphinx_highlight.js +0 -0
  187. {alembic-1.13.2 → alembic-1.13.3}/docs/_static/sphinx_paramlinks.css +0 -0
  188. {alembic-1.13.2 → alembic-1.13.3}/docs/build/_static/nature_override.css +0 -0
  189. {alembic-1.13.2 → alembic-1.13.3}/docs/build/_static/site_custom_css.css +0 -0
  190. {alembic-1.13.2 → alembic-1.13.3}/docs/build/_templates/site_custom_sidebars.html +0 -0
  191. {alembic-1.13.2 → alembic-1.13.3}/docs/build/api/api_overview.png +0 -0
  192. /alembic-1.13.2/docs/_sources/api/autogenerate.rst.txt → /alembic-1.13.3/docs/build/api/autogenerate.rst +0 -0
  193. /alembic-1.13.2/docs/_sources/api/commands.rst.txt → /alembic-1.13.3/docs/build/api/commands.rst +0 -0
  194. /alembic-1.13.2/docs/_sources/api/config.rst.txt → /alembic-1.13.3/docs/build/api/config.rst +0 -0
  195. /alembic-1.13.2/docs/_sources/api/ddl.rst.txt → /alembic-1.13.3/docs/build/api/ddl.rst +0 -0
  196. /alembic-1.13.2/docs/_sources/api/index.rst.txt → /alembic-1.13.3/docs/build/api/index.rst +0 -0
  197. /alembic-1.13.2/docs/_sources/api/operations.rst.txt → /alembic-1.13.3/docs/build/api/operations.rst +0 -0
  198. /alembic-1.13.2/docs/_sources/api/overview.rst.txt → /alembic-1.13.3/docs/build/api/overview.rst +0 -0
  199. /alembic-1.13.2/docs/_sources/api/runtime.rst.txt → /alembic-1.13.3/docs/build/api/runtime.rst +0 -0
  200. /alembic-1.13.2/docs/_sources/api/script.rst.txt → /alembic-1.13.3/docs/build/api/script.rst +0 -0
  201. /alembic-1.13.2/docs/_sources/autogenerate.rst.txt → /alembic-1.13.3/docs/build/autogenerate.rst +0 -0
  202. /alembic-1.13.2/docs/_sources/batch.rst.txt → /alembic-1.13.3/docs/build/batch.rst +0 -0
  203. /alembic-1.13.2/docs/_sources/branches.rst.txt → /alembic-1.13.3/docs/build/branches.rst +0 -0
  204. /alembic-1.13.2/docs/_sources/front.rst.txt → /alembic-1.13.3/docs/build/front.rst +0 -0
  205. /alembic-1.13.2/docs/_sources/index.rst.txt → /alembic-1.13.3/docs/build/index.rst +0 -0
  206. /alembic-1.13.2/docs/_sources/naming.rst.txt → /alembic-1.13.3/docs/build/naming.rst +0 -0
  207. /alembic-1.13.2/docs/_sources/offline.rst.txt → /alembic-1.13.3/docs/build/offline.rst +0 -0
  208. /alembic-1.13.2/docs/_sources/ops.rst.txt → /alembic-1.13.3/docs/build/ops.rst +0 -0
  209. {alembic-1.13.2 → alembic-1.13.3}/docs/build/unreleased/README.txt +0 -0
  210. {alembic-1.13.2 → alembic-1.13.3}/setup.py +0 -0
  211. {alembic-1.13.2 → alembic-1.13.3}/tests/__init__.py +0 -0
  212. {alembic-1.13.2 → alembic-1.13.3}/tests/_large_map.py +0 -0
  213. {alembic-1.13.2 → alembic-1.13.3}/tests/conftest.py +0 -0
  214. {alembic-1.13.2 → alembic-1.13.3}/tests/requirements.py +0 -0
  215. {alembic-1.13.2 → alembic-1.13.3}/tests/test_autogen_composition.py +0 -0
  216. {alembic-1.13.2 → alembic-1.13.3}/tests/test_autogen_diffs.py +0 -0
  217. {alembic-1.13.2 → alembic-1.13.3}/tests/test_autogen_indexes.py +0 -0
  218. {alembic-1.13.2 → alembic-1.13.3}/tests/test_batch.py +0 -0
  219. {alembic-1.13.2 → alembic-1.13.3}/tests/test_bulk_insert.py +0 -0
  220. {alembic-1.13.2 → alembic-1.13.3}/tests/test_command.py +0 -0
  221. {alembic-1.13.2 → alembic-1.13.3}/tests/test_editor.py +0 -0
  222. {alembic-1.13.2 → alembic-1.13.3}/tests/test_environment.py +0 -0
  223. {alembic-1.13.2 → alembic-1.13.3}/tests/test_external_dialect.py +0 -0
  224. {alembic-1.13.2 → alembic-1.13.3}/tests/test_impl.py +0 -0
  225. {alembic-1.13.2 → alembic-1.13.3}/tests/test_messaging.py +0 -0
  226. {alembic-1.13.2 → alembic-1.13.3}/tests/test_mssql.py +0 -0
  227. {alembic-1.13.2 → alembic-1.13.3}/tests/test_mysql.py +0 -0
  228. {alembic-1.13.2 → alembic-1.13.3}/tests/test_offline_environment.py +0 -0
  229. {alembic-1.13.2 → alembic-1.13.3}/tests/test_op_naming_convention.py +0 -0
  230. {alembic-1.13.2 → alembic-1.13.3}/tests/test_oracle.py +0 -0
  231. {alembic-1.13.2 → alembic-1.13.3}/tests/test_post_write.py +0 -0
  232. {alembic-1.13.2 → alembic-1.13.3}/tests/test_postgresql.py +0 -0
  233. {alembic-1.13.2 → alembic-1.13.3}/tests/test_revision.py +0 -0
  234. {alembic-1.13.2 → alembic-1.13.3}/tests/test_script_consumption.py +0 -0
  235. {alembic-1.13.2 → alembic-1.13.3}/tests/test_script_production.py +0 -0
  236. {alembic-1.13.2 → alembic-1.13.3}/tests/test_sqlite.py +0 -0
  237. {alembic-1.13.2 → alembic-1.13.3}/tests/test_stubs.py +0 -0
  238. {alembic-1.13.2 → alembic-1.13.3}/tests/test_suite.py +0 -0
  239. {alembic-1.13.2 → alembic-1.13.3}/tests/test_version_table.py +0 -0
  240. {alembic-1.13.2 → alembic-1.13.3}/tests/test_version_traversal.py +0 -0
  241. {alembic-1.13.2 → alembic-1.13.3}/tools/write_pyi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: alembic
3
- Version: 1.13.2
3
+ Version: 1.13.3
4
4
  Summary: A database migration tool for SQLAlchemy.
5
5
  Home-page: https://alembic.sqlalchemy.org
6
6
  Author: Mike Bayer
@@ -1,4 +1,4 @@
1
1
  from . import context
2
2
  from . import op
3
3
 
4
- __version__ = "1.13.2"
4
+ __version__ = "1.13.3"
@@ -279,6 +279,9 @@ def _add_table(autogen_context: AutogenContext, op: ops.CreateTableOp) -> str:
279
279
  prefixes = ", ".join("'%s'" % p for p in table._prefixes)
280
280
  text += ",\nprefixes=[%s]" % prefixes
281
281
 
282
+ if op.if_not_exists is not None:
283
+ text += ",\nif_not_exists=%r" % bool(op.if_not_exists)
284
+
282
285
  text += "\n)"
283
286
  return text
284
287
 
@@ -291,6 +294,10 @@ def _drop_table(autogen_context: AutogenContext, op: ops.DropTableOp) -> str:
291
294
  }
292
295
  if op.schema:
293
296
  text += ", schema=%r" % _ident(op.schema)
297
+
298
+ if op.if_exists is not None:
299
+ text += ", if_exists=%r" % bool(op.if_exists)
300
+
294
301
  text += ")"
295
302
  return text
296
303
 
@@ -324,6 +331,8 @@ def _add_index(autogen_context: AutogenContext, op: ops.CreateIndexOp) -> str:
324
331
  assert index.table is not None
325
332
 
326
333
  opts = _render_dialect_kwargs_items(autogen_context, index)
334
+ if op.if_not_exists is not None:
335
+ opts.append("if_not_exists=%r" % bool(op.if_not_exists))
327
336
  text = tmpl % {
328
337
  "prefix": _alembic_autogenerate_prefix(autogen_context),
329
338
  "name": _render_gen_name(autogen_context, index.name),
@@ -356,6 +365,8 @@ def _drop_index(autogen_context: AutogenContext, op: ops.DropIndexOp) -> str:
356
365
  "table_name=%(table_name)r%(schema)s%(kwargs)s)"
357
366
  )
358
367
  opts = _render_dialect_kwargs_items(autogen_context, index)
368
+ if op.if_exists is not None:
369
+ opts.append("if_exists=%r" % bool(op.if_exists))
359
370
  text = tmpl % {
360
371
  "prefix": _alembic_autogenerate_prefix(autogen_context),
361
372
  "name": _render_gen_name(autogen_context, op.index_name),
@@ -362,11 +362,11 @@ class DefaultImpl(metaclass=ImplMeta):
362
362
  base.RenameTable(old_table_name, new_table_name, schema=schema)
363
363
  )
364
364
 
365
- def create_table(self, table: Table) -> None:
365
+ def create_table(self, table: Table, **kw: Any) -> None:
366
366
  table.dispatch.before_create(
367
367
  table, self.connection, checkfirst=False, _ddl_runner=self
368
368
  )
369
- self._exec(schema.CreateTable(table))
369
+ self._exec(schema.CreateTable(table, **kw))
370
370
  table.dispatch.after_create(
371
371
  table, self.connection, checkfirst=False, _ddl_runner=self
372
372
  )
@@ -385,11 +385,11 @@ class DefaultImpl(metaclass=ImplMeta):
385
385
  if comment and with_comment:
386
386
  self.create_column_comment(column)
387
387
 
388
- def drop_table(self, table: Table) -> None:
388
+ def drop_table(self, table: Table, **kw: Any) -> None:
389
389
  table.dispatch.before_drop(
390
390
  table, self.connection, checkfirst=False, _ddl_runner=self
391
391
  )
392
- self._exec(schema.DropTable(table))
392
+ self._exec(schema.DropTable(table, **kw))
393
393
  table.dispatch.after_drop(
394
394
  table, self.connection, checkfirst=False, _ddl_runner=self
395
395
  )
@@ -747,7 +747,12 @@ def create_primary_key(
747
747
 
748
748
  """
749
749
 
750
- def create_table(table_name: str, *columns: SchemaItem, **kw: Any) -> Table:
750
+ def create_table(
751
+ table_name: str,
752
+ *columns: SchemaItem,
753
+ if_not_exists: Optional[bool] = None,
754
+ **kw: Any,
755
+ ) -> Table:
751
756
  r"""Issue a "create table" instruction using the current migration
752
757
  context.
753
758
 
@@ -818,6 +823,10 @@ def create_table(table_name: str, *columns: SchemaItem, **kw: Any) -> Table:
818
823
  quoting of the schema outside of the default behavior, use
819
824
  the SQLAlchemy construct
820
825
  :class:`~sqlalchemy.sql.elements.quoted_name`.
826
+ :param if_not_exists: If True, adds IF NOT EXISTS operator when
827
+ creating the new table.
828
+
829
+ .. versionadded:: 1.13.3
821
830
  :param \**kw: Other keyword arguments are passed to the underlying
822
831
  :class:`sqlalchemy.schema.Table` object created for the command.
823
832
 
@@ -998,7 +1007,11 @@ def drop_index(
998
1007
  """
999
1008
 
1000
1009
  def drop_table(
1001
- table_name: str, *, schema: Optional[str] = None, **kw: Any
1010
+ table_name: str,
1011
+ *,
1012
+ schema: Optional[str] = None,
1013
+ if_exists: Optional[bool] = None,
1014
+ **kw: Any,
1002
1015
  ) -> None:
1003
1016
  r"""Issue a "drop table" instruction using the current
1004
1017
  migration context.
@@ -1013,6 +1026,10 @@ def drop_table(
1013
1026
  quoting of the schema outside of the default behavior, use
1014
1027
  the SQLAlchemy construct
1015
1028
  :class:`~sqlalchemy.sql.elements.quoted_name`.
1029
+ :param if_exists: If True, adds IF EXISTS operator when
1030
+ dropping the table.
1031
+
1032
+ .. versionadded:: 1.13.3
1016
1033
  :param \**kw: Other keyword arguments are passed to the underlying
1017
1034
  :class:`sqlalchemy.schema.Table` object created for the command.
1018
1035
 
@@ -1175,7 +1175,11 @@ class Operations(AbstractOperations):
1175
1175
  ...
1176
1176
 
1177
1177
  def create_table(
1178
- self, table_name: str, *columns: SchemaItem, **kw: Any
1178
+ self,
1179
+ table_name: str,
1180
+ *columns: SchemaItem,
1181
+ if_not_exists: Optional[bool] = None,
1182
+ **kw: Any,
1179
1183
  ) -> Table:
1180
1184
  r"""Issue a "create table" instruction using the current migration
1181
1185
  context.
@@ -1247,6 +1251,10 @@ class Operations(AbstractOperations):
1247
1251
  quoting of the schema outside of the default behavior, use
1248
1252
  the SQLAlchemy construct
1249
1253
  :class:`~sqlalchemy.sql.elements.quoted_name`.
1254
+ :param if_not_exists: If True, adds IF NOT EXISTS operator when
1255
+ creating the new table.
1256
+
1257
+ .. versionadded:: 1.13.3
1250
1258
  :param \**kw: Other keyword arguments are passed to the underlying
1251
1259
  :class:`sqlalchemy.schema.Table` object created for the command.
1252
1260
 
@@ -1438,7 +1446,12 @@ class Operations(AbstractOperations):
1438
1446
  ...
1439
1447
 
1440
1448
  def drop_table(
1441
- self, table_name: str, *, schema: Optional[str] = None, **kw: Any
1449
+ self,
1450
+ table_name: str,
1451
+ *,
1452
+ schema: Optional[str] = None,
1453
+ if_exists: Optional[bool] = None,
1454
+ **kw: Any,
1442
1455
  ) -> None:
1443
1456
  r"""Issue a "drop table" instruction using the current
1444
1457
  migration context.
@@ -1453,6 +1466,10 @@ class Operations(AbstractOperations):
1453
1466
  quoting of the schema outside of the default behavior, use
1454
1467
  the SQLAlchemy construct
1455
1468
  :class:`~sqlalchemy.sql.elements.quoted_name`.
1469
+ :param if_exists: If True, adds IF EXISTS operator when
1470
+ dropping the table.
1471
+
1472
+ .. versionadded:: 1.13.3
1456
1473
  :param \**kw: Other keyword arguments are passed to the underlying
1457
1474
  :class:`sqlalchemy.schema.Table` object created for the command.
1458
1475
 
@@ -1159,6 +1159,7 @@ class CreateTableOp(MigrateOperation):
1159
1159
  columns: Sequence[SchemaItem],
1160
1160
  *,
1161
1161
  schema: Optional[str] = None,
1162
+ if_not_exists: Optional[bool] = None,
1162
1163
  _namespace_metadata: Optional[MetaData] = None,
1163
1164
  _constraints_included: bool = False,
1164
1165
  **kw: Any,
@@ -1166,6 +1167,7 @@ class CreateTableOp(MigrateOperation):
1166
1167
  self.table_name = table_name
1167
1168
  self.columns = columns
1168
1169
  self.schema = schema
1170
+ self.if_not_exists = if_not_exists
1169
1171
  self.info = kw.pop("info", {})
1170
1172
  self.comment = kw.pop("comment", None)
1171
1173
  self.prefixes = kw.pop("prefixes", None)
@@ -1228,6 +1230,7 @@ class CreateTableOp(MigrateOperation):
1228
1230
  operations: Operations,
1229
1231
  table_name: str,
1230
1232
  *columns: SchemaItem,
1233
+ if_not_exists: Optional[bool] = None,
1231
1234
  **kw: Any,
1232
1235
  ) -> Table:
1233
1236
  r"""Issue a "create table" instruction using the current migration
@@ -1300,6 +1303,10 @@ class CreateTableOp(MigrateOperation):
1300
1303
  quoting of the schema outside of the default behavior, use
1301
1304
  the SQLAlchemy construct
1302
1305
  :class:`~sqlalchemy.sql.elements.quoted_name`.
1306
+ :param if_not_exists: If True, adds IF NOT EXISTS operator when
1307
+ creating the new table.
1308
+
1309
+ .. versionadded:: 1.13.3
1303
1310
  :param \**kw: Other keyword arguments are passed to the underlying
1304
1311
  :class:`sqlalchemy.schema.Table` object created for the command.
1305
1312
 
@@ -1307,7 +1314,7 @@ class CreateTableOp(MigrateOperation):
1307
1314
  to the parameters given.
1308
1315
 
1309
1316
  """
1310
- op = cls(table_name, columns, **kw)
1317
+ op = cls(table_name, columns, if_not_exists=if_not_exists, **kw)
1311
1318
  return operations.invoke(op)
1312
1319
 
1313
1320
 
@@ -1320,11 +1327,13 @@ class DropTableOp(MigrateOperation):
1320
1327
  table_name: str,
1321
1328
  *,
1322
1329
  schema: Optional[str] = None,
1330
+ if_exists: Optional[bool] = None,
1323
1331
  table_kw: Optional[MutableMapping[Any, Any]] = None,
1324
1332
  _reverse: Optional[CreateTableOp] = None,
1325
1333
  ) -> None:
1326
1334
  self.table_name = table_name
1327
1335
  self.schema = schema
1336
+ self.if_exists = if_exists
1328
1337
  self.table_kw = table_kw or {}
1329
1338
  self.comment = self.table_kw.pop("comment", None)
1330
1339
  self.info = self.table_kw.pop("info", None)
@@ -1385,6 +1394,7 @@ class DropTableOp(MigrateOperation):
1385
1394
  table_name: str,
1386
1395
  *,
1387
1396
  schema: Optional[str] = None,
1397
+ if_exists: Optional[bool] = None,
1388
1398
  **kw: Any,
1389
1399
  ) -> None:
1390
1400
  r"""Issue a "drop table" instruction using the current
@@ -1400,11 +1410,15 @@ class DropTableOp(MigrateOperation):
1400
1410
  quoting of the schema outside of the default behavior, use
1401
1411
  the SQLAlchemy construct
1402
1412
  :class:`~sqlalchemy.sql.elements.quoted_name`.
1413
+ :param if_exists: If True, adds IF EXISTS operator when
1414
+ dropping the table.
1415
+
1416
+ .. versionadded:: 1.13.3
1403
1417
  :param \**kw: Other keyword arguments are passed to the underlying
1404
1418
  :class:`sqlalchemy.schema.Table` object created for the command.
1405
1419
 
1406
1420
  """
1407
- op = cls(table_name, schema=schema, table_kw=kw)
1421
+ op = cls(table_name, schema=schema, if_exists=if_exists, table_kw=kw)
1408
1422
  operations.invoke(op)
1409
1423
 
1410
1424
 
@@ -79,8 +79,14 @@ def alter_column(
79
79
 
80
80
  @Operations.implementation_for(ops.DropTableOp)
81
81
  def drop_table(operations: "Operations", operation: "ops.DropTableOp") -> None:
82
+ kw = {}
83
+ if operation.if_exists is not None:
84
+ if not sqla_14:
85
+ raise NotImplementedError("SQLAlchemy 1.4+ required")
86
+
87
+ kw["if_exists"] = operation.if_exists
82
88
  operations.impl.drop_table(
83
- operation.to_table(operations.migration_context)
89
+ operation.to_table(operations.migration_context), **kw
84
90
  )
85
91
 
86
92
 
@@ -127,8 +133,14 @@ def drop_index(operations: "Operations", operation: "ops.DropIndexOp") -> None:
127
133
  def create_table(
128
134
  operations: "Operations", operation: "ops.CreateTableOp"
129
135
  ) -> "Table":
136
+ kw = {}
137
+ if operation.if_not_exists is not None:
138
+ if not sqla_14:
139
+ raise NotImplementedError("SQLAlchemy 1.4+ required")
140
+
141
+ kw["if_not_exists"] = operation.if_not_exists
130
142
  table = operation.to_table(operations.migration_context)
131
- operations.impl.create_table(table)
143
+ operations.impl.create_table(table, **kw)
132
144
  return table
133
145
 
134
146
 
@@ -187,6 +187,7 @@ class ScriptDirectory:
187
187
  split_on_path = {
188
188
  None: None,
189
189
  "space": " ",
190
+ "newline": "\n",
190
191
  "os": os.pathsep,
191
192
  ":": ":",
192
193
  ";": ";",
@@ -200,7 +201,8 @@ class ScriptDirectory:
200
201
  raise ValueError(
201
202
  "'%s' is not a valid value for "
202
203
  "version_path_separator; "
203
- "expected 'space', 'os', ':', ';'" % version_path_separator
204
+ "expected 'space', 'newline', 'os', ':', ';'"
205
+ % version_path_separator
204
206
  ) from ke
205
207
  else:
206
208
  if split_char is None:
@@ -210,7 +212,9 @@ class ScriptDirectory:
210
212
  )
211
213
  else:
212
214
  version_locations = [
213
- x for x in version_locations_str.split(split_char) if x
215
+ x.strip()
216
+ for x in version_locations_str.split(split_char)
217
+ if x
214
218
  ]
215
219
  else:
216
220
  version_locations = None
@@ -47,6 +47,7 @@ prepend_sys_path = .
47
47
  # version_path_separator = :
48
48
  # version_path_separator = ;
49
49
  # version_path_separator = space
50
+ # version_path_separator = newline
50
51
  version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
51
52
 
52
53
  # set to 'true' to search source files recursively
@@ -49,6 +49,7 @@ prepend_sys_path = .
49
49
  # version_path_separator = :
50
50
  # version_path_separator = ;
51
51
  # version_path_separator = space
52
+ # version_path_separator = newline
52
53
  version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
53
54
 
54
55
  # set to 'true' to search source files recursively
@@ -49,6 +49,7 @@ prepend_sys_path = .
49
49
  # version_path_separator = :
50
50
  # version_path_separator = ;
51
51
  # version_path_separator = space
52
+ # version_path_separator = newline
52
53
  version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
53
54
 
54
55
  # set to 'true' to search source files recursively
@@ -74,7 +74,9 @@ class _ErrorContainer:
74
74
 
75
75
 
76
76
  @contextlib.contextmanager
77
- def _expect_raises(except_cls, msg=None, check_context=False):
77
+ def _expect_raises(
78
+ except_cls, msg=None, check_context=False, text_exact=False
79
+ ):
78
80
  ec = _ErrorContainer()
79
81
  if check_context:
80
82
  are_we_already_in_a_traceback = sys.exc_info()[0]
@@ -85,7 +87,10 @@ def _expect_raises(except_cls, msg=None, check_context=False):
85
87
  ec.error = err
86
88
  success = True
87
89
  if msg is not None:
88
- assert re.search(msg, str(err), re.UNICODE), f"{msg} !~ {err}"
90
+ if text_exact:
91
+ assert str(err) == msg, f"{msg} != {err}"
92
+ else:
93
+ assert re.search(msg, str(err), re.UNICODE), f"{msg} !~ {err}"
89
94
  if check_context and not are_we_already_in_a_traceback:
90
95
  _assert_proper_exception_context(err)
91
96
  print(str(err).encode("utf-8"))
@@ -98,8 +103,12 @@ def expect_raises(except_cls, check_context=True):
98
103
  return _expect_raises(except_cls, check_context=check_context)
99
104
 
100
105
 
101
- def expect_raises_message(except_cls, msg, check_context=True):
102
- return _expect_raises(except_cls, msg=msg, check_context=check_context)
106
+ def expect_raises_message(
107
+ except_cls, msg, check_context=True, text_exact=False
108
+ ):
109
+ return _expect_raises(
110
+ except_cls, msg=msg, check_context=check_context, text_exact=text_exact
111
+ )
103
112
 
104
113
 
105
114
  def eq_ignore_whitespace(a, b, msg=None):
@@ -527,7 +527,7 @@ class _textual_index_element(sql.ColumnElement):
527
527
  self.fake_column = schema.Column(self.text.text, sqltypes.NULLTYPE)
528
528
  table.append_column(self.fake_column)
529
529
 
530
- def get_children(self):
530
+ def get_children(self, **kw):
531
531
  return [self.fake_column]
532
532
 
533
533
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: alembic
3
- Version: 1.13.2
3
+ Version: 1.13.3
4
4
  Summary: A database migration tool for SQLAlchemy.
5
5
  Home-page: https://alembic.sqlalchemy.org
6
6
  Author: Mike Bayer
@@ -107,26 +107,26 @@ docs/search.html
107
107
  docs/searchindex.js
108
108
  docs/tutorial.html
109
109
  docs/_images/api_overview.png
110
- docs/_sources/autogenerate.rst.txt
111
- docs/_sources/batch.rst.txt
112
- docs/_sources/branches.rst.txt
113
- docs/_sources/changelog.rst.txt
114
- docs/_sources/cookbook.rst.txt
115
- docs/_sources/front.rst.txt
116
- docs/_sources/index.rst.txt
117
- docs/_sources/naming.rst.txt
118
- docs/_sources/offline.rst.txt
119
- docs/_sources/ops.rst.txt
120
- docs/_sources/tutorial.rst.txt
121
- docs/_sources/api/autogenerate.rst.txt
122
- docs/_sources/api/commands.rst.txt
123
- docs/_sources/api/config.rst.txt
124
- docs/_sources/api/ddl.rst.txt
125
- docs/_sources/api/index.rst.txt
126
- docs/_sources/api/operations.rst.txt
127
- docs/_sources/api/overview.rst.txt
128
- docs/_sources/api/runtime.rst.txt
129
- docs/_sources/api/script.rst.txt
110
+ docs/_sources/autogenerate.rst
111
+ docs/_sources/batch.rst
112
+ docs/_sources/branches.rst
113
+ docs/_sources/changelog.rst
114
+ docs/_sources/cookbook.rst
115
+ docs/_sources/front.rst
116
+ docs/_sources/index.rst
117
+ docs/_sources/naming.rst
118
+ docs/_sources/offline.rst
119
+ docs/_sources/ops.rst
120
+ docs/_sources/tutorial.rst
121
+ docs/_sources/api/autogenerate.rst
122
+ docs/_sources/api/commands.rst
123
+ docs/_sources/api/config.rst
124
+ docs/_sources/api/ddl.rst
125
+ docs/_sources/api/index.rst
126
+ docs/_sources/api/operations.rst
127
+ docs/_sources/api/overview.rst
128
+ docs/_sources/api/runtime.rst
129
+ docs/_sources/api/script.rst
130
130
  docs/_static/basic.css
131
131
  docs/_static/changelog.css
132
132
  docs/_static/clipboard.min.js
@@ -138,14 +138,28 @@ docs/_static/documentation_options.js
138
138
  docs/_static/file.png
139
139
  docs/_static/language_data.js
140
140
  docs/_static/minus.png
141
- docs/_static/nature.css
142
141
  docs/_static/nature_override.css
143
142
  docs/_static/plus.png
144
143
  docs/_static/pygments.css
144
+ docs/_static/sbt-webpack-macros.html
145
145
  docs/_static/searchtools.js
146
146
  docs/_static/site_custom_css.css
147
147
  docs/_static/sphinx_highlight.js
148
148
  docs/_static/sphinx_paramlinks.css
149
+ docs/_static/webpack-macros.html
150
+ docs/_static/images/logo_colab.png
151
+ docs/_static/scripts/bootstrap.js
152
+ docs/_static/scripts/bootstrap.js.LICENSE.txt
153
+ docs/_static/scripts/pydata-sphinx-theme.js
154
+ docs/_static/scripts/sphinx-book-theme.js
155
+ docs/_static/styles/bootstrap.css
156
+ docs/_static/styles/pydata-sphinx-theme.css
157
+ docs/_static/styles/sphinx-book-theme.css
158
+ docs/_static/styles/theme.css
159
+ docs/_static/vendor/fontawesome/6.5.2/LICENSE.txt
160
+ docs/_static/vendor/fontawesome/6.5.2/css/all.min.css
161
+ docs/_static/vendor/fontawesome/6.5.2/js/all.min.js
162
+ docs/_static/vendor/fontawesome/6.5.2/js/all.min.js.LICENSE.txt
149
163
  docs/api/autogenerate.html
150
164
  docs/api/commands.html
151
165
  docs/api/config.html
@@ -3,6 +3,53 @@
3
3
  Changelog
4
4
  ==========
5
5
 
6
+ .. changelog::
7
+ :version: 1.13.3
8
+ :released: September 23, 2024
9
+
10
+ .. change::
11
+ :tags: usecase, autogenerate
12
+
13
+ Render ``if_exists`` and ``if_not_exists`` parameters in
14
+ :class:`.CreateTableOp`, :class:`.CreateIndexOp`, :class:`.DropTableOp` and
15
+ :class:`.DropIndexOp` in an autogenerate context. While Alembic does not
16
+ set these parameters during an autogenerate run, they can be enabled using
17
+ a custom :class:`.Rewriter` in the ``env.py`` file, where they will now be
18
+ part of the rendered Python code in revision files. Pull request courtesy
19
+ of Louis-Amaury Chaib (@lachaib).
20
+
21
+ .. change::
22
+ :tags: usecase, environment
23
+ :tickets: 1509
24
+
25
+ Enhance ``version_locations`` parsing to handle paths containing newlines.
26
+
27
+ .. change::
28
+ :tags: usecase, operations
29
+ :tickets: 1520
30
+
31
+ Added support for :paramref:`.Operations.create_table.if_not_exists` and
32
+ :paramref:`.Operations.drop_table.if_exists`, adding similar functionality
33
+ to render IF [NOT] EXISTS for table operations in a similar way as with
34
+ indexes. Pull request courtesy Aaron Griffin.
35
+
36
+
37
+ .. change::
38
+ :tags: change, general
39
+
40
+ The pin for ``setuptools<69.3`` in ``pyproject.toml`` has been removed.
41
+ This pin was to prevent a sudden change to :pep:`625` in setuptools from
42
+ taking place which changes the file name of SQLAlchemy's source
43
+ distribution on pypi to be an all lower case name, and the change was
44
+ extended to all SQLAlchemy projects to prevent any further surprises.
45
+ However, the presence of this pin is now holding back environments that
46
+ otherwise want to use a newer setuptools, so we've decided to move forward
47
+ with this change, with the assumption that build environments will have
48
+ largely accommodated the setuptools change by now.
49
+
50
+
51
+
52
+
6
53
  .. changelog::
7
54
  :version: 1.13.2
8
55
  :released: June 26, 2024
@@ -776,8 +776,8 @@ recreated again within the downgrade for this migration::
776
776
 
777
777
  .. _cookbook_postgresql_multi_tenancy:
778
778
 
779
- Rudimental Schema-Level Multi Tenancy for PostgreSQL Databases
780
- ==============================================================
779
+ Rudimental Schema-Level Multi Tenancy for PostgreSQL, MySQL, Other Databases
780
+ ============================================================================
781
781
 
782
782
  **Multi tenancy** refers to an application that accommodates for many
783
783
  clients simultaneously. Within the scope of a database migrations tool,
@@ -789,9 +789,19 @@ the approach must involve running Alembic multiple times against different
789
789
  database URLs.
790
790
 
791
791
  One common approach to multi-tenancy, particularly on the PostgreSQL database,
792
- is to install tenants within **individual PostgreSQL schemas**. When using
793
- PostgreSQL's schemas, a special variable ``search_path`` is offered that is
794
- intended to assist with targeting of different schemas.
792
+ is to install tenants within **individual PostgreSQL schemas**; similarly
793
+ when using MySQL/MariaDB, **individual MySQL/MariaDB databases** are addressed
794
+ in the same way as "schemas" on PostgreSQL.
795
+
796
+ When using PostgreSQL's schemas, a special variable ``search_path`` is offered
797
+ that is intended to assist with targeting of different schemas. When using
798
+ MySQL or MariaDB databases, a similar command is available at the SQL level
799
+ called the ``USE`` command. This command may be used in a similar fashion as
800
+ that of PostgreSQL's ``search_path`` variable to achieve a similar effect.
801
+
802
+ Overall, this recipe can be used on **any database that supports runtime
803
+ modification of the current "tenant" via SQL commands on a particular
804
+ connection**.
795
805
 
796
806
  .. note:: SQLAlchemy includes a system of directing a common set of
797
807
  ``Table`` metadata to many schemas called `schema_translate_map <https://docs.sqlalchemy.org/core/connections.html#translation-of-schema-names>`_. Alembic at the time
@@ -801,7 +811,7 @@ intended to assist with targeting of different schemas.
801
811
 
802
812
  The recipe below can be altered for flexibility. The primary purpose of this
803
813
  recipe is to illustrate how to point the Alembic process towards one PostgreSQL
804
- schema or another.
814
+ or MySQL/MariaDB schema or another.
805
815
 
806
816
  1. The model metadata used as the target for autogenerate must not include any
807
817
  schema name for tables; the schema must be non-present or set to ``None``.
@@ -841,12 +851,20 @@ schema or another.
841
851
  current_tenant = context.get_x_argument(as_dictionary=True).get("tenant")
842
852
  with connectable.connect() as connection:
843
853
 
844
- # set search path on the connection, which ensures that
845
- # PostgreSQL will emit all CREATE / ALTER / DROP statements
846
- # in terms of this schema by default
847
- connection.execute(text('set search_path to "%s"' % current_tenant))
848
- # in SQLAlchemy v2+ the search path change needs to be committed
849
- connection.commit()
854
+ if connection.dialect.name == "postgresql":
855
+ # set search path on the connection, which ensures that
856
+ # PostgreSQL will emit all CREATE / ALTER / DROP statements
857
+ # in terms of this schema by default
858
+
859
+ connection.execute(text('set search_path to "%s"' % current_tenant))
860
+ # in SQLAlchemy v2+ the search path change needs to be committed
861
+ connection.commit()
862
+ elif connection.dialect.name in ("mysql", "mariadb"):
863
+ # set "USE" on the connection, which ensures that
864
+ # MySQL/MariaDB will emit all CREATE / ALTER / DROP statements
865
+ # in terms of this schema by default
866
+
867
+ connection.execute(text('USE %s' % current_tenant))
850
868
 
851
869
  # make use of non-supported SQLAlchemy attribute to ensure
852
870
  # the dialect reflects tables in terms of the current tenant name
@@ -860,17 +878,18 @@ schema or another.
860
878
  with context.begin_transaction():
861
879
  context.run_migrations()
862
880
 
863
- The current tenant is set using the PostgreSQL ``search_path`` variable on
864
- the connection. Note above we must employ a **non-supported SQLAlchemy
865
- workaround** at the moment which is to hardcode the SQLAlchemy dialect's
866
- default schema name to our target schema.
881
+ The current tenant is set using the PostgreSQL ``search_path`` variable, or
882
+ the MySQL/MariaDB ``USE`` statement, on the connection. Note above we must
883
+ employ a **non-supported SQLAlchemy workaround** at the moment which is to
884
+ hardcode the SQLAlchemy dialect's default schema name to our target schema.
867
885
 
868
886
  It is also important to note that the above changes **remain on the connection
869
887
  permanently unless reversed explicitly**. If the alembic application simply
870
888
  exits above, there is no issue. However if the application attempts to
871
889
  continue using the above connection for other purposes, it may be necessary
872
890
  to reset these variables back to the default, which for PostgreSQL is usually
873
- the name "public" however may be different based on configuration.
891
+ the name "public" however may be different based on configuration, and
892
+ for MySQL/MariaDB is typically the "database" portion of the database URL.
874
893
 
875
894
 
876
895
  4. Alembic operations will now proceed in terms of whichever schema we pass
@@ -174,6 +174,7 @@ The file generated with the "generic" configuration looks like::
174
174
  # version_path_separator = :
175
175
  # version_path_separator = ;
176
176
  # version_path_separator = space
177
+ # version_path_separator = newline
177
178
  version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
178
179
 
179
180
  # set to 'true' to search source files recursively
@@ -55,7 +55,7 @@ div.sphinxsidebarwrapper {
55
55
 
56
56
  div.sphinxsidebar {
57
57
  float: left;
58
- width: 230px;
58
+ width: 270px;
59
59
  margin-left: -100%;
60
60
  font-size: 90%;
61
61
  word-wrap: break-word;