execsql2 2.23.1__tar.gz → 2.25.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 (468) hide show
  1. execsql2-2.25.0/.github/dependabot.yml +48 -0
  2. {execsql2-2.23.1 → execsql2-2.25.0}/.github/workflows/ci-cd.yml +77 -7
  3. {execsql2-2.23.1 → execsql2-2.25.0}/.pre-commit-config.yaml +1 -0
  4. execsql2-2.25.0/.pre-commit-hooks.yaml +17 -0
  5. {execsql2-2.23.1 → execsql2-2.25.0}/CHANGELOG.md +114 -1
  6. {execsql2-2.23.1 → execsql2-2.25.0}/CONTRIBUTING.md +4 -0
  7. {execsql2-2.23.1 → execsql2-2.25.0}/PKG-INFO +122 -63
  8. {execsql2-2.23.1 → execsql2-2.25.0}/README.md +118 -59
  9. {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/divergence.md +110 -52
  10. execsql2-2.25.0/docs/api/index.md +119 -0
  11. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_db_adapters.md +18 -20
  12. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_metacommands.md +10 -10
  13. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/architecture.md +30 -36
  14. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/releasing.md +35 -25
  15. execsql2-2.25.0/docs/getting-started/installation.md +84 -0
  16. {execsql2-2.23.1 → execsql2-2.25.0}/docs/getting-started/requirements.md +5 -30
  17. execsql2-2.25.0/docs/getting-started/syntax.md +519 -0
  18. execsql2-2.25.0/docs/guides/debugging.md +121 -0
  19. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/examples.md +20 -16
  20. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/formatter.md +83 -35
  21. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/logging.md +10 -10
  22. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/usage.md +2 -2
  23. {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/configuration.md +68 -6
  24. execsql2-2.25.0/docs/reference/lint.md +373 -0
  25. {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/metacommands.md +71 -21
  26. {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/security.md +26 -5
  27. {execsql2-2.23.1 → execsql2-2.25.0}/docs/reference/substitution_vars.md +2 -0
  28. {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/README.md +2 -2
  29. {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +2 -2
  30. {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/tests/test_plugin.py.example +3 -2
  31. execsql2-2.25.0/extras/vscode-execsql/.vscodeignore +3 -0
  32. execsql2-2.25.0/extras/vscode-execsql/LICENSE.txt +12 -0
  33. execsql2-2.25.0/extras/vscode-execsql/icon.png +0 -0
  34. execsql2-2.25.0/extras/vscode-execsql/package.json +46 -0
  35. {execsql2-2.23.1 → execsql2-2.25.0}/justfile +21 -0
  36. {execsql2-2.23.1 → execsql2-2.25.0}/pyproject.toml +34 -7
  37. {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/run_benchmarks.py +1 -1
  38. {execsql2-2.23.1 → execsql2-2.25.0}/scripts/generate_vscode_grammar.py +6 -6
  39. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/api.py +169 -160
  40. execsql2-2.25.0/src/execsql/cli/__init__.py +83 -0
  41. execsql2-2.25.0/src/execsql/cli/application.py +309 -0
  42. execsql2-2.25.0/src/execsql/cli/commands/__init__.py +13 -0
  43. execsql2-2.25.0/src/execsql/cli/commands/config.py +205 -0
  44. execsql2-2.25.0/src/execsql/cli/commands/format.py +100 -0
  45. execsql2-2.25.0/src/execsql/cli/commands/init.py +135 -0
  46. execsql2-2.25.0/src/execsql/cli/commands/lint.py +225 -0
  47. execsql2-2.25.0/src/execsql/cli/commands/listing.py +81 -0
  48. execsql2-2.25.0/src/execsql/cli/commands/run.py +459 -0
  49. execsql2-2.25.0/src/execsql/cli/dispatch.py +66 -0
  50. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/cli/dsn.py +11 -4
  51. execsql2-2.25.0/src/execsql/cli/help.py +302 -0
  52. execsql2-2.25.0/src/execsql/cli/lint.py +1186 -0
  53. execsql2-2.25.0/src/execsql/cli/options.py +108 -0
  54. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/cli/run.py +96 -32
  55. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/config.py +256 -173
  56. execsql2-2.25.0/src/execsql/config_validation.py +282 -0
  57. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/data/execsql.conf.template +38 -5
  58. execsql2-2.25.0/src/execsql/data/script_header.sql +23 -0
  59. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/access.py +29 -8
  60. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/base.py +40 -8
  61. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/dsn.py +13 -4
  62. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/duckdb.py +3 -1
  63. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/factory.py +13 -4
  64. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/firebird.py +21 -7
  65. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/mysql.py +37 -16
  66. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/oracle.py +49 -16
  67. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/postgres.py +30 -6
  68. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/sqlite.py +7 -9
  69. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/sqlserver.py +25 -8
  70. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/debug/repl.py +51 -193
  71. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exceptions.py +9 -0
  72. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/delimited.py +87 -28
  73. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xlsx.py +24 -9
  74. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/zip.py +1 -2
  75. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/format.py +115 -76
  76. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/desktop.py +1 -3
  77. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/tui.py +2 -2
  78. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/base.py +35 -1
  79. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/csv.py +3 -1
  80. execsql2-2.25.0/src/execsql/interactive.py +232 -0
  81. execsql2-2.25.0/src/execsql/manifest.py +200 -0
  82. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/conditions.py +7 -8
  83. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/control.py +2 -3
  84. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/data.py +4 -1
  85. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/debug.py +2 -4
  86. execsql2-2.25.0/src/execsql/metacommands/effects.py +124 -0
  87. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_fileops.py +62 -37
  88. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_import.py +0 -1
  89. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/prompt.py +2 -0
  90. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/upsert.py +5 -2
  91. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/models.py +3 -2
  92. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/parser.py +14 -5
  93. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/plugins.py +24 -0
  94. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/__init__.py +0 -9
  95. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/ast.py +1 -1
  96. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/engine.py +46 -104
  97. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/executor.py +162 -39
  98. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/parser.py +167 -118
  99. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/state.py +34 -11
  100. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/state.pyi +11 -0
  101. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/types.py +22 -13
  102. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/auth.py +169 -24
  103. execsql2-2.25.0/src/execsql/utils/color.py +18 -0
  104. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/datetime.py +55 -17
  105. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/errors.py +82 -10
  106. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/fileio.py +404 -117
  107. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/gui.py +3 -0
  108. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/mail.py +37 -12
  109. {execsql2-2.23.1 → execsql2-2.25.0}/templates/README.md +1 -1
  110. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli.py +111 -63
  111. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli_e2e.py +48 -15
  112. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_cli_run.py +42 -41
  113. execsql2-2.25.0/tests/cli/test_cli_surface.py +232 -0
  114. execsql2-2.25.0/tests/cli/test_commands.py +589 -0
  115. execsql2-2.25.0/tests/cli/test_config_validate.py +294 -0
  116. execsql2-2.25.0/tests/cli/test_dispatch.py +456 -0
  117. execsql2-2.25.0/tests/cli/test_error_location.py +32 -0
  118. execsql2-2.25.0/tests/cli/test_init.py +119 -0
  119. execsql2-2.25.0/tests/cli/test_lint.py +1192 -0
  120. execsql2-2.25.0/tests/cli/test_lint_fixtures.py +161 -0
  121. execsql2-2.25.0/tests/cli/test_log_exit_record.py +71 -0
  122. execsql2-2.25.0/tests/cli/test_manifest.py +172 -0
  123. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_ping.py +3 -3
  124. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/test_profile.py +8 -5
  125. execsql2-2.25.0/tests/cli/test_sigterm.py +105 -0
  126. execsql2-2.25.0/tests/cli/test_undeclared_imports.py +45 -0
  127. {execsql2-2.23.1 → execsql2-2.25.0}/tests/conftest.py +51 -1
  128. execsql2-2.25.0/tests/data/formatter_shapes/escapes_and_literals.sql +58 -0
  129. execsql2-2.25.0/tests/data/formatter_shapes/substitution_and_metacommands.sql +43 -0
  130. execsql2-2.25.0/tests/data/formatter_shapes/unparsable_sql.sql +41 -0
  131. execsql2-2.25.0/tests/data/lint/conditions_and_blocks.sql +222 -0
  132. execsql2-2.25.0/tests/data/lint/does_not_parse.sql +39 -0
  133. execsql2-2.25.0/tests/data/lint/every_metacommand.sql +289 -0
  134. execsql2-2.25.0/tests/data/lint/invalid.sql +134 -0
  135. execsql2-2.25.0/tests/db/test_copy_new.py +125 -0
  136. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_db_adapters_mocked.py +9 -13
  137. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_db_adapters_mocked_extra.py +43 -3
  138. execsql2-2.25.0/tests/db/test_factory_postgres_encoding.py +27 -0
  139. execsql2-2.25.0/tests/db/test_import_atomic.py +100 -0
  140. execsql2-2.25.0/tests/db/test_import_replacement_quoted.py +22 -0
  141. execsql2-2.25.0/tests/db/test_import_short_rows.py +60 -0
  142. execsql2-2.25.0/tests/db/test_import_timezones.py +68 -0
  143. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_mysql_inprocess.py +1 -4
  144. execsql2-2.25.0/tests/db/test_new_table_checks.py +152 -0
  145. execsql2-2.25.0/tests/db/test_oracle_driver.py +80 -0
  146. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_postgres_inprocess.py +0 -4
  147. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlite_extra.py +11 -11
  148. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlserver_inprocess.py +25 -0
  149. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_transactions.py +12 -15
  150. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_delimited.py +0 -18
  151. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_xlsx.py +1 -1
  152. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xlsx.py +69 -2
  153. execsql2-2.25.0/tests/importers/test_csv_blank_lines.py +108 -0
  154. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_csv_edge_cases.py +36 -9
  155. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/conftest.py +1 -1
  156. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_dsn.py +1 -1
  157. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_mysql.py +73 -1
  158. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_postgres.py +129 -1
  159. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_sqlite.py +1 -1
  160. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_breakpoint.py +1 -101
  161. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_conditions_extra.py +2 -2
  162. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands.py +5 -2
  163. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_data.py +7 -7
  164. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_pg_upsert.py +1 -1
  165. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_row_count.py +8 -5
  166. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/test_sql_scripts.py +4 -2
  167. execsql2-2.25.0/tests/security/test_log_secrets.py +214 -0
  168. execsql2-2.25.0/tests/test_api_errors.py +106 -0
  169. execsql2-2.25.0/tests/test_api_filewriter.py +345 -0
  170. execsql2-2.25.0/tests/test_api_isolation.py +92 -0
  171. execsql2-2.25.0/tests/test_api_subprocess.py +76 -0
  172. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_ast_parser.py +124 -0
  173. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_bundled_templates.py +3 -3
  174. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config.py +2 -12
  175. execsql2-2.25.0/tests/test_date_inference.py +113 -0
  176. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_debug_repl.py +2 -171
  177. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_engine.py +52 -81
  178. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_error_messages.py +3 -3
  179. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_executor.py +4 -3
  180. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_executor_inprocess.py +52 -18
  181. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_format.py +37 -15
  182. execsql2-2.25.0/tests/test_interactive.py +260 -0
  183. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_mail.py +8 -2
  184. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_models.py +2 -2
  185. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_registry.py +22 -6
  186. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_script.py +0 -49
  187. execsql2-2.25.0/tests/test_tooling_versions.py +38 -0
  188. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_types.py +57 -10
  189. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_auth.py +32 -13
  190. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_auth_extra.py +5 -2
  191. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_datetime.py +64 -0
  192. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_errors.py +22 -0
  193. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_fileio_extra.py +129 -19
  194. execsql2-2.25.0/tests/utils/test_keyring_rules.py +289 -0
  195. execsql2-2.25.0/tests/utils/test_mail_tls.py +192 -0
  196. execsql2-2.25.0/uv.lock +4177 -0
  197. {execsql2-2.23.1 → execsql2-2.25.0}/zensical.toml +2 -1
  198. execsql2-2.23.1/.github/dependabot.yml +0 -21
  199. execsql2-2.23.1/.pre-commit-hooks.yaml +0 -9
  200. execsql2-2.23.1/docs/api/index.md +0 -85
  201. execsql2-2.23.1/docs/getting-started/installation.md +0 -45
  202. execsql2-2.23.1/docs/getting-started/syntax.md +0 -270
  203. execsql2-2.23.1/docs/guides/debugging.md +0 -110
  204. execsql2-2.23.1/extras/vscode-execsql/package.json +0 -24
  205. execsql2-2.23.1/src/execsql/cli/__init__.py +0 -650
  206. execsql2-2.23.1/src/execsql/cli/help.py +0 -151
  207. execsql2-2.23.1/src/execsql/cli/lint.py +0 -506
  208. execsql2-2.23.1/tests/cli/test_lint.py +0 -329
  209. execsql2-2.23.1/tests/test_api_filewriter.py +0 -158
  210. execsql2-2.23.1/uv.lock +0 -3471
  211. {execsql2-2.23.1 → execsql2-2.25.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  212. {execsql2-2.23.1 → execsql2-2.25.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  213. {execsql2-2.23.1 → execsql2-2.25.0}/.gitignore +0 -0
  214. {execsql2-2.23.1 → execsql2-2.25.0}/.python-version +0 -0
  215. {execsql2-2.23.1 → execsql2-2.25.0}/.readthedocs.yaml +0 -0
  216. {execsql2-2.23.1 → execsql2-2.25.0}/LICENSE.txt +0 -0
  217. {execsql2-2.23.1 → execsql2-2.25.0}/NOTICE +0 -0
  218. {execsql2-2.23.1 → execsql2-2.25.0}/SECURITY.md +0 -0
  219. {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/contributors.md +0 -0
  220. {execsql2-2.23.1 → execsql2-2.25.0}/docs/about/copyright.md +0 -0
  221. {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/cli.md +0 -0
  222. {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/db.md +0 -0
  223. {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/exporters.md +0 -0
  224. {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/importers.md +0 -0
  225. {execsql2-2.23.1 → execsql2-2.25.0}/docs/api/metacommands.md +0 -0
  226. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_exporters.md +0 -0
  227. {execsql2-2.23.1 → execsql2-2.25.0}/docs/dev/adding_importers.md +0 -0
  228. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/documentation.md +0 -0
  229. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/encoding.md +0 -0
  230. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/sql_syntax.md +0 -0
  231. {execsql2-2.23.1 → execsql2-2.25.0}/docs/guides/using_scripts.md +0 -0
  232. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/Compare_planets.png +0 -0
  233. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/actions.png +0 -0
  234. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/actions2.png +0 -0
  235. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/checkboxes.png +0 -0
  236. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/connect.b64 +0 -0
  237. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/connect.png +0 -0
  238. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/create_conf.png +0 -0
  239. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/data_error1_screenshot.jpg +0 -0
  240. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/entry_form.png +0 -0
  241. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/execsql_console.png +0 -0
  242. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/execsql_logo_01.png +0 -0
  243. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/fatals.png +0 -0
  244. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/logo_small.png +0 -0
  245. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal.png +0 -0
  246. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal_sm.b64 +0 -0
  247. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/pause_terminal_sm.png +0 -0
  248. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/prompt_compare.png +0 -0
  249. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/set_build_commands.jpg +0 -0
  250. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unit_conversions.b64 +0 -0
  251. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unit_conversions_029.png +0 -0
  252. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/unmatched.png +0 -0
  253. {execsql2-2.23.1 → execsql2-2.25.0}/docs/images/vim_execsql_highlight.png +0 -0
  254. {execsql2-2.23.1 → execsql2-2.25.0}/docs/index.md +0 -0
  255. {execsql2-2.23.1 → execsql2-2.25.0}/extras/plugin-template/pyproject.toml +0 -0
  256. {execsql2-2.23.1 → execsql2-2.25.0}/extras/vscode-execsql/README.md +0 -0
  257. {execsql2-2.23.1 → execsql2-2.25.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
  258. {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/README.md +0 -0
  259. {execsql2-2.23.1 → execsql2-2.25.0}/scripts/benchmarks/results/.gitignore +0 -0
  260. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/__init__.py +0 -0
  261. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/__main__.py +0 -0
  262. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/data/__init__.py +0 -0
  263. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/__init__.py +0 -0
  264. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/db/tiers.py +0 -0
  265. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/debug/__init__.py +0 -0
  266. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/__init__.py +0 -0
  267. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/base.py +0 -0
  268. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/duckdb.py +0 -0
  269. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/feather.py +0 -0
  270. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/html.py +0 -0
  271. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/json.py +0 -0
  272. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/latex.py +0 -0
  273. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/markdown.py +0 -0
  274. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/ods.py +0 -0
  275. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/parquet.py +0 -0
  276. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/pretty.py +0 -0
  277. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/protocol.py +0 -0
  278. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/raw.py +0 -0
  279. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/sqlite.py +0 -0
  280. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/templates.py +0 -0
  281. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/values.py +0 -0
  282. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xls.py +0 -0
  283. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/xml.py +0 -0
  284. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/exporters/yaml.py +0 -0
  285. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/__init__.py +0 -0
  286. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/base.py +0 -0
  287. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/gui/console.py +0 -0
  288. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/__init__.py +0 -0
  289. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/feather.py +0 -0
  290. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/json.py +0 -0
  291. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/ods.py +0 -0
  292. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/importers/xls.py +0 -0
  293. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/__init__.py +0 -0
  294. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/connect.py +0 -0
  295. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/dispatch.py +0 -0
  296. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io.py +0 -0
  297. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_export.py +0 -0
  298. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/io_write.py +0 -0
  299. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/script_ext.py +0 -0
  300. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/metacommands/system.py +0 -0
  301. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/py.typed +0 -0
  302. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/control.py +0 -0
  303. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/script/variables.py +0 -0
  304. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/__init__.py +0 -0
  305. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/crypto.py +0 -0
  306. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/numeric.py +0 -0
  307. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/regex.py +0 -0
  308. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/strings.py +0 -0
  309. {execsql2-2.23.1 → execsql2-2.25.0}/src/execsql/utils/timer.py +0 -0
  310. {execsql2-2.23.1 → execsql2-2.25.0}/templates/config_settings.sqlite +0 -0
  311. {execsql2-2.23.1 → execsql2-2.25.0}/templates/example_config_prompt.sql +0 -0
  312. {execsql2-2.23.1 → execsql2-2.25.0}/templates/make_config_db.sql +0 -0
  313. {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_compare.sql +0 -0
  314. {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_glossary.sql +0 -0
  315. {execsql2-2.23.1 → execsql2-2.25.0}/templates/md_upsert.sql +0 -0
  316. {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_compare.sql +0 -0
  317. {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_glossary.sql +0 -0
  318. {execsql2-2.23.1 → execsql2-2.25.0}/templates/pg_upsert.sql +0 -0
  319. {execsql2-2.23.1 → execsql2-2.25.0}/templates/script_template.sql +0 -0
  320. {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_compare.sql +0 -0
  321. {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_glossary.sql +0 -0
  322. {execsql2-2.23.1 → execsql2-2.25.0}/templates/ss_upsert.sql +0 -0
  323. {execsql2-2.23.1 → execsql2-2.25.0}/tests/__init__.py +0 -0
  324. {execsql2-2.23.1 → execsql2-2.25.0}/tests/cli/__init__.py +0 -0
  325. {execsql2-2.23.1 → execsql2-2.25.0}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
  326. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/__init__.py +0 -0
  327. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_access_windows.py +0 -0
  328. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_base.py +0 -0
  329. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_dsn.py +0 -0
  330. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_duckdb.py +0 -0
  331. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_factory.py +0 -0
  332. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_mysql_case_folding.py +0 -0
  333. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_postgres.py +0 -0
  334. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_roundtrip_adapters.py +0 -0
  335. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_sqlite.py +0 -0
  336. {execsql2-2.23.1 → execsql2-2.25.0}/tests/db/test_tiers.py +0 -0
  337. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/__init__.py +0 -0
  338. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/conftest.py +0 -0
  339. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_base.py +0 -0
  340. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_db.py +0 -0
  341. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_duckdb_exporter.py +0 -0
  342. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_exporters.py +0 -0
  343. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_feather.py +0 -0
  344. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_html_extended.py +0 -0
  345. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_html_latex.py +0 -0
  346. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_json.py +0 -0
  347. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_json_extended.py +0 -0
  348. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_latex_extended.py +0 -0
  349. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_markdown.py +0 -0
  350. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_ods.py +0 -0
  351. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_ods_export.py +0 -0
  352. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_parquet.py +0 -0
  353. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_pretty_extended.py +0 -0
  354. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_raw_extended.py +0 -0
  355. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_columnar.py +0 -0
  356. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_dbfile.py +0 -0
  357. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_delimited.py +0 -0
  358. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_json.py +0 -0
  359. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
  360. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_markup.py +0 -0
  361. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_ods.py +0 -0
  362. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
  363. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_template.py +0 -0
  364. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_roundtrip_values.py +0 -0
  365. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_sqlite_exporter.py +0 -0
  366. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_templates.py +0 -0
  367. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_templates_extended.py +0 -0
  368. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_values_extended.py +0 -0
  369. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xls_xlsx.py +0 -0
  370. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_xml.py +0 -0
  371. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_yaml.py +0 -0
  372. {execsql2-2.23.1 → execsql2-2.25.0}/tests/exporters/test_zip.py +0 -0
  373. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/__init__.py +0 -0
  374. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_backends.py +0 -0
  375. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_backends_extended.py +0 -0
  376. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_compare_stats.py +0 -0
  377. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_compute_row_diffs.py +0 -0
  378. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_desktop_dialogs.py +0 -0
  379. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_format_table.py +0 -0
  380. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_tui_pilot.py +0 -0
  381. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_tui_pilot_complex.py +0 -0
  382. {execsql2-2.23.1 → execsql2-2.25.0}/tests/gui/test_utils_gui_extended.py +0 -0
  383. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/__init__.py +0 -0
  384. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/conftest.py +0 -0
  385. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_base_extended.py +0 -0
  386. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_csv_importer.py +0 -0
  387. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_feather_importer.py +0 -0
  388. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_json_importer.py +0 -0
  389. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_ods_importer.py +0 -0
  390. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_roundtrip_csv.py +0 -0
  391. {execsql2-2.23.1 → execsql2-2.25.0}/tests/importers/test_xls_importer.py +0 -0
  392. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/__init__.py +0 -0
  393. {execsql2-2.23.1 → execsql2-2.25.0}/tests/integration/test_duckdb.py +0 -0
  394. {execsql2-2.23.1 → execsql2-2.25.0}/tests/live_db.py +0 -0
  395. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/__init__.py +0 -0
  396. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_assert.py +0 -0
  397. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_connect.py +0 -0
  398. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_io_export.py +0 -0
  399. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_io_import.py +0 -0
  400. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_connect.py +0 -0
  401. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_extended.py +0 -0
  402. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
  403. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_io.py +0 -0
  404. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  405. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
  406. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_system.py +0 -0
  407. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  408. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_prompt.py +0 -0
  409. {execsql2-2.23.1 → execsql2-2.25.0}/tests/metacommands/test_show_scripts.py +0 -0
  410. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/__init__.py +0 -0
  411. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  412. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  413. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  414. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  415. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/config_runtime.sql +0 -0
  416. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/control_flow.sql +0 -0
  417. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  418. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/error_handling.sql +0 -0
  419. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  420. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/import_options.sql +0 -0
  421. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/includes/helper.sql +0 -0
  422. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/includes.sql +0 -0
  423. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/io_formats.sql +0 -0
  424. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  425. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/multi_db.sql +0 -0
  426. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  427. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  428. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/predicates.sql +0 -0
  429. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/scripts.sql +0 -0
  430. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/smoke.sql +0 -0
  431. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  432. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  433. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  434. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/template_export.sql +0 -0
  435. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/timer.sql +0 -0
  436. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/transactions.sql +0 -0
  437. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/write_create_table.sql +0 -0
  438. {execsql2-2.23.1 → execsql2-2.25.0}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  439. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/__init__.py +0 -0
  440. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_env_detection.py +0 -0
  441. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_expansion_bomb.py +0 -0
  442. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_import_regex_hardening.py +0 -0
  443. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_log_redaction.py +0 -0
  444. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_odbc_injection.py +0 -0
  445. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_path_containment.py +0 -0
  446. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_substitution_injection.py +0 -0
  447. {execsql2-2.23.1 → execsql2-2.25.0}/tests/security/test_zip_bomb.py +0 -0
  448. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_api.py +0 -0
  449. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_api_extended.py +0 -0
  450. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_ast.py +0 -0
  451. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config_data.py +0 -0
  452. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_config_extended.py +0 -0
  453. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_exceptions.py +0 -0
  454. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_package.py +0 -0
  455. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_parser.py +0 -0
  456. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_parser_params.py +0 -0
  457. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_plugins.py +0 -0
  458. {execsql2-2.23.1 → execsql2-2.25.0}/tests/test_state.py +0 -0
  459. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/__init__.py +0 -0
  460. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_crypto.py +0 -0
  461. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_encodedfile_context.py +0 -0
  462. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_errors_extra.py +0 -0
  463. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_fileio.py +0 -0
  464. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_numeric.py +0 -0
  465. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_regex.py +0 -0
  466. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_strings.py +0 -0
  467. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_timer.py +0 -0
  468. {execsql2-2.23.1 → execsql2-2.25.0}/tests/utils/test_timer_extra.py +0 -0
@@ -0,0 +1,48 @@
1
+ # Dependabot keeps the SHA-pinned GitHub Actions in ci-cd.yml up to
2
+ # date. The audit's B22 finding (F059) called out that pinning to
3
+ # major-version tags (e.g. `actions/checkout@v6`) is supply-chain
4
+ # exposure — an attacker who compromises the repo can retag any v6.x
5
+ # release to point at malicious code and every consumer pulls it on
6
+ # the next run. Pinning to a 40-char SHA closes that hole, but the
7
+ # pins must be refreshed when upstream ships a real new release;
8
+ # Dependabot files a PR with the new SHA and a CHANGELOG link.
9
+ version: 2
10
+ updates:
11
+ - package-ecosystem: github-actions
12
+ directory: /
13
+ schedule:
14
+ interval: weekly
15
+ groups:
16
+ actions-minor-and-patch:
17
+ patterns:
18
+ - "*"
19
+ update-types:
20
+ - minor
21
+ - patch
22
+ # Python packages in uv.lock (the development environment; users resolve
23
+ # their own versions from pyproject.toml). ruff is bumped through the
24
+ # pre-commit entry below: tests/test_tooling_versions.py requires the
25
+ # uv.lock ruff to equal the pre-commit rev, so on that PR run
26
+ # `uv lock --upgrade-package ruff==<new version>` and push.
27
+ - package-ecosystem: uv
28
+ directory: /
29
+ schedule:
30
+ interval: weekly
31
+ ignore:
32
+ - dependency-name: ruff
33
+ groups:
34
+ python-minor-and-patch:
35
+ patterns:
36
+ - "*"
37
+ update-types:
38
+ - minor
39
+ - patch
40
+ # Hook revs in .pre-commit-config.yaml.
41
+ - package-ecosystem: pre-commit
42
+ directory: /
43
+ schedule:
44
+ interval: weekly
45
+ groups:
46
+ pre-commit-hooks:
47
+ patterns:
48
+ - "*"
@@ -24,7 +24,13 @@ jobs:
24
24
  - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
25
25
  with:
26
26
  python-version: "3.13"
27
- - run: python -m pip install ruff
27
+ # The ruff that pre-commit runs, so the two jobs cannot disagree;
28
+ # tests/test_tooling_versions.py keeps uv.lock on the same version.
29
+ - name: Install the ruff pinned in .pre-commit-config.yaml
30
+ run: |
31
+ version=$(grep -A1 'astral-sh/ruff-pre-commit' .pre-commit-config.yaml | grep -oP 'rev: v\K[0-9.]+')
32
+ echo "ruff $version"
33
+ python -m pip install "ruff==$version"
28
34
  - run: ruff check src/ tests/
29
35
  - run: ruff format --check src/ tests/
30
36
 
@@ -35,13 +41,56 @@ jobs:
35
41
  contents: read
36
42
  steps:
37
43
  - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
44
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
45
+ with:
46
+ python-version: "3.13"
47
+ - uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
48
+ # The environment `just setup` builds: mypy and the packages it
49
+ # type-checks against come from uv.lock, so CI and local runs agree.
50
+ # --locked also fails the job when uv.lock is out of date.
51
+ - run: uv sync --locked --all-extras
52
+ - run: uv run --no-sync mypy src/execsql/
53
+
54
+ formatter-corpus:
55
+ name: formatter-corpus
56
+ runs-on: ubuntu-latest
57
+ permissions:
58
+ contents: read
59
+ steps:
60
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
38
61
  - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
39
62
  with:
40
63
  python-version: "3.13"
41
64
  cache: "pip"
42
65
  - run: python -m pip install --upgrade pip
43
66
  - run: python -m pip install ".[dev]"
44
- - run: mypy src/execsql/
67
+ # Every formatter bug to date came from real SQL containing a
68
+ # construct the project's own scripts lack. This gate runs those
69
+ # checks under their own name so a corpus failure is legible
70
+ # without reading a 6,000-test log.
71
+ - run: pytest tests/test_format.py -k corpus --no-cov -q
72
+
73
+ typer-floor:
74
+ name: typer-floor
75
+ runs-on: ubuntu-latest
76
+ permissions:
77
+ contents: read
78
+ steps:
79
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
80
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
81
+ with:
82
+ python-version: "3.10"
83
+ cache: "pip"
84
+ - run: python -m pip install --upgrade pip
85
+ # Help rendering and flag parsing lean on Typer internals that
86
+ # move between releases, and every other job runs the newest
87
+ # Typer. Install the declared minimum, read from pyproject.toml so
88
+ # the two cannot drift, and run the CLI tests against it.
89
+ - run: |
90
+ floor=$(grep -oP '"typer>=\K[0-9.]+' pyproject.toml)
91
+ echo "Typer floor: $floor"
92
+ python -m pip install ".[dev]" "typer==$floor"
93
+ - run: pytest tests/cli --no-cov -q
45
94
 
46
95
  pre-commit:
47
96
  name: pre-commit
@@ -213,7 +262,7 @@ jobs:
213
262
  - name: Install dependencies
214
263
  run: |
215
264
  python -m pip install --upgrade pip
216
- python -m pip install ".[dev,postgres,mysql,mssql]"
265
+ python -m pip install ".[dev,postgres,mysql,mssql,upsert]"
217
266
  - name: Run subprocess integration tests
218
267
  run: |
219
268
  python -m pytest tests/integration/test_postgres.py tests/integration/test_mysql.py -v --override-ini="addopts="
@@ -289,7 +338,7 @@ jobs:
289
338
  build:
290
339
  name: Build distribution 📦
291
340
  runs-on: ubuntu-latest
292
- needs: [ lint, typecheck, pre-commit, docs, tests, integration-tests ]
341
+ needs: [ lint, typecheck, pre-commit, formatter-corpus, typer-floor, docs, tests, integration-tests ]
293
342
  # Deliberately NOT gated on tags: packaging breaks must surface on a PR,
294
343
  # not at release time. Only publish/generate-release below are tag-gated.
295
344
  permissions:
@@ -301,6 +350,16 @@ jobs:
301
350
  with:
302
351
  python-version: "3.13"
303
352
  cache: "pip"
353
+ - name: Check the tag matches the package version
354
+ # A tag on a commit whose pyproject.toml has another version
355
+ # would build, and release, the wrong version under the tag.
356
+ if: startsWith(github.ref, 'refs/tags/v')
357
+ run: |
358
+ version="$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")"
359
+ if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
360
+ echo "::error::Tag $GITHUB_REF_NAME does not match project.version $version in pyproject.toml"
361
+ exit 1
362
+ fi
304
363
  - name: Build sdist + wheel
305
364
  run: |
306
365
  python -m pip install --upgrade pip
@@ -339,11 +398,12 @@ jobs:
339
398
  uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
340
399
  with:
341
400
  packages-dir: dist
342
- skip-existing: true
343
401
 
344
402
  generate-release:
345
403
  name: Generate GitHub Release
346
- needs: [ build ]
404
+ # After the PyPI upload, so a release is never announced for a
405
+ # version that pip cannot install.
406
+ needs: [ publish ]
347
407
  if: startsWith(github.ref, 'refs/tags/v')
348
408
  runs-on: ubuntu-latest
349
409
  permissions:
@@ -356,11 +416,21 @@ jobs:
356
416
  with:
357
417
  name: ${{ github.event.repository.name }}
358
418
  path: dist/
419
+ - name: Detect pre-release tag
420
+ id: tag
421
+ # PEP 440 pre-release suffix (a1, b2, rc1) on the tag -> mark the
422
+ # GitHub Release as a pre-release so it never becomes "latest".
423
+ run: |
424
+ if [[ "${GITHUB_REF_NAME#v}" =~ (a|b|rc)[0-9]+$ ]]; then
425
+ echo "prerelease=true" >> "$GITHUB_OUTPUT"
426
+ else
427
+ echo "prerelease=false" >> "$GITHUB_OUTPUT"
428
+ fi
359
429
  - name: Create release
360
430
  uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
361
431
  with:
362
432
  draft: false
363
- prerelease: false
433
+ prerelease: ${{ steps.tag.outputs.prerelease }}
364
434
  generate_release_notes: true
365
435
  files: |
366
436
  dist/*
@@ -67,6 +67,7 @@ repos:
67
67
  rev: v1.44.0
68
68
  hooks:
69
69
  - id: typos
70
+ args: [--force-exclude]
70
71
  # Lint & format with ruff
71
72
  - repo: https://github.com/astral-sh/ruff-pre-commit
72
73
  rev: v0.15.7
@@ -0,0 +1,17 @@
1
+ - id: execsql-format
2
+ name: execsql-format
3
+ description: Format execsql SQL scripts — normalize metacommand indentation and uppercase keywords.
4
+ entry: execsql format
5
+ language: python
6
+ types: [file]
7
+ files: \.sql$
8
+ args: [--in-place]
9
+ additional_dependencies: ["sqlglot>=25.0,<31"]
10
+
11
+ - id: execsql-lint
12
+ name: execsql-lint
13
+ description: Statically check execsql SQL scripts without a database — unclosed blocks, undefined or unused variables, missing INCLUDE targets, unreachable code.
14
+ entry: execsql lint
15
+ language: python
16
+ types: [file]
17
+ files: \.sql$
@@ -13,6 +13,119 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.25.0] - 2026-10-09
17
+
18
+ ### Added
19
+
20
+ - **`execsql lint` rule `P002` (`split-dollar-quote`):** reports a `$$ ... $$` function or `DO` body that is not between `BEGIN SQL` and `END SQL`, which execsql would send in pieces at the first line ending in `;`.
21
+ - **`execsql lint` rule `P003` (`unknown-metacommand`):** reports a misspelled or malformed metacommand, such as `SUBSTITUTE x 1` for `SUB x 1`, or `EXPORT t TOO out.csv`, that `execsql run` would stop at with `Unknown metacommand`.
22
+ - **`execsql lint` rule `P004` (`unknown-condition`):** reports a condition with an unknown test, such as `IF(hasrowz(t))`, or one that cannot be parsed, such as `ASSERT !!flag!! = TRUE`, in `IF`, `ELSEIF`, `ANDIF`, `ORIF`, `LOOP`, `EXECUTE SCRIPT ... WHILE`, `ASSERT` and `WAIT_UNTIL`.
23
+ - **`[email] ca_file` and `verify_certificate` settings** for the SMTP server's TLS certificate: trust an internal CA, or turn verification off for a test relay.
24
+
25
+ ### Changed
26
+
27
+ - **`EMAIL` over TLS verifies the server certificate.** With `use_ssl` or `use_tls`, a mail server whose certificate is untrusted or does not match `host` stops the `EMAIL` metacommand before the password is sent. For a relay with an internal certificate, set `[email] ca_file`; to turn the check off, set `verify_certificate = No`.
28
+ - **A `--dsn` / `execsql.run(dsn=...)` user, password or database is percent-decoded**, so `@`, `:`, `/`, `?`, `#` and `%` can be given encoded (`p%40ss`). A password that contains `%` followed by two hex digits must now be written with `%25`.
29
+ - **A relative `WRITE ... TO` path after `CD`** lands in the new directory, as `EXPORT` output already did. Use an absolute path to keep writing to the directory execsql started in.
30
+ - **A locked output file can delay the end of a run.** At the end of a script and before `SYSTEM_CMD`, the CLI waits up to `outfile_open_timeout` (default 600 s) for a `WRITE` / `EXPORT` file another process has locked; if it stays locked, the run fails naming the file and how many lines were lost. Lower `outfile_open_timeout` for unattended runs.
31
+ - **Output that cannot be written fails the run.** When writing a `WRITE`, `EXPORT` or `TEE` file fails (a full disk, a network share that drops), its output is lost, other files are still written, and the run ends with an error naming the file: exit status 1, or `success=False` from `execsql.run()`. A target that can never be opened, such as a directory, fails at once.
32
+ - **Error messages from the database or a driver** show just the error, such as `OperationalError: table t already exists`, without a path into execsql's source. `execsql.log` records where in execsql the error was raised, for bug reports.
33
+ - **`execsql lint` on a script with block-structure errors** reports every unmatched or unclosed `IF`, `LOOP`, `BEGIN BATCH`, `BEGIN SCRIPT` and `BEGIN SQL` as a `P001` on its own line, and runs every other rule on the rest of the script.
34
+ - **Faster start-up:** every `execsql` command and `import execsql` start about 0.7 s sooner.
35
+
36
+ ### Removed
37
+
38
+ - **`execsql.utils.fileio` writer globals:** `filewriter`, `fw_input` and `fw_output` are gone, and `FileWriter` no longer takes queue arguments. Code that started a writer by hand before calling `execsql.run()` (the workaround for [#46](https://github.com/geocoug/execsql/issues/46) before 2.23.0) can drop it.
39
+
40
+ ### Fixed
41
+
42
+ - **Output lost when a script halts is reported.** A `WRITE`, `TEE` or `ON ERROR_HALT WRITE` file still locked when the script halts gets up to 10 seconds; output still lost is reported on the console, in the log, in the `--manifest` file and in `execsql.run()`'s errors.
43
+ - **SIGTERM** (`kill`, `timeout`, `docker stop`, a cancelled CI job) ends a `run` like Ctrl-C: the open transaction is rolled back, a running `SYSTEM_CMD` is stopped, and `execsql.log` gets an `exit` record of type `terminated` (exit status 143).
44
+ - **`execsql.log` `exit` record** is written for a run that ends with an error, a `HALT` or a cancelled prompt (type `error` or `halt`, with the message). Ctrl-C is recorded as `interrupted`.
45
+ - **`execsql.log` `run_db_file` record** names the database file for SQLite, DuckDB and Access runs.
46
+ - **`execsql.log` no longer shows `-a` values** in the `run` record; it gives how many there were.
47
+ - **Passwords in `execsql.log`** from a `--dsn` URL, the `[email]` section, the password prompt or keyring, `PROMPT ENTER_SUB ... PASSWORD`, `PROMPT CREDENTIALS` and `SUB_DECRYPT` are replaced with `***`, such as in SQL logged with `LOG_SQL ON` or a `SYSTEM_CMD` line.
48
+ - **Stored passwords (keyring) are saved only after the connection succeeds**, so a mistyped password is no longer stored.
49
+ - **A stored password is deleted, and you are prompted again, only when the server rejects it.** A timeout, a closed port or a missing database keeps it, so an unattended run no longer stops at a prompt.
50
+ - **Keyring entries are named with the server's port** (`execsql/PostgreSQL/host:5432/db`), so two servers on one host no longer share a password. An entry stored without the port is still used on the default port, and renamed once it works.
51
+ - **Oracle (`-t o`, `oracle://`) connects with the `oracledb` driver** that `execsql2[oracle]` installs.
52
+ - **`-n` with `-e` on PostgreSQL** creates the database with the given encoding, as `CONNECT TO POSTGRESQL(..., ENCODING=..., NEW)` does. PostgreSQL refuses an encoding other than its template database's (usually UTF8), so `-n -e LATIN1` on such a server stops with PostgreSQL's error.
53
+ - **`-d` / `--directories`** rejects a value other than `0`, `1`, `t`, `f`, `y` or `n` (exit 2), as upstream did, so `-d script.sql` names the bad value.
54
+ - **`access_use_numeric`** (config section `input`) works again: with `Yes`, `IMPORT` and `COPY` create MS-Access decimal columns as `NUMERIC(precision,scale)` instead of `DOUBLE`.
55
+ - **`IMPORT ... TO NEW` and `COPY ... TO NEW` onto a table that already exists** stop with `Table <name> already exists` before creating anything, on every DBMS. A name without a schema counts only in the schema the table would be created in (on MySQL, the current database).
56
+ - **`IMPORT` / `COPY ... TO REPLACEMENT` of a table whose name needs quoting** (a space, a hyphen, ...) replaces it on SQLite, SQL Server, Oracle, Firebird and Access, and a schema-qualified name such as `staging.t` is dropped correctly on SQL Server, Oracle and Firebird.
57
+ - **`COPY` and `COPY QUERY` copy text values as written:** a text column of `1`/`0`, dates or numbers is no longer created as boolean, timestamp or numeric by `NEW` / `REPLACEMENT`, and `1` copied into a text column stays `1`.
58
+ - **`COPY ... TO NEW` / `REPLACEMENT` no longer holds every source row in memory.**
59
+ - **`IMPORT` / `COPY` into DuckDB that fails part-way keeps no rows**, as on SQLite and PostgreSQL, so a re-run no longer duplicates them.
60
+ - **`IMPORT` of a data line with fewer values than the header** loads the missing values as NULL on every DBMS.
61
+ - **`IMPORT` of a delimited file with a blank line** imports the rows after it. The blank line itself is a row of NULLs, or dropped with `CONFIG EMPTY_ROWS NO`; blank lines at the end of the file are ignored.
62
+ - **PostgreSQL `IMPORT` of a quoted file with a blank line** no longer fails with `missing data for column`.
63
+ - **`IMPORT ... TO NEW` / `REPLACEMENT` type inference** no longer takes `1-2`, `5/6`, `March 5`, `Jan` or `Monday` for a date; such a column is created as text. A date must give the year (`2024-01-05`, `1/5/2024`), or a two-digit year month-first (`1/5/24`).
64
+ - **`IMPORT ... TO NEW` / `REPLACEMENT` of a timestamp column mixing values with and without a UTC offset** creates the column as text and keeps every value as written, instead of converting with the importing machine's time zone.
65
+ - **MySQL `IMPORT` of values with backslashes:** `C:\new\tbl`, `\N` and regular expressions load as written, and a file whose path contains a backslash imports.
66
+ - **`EXPORT ... AS XLSX`** writes text that starts with `=` as text, not as a formula.
67
+ - **`execsql.run()` from a script without an `if __name__ == "__main__":` guard** no longer runs the script's SQL twice on macOS and Windows.
68
+ - **Concurrent `execsql.run()` calls** each write files through their own writer, so two threads both get complete output, and a run that halts does not discard another run's output.
69
+ - **Repeated `execsql.run()` calls in one process** no longer pile up exit hooks or duplicate plugin metacommands.
70
+ - **`execsql.run()` cleans up when it returns:** its temp files are removed, and a run interrupted with Ctrl-C closes the connection it opened.
71
+ - **`execsql.run()` with `--manifest`** no longer records into a manifest that belongs to another run in the same thread.
72
+ - **`execsql.run()` error details:** a run halted by a failed SQL statement or metacommand reports that error (and the failed statement in `ScriptError.sql`), a `HALT` reports its exit status, and `result.errors` lists errors in the order they happened.
73
+ - **`execsql.run()` setup failures** (an unreadable script, a missing or invalid `config_file`, a `dsn` that cannot be parsed or opened) return `success=False` with an error whose `source` is the script, `<config>` or `<connect>`, instead of raising.
74
+ - **`execsql lint` `V001` (`undefined-variable`)** no longer reports variables set by `PROMPT ENTER_SUB`, `ASK ... SUB`, `PROMPT ASK ... SUB`, `PROMPT OPENFILE` / `SAVEFILE` / `DIRECTORY SUB`, `PROMPT CREDENTIALS`, `SUB_TEMPFILE` and the keys of `SUB_QUERYSTRING`.
75
+ - **`execsql lint` `V001`** reports a user variable named like a system variable without its `$` (`!!date_tag!!`), and a `SUB` variable written with a `$` (`!!$region!!`).
76
+ - **`execsql lint` `V002` (`unused-variable`)** no longer reports a variable read only by `sub_defined(...)` or `sub_empty(...)`.
77
+ - **`execsql lint` `F001`** no longer calls `IF(1=1)`, `IF(1=0)` or `IF(0=1)` a constant condition; `execsql run` rejects them, and lint reports them as `P004`.
78
+ - **Install hints in error messages** name the right extra: `formats` for XLSX (not `excel`), and none for Textual, which execsql2 includes.
79
+ - **Documentation:** install instructions use `uv tool install` / `pipx install` and quote every extra (`"execsql2[postgres]"`); `SERVE` and `allow_serve` are described correctly (`SERVE` opens no network port); the 2.17.0 `PG_UPSERT` migration note's `ASSERT !!$PG_UPSERT_QA_PASSED!! = TRUE`, which always fails, is corrected to `ASSERT IS_TRUE(!!$PG_UPSERT_QA_PASSED!!) "QA failed"`.
80
+
81
+ ______________________________________________________________________
82
+
83
+ ## [2.24.0] - 2026-10-01
84
+
85
+ ### Added
86
+
87
+ - **Commands:** `execsql run`, `format`, `lint`, `config`, `list` and `init`. `format` and `lint` take files or directories and need no database, so a whole script library can be linted at once. See [Commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#commands).
88
+ - **`run`:** `--manifest FILE` writes a JSON record of the run (files read and written, connections, statement counts and any error), even when the run fails. `--var NAME=VALUE` sets `!!NAME!!` from the command line.
89
+ - **`lint`:** every issue has a rule code (`V001`, `F002`, …) that `--select` and `--ignore` filter on. `--output-format json|concise|github`, `--statistics`, and `--strict` to fail on warnings. New checks for a `SUB` variable nothing reads, an `IF` whose condition never changes, and statements after `HALT`. See the [lint rules reference](https://execsql2.readthedocs.io/en/latest/reference/lint/).
90
+ - **`execsql-lint` pre-commit hook**, alongside `execsql-format`.
91
+ - **`format`:** `--diff` shows what would change without writing. `--sql` and `--no-leading-comma` override the config for one run.
92
+ - **`format` and `lint`:** read a script from stdin with `-`, and take `-f`/`--script-encoding` and `--config`.
93
+ - **`[format]` and `[lint]` config sections** set project defaults; a command-line flag wins.
94
+ - **`config`:** lists every option with its value, its default and the file that set it, with passwords shown as `***`. `--validate` reports every problem in every config file with its file and line. `--init` prints the config template.
95
+ - **`init`:** creates `execsql.conf`, a starter script and the pre-commit hooks. Existing files are kept unless you pass `--force`.
96
+ - **`list`:** `metacommands`, `encodings`, `plugins` and `keywords`, as text or JSON.
97
+ - **`PG_UPSERT` character-length check:** a staging value longer than its `varchar(n)` or `char(n)` base column fails QA and appears in the `EXPORT_FAILURES` fix sheet.
98
+
99
+ ### Deprecated
100
+
101
+ - Running a script without a command (`execsql script.sql myserver mydb`) prints a warning and stops working in execsql2 3.0. Put `run` first: `execsql run script.sql myserver mydb`. `-m`, `-y`, `--list-plugins`, `--dump-keywords`, `--init-config` and `--ping` without a command warn the same way and name their replacement; see [Flags that became commands](https://execsql2.readthedocs.io/en/latest/getting-started/syntax/#former_flags). After `run` they still work without a warning, but `execsql run --help` no longer lists them.
102
+
103
+ ### Removed
104
+
105
+ - `--lint`: use `execsql lint`. `execsql run --lint` now exits with status 2 without running the script, so update CI steps and hooks that call it.
106
+ - The `execsql-format` command: use `execsql format`, which takes the same options. Pre-commit users need no change, because the hook id is still `execsql-format`. Shell scripts, Makefiles and CI steps that call `execsql-format` must be updated.
107
+ - `SqlStmt`, `MetacommandStmt` and `ScriptCmd` from `execsql.script`. Only Python code that imports them is affected; scripts are not.
108
+
109
+ ### Changed
110
+
111
+ - **`PG_UPSERT` QA follows `METHOD` and `EXCLUDE`:** all three modes check only the staging rows the load would write, so pass `PG_UPSERT QA` the same `METHOD` and `EXCLUDE` as the load that follows it. `CHECK ... METHOD update` treats a missing `NOT NULL` column as a warning. The `upsert` extra now requires pg-upsert 1.25.0 or newer. See [QA follows METHOD and EXCLUDE](https://execsql2.readthedocs.io/en/latest/reference/metacommands/#pg_upsert_qa_method).
112
+ - **`PG_UPSERT` QA can fail where it passed before:** it now catches a unique key that collides with an existing base row, a foreign key parent that is not in `TABLES`, and an excluded `NOT NULL` column on an inserted row, all of which used to fail during the load.
113
+ - A script named exactly like a command (`run`, `format`, `lint`, `config`, `list` or `init`, with no extension) must be run as `execsql run NAME`.
114
+ - `execsql format --encoding` is now `-f`/`--script-encoding`, matching `run`. `--encoding` still works.
115
+ - The debug REPL (`BREAKPOINT`, `--debug`) runs metacommands and blocks as well as SQL, as if they were the next lines of the script where it paused: a `SUB` stays set when the script resumes, and SQL is committed as the script's own SQL would be. See [Debugging](https://execsql2.readthedocs.io/en/latest/guides/debugging/).
116
+ - CLI help is plain text, colored on a terminal (`NO_COLOR` or `EXECSQL_NO_COLOR` turns color off), and uses the terminal's full width. `execsql` with no arguments prints it and exits with status 2.
117
+ - Lint output groups issues under each file in line order, with one summary line. A script that fails to parse is reported on one line with its line number.
118
+ - Error messages name the fix: a missing SQLite or DuckDB file suggests `-n`/`--new-db`, and a config file error names the file and line and suggests `execsql config --validate`.
119
+ - Requires Typer 0.26 or newer (previously 0.12).
120
+
121
+ ### Fixed
122
+
123
+ - `execsql format` without the `[formatter]` extra says sqlglot is needed and how to install it, instead of an uncaught `ImportError`.
124
+ - `-h` works as a short form of `--help`, as it did in upstream execsql.
125
+ - The debug REPL's `.set VAR VALUE` keeps the value's case instead of lowercasing it, and `.vars all` lists environment variables instead of looking up a variable named `all`.
126
+
127
+ ______________________________________________________________________
128
+
16
129
  ## [2.23.1] - 2026-09-29
17
130
 
18
131
  ### Added
@@ -352,7 +465,7 @@ ______________________________________________________________________
352
465
 
353
466
  ### Changed
354
467
 
355
- - **Behavior change.** `PG_UPSERT`, `PG_UPSERT QA`, and `PG_UPSERT CHECK` no longer raise a metacommand error when QA checks fail. The outcome is reported via `$PG_UPSERT_QA_PASSED`, `$PG_UPSERT_TABLE_QA_PASSED`, and `$PG_UPSERT_RESULT_JSON`, so the script controls flow with `IF` or `ASSERT`. `EXPORT_FAILURES` still runs and the upsert is still skipped on QA failure. Migration: add `ASSERT !!$PG_UPSERT_QA_PASSED!! = TRUE` at the call site to preserve the previous halt-on-failure behavior.
468
+ - **Behavior change.** `PG_UPSERT`, `PG_UPSERT QA`, and `PG_UPSERT CHECK` no longer raise a metacommand error when QA checks fail. The outcome is reported via `$PG_UPSERT_QA_PASSED`, `$PG_UPSERT_TABLE_QA_PASSED`, and `$PG_UPSERT_RESULT_JSON`, so the script controls flow with `IF` or `ASSERT`. `EXPORT_FAILURES` still runs and the upsert is still skipped on QA failure. Migration: add `ASSERT IS_TRUE(!!$PG_UPSERT_QA_PASSED!!) "QA failed"` at the call site to preserve the previous halt-on-failure behavior. (Corrected after release: this note first gave an `=` comparison, which is not a valid condition and fails on every run.)
356
469
 
357
470
  ### Fixed
358
471
 
@@ -98,6 +98,10 @@ git push origin <branch> --follow-tags
98
98
 
99
99
  Pre-releases are published to PyPI but are not installed by default — `pip install execsql2` will not pick them up unless `--pre` is passed.
100
100
 
101
+ The GitHub Release for a pre-release tag is marked as a pre-release. Promote to the final version with the same recipe and the final version string (`just bump-pre 2.0.0`). `just bump-patch` from `2.0.0rc1` would skip ahead to `2.0.1`.
102
+
103
+ Always preview a bump first: `uv run bump-my-version bump --new-version 2.0.0a1 patch --dry-run -v` should print `New version will be '2.0.0a1'`.
104
+
101
105
  ### CI/CD pipeline (`ci-cd.yml`)
102
106
 
103
107
  Triggered on pushes to `main`, any `v*.*.*` tag, and pull requests.