execsql2 2.26.0__tar.gz → 2.28.0__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 (485) hide show
  1. {execsql2-2.26.0 → execsql2-2.28.0}/.github/dependabot.yml +9 -0
  2. {execsql2-2.26.0 → execsql2-2.28.0}/.github/workflows/ci-cd.yml +38 -2
  3. {execsql2-2.26.0 → execsql2-2.28.0}/.gitignore +4 -0
  4. {execsql2-2.26.0 → execsql2-2.28.0}/.pre-commit-config.yaml +6 -6
  5. {execsql2-2.26.0 → execsql2-2.28.0}/.readthedocs.yaml +1 -1
  6. {execsql2-2.26.0 → execsql2-2.28.0}/CHANGELOG.md +55 -0
  7. {execsql2-2.26.0 → execsql2-2.28.0}/PKG-INFO +34 -18
  8. {execsql2-2.26.0 → execsql2-2.28.0}/README.md +18 -16
  9. {execsql2-2.26.0 → execsql2-2.28.0}/docs/about/divergence.md +6 -2
  10. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/adding_metacommands.md +26 -1
  11. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/releasing.md +11 -10
  12. {execsql2-2.26.0 → execsql2-2.28.0}/docs/getting-started/installation.md +19 -18
  13. {execsql2-2.26.0 → execsql2-2.28.0}/docs/getting-started/syntax.md +19 -16
  14. execsql2-2.28.0/docs/guides/editors.md +229 -0
  15. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/formatter.md +11 -2
  16. {execsql2-2.26.0 → execsql2-2.28.0}/docs/reference/lint.md +1 -1
  17. {execsql2-2.26.0 → execsql2-2.28.0}/docs/reference/metacommands.md +5 -5
  18. {execsql2-2.26.0 → execsql2-2.28.0}/extras/vscode-execsql/README.md +60 -4
  19. execsql2-2.28.0/extras/vscode-execsql/extension.js +135 -0
  20. execsql2-2.28.0/extras/vscode-execsql/package-lock.json +1901 -0
  21. execsql2-2.28.0/extras/vscode-execsql/package.json +87 -0
  22. {execsql2-2.26.0 → execsql2-2.28.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +1 -1
  23. {execsql2-2.26.0 → execsql2-2.28.0}/justfile +4 -2
  24. {execsql2-2.26.0 → execsql2-2.28.0}/pyproject.toml +21 -4
  25. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/__init__.py +1 -0
  26. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/format.py +2 -1
  27. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/listing.py +32 -5
  28. execsql2-2.28.0/src/execsql/cli/commands/lsp.py +64 -0
  29. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/dispatch.py +1 -1
  30. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/help.py +44 -96
  31. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/lint.py +58 -22
  32. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/access.py +4 -4
  33. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/base.py +17 -3
  34. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/dsn.py +2 -2
  35. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/duckdb.py +14 -2
  36. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/firebird.py +2 -3
  37. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/mysql.py +2 -2
  38. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/oracle.py +5 -5
  39. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/postgres.py +2 -3
  40. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/sqlserver.py +2 -2
  41. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/duckdb.py +2 -2
  42. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/ods.py +2 -2
  43. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/templates.py +2 -2
  44. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/xls.py +3 -3
  45. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/xlsx.py +2 -2
  46. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/yaml.py +3 -4
  47. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/format.py +71 -21
  48. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/base.py +6 -10
  49. execsql2-2.28.0/src/execsql/lsp/__init__.py +6 -0
  50. execsql2-2.28.0/src/execsql/lsp/code_actions.py +217 -0
  51. execsql2-2.28.0/src/execsql/lsp/completion.py +203 -0
  52. execsql2-2.28.0/src/execsql/lsp/diagnostics.py +66 -0
  53. execsql2-2.28.0/src/execsql/lsp/document.py +210 -0
  54. execsql2-2.28.0/src/execsql/lsp/folding.py +59 -0
  55. execsql2-2.28.0/src/execsql/lsp/formatting.py +37 -0
  56. execsql2-2.28.0/src/execsql/lsp/hover.py +119 -0
  57. execsql2-2.28.0/src/execsql/lsp/navigation.py +169 -0
  58. execsql2-2.28.0/src/execsql/lsp/rename.py +91 -0
  59. execsql2-2.28.0/src/execsql/lsp/server.py +358 -0
  60. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/debug.py +2 -2
  61. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/dispatch.py +7 -0
  62. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/io_fileops.py +6 -6
  63. execsql2-2.28.0/src/execsql/metacommands/reference.py +1404 -0
  64. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/upsert.py +2 -5
  65. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/models.py +11 -0
  66. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/errors.py +16 -0
  67. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_cli.py +2 -3
  68. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_cli_surface.py +1 -0
  69. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_commands.py +28 -2
  70. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_lint.py +19 -0
  71. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_copy_new.py +37 -0
  72. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_duckdb.py +8 -1
  73. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_new_table_checks.py +24 -1
  74. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/test_postgres.py +26 -0
  75. execsql2-2.28.0/tests/lsp/test_code_actions.py +94 -0
  76. execsql2-2.28.0/tests/lsp/test_completion.py +112 -0
  77. execsql2-2.28.0/tests/lsp/test_diagnostics.py +63 -0
  78. execsql2-2.28.0/tests/lsp/test_document.py +101 -0
  79. execsql2-2.28.0/tests/lsp/test_folding.py +63 -0
  80. execsql2-2.28.0/tests/lsp/test_formatting.py +42 -0
  81. execsql2-2.28.0/tests/lsp/test_hover.py +83 -0
  82. execsql2-2.28.0/tests/lsp/test_lsp_command.py +71 -0
  83. execsql2-2.28.0/tests/lsp/test_navigation.py +103 -0
  84. execsql2-2.28.0/tests/lsp/test_rename.py +99 -0
  85. execsql2-2.28.0/tests/lsp/test_server.py +436 -0
  86. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_extended.py +11 -0
  87. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_fileops_extra.py +4 -2
  88. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_pg_upsert.py +1 -1
  89. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_format.py +60 -0
  90. execsql2-2.28.0/tests/test_reference.py +225 -0
  91. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_tooling_versions.py +9 -0
  92. execsql2-2.28.0/tests/utils/__init__.py +0 -0
  93. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_errors.py +27 -0
  94. {execsql2-2.26.0 → execsql2-2.28.0}/uv.lock +162 -41
  95. {execsql2-2.26.0 → execsql2-2.28.0}/zensical.toml +1 -0
  96. execsql2-2.26.0/extras/vscode-execsql/package.json +0 -46
  97. {execsql2-2.26.0 → execsql2-2.28.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  98. {execsql2-2.26.0 → execsql2-2.28.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  99. {execsql2-2.26.0 → execsql2-2.28.0}/.pre-commit-hooks.yaml +0 -0
  100. {execsql2-2.26.0 → execsql2-2.28.0}/.python-version +0 -0
  101. {execsql2-2.26.0 → execsql2-2.28.0}/CONTRIBUTING.md +0 -0
  102. {execsql2-2.26.0 → execsql2-2.28.0}/LICENSE.txt +0 -0
  103. {execsql2-2.26.0 → execsql2-2.28.0}/NOTICE +0 -0
  104. {execsql2-2.26.0 → execsql2-2.28.0}/SECURITY.md +0 -0
  105. {execsql2-2.26.0 → execsql2-2.28.0}/docs/about/contributors.md +0 -0
  106. {execsql2-2.26.0 → execsql2-2.28.0}/docs/about/copyright.md +0 -0
  107. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/cli.md +0 -0
  108. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/db.md +0 -0
  109. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/exporters.md +0 -0
  110. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/importers.md +0 -0
  111. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/index.md +0 -0
  112. {execsql2-2.26.0 → execsql2-2.28.0}/docs/api/metacommands.md +0 -0
  113. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/adding_db_adapters.md +0 -0
  114. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/adding_exporters.md +0 -0
  115. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/adding_importers.md +0 -0
  116. {execsql2-2.26.0 → execsql2-2.28.0}/docs/dev/architecture.md +0 -0
  117. {execsql2-2.26.0 → execsql2-2.28.0}/docs/getting-started/requirements.md +0 -0
  118. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/debugging.md +0 -0
  119. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/documentation.md +0 -0
  120. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/encoding.md +0 -0
  121. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/examples.md +0 -0
  122. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/logging.md +0 -0
  123. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/sql_syntax.md +0 -0
  124. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/usage.md +0 -0
  125. {execsql2-2.26.0 → execsql2-2.28.0}/docs/guides/using_scripts.md +0 -0
  126. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/Compare_planets.png +0 -0
  127. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/actions.png +0 -0
  128. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/actions2.png +0 -0
  129. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/checkboxes.png +0 -0
  130. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/connect.b64 +0 -0
  131. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/connect.png +0 -0
  132. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/create_conf.png +0 -0
  133. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/data_error1_screenshot.jpg +0 -0
  134. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/entry_form.png +0 -0
  135. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/execsql_console.png +0 -0
  136. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/execsql_logo_01.png +0 -0
  137. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/fatals.png +0 -0
  138. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/logo_small.png +0 -0
  139. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/pause_terminal.png +0 -0
  140. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/pause_terminal_sm.b64 +0 -0
  141. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/pause_terminal_sm.png +0 -0
  142. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/prompt_compare.png +0 -0
  143. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/set_build_commands.jpg +0 -0
  144. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/unit_conversions.b64 +0 -0
  145. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/unit_conversions_029.png +0 -0
  146. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/unmatched.png +0 -0
  147. {execsql2-2.26.0 → execsql2-2.28.0}/docs/images/vim_execsql_highlight.png +0 -0
  148. {execsql2-2.26.0 → execsql2-2.28.0}/docs/index.md +0 -0
  149. {execsql2-2.26.0 → execsql2-2.28.0}/docs/reference/configuration.md +0 -0
  150. {execsql2-2.26.0 → execsql2-2.28.0}/docs/reference/security.md +0 -0
  151. {execsql2-2.26.0 → execsql2-2.28.0}/docs/reference/substitution_vars.md +0 -0
  152. {execsql2-2.26.0 → execsql2-2.28.0}/extras/plugin-template/README.md +0 -0
  153. {execsql2-2.26.0 → execsql2-2.28.0}/extras/plugin-template/pyproject.toml +0 -0
  154. {execsql2-2.26.0 → execsql2-2.28.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
  155. {execsql2-2.26.0 → execsql2-2.28.0}/extras/plugin-template/tests/test_plugin.py.example +0 -0
  156. {execsql2-2.26.0 → execsql2-2.28.0}/extras/vscode-execsql/.vscodeignore +0 -0
  157. {execsql2-2.26.0 → execsql2-2.28.0}/extras/vscode-execsql/LICENSE.txt +0 -0
  158. {execsql2-2.26.0 → execsql2-2.28.0}/extras/vscode-execsql/icon.png +0 -0
  159. {execsql2-2.26.0 → execsql2-2.28.0}/scripts/benchmarks/README.md +0 -0
  160. {execsql2-2.26.0 → execsql2-2.28.0}/scripts/benchmarks/results/.gitignore +0 -0
  161. {execsql2-2.26.0 → execsql2-2.28.0}/scripts/benchmarks/run_benchmarks.py +0 -0
  162. {execsql2-2.26.0 → execsql2-2.28.0}/scripts/generate_vscode_grammar.py +0 -0
  163. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/__init__.py +0 -0
  164. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/__main__.py +0 -0
  165. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/api.py +0 -0
  166. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/__init__.py +0 -0
  167. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/application.py +0 -0
  168. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/config.py +0 -0
  169. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/init.py +0 -0
  170. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/lint.py +0 -0
  171. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/commands/run.py +0 -0
  172. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/dsn.py +0 -0
  173. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/options.py +0 -0
  174. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/cli/run.py +0 -0
  175. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/config.py +0 -0
  176. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/config_validation.py +0 -0
  177. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/data/__init__.py +0 -0
  178. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/data/execsql.conf.template +0 -0
  179. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/data/script_header.sql +0 -0
  180. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/__init__.py +0 -0
  181. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/factory.py +0 -0
  182. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/sqlite.py +0 -0
  183. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/db/tiers.py +0 -0
  184. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/debug/__init__.py +0 -0
  185. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/debug/repl.py +0 -0
  186. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exceptions.py +0 -0
  187. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/__init__.py +0 -0
  188. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/base.py +0 -0
  189. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/delimited.py +0 -0
  190. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/feather.py +0 -0
  191. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/html.py +0 -0
  192. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/json.py +0 -0
  193. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/latex.py +0 -0
  194. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/markdown.py +0 -0
  195. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/parquet.py +0 -0
  196. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/pretty.py +0 -0
  197. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/protocol.py +0 -0
  198. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/raw.py +0 -0
  199. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/sqlite.py +0 -0
  200. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/values.py +0 -0
  201. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/xml.py +0 -0
  202. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/exporters/zip.py +0 -0
  203. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/gui/__init__.py +0 -0
  204. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/gui/base.py +0 -0
  205. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/gui/console.py +0 -0
  206. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/gui/desktop.py +0 -0
  207. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/gui/tui.py +0 -0
  208. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/__init__.py +0 -0
  209. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/csv.py +0 -0
  210. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/feather.py +0 -0
  211. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/json.py +0 -0
  212. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/ods.py +0 -0
  213. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/importers/xls.py +0 -0
  214. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/interactive.py +0 -0
  215. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/manifest.py +0 -0
  216. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/__init__.py +0 -0
  217. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/conditions.py +0 -0
  218. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/connect.py +0 -0
  219. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/control.py +0 -0
  220. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/data.py +0 -0
  221. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/effects.py +0 -0
  222. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/io.py +0 -0
  223. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/io_export.py +0 -0
  224. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/io_import.py +0 -0
  225. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/io_write.py +0 -0
  226. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/prompt.py +0 -0
  227. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/script_ext.py +0 -0
  228. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/metacommands/system.py +0 -0
  229. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/parser.py +0 -0
  230. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/plugins.py +0 -0
  231. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/py.typed +0 -0
  232. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/__init__.py +0 -0
  233. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/ast.py +0 -0
  234. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/control.py +0 -0
  235. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/engine.py +0 -0
  236. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/executor.py +0 -0
  237. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/parser.py +0 -0
  238. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/script/variables.py +0 -0
  239. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/state.py +0 -0
  240. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/state.pyi +0 -0
  241. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/types.py +0 -0
  242. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/__init__.py +0 -0
  243. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/auth.py +0 -0
  244. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/color.py +0 -0
  245. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/crypto.py +0 -0
  246. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/datetime.py +0 -0
  247. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/fileio.py +0 -0
  248. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/gui.py +0 -0
  249. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/mail.py +0 -0
  250. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/numeric.py +0 -0
  251. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/regex.py +0 -0
  252. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/strings.py +0 -0
  253. {execsql2-2.26.0 → execsql2-2.28.0}/src/execsql/utils/timer.py +0 -0
  254. {execsql2-2.26.0 → execsql2-2.28.0}/templates/README.md +0 -0
  255. {execsql2-2.26.0 → execsql2-2.28.0}/templates/config_settings.sqlite +0 -0
  256. {execsql2-2.26.0 → execsql2-2.28.0}/templates/example_config_prompt.sql +0 -0
  257. {execsql2-2.26.0 → execsql2-2.28.0}/templates/make_config_db.sql +0 -0
  258. {execsql2-2.26.0 → execsql2-2.28.0}/templates/md_compare.sql +0 -0
  259. {execsql2-2.26.0 → execsql2-2.28.0}/templates/md_glossary.sql +0 -0
  260. {execsql2-2.26.0 → execsql2-2.28.0}/templates/md_upsert.sql +0 -0
  261. {execsql2-2.26.0 → execsql2-2.28.0}/templates/pg_compare.sql +0 -0
  262. {execsql2-2.26.0 → execsql2-2.28.0}/templates/pg_glossary.sql +0 -0
  263. {execsql2-2.26.0 → execsql2-2.28.0}/templates/pg_upsert.sql +0 -0
  264. {execsql2-2.26.0 → execsql2-2.28.0}/templates/script_template.sql +0 -0
  265. {execsql2-2.26.0 → execsql2-2.28.0}/templates/ss_compare.sql +0 -0
  266. {execsql2-2.26.0 → execsql2-2.28.0}/templates/ss_glossary.sql +0 -0
  267. {execsql2-2.26.0 → execsql2-2.28.0}/templates/ss_upsert.sql +0 -0
  268. {execsql2-2.26.0 → execsql2-2.28.0}/tests/__init__.py +0 -0
  269. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/__init__.py +0 -0
  270. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_cli_e2e.py +0 -0
  271. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_cli_run.py +0 -0
  272. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_config_validate.py +0 -0
  273. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_dispatch.py +0 -0
  274. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_error_location.py +0 -0
  275. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_init.py +0 -0
  276. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_lint_fixtures.py +0 -0
  277. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_log_exit_record.py +0 -0
  278. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_manifest.py +0 -0
  279. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_ping.py +0 -0
  280. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_profile.py +0 -0
  281. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_sigterm.py +0 -0
  282. {execsql2-2.26.0 → execsql2-2.28.0}/tests/cli/test_undeclared_imports.py +0 -0
  283. {execsql2-2.26.0 → execsql2-2.28.0}/tests/conftest.py +0 -0
  284. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
  285. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/formatter_shapes/escapes_and_literals.sql +0 -0
  286. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/formatter_shapes/substitution_and_metacommands.sql +0 -0
  287. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/formatter_shapes/unparsable_sql.sql +0 -0
  288. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/lint/conditions_and_blocks.sql +0 -0
  289. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/lint/does_not_parse.sql +0 -0
  290. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/lint/every_metacommand.sql +0 -0
  291. {execsql2-2.26.0 → execsql2-2.28.0}/tests/data/lint/invalid.sql +0 -0
  292. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/__init__.py +0 -0
  293. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_access_windows.py +0 -0
  294. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_base.py +0 -0
  295. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_db_adapters_mocked.py +0 -0
  296. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_db_adapters_mocked_extra.py +0 -0
  297. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_dsn.py +0 -0
  298. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_factory.py +0 -0
  299. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_factory_postgres_encoding.py +0 -0
  300. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_import_atomic.py +0 -0
  301. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_import_replacement_quoted.py +0 -0
  302. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_import_short_rows.py +0 -0
  303. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_import_timezones.py +0 -0
  304. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_mysql_case_folding.py +0 -0
  305. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_mysql_inprocess.py +0 -0
  306. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_oracle_driver.py +0 -0
  307. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_postgres.py +0 -0
  308. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_postgres_inprocess.py +0 -0
  309. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_roundtrip_adapters.py +0 -0
  310. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_sqlite.py +0 -0
  311. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_sqlite_extra.py +0 -0
  312. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_sqlserver_inprocess.py +0 -0
  313. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_tiers.py +0 -0
  314. {execsql2-2.26.0 → execsql2-2.28.0}/tests/db/test_transactions.py +0 -0
  315. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/__init__.py +0 -0
  316. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/conftest.py +0 -0
  317. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_base.py +0 -0
  318. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_db.py +0 -0
  319. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_delimited.py +0 -0
  320. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_duckdb_exporter.py +0 -0
  321. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_exporters.py +0 -0
  322. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_feather.py +0 -0
  323. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_html_extended.py +0 -0
  324. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_html_latex.py +0 -0
  325. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_json.py +0 -0
  326. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_json_extended.py +0 -0
  327. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_latex_extended.py +0 -0
  328. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_markdown.py +0 -0
  329. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_ods.py +0 -0
  330. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_ods_export.py +0 -0
  331. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_parquet.py +0 -0
  332. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_pretty_extended.py +0 -0
  333. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_raw_extended.py +0 -0
  334. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
  335. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
  336. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
  337. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_json.py +0 -0
  338. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
  339. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_markup.py +0 -0
  340. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_ods.py +0 -0
  341. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
  342. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_template.py +0 -0
  343. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_values.py +0 -0
  344. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_roundtrip_xlsx.py +0 -0
  345. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_sqlite_exporter.py +0 -0
  346. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_templates.py +0 -0
  347. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_templates_extended.py +0 -0
  348. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_values_extended.py +0 -0
  349. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_xls_xlsx.py +0 -0
  350. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_xlsx.py +0 -0
  351. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_xml.py +0 -0
  352. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_yaml.py +0 -0
  353. {execsql2-2.26.0 → execsql2-2.28.0}/tests/exporters/test_zip.py +0 -0
  354. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/__init__.py +0 -0
  355. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_backends.py +0 -0
  356. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_backends_extended.py +0 -0
  357. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_compare_stats.py +0 -0
  358. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_compute_row_diffs.py +0 -0
  359. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_desktop_dialogs.py +0 -0
  360. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_format_table.py +0 -0
  361. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_tui_pilot.py +0 -0
  362. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_tui_pilot_complex.py +0 -0
  363. {execsql2-2.26.0 → execsql2-2.28.0}/tests/gui/test_utils_gui_extended.py +0 -0
  364. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/__init__.py +0 -0
  365. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/conftest.py +0 -0
  366. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_base_extended.py +0 -0
  367. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_csv_blank_lines.py +0 -0
  368. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_csv_edge_cases.py +0 -0
  369. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_csv_importer.py +0 -0
  370. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_feather_importer.py +0 -0
  371. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_json_importer.py +0 -0
  372. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_ods_importer.py +0 -0
  373. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_roundtrip_csv.py +0 -0
  374. {execsql2-2.26.0 → execsql2-2.28.0}/tests/importers/test_xls_importer.py +0 -0
  375. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/__init__.py +0 -0
  376. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/conftest.py +0 -0
  377. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/test_dsn.py +0 -0
  378. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/test_duckdb.py +0 -0
  379. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/test_mysql.py +0 -0
  380. {execsql2-2.26.0 → execsql2-2.28.0}/tests/integration/test_sqlite.py +0 -0
  381. {execsql2-2.26.0 → execsql2-2.28.0}/tests/live_db.py +0 -0
  382. {execsql2-2.26.0/tests/metacommands → execsql2-2.28.0/tests/lsp}/__init__.py +0 -0
  383. {execsql2-2.26.0/tests/scripts → execsql2-2.28.0/tests/metacommands}/__init__.py +0 -0
  384. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_assert.py +0 -0
  385. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_breakpoint.py +0 -0
  386. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_conditions_extra.py +0 -0
  387. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_connect.py +0 -0
  388. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_io_export.py +0 -0
  389. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_io_import.py +0 -0
  390. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands.py +0 -0
  391. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_connect.py +0 -0
  392. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_data.py +0 -0
  393. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_io.py +0 -0
  394. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  395. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
  396. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_system.py +0 -0
  397. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  398. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_prompt.py +0 -0
  399. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_row_count.py +0 -0
  400. {execsql2-2.26.0 → execsql2-2.28.0}/tests/metacommands/test_show_scripts.py +0 -0
  401. {execsql2-2.26.0/tests/security → execsql2-2.28.0/tests/scripts}/__init__.py +0 -0
  402. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  403. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  404. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  405. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  406. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
  407. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/control_flow.sql +0 -0
  408. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  409. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/error_handling.sql +0 -0
  410. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  411. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/import_options.sql +0 -0
  412. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
  413. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/includes.sql +0 -0
  414. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/io_formats.sql +0 -0
  415. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  416. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/multi_db.sql +0 -0
  417. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  418. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  419. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/predicates.sql +0 -0
  420. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/scripts.sql +0 -0
  421. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/smoke.sql +0 -0
  422. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  423. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  424. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  425. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/template_export.sql +0 -0
  426. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/timer.sql +0 -0
  427. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/transactions.sql +0 -0
  428. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
  429. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  430. {execsql2-2.26.0 → execsql2-2.28.0}/tests/scripts/test_sql_scripts.py +0 -0
  431. {execsql2-2.26.0/tests/utils → execsql2-2.28.0/tests/security}/__init__.py +0 -0
  432. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_env_detection.py +0 -0
  433. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_expansion_bomb.py +0 -0
  434. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_import_regex_hardening.py +0 -0
  435. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_log_redaction.py +0 -0
  436. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_log_secrets.py +0 -0
  437. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_odbc_injection.py +0 -0
  438. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_path_containment.py +0 -0
  439. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_substitution_injection.py +0 -0
  440. {execsql2-2.26.0 → execsql2-2.28.0}/tests/security/test_zip_bomb.py +0 -0
  441. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api.py +0 -0
  442. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api_errors.py +0 -0
  443. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api_extended.py +0 -0
  444. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api_filewriter.py +0 -0
  445. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api_isolation.py +0 -0
  446. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_api_subprocess.py +0 -0
  447. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_ast.py +0 -0
  448. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_ast_parser.py +0 -0
  449. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_bundled_templates.py +0 -0
  450. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_config.py +0 -0
  451. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_config_data.py +0 -0
  452. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_config_extended.py +0 -0
  453. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_date_inference.py +0 -0
  454. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_debug_repl.py +0 -0
  455. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_engine.py +0 -0
  456. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_error_messages.py +0 -0
  457. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_exceptions.py +0 -0
  458. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_executor.py +0 -0
  459. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_executor_inprocess.py +0 -0
  460. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_interactive.py +0 -0
  461. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_mail.py +0 -0
  462. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_models.py +0 -0
  463. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_package.py +0 -0
  464. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_parser.py +0 -0
  465. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_parser_params.py +0 -0
  466. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_plugins.py +0 -0
  467. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_registry.py +0 -0
  468. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_script.py +0 -0
  469. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_state.py +0 -0
  470. {execsql2-2.26.0 → execsql2-2.28.0}/tests/test_types.py +0 -0
  471. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_auth.py +0 -0
  472. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_auth_extra.py +0 -0
  473. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_crypto.py +0 -0
  474. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_datetime.py +0 -0
  475. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_encodedfile_context.py +0 -0
  476. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_errors_extra.py +0 -0
  477. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_fileio.py +0 -0
  478. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_fileio_extra.py +0 -0
  479. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_keyring_rules.py +0 -0
  480. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_mail_tls.py +0 -0
  481. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_numeric.py +0 -0
  482. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_regex.py +0 -0
  483. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_strings.py +0 -0
  484. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_timer.py +0 -0
  485. {execsql2-2.26.0 → execsql2-2.28.0}/tests/utils/test_timer_extra.py +0 -0
@@ -51,3 +51,12 @@ updates:
51
51
  pre-commit-hooks:
52
52
  patterns:
53
53
  - "*"
54
+ # The VS Code extension's language client and its packaging tool.
55
+ - package-ecosystem: npm
56
+ directory: /extras/vscode-execsql
57
+ schedule:
58
+ interval: weekly
59
+ groups:
60
+ vscode-extension:
61
+ patterns:
62
+ - "*"
@@ -110,6 +110,37 @@ jobs:
110
110
  env:
111
111
  SKIP: mypy
112
112
 
113
+ vscode-extension:
114
+ name: vscode-extension
115
+ runs-on: ubuntu-latest
116
+ permissions:
117
+ contents: read
118
+ steps:
119
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
120
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
121
+ with:
122
+ node-version: "22"
123
+ # Dependencies come from the committed package-lock.json, and no
124
+ # install script of any dependency runs.
125
+ - name: Install dependencies
126
+ working-directory: extras/vscode-execsql
127
+ run: npm ci --ignore-scripts --no-audit --no-fund
128
+ # A release's extension carries the release's version (VS Code
129
+ # versions are X.Y.Z, so a pre-release suffix is dropped).
130
+ - name: Set the extension version from the tag
131
+ if: startsWith(github.ref, 'refs/tags/v')
132
+ working-directory: extras/vscode-execsql
133
+ run: |
134
+ version="$(echo "${GITHUB_REF_NAME#v}" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+')"
135
+ npm pkg set version="$version"
136
+ - name: Package the .vsix
137
+ working-directory: extras/vscode-execsql
138
+ run: ./node_modules/.bin/vsce package --out "../../execsql-syntax.vsix"
139
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
140
+ with:
141
+ name: vscode-extension
142
+ path: execsql-syntax.vsix
143
+
113
144
  docs:
114
145
  name: docs
115
146
  runs-on: ubuntu-latest
@@ -338,7 +369,7 @@ jobs:
338
369
  build:
339
370
  name: Build distribution 📦
340
371
  runs-on: ubuntu-latest
341
- needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests ]
372
+ needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests, vscode-extension ]
342
373
  # Deliberately NOT gated on tags: packaging breaks must surface on a PR,
343
374
  # not at release time. Only publish/generate-release below are tag-gated.
344
375
  permissions:
@@ -403,7 +434,7 @@ jobs:
403
434
  name: Generate GitHub Release
404
435
  # After the PyPI upload, so a release is never announced for a
405
436
  # version that pip cannot install.
406
- needs: [ publish ]
437
+ needs: [ publish, vscode-extension ]
407
438
  if: startsWith(github.ref, 'refs/tags/v')
408
439
  runs-on: ubuntu-latest
409
440
  permissions:
@@ -416,6 +447,11 @@ jobs:
416
447
  with:
417
448
  name: ${{ github.event.repository.name }}
418
449
  path: dist/
450
+ - name: Download the VS Code extension
451
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
452
+ with:
453
+ name: vscode-extension
454
+ path: dist/
419
455
  - name: Detect pre-release tag
420
456
  id: tag
421
457
  # PEP 440 pre-release suffix (a1, b2, rc1) on the tag -> mark the
@@ -56,3 +56,7 @@ PROMPTS.md
56
56
  audit/
57
57
  AGENTS.md
58
58
  .codex/
59
+
60
+ # VS Code extension dependencies (npm ci in extras/vscode-execsql)
61
+ node_modules/
62
+ *.vsix
@@ -13,12 +13,12 @@ repos:
13
13
  - id: check-hooks-apply
14
14
  # Protect secrets using Gitleaks
15
15
  - repo: https://github.com/zricethezav/gitleaks
16
- rev: v8.30.0
16
+ rev: v8.30.1
17
17
  hooks:
18
18
  - id: gitleaks
19
19
  # uv lockfile management
20
20
  - repo: https://github.com/astral-sh/uv-pre-commit
21
- rev: 0.11.1
21
+ rev: 0.12.23
22
22
  hooks:
23
23
  - id: uv-lock
24
24
  # Base hooks
@@ -44,7 +44,7 @@ repos:
44
44
  - id: mdformat
45
45
  language: python
46
46
  additional_dependencies:
47
- - mdformat-mkdocs==5.1.1
47
+ - mdformat-mkdocs==5.3.0
48
48
  exclude: |
49
49
  (?x)^(
50
50
  \.claude/.*|
@@ -56,7 +56,7 @@ repos:
56
56
  )$
57
57
  # Markdown lint
58
58
  - repo: https://github.com/igorshubovych/markdownlint-cli
59
- rev: v0.48.0
59
+ rev: v0.49.1
60
60
  hooks:
61
61
  - id: markdownlint
62
62
  types: [file]
@@ -64,13 +64,13 @@ repos:
64
64
  args: [--disable, MD013]
65
65
  # Spell check
66
66
  - repo: https://github.com/crate-ci/typos
67
- rev: v1.44.0
67
+ rev: v1.51.0
68
68
  hooks:
69
69
  - id: typos
70
70
  args: [--force-exclude]
71
71
  # Lint & format with ruff
72
72
  - repo: https://github.com/astral-sh/ruff-pre-commit
73
- rev: v0.15.7
73
+ rev: v0.16.10
74
74
  hooks:
75
75
  - id: ruff-check
76
76
  args: [--config=pyproject.toml, --exit-non-zero-on-fix]
@@ -9,7 +9,7 @@ build:
9
9
  python: "3.13"
10
10
  jobs:
11
11
  install:
12
- - pip install "zensical==0.0.28" mkdocstrings-python
12
+ - pip install "zensical==0.0.67" mkdocstrings-python
13
13
  - pip install -e .
14
14
  pre_build:
15
15
  - cp CHANGELOG.md docs/about/change_log.md
@@ -13,6 +13,61 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.28.0] - 2026-10-13
17
+
18
+ ### Added
19
+
20
+ - **`execsql lsp --check`** reports whether the language server can start (exit 0) or what is missing (exit 1).
21
+
22
+ ### Changed
23
+
24
+ - **Missing-package messages** (database drivers, spreadsheet, YAML and template exports, `PG_UPSERT`, the formatter and the language server) name the execsql2 extra and show how to add it while keeping the extras already installed.
25
+
26
+ ### Fixed
27
+
28
+ - **`execsql format` keeps optimizer hints and MySQL executable comments:** a statement holding `/*+ ... */` or `/*! ... */` is left as written in both modes. It was rewritten to `/* + ... */` and the hint moved off its keyword, so MySQL skipped the `/*! */` SQL (for example a `WHERE` or `PARTITION BY`) and Oracle/MySQL ignored the hint; re-check files the formatter or its pre-commit hook rewrote.
29
+ - **`execsql format` no longer ends a final statement with a `;` the script did not have:** a script execsql refused for an unfinished last statement became one that ran it.
30
+ - **`execsql format`:** a statement kept as written after another on the same line no longer starts with a space.
31
+ - **`execsql format` without sqlglot** printed its `pip install` hint without the `[formatter]` extra.
32
+ - **`execsql lint` and the language server read a `SUB_INI` file once** however many lines name it; a script naming a large INI file on many lines took minutes to lint and froze the editor. V002 for a variable a `SUB_INI` defines is reported at the `SUB_INI` line, not line 0.
33
+ - **`execsql lsp` with an incompatible pygls** names the installed pygls version instead of saying the `lsp` extra is missing.
34
+ - **`COPY` keeps binary columns** (SQLite/DuckDB BLOB, PostgreSQL `bytea`) byte for byte, and `COPY ... TO NEW` creates them as binary columns. They were copied as escaped text (`\x89PNG...`), and into PostgreSQL as text.
35
+ - **DuckDB `TO NEW`** is no longer refused because a table of the same name exists in an `ATTACH`ed database; only the current database counts.
36
+
37
+ ______________________________________________________________________
38
+
39
+ ## [2.27.0] - 2026-10-12
40
+
41
+ ### Added
42
+
43
+ - **`execsql lsp`**, a language server for editors. Install the new `lsp` extra (`uv tool install "execsql2[lsp]"`; to add it to an existing install, name the extras you already have, e.g. `"execsql2[postgres,lsp]"`); setup for VS Code, Neovim, Helix and other editors is in the new Editor Support guide. It provides:
44
+
45
+ - `execsql lint` findings as you type, using the workspace's `[lint]` settings;
46
+ - completion of metacommands (as fill-in templates of their documented syntax), conditional tests, variables and export formats;
47
+ - hover explanations of metacommands, conditional tests and variables;
48
+ - Go to Definition, Find All References, Rename Symbol (variables), the outline and `INCLUDE` links;
49
+ - folding of `IF` branches, `LOOP`, `SCRIPT`, `BATCH` and `SQL` blocks, multi-line statements and comments;
50
+ - quick fixes for misspelled metacommands, conditional tests and variables (P003, P004, V001) and split dollar-quoted bodies (P002);
51
+ - Format Document, the same as `execsql format` with the workspace's `[format]` settings;
52
+ - `execsql.conf` read again when it changes, and open scripts linted again when a file they `INCLUDE` changes;
53
+ - each folder of a multi-root workspace linted and formatted with its own `execsql.conf`.
54
+
55
+ The server never runs a script or connects to a database. It reads the open scripts, the files they `INCLUDE` or name in `SUB_INI` (regular files of bounded size), and the configuration files `execsql lint` reads.
56
+
57
+ - **VS Code extension** starts `execsql lsp` for `.sql` files, with `execsql.server.path` and `execsql.server.enabled` settings and an **execsql: Restart Language Server** command. Each GitHub release attaches it as `execsql-syntax.vsix`; install with `code --install-extension execsql-syntax.vsix`. The server starts only in a trusted folder; highlighting works in any. `execsql.server.path` is a command name looked up in PATH or an absolute path, and the extension never runs an `execsql` found in the open folder.
58
+
59
+ ### Changed
60
+
61
+ - **`lsp` is a command name:** `execsql lsp` starts the language server. Run a script file named `lsp` (with no extension) as `execsql run lsp`.
62
+ - **`execsql list metacommands`** lists every metacommand (all 95; some were missing) with its category and a one-line summary, and `execsql list metacommands <KEYWORD>` shows that metacommand's syntax, as the reference docs write it, with a link. In `--output-format json`, `syntax` is now the full first syntax line, and each entry adds `forms`, `category`, `summary` and `url`. Read `forms` for every syntax line.
63
+
64
+ ### Fixed
65
+
66
+ - **DuckDB `TIMESTAMPTZ` values** are read instead of stopping the script: the `duckdb` and `all-db` extras now install `pytz`, which duckdb needs for them.
67
+ - **`CONFIG MAX_INT <n>`** works as documented; it stopped with `Unknown metacommand`, and only the bare `MAX_INT <n>` (still accepted) was recognized.
68
+
69
+ ______________________________________________________________________
70
+
16
71
  ## [2.26.0] - 2026-10-09
17
72
 
18
73
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.26.0
3
+ Version: 2.28.0
4
4
  Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
5
5
  Project-URL: Homepage, https://execsql2.readthedocs.io
6
6
  Project-URL: Repository, https://github.com/geocoug/execsql
@@ -49,14 +49,17 @@ Requires-Dist: duckdb>=1.0; extra == 'all'
49
49
  Requires-Dist: firebird-driver>=1.10; extra == 'all'
50
50
  Requires-Dist: jinja2>=3.1; extra == 'all'
51
51
  Requires-Dist: keyring>=25.0; extra == 'all'
52
+ Requires-Dist: lsprotocol>=2025.0.0; extra == 'all'
52
53
  Requires-Dist: odfpy>=1.4; extra == 'all'
53
54
  Requires-Dist: openpyxl>=3.1; extra == 'all'
54
55
  Requires-Dist: oracledb>=3.0; extra == 'all'
55
56
  Requires-Dist: pg-upsert>=1.25.0; extra == 'all'
56
57
  Requires-Dist: polars>=1.0; extra == 'all'
57
58
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all'
59
+ Requires-Dist: pygls<3,>=2.1; extra == 'all'
58
60
  Requires-Dist: pymysql>=1.1; extra == 'all'
59
61
  Requires-Dist: pyodbc>=5.0; extra == 'all'
62
+ Requires-Dist: pytz; extra == 'all'
60
63
  Requires-Dist: pyyaml>=6.0; extra == 'all'
61
64
  Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'all'
62
65
  Requires-Dist: tables>=3.10; extra == 'all'
@@ -69,6 +72,7 @@ Requires-Dist: oracledb>=3.0; extra == 'all-db'
69
72
  Requires-Dist: psycopg[binary]<4,>=3.1; extra == 'all-db'
70
73
  Requires-Dist: pymysql>=1.1; extra == 'all-db'
71
74
  Requires-Dist: pyodbc>=5.0; extra == 'all-db'
75
+ Requires-Dist: pytz; extra == 'all-db'
72
76
  Provides-Extra: auth
73
77
  Requires-Dist: keyring>=25.0; extra == 'auth'
74
78
  Provides-Extra: auth-encrypted
@@ -83,13 +87,18 @@ Requires-Dist: build>=1.2.2.post1; extra == 'dev'
83
87
  Requires-Dist: bump-my-version>=1.2.7; extra == 'dev'
84
88
  Requires-Dist: defusedxml>=0.7; extra == 'dev'
85
89
  Requires-Dist: jinja2>=3.1; extra == 'dev'
90
+ Requires-Dist: lsprotocol>=2025.0.0; extra == 'dev'
86
91
  Requires-Dist: mkdocstrings-python>=2.0.3; extra == 'dev'
87
92
  Requires-Dist: mypy>=1.10; extra == 'dev'
88
93
  Requires-Dist: odfpy>=1.4; extra == 'dev'
89
94
  Requires-Dist: openpyxl>=3.1; extra == 'dev'
90
95
  Requires-Dist: polars>=1.0; extra == 'dev'
91
96
  Requires-Dist: pre-commit>=3.5.0; extra == 'dev'
97
+ Requires-Dist: pygls<3,>=2.1; extra == 'dev'
98
+ Requires-Dist: pytest-asyncio>=1.0; extra == 'dev'
92
99
  Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
100
+ Requires-Dist: pytest-lsp>=1.0; extra == 'dev'
101
+ Requires-Dist: pytest>=8; extra == 'dev'
93
102
  Requires-Dist: pyyaml>=6.0; extra == 'dev'
94
103
  Requires-Dist: ruff>=0.4; extra == 'dev'
95
104
  Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'dev'
@@ -97,9 +106,10 @@ Requires-Dist: tables>=3.10; extra == 'dev'
97
106
  Requires-Dist: tox-uv>=1.13.1; extra == 'dev'
98
107
  Requires-Dist: twine>=6.1.0; extra == 'dev'
99
108
  Requires-Dist: xlrd>=2.0; extra == 'dev'
100
- Requires-Dist: zensical==0.0.28; extra == 'dev'
109
+ Requires-Dist: zensical==0.0.67; extra == 'dev'
101
110
  Provides-Extra: duckdb
102
111
  Requires-Dist: duckdb>=1.0; extra == 'duckdb'
112
+ Requires-Dist: pytz; extra == 'duckdb'
103
113
  Provides-Extra: firebird
104
114
  Requires-Dist: firebird-driver>=1.10; extra == 'firebird'
105
115
  Provides-Extra: formats
@@ -113,6 +123,10 @@ Requires-Dist: tables>=3.10; extra == 'formats'
113
123
  Requires-Dist: xlrd>=2.0; extra == 'formats'
114
124
  Provides-Extra: formatter
115
125
  Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'formatter'
126
+ Provides-Extra: lsp
127
+ Requires-Dist: lsprotocol>=2025.0.0; extra == 'lsp'
128
+ Requires-Dist: pygls<3,>=2.1; extra == 'lsp'
129
+ Requires-Dist: sqlglot<30.22,>=30.21.0; extra == 'lsp'
116
130
  Provides-Extra: map
117
131
  Requires-Dist: tkintermapview>=1.29; extra == 'map'
118
132
  Provides-Extra: mssql
@@ -158,15 +172,16 @@ Description-Content-Type: text/markdown
158
172
 
159
173
  Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), which add importing and exporting data, copying between databases, conditional execution, looping, substitution variables, and interactive prompts. Because the metacommands live in comments, the scripts stay valid SQL and other tools (`psql`, `sqlcmd`, your editor) ignore them.
160
174
 
161
- | Command | What it does | Needs a database? |
162
- | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
163
- | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
164
- | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
165
- | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
166
- | `execsql config` | Show every config option, its value, and the file that set it | No |
167
- | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
168
- | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
169
- | [VS Code extension](extras/vscode-execsql) | Syntax highlighting for metacommands and variables | No |
175
+ | Command | What it does | Needs a database? |
176
+ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
177
+ | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
178
+ | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
179
+ | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
180
+ | `execsql config` | Show every config option, its value, and the file that set it | No |
181
+ | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
182
+ | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
183
+ | `execsql lsp` | [Language server](https://execsql2.readthedocs.io/en/latest/guides/editors/): lint findings, completion, hover, navigation, quick fixes and formatting in your editor | No |
184
+ | [VS Code extension](extras/vscode-execsql) | Highlighting plus everything `execsql lsp` provides | No |
170
185
 
171
186
  `format` and `lint` take files or directories.
172
187
 
@@ -451,7 +466,7 @@ execsql format --no-sql --in-place scripts/
451
466
  ```yaml
452
467
  repos:
453
468
  - repo: https://github.com/geocoug/execsql
454
- rev: v2.26.0
469
+ rev: v2.28.0
455
470
  hooks:
456
471
  - id: execsql-format
457
472
  - id: execsql-lint
@@ -459,17 +474,18 @@ repos:
459
474
 
460
475
  The format hook rewrites `*.sql` files in place by default; the lint hook fails the commit when a script has a lint error. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
461
476
 
462
- ## VS Code Syntax Highlighting
477
+ ## VS Code
463
478
 
464
- A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options, all layered on top of standard SQL highlighting.
465
-
466
- To install, symlink the extension folder into your VS Code extensions directory:
479
+ The VS Code extension in [`extras/vscode-execsql`](extras/vscode-execsql) highlights execsql syntax in `.sql` files (metacommand markers, keywords, variable substitutions, export formats, config options) on top of standard SQL highlighting, and starts the execsql language server for lint findings as you type and completion. Each GitHub release has the extension attached as `execsql-syntax.vsix`:
467
480
 
468
481
  ```sh
469
- ln -s /path/to/execsql/extras/vscode-execsql ~/.vscode/extensions/execsql-syntax
482
+ uv tool install "execsql2[lsp]" # the language server
483
+ code --install-extension execsql-syntax.vsix # the extension, from the release
470
484
  ```
471
485
 
472
- See the [extension README](extras/vscode-execsql/README.md) for Windows instructions, color customization, and troubleshooting.
486
+ If execsql is already installed with other extras, name them too, e.g. `uv tool install "execsql2[postgres,lsp]"` or `pipx install --force "execsql2[postgres,lsp]"`: the new list replaces the old one (see [Adding an extra later](https://execsql2.readthedocs.io/en/latest/getting-started/installation/#adding-an-extra-later)).
487
+
488
+ Other editors use the language server directly: see [Editor Support](https://execsql2.readthedocs.io/en/latest/guides/editors/). The [extension README](extras/vscode-execsql/README.md) covers settings, installing from a clone, color customization, and troubleshooting.
473
489
 
474
490
  ## Templates
475
491
 
@@ -27,15 +27,16 @@
27
27
 
28
28
  Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), which add importing and exporting data, copying between databases, conditional execution, looping, substitution variables, and interactive prompts. Because the metacommands live in comments, the scripts stay valid SQL and other tools (`psql`, `sqlcmd`, your editor) ignore them.
29
29
 
30
- | Command | What it does | Needs a database? |
31
- | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
32
- | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
33
- | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
34
- | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
35
- | `execsql config` | Show every config option, its value, and the file that set it | No |
36
- | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
37
- | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
38
- | [VS Code extension](extras/vscode-execsql) | Syntax highlighting for metacommands and variables | No |
30
+ | Command | What it does | Needs a database? |
31
+ | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
32
+ | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
33
+ | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
34
+ | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
35
+ | `execsql config` | Show every config option, its value, and the file that set it | No |
36
+ | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
37
+ | `execsql init` | Set up a project: config file, a script with a header, pre-commit hooks | No |
38
+ | `execsql lsp` | [Language server](https://execsql2.readthedocs.io/en/latest/guides/editors/): lint findings, completion, hover, navigation, quick fixes and formatting in your editor | No |
39
+ | [VS Code extension](extras/vscode-execsql) | Highlighting plus everything `execsql lsp` provides | No |
39
40
 
40
41
  `format` and `lint` take files or directories.
41
42
 
@@ -320,7 +321,7 @@ execsql format --no-sql --in-place scripts/
320
321
  ```yaml
321
322
  repos:
322
323
  - repo: https://github.com/geocoug/execsql
323
- rev: v2.26.0
324
+ rev: v2.28.0
324
325
  hooks:
325
326
  - id: execsql-format
326
327
  - id: execsql-lint
@@ -328,17 +329,18 @@ repos:
328
329
 
329
330
  The format hook rewrites `*.sql` files in place by default; the lint hook fails the commit when a script has a lint error. See the [formatter documentation](https://execsql2.readthedocs.io/en/latest/guides/formatter/) for `--check`, `--indent`, and other options.
330
331
 
331
- ## VS Code Syntax Highlighting
332
+ ## VS Code
332
333
 
333
- A VS Code extension for execsql syntax highlighting is included in [`extras/vscode-execsql`](extras/vscode-execsql). It injects a TextMate grammar into `.sql` files, adding highlighting for `-- !x!` metacommand markers, keywords (control flow, block, action, directive), variable substitutions (`!!var!!`, `!{var}!`), built-in functions, export formats, and config options, all layered on top of standard SQL highlighting.
334
-
335
- To install, symlink the extension folder into your VS Code extensions directory:
334
+ The VS Code extension in [`extras/vscode-execsql`](extras/vscode-execsql) highlights execsql syntax in `.sql` files (metacommand markers, keywords, variable substitutions, export formats, config options) on top of standard SQL highlighting, and starts the execsql language server for lint findings as you type and completion. Each GitHub release has the extension attached as `execsql-syntax.vsix`:
336
335
 
337
336
  ```sh
338
- ln -s /path/to/execsql/extras/vscode-execsql ~/.vscode/extensions/execsql-syntax
337
+ uv tool install "execsql2[lsp]" # the language server
338
+ code --install-extension execsql-syntax.vsix # the extension, from the release
339
339
  ```
340
340
 
341
- See the [extension README](extras/vscode-execsql/README.md) for Windows instructions, color customization, and troubleshooting.
341
+ If execsql is already installed with other extras, name them too, e.g. `uv tool install "execsql2[postgres,lsp]"` or `pipx install --force "execsql2[postgres,lsp]"`: the new list replaces the old one (see [Adding an extra later](https://execsql2.readthedocs.io/en/latest/getting-started/installation/#adding-an-extra-later)).
342
+
343
+ Other editors use the language server directly: see [Editor Support](https://execsql2.readthedocs.io/en/latest/guides/editors/). The [extension README](extras/vscode-execsql/README.md) covers settings, installing from a clone, color customization, and troubleshooting.
342
344
 
343
345
  ## Templates
344
346
 
@@ -71,6 +71,7 @@ ______________________________________________________________________
71
71
  | Fix | Description |
72
72
  | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
73
73
  | Variable EXECUTE SCRIPT targets | `EXECUTE SCRIPT !!#var!!` now works — the parser accepts substitution variable patterns as script identifiers, and the executor resolves them at runtime. |
74
+ | `CONFIG MAX_INT` | The documented `CONFIG MAX_INT <n>` form is accepted. Upstream documented it but recognized only the bare `MAX_INT <n>`, which still works. |
74
75
  | Quoted parameter defaults | `BEGIN SCRIPT proc(name="value")` previously stored the literal `"value"` (with surrounding quotes), causing substitutions like `WRITE "!!#name!!"` to expand to `WRITE ""value""` and fail. Defaults now strip surrounding quotes at parse time, matching the `wo_quotes` handling already applied to passed arguments. |
75
76
 
76
77
  ### Conditional Tests
@@ -134,8 +135,9 @@ today — a script named exactly like a command — is recorded under
134
135
  | `execsql format` | The formatter, reached through the main command. It replaced the standalone `execsql-format` console script, which was removed. The published pre-commit hook **id** is still `execsql-format`, so downstream `.pre-commit-config.yaml` files need no change — only the hook's internal `entry` moved. Formatter for normalizing metacommand indentation and uppercasing SQL keywords. Supports `--check`, `--in-place`, `--indent N` (controls both metacommand and SQL indentation), `--leading-comma` (commas at start of lines), `--no-sql` (skip SQL reformatting), `--rewrite-sql` (accept sqlglot's rewrites of SQL text; off by default, so only layout changes), `-f`/`--script-encoding` (formerly `--encoding`, still accepted), and `--config`; `-` formats stdin to stdout. Also available as a [pre-commit hook](../guides/formatter.md) — the published hook defaults to `args: [--in-place]` so downstream consumers get formatting on commit without extra wiring. SQL reformatting (the optional sqlglot pass) requires the `[formatter]` extra as of 2.19.0; `--no-sql` works without it. |
135
136
  | `execsql lint` | Static checks over files *and directories*, walking directories recursively for `*.sql`; `-` reads stdin. Scripts are read with `-f`/`--script-encoding` or `[encoding] script` from config, like `run`. Every issue carries a [rule code](../reference/lint.md#rules); `--select` / `--ignore` choose rules, `--output-format json` feeds tools, and `--statistics` counts issues per rule. It replaced the `--lint` flag, which checked only the one script it was given. |
136
137
  | `execsql config` | List every config option with its current value, default, and the file that set it, resolved as a run would (pass a script to include its directory's `execsql.conf`). Passwords are masked. `--init` prints the template (replaces `--init-config`). `--validate` reports every problem in every config file a run reads, with file and line: invalid values and unparsable files as errors, unknown or misplaced sections and keys as warnings — upstream stopped at the first bad value and ignored unknown names silently. |
137
- | `execsql list` | `metacommands`, `encodings`, `plugins` or `keywords`, as text or JSON. Replaces `-m`, `-y`, `--list-plugins` and `--dump-keywords`; `-m` and `-y` are upstream flags and keep working as hidden aliases, deprecated when used without a command. |
138
+ | `execsql list` | `metacommands`, `encodings`, `plugins` or `keywords`, as text or JSON. Replaces `-m`, `-y`, `--list-plugins` and `--dump-keywords`; `-m` and `-y` are upstream flags and keep working as hidden aliases, deprecated when used without a command. `-m` / `list metacommands` prints each metacommand's category and one-line summary (and its syntax when given a keyword) instead of upstream's listing. |
138
139
  | `execsql init` | Set up a project: `execsql.conf` from the template, a script with a header (from the upstream script template), and the `execsql-format` / `execsql-lint` pre-commit hooks. Never overwrites without `--force`, and never rewrites an existing `.pre-commit-config.yaml`. |
140
+ | `execsql lsp` | A language server for editors, started over stdio: `execsql lint` findings shown as you type, with the `[lint]` settings of the workspace's config, completion of metacommands (as templates of their documented syntax), conditional tests, variables and export formats, hover explanations, navigation (definition, references, outline, `INCLUDE` links), Rename Symbol for variables, folding, quick fixes for P003, P004, V001 and P002, and Format Document (`execsql format` with the workspace's `[format]` settings). Settings are read per workspace folder and again when `execsql.conf` or an included file changes. The VS Code extension in `extras/vscode-execsql` starts it only in a trusted workspace. Needs the `lsp` extra (pygls). See [Editor Support](../guides/editors.md#editors). |
139
141
 
140
142
  Formatter correctness notes added in the 2.19.x line:
141
143
 
@@ -284,6 +286,7 @@ The legacy flat command-list engine (`_parse_script_lines` / `runscripts` / `Com
284
286
  - **Exception hierarchy** — All custom exceptions inherit from `ExecSqlError`, enabling `except ExecSqlError` to catch any execsql-originated error.
285
287
  - **Exception chaining** — All `raise` statements inside `except` blocks preserve the original traceback via `from`.
286
288
  - **Database and driver error messages** — End with the error itself (`OperationalError: table t already exists`). Upstream appended "in <file> on line N of execsql", a line of its own source; in the package the file was often a driver's and the line number another file's. Where in execsql the error was raised goes to `execsql.log` as `Raised at: execsql/<module>.py:<line>`.
289
+ - **Missing optional package messages** — Name the execsql2 extra that installs the package and how to add it to a `uv tool` or `pipx` install without dropping the extras already there (`uv tool install "execsql2[...,postgres]"`). Upstream pointed at the package's web page.
287
290
  - **Config file errors** — An invalid value in `execsql.conf` stops a run with `Configuration error: <file>: <problem>` (and the line, for an unreadable file) plus a pointer to `execsql config --validate`. Upstream printed `Configuration error on line N of execsql.py`, where N was a line of its own source. A duplicate key, a missing section header or a bare `%` is reported the same way; upstream failed with an uncaught exception. Errors raised by `ConfigData` for a file are `ConfigFileError`, a subclass of `ConfigError`.
288
291
  - **ASSERT error type** — `ASSERT` failures now use a dedicated `"assert"` error type that produces `**** Assertion failed.` instead of `**** Error in metacommand.`. This distinguishes intentional script-level checks from actual metacommand errors. Upstream did not have `ASSERT`.
289
292
 
@@ -358,10 +361,11 @@ These are behavioral changes driven by security or correctness issues in the ups
358
361
  | `DT_Timestamp` claims time-only values | `dateutil.parser.parse()` silently fills in today's date for bare time strings like `"13:15:45"`, so `DT_Timestamp` matched before `DT_Time` in the inference order. `parse_datetime()` now rejects time-only strings. |
359
362
  | Partial dates inferred as timestamps | `dateutil` fills fields missing from a value with today's date, so `1-2`, `5/6`, `March 5`, `Jan` and `Monday` were inferred as timestamps and, on DuckDB, SQL Server, MySQL, Oracle, Firebird, Access and every ODS/XLSX/JSON/Parquet/Feather import, stored as dates in the current year. Inference now requires a four-digit year (or a month-first `m/d/yy` or `m-d-yy`) and a month and day, which restores upstream's behaviour for these values. `m-d-yy` is accepted in addition to upstream's `m/d/yy`. |
360
363
  | Offset values stored as plain timestamps | With `dateutil`, a value with a UTC offset (`2024-01-01 10:00+05:00`) also counted as a plain timestamp, so a column mixing offset and plain values was created as `timestamp` and the driver converted the offset values with the client's time zone: the stored value depended on the machine that ran the import. A value with an offset is again not a plain timestamp, as with upstream's offset-free format list, so a mixed column is text and keeps each value as written. A column where every value has an offset is still `timestamptz`. |
364
+ | Binary columns in `COPY` | Every value a source cursor returned as bytes was decoded to text (undecodable bytes as `\xNN` escapes) before `COPY` wrote it, and `TO NEW` typed the column as text. Upstream did the same for SQLite BLOBs; with psycopg2 a PostgreSQL `bytea` arrived as a `memoryview` and escaped the decode, so for PostgreSQL this was an execsql2 regression. `COPY` now moves bytes unchanged and creates binary columns. Exports still write the decoded text. |
361
365
  | Short data lines on import | A line with fewer values than the header was padded with NULLs only on PostgreSQL and MySQL. SQLite stopped with "Too few values", DuckDB and the other DBMSs with a driver parameter-count error. With `TO NEW` / `REPLACEMENT`, type inference skipped the missing values, so the column could be created `NOT NULL` and then reject the padded line, on PostgreSQL too. Missing trailing values are now NULL on every DBMS, and inference counts them as NULL. |
362
366
  | `COPY` re-typed text values | Upstream described the destination table by re-reading the source's text values as if they came from a file, so a text column of `1`/`0` became `boolean` and one of dates became `timestamp` with `NEW` / `REPLACEMENT`, and values copied into an existing text column were converted on the way in (`1` stored as `true`). Text from the source database now stays text. Upstream also ran the source query twice, once to describe the table and once to copy it; execsql2 runs it once and holds the rows in a temporary file in between. |
363
367
  | `REPLACEMENT` of a quoted or schema-qualified table | The SQLite, SQL Server, Oracle, Firebird and Access adapters quoted the table name a second time before dropping it, so `IMPORT` / `COPY ... TO REPLACEMENT "my tbl"` dropped a table named `"my tbl"` (quotes included) that did not exist and then failed to create the table, and on SQL Server, Oracle and Firebird `REPLACEMENT staging.t` tried to drop one table named `staging.t`. The name is now quoted once. |
364
- | `TO NEW` onto an existing table | `COPY`'s checks that the source exists and that a `NEW` target does not were dead code: each raised its error inside a `try` that discarded it. `IMPORT ... TO NEW` had no check. Both now stop with `Table <name> already exists` before any DDL (when the database cannot say whether the table exists, the command goes ahead). A name without a schema counts only in the schema the table would be created in (MySQL: the current database). The source check was removed instead of revived: PostgreSQL reads an unquoted `COPY Orders` as `orders`, which the check would have reported missing. |
368
+ | `TO NEW` onto an existing table | `COPY`'s checks that the source exists and that a `NEW` target does not were dead code: each raised its error inside a `try` that discarded it. `IMPORT ... TO NEW` had no check. Both now stop with `Table <name> already exists` before any DDL (when the database cannot say whether the table exists, the command goes ahead). A name without a schema counts only in the schema the table would be created in (MySQL: the current database), and on DuckDB only in the current database, not an `ATTACH`ed one. The source check was removed instead of revived: PostgreSQL reads an unquoted `COPY Orders` as `orders`, which the check would have reported missing. |
365
369
  | No `exit` log record on error or halt | The log was closed before the `exit` record was written, so a run that ended with an error, a `HALT` or a cancelled prompt left no `exit` line, and Ctrl-C was recorded as `unknown`. Every run now writes exactly one `exit` record; Ctrl-C is `interrupted`. |
366
370
  | SIGTERM lost the run's log | Python's default SIGTERM action ends the process without running exit handlers, so the buffered `execsql.log` (every record of the run) was never written, the transaction was not rolled back explicitly and a running `SYSTEM_CMD` kept going. The `execsql` command now turns SIGTERM into a normal exit with status 143 and an `exit` record of type `terminated`. `execsql.run()` does not install a handler. |
367
371
  | `access_use_numeric` ignored | The config option was read but never applied, so MS-Access tables created by `IMPORT` / `COPY` always got `DOUBLE` for decimal data. With `Yes` they get `NUMERIC(precision,scale)` again, as upstream. The setting is read when each table is created, so it applies per run (upstream changed the shared type map once at startup). |
@@ -223,9 +223,32 @@ ______________________________________________________________________
223
223
  - [ ] Handler function added to the appropriate `src/execsql/metacommands/*.py` module
224
224
  - [ ] Handler imported in `src/execsql/metacommands/dispatch.py`
225
225
  - [ ] `mcl.add(...)` call added in `build_dispatch_table()` with `description=` and `category=`
226
+ - [ ] Entry added to `src/execsql/metacommands/reference.py`: the syntax line(s) as the reference docs write them, a one-line summary and the docs anchor (see below)
227
+ - [ ] A line using it added to `tests/data/lint/every_metacommand.sql`
226
228
  - [ ] Run `just install-vscode` to regenerate the VS Code grammar
227
229
  - [ ] Integration test added to `tests/test_metacommands.py` (or relevant file)
228
- - [ ] `pytest` passes locally (including `tests/test_registry.py` keyword consistency checks)
230
+ - [ ] `pytest` passes locally (including `tests/test_registry.py` and `tests/test_reference.py`)
231
+
232
+ ### The readable syntax entry
233
+
234
+ The dispatch table's regular expressions are not something to show a person.
235
+ `execsql.metacommands.reference` holds what editors (`execsql lsp`) and
236
+ `execsql list metacommands` show instead:
237
+
238
+ ```python
239
+ Metacommand(
240
+ "MY_COMMAND", # the description= keyword
241
+ "action", # the category=
242
+ ("MY_COMMAND <table> TO <file>",), # syntax lines, docs notation: <value>, [optional], A|B
243
+ "Does one thing to a table.", # one sentence, at most 120 characters
244
+ "my_command", # the heading's anchor in docs/reference/metacommands.md
245
+ ),
246
+ ```
247
+
248
+ Editor completion turns each syntax line into a fill-in template (`<value>`
249
+ becomes a tab stop, `A|B` a choice). `tests/test_reference.py` fails until the
250
+ entry exists, its anchor is a real heading, and each syntax line, filled with
251
+ sample values, is accepted by the dispatch table.
229
252
 
230
253
  ______________________________________________________________________
231
254
 
@@ -251,3 +274,5 @@ mcl.add(
251
274
  ```
252
275
 
253
276
  The result is exposed as `CONDITIONAL_TABLE` and consumed at runtime via `_state.conditionallist`.
277
+
278
+ Add a `Condition(...)` entry to `src/execsql/metacommands/reference.py` as well (name, syntax line such as `MY_TEST(<table>)`, one-line summary, docs anchor) and a use of it to `tests/data/lint/conditions_and_blocks.sql`; `tests/test_reference.py` checks that every conditional test has an entry.
@@ -53,15 +53,16 @@ fails. Stay on the command until it exits.
53
53
 
54
54
  ### What runs on a tag push
55
55
 
56
- | Job | Gating? | Purpose |
57
- | ---------------------- | ---------------------------------- | --------------------------------------------------------------------------------- |
58
- | `lint` | yes | ruff check + ruff format check |
59
- | `tests` (matrix) | yes | py3.10–3.14 × {ubuntu, macos, windows} |
60
- | `integration-tests` | yes | PostgreSQL, MySQL, MSSQL service containers |
61
- | `access-tests-windows` | yes (when Access install succeeds) | Real Access driver on `windows-latest` |
62
- | `build` | yes | Checks the tag equals `project.version`; `python -m build` produces sdist + wheel |
63
- | `publish` | yes (tag-gated) | OIDC trusted-publisher PyPI upload |
64
- | `generate-release` | yes (tag-gated, after `publish`) | Creates the GitHub release with auto-extracted CHANGELOG section |
56
+ | Job | Gating? | Purpose |
57
+ | ---------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
58
+ | `lint` | yes | ruff check + ruff format check |
59
+ | `tests` (matrix) | yes | py3.10–3.14 × {ubuntu, macos, windows} |
60
+ | `integration-tests` | yes | PostgreSQL, MySQL, MSSQL service containers |
61
+ | `access-tests-windows` | yes (when Access install succeeds) | Real Access driver on `windows-latest` |
62
+ | `build` | yes | Checks the tag equals `project.version`; `python -m build` produces sdist + wheel |
63
+ | `publish` | yes (tag-gated) | OIDC trusted-publisher PyPI upload |
64
+ | `vscode-extension` | yes | Packages `extras/vscode-execsql` into `execsql-syntax.vsix` (on a tag, with the tag's X.Y.Z version) |
65
+ | `generate-release` | yes (tag-gated, after `publish` and `vscode-extension`) | Creates the GitHub release with auto-extracted CHANGELOG section; attaches the sdist, wheel and `.vsix` |
65
66
 
66
67
  Publish / generate-release run only on tag refs
67
68
  (`if: startsWith(github.ref, 'refs/tags/v')`), so a non-bump push to
@@ -129,6 +130,6 @@ After `gh run watch` exits green:
129
130
  - `pip install execsql2==2.X.Y` in a throwaway venv — confirms the
130
131
  wheel landed on PyPI.
131
132
  - Browse the new GitHub release page; check the CHANGELOG section
132
- matches what's on `main`.
133
+ matches what's on `main` and that `execsql-syntax.vsix` is attached.
133
134
  - `git pull` locally to retrieve the bump commit (you already had it
134
135
  locally if you bumped yourself, but other contributors will sync).