execsql2 2.24.0__tar.gz → 2.25.1__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 (460) hide show
  1. execsql2-2.25.1/.github/dependabot.yml +48 -0
  2. {execsql2-2.24.0 → execsql2-2.25.1}/.github/workflows/ci-cd.yml +37 -72
  3. {execsql2-2.24.0 → execsql2-2.25.1}/.pre-commit-config.yaml +1 -0
  4. {execsql2-2.24.0 → execsql2-2.25.1}/CHANGELOG.md +77 -1
  5. {execsql2-2.24.0 → execsql2-2.25.1}/CONTRIBUTING.md +4 -0
  6. {execsql2-2.24.0 → execsql2-2.25.1}/PKG-INFO +18 -12
  7. {execsql2-2.24.0 → execsql2-2.25.1}/README.md +17 -11
  8. {execsql2-2.24.0 → execsql2-2.25.1}/docs/about/divergence.md +40 -18
  9. execsql2-2.25.1/docs/api/index.md +119 -0
  10. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/adding_db_adapters.md +16 -18
  11. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/adding_metacommands.md +1 -1
  12. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/architecture.md +2 -11
  13. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/releasing.md +35 -25
  14. execsql2-2.25.1/docs/getting-started/installation.md +84 -0
  15. {execsql2-2.24.0 → execsql2-2.25.1}/docs/getting-started/requirements.md +3 -28
  16. {execsql2-2.24.0 → execsql2-2.25.1}/docs/getting-started/syntax.md +12 -6
  17. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/examples.md +1 -1
  18. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/formatter.md +14 -12
  19. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/logging.md +10 -10
  20. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/usage.md +1 -1
  21. {execsql2-2.24.0 → execsql2-2.25.1}/docs/reference/configuration.md +20 -5
  22. {execsql2-2.24.0 → execsql2-2.25.1}/docs/reference/lint.md +125 -17
  23. {execsql2-2.24.0 → execsql2-2.25.1}/docs/reference/metacommands.md +30 -12
  24. {execsql2-2.24.0 → execsql2-2.25.1}/docs/reference/security.md +25 -4
  25. {execsql2-2.24.0 → execsql2-2.25.1}/justfile +0 -8
  26. {execsql2-2.24.0 → execsql2-2.25.1}/pyproject.toml +20 -3
  27. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/api.py +169 -160
  28. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/__init__.py +2 -0
  29. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/lint.py +2 -10
  30. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/run.py +35 -27
  31. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/dsn.py +11 -4
  32. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/lint.py +351 -48
  33. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/options.py +1 -1
  34. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/run.py +56 -19
  35. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/config.py +5 -19
  36. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/data/execsql.conf.template +14 -4
  37. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/access.py +29 -8
  38. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/base.py +40 -8
  39. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/dsn.py +13 -4
  40. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/duckdb.py +3 -1
  41. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/factory.py +11 -2
  42. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/firebird.py +21 -7
  43. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/mysql.py +37 -16
  44. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/oracle.py +49 -16
  45. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/postgres.py +30 -6
  46. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/sqlite.py +7 -9
  47. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/sqlserver.py +25 -8
  48. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/delimited.py +87 -28
  49. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/xlsx.py +24 -9
  50. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/zip.py +1 -2
  51. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/format.py +29 -2
  52. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/gui/desktop.py +1 -3
  53. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/gui/tui.py +2 -2
  54. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/base.py +35 -1
  55. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/csv.py +3 -1
  56. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/manifest.py +33 -22
  57. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/conditions.py +6 -7
  58. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/data.py +4 -1
  59. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/debug.py +2 -4
  60. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/io_fileops.py +62 -37
  61. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/io_import.py +0 -1
  62. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/prompt.py +2 -0
  63. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/upsert.py +5 -2
  64. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/models.py +3 -2
  65. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/parser.py +14 -5
  66. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/plugins.py +24 -0
  67. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/engine.py +40 -11
  68. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/executor.py +9 -5
  69. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/parser.py +167 -118
  70. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/state.py +23 -9
  71. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/state.pyi +8 -0
  72. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/types.py +22 -13
  73. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/auth.py +169 -24
  74. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/datetime.py +55 -17
  75. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/errors.py +71 -9
  76. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/fileio.py +404 -117
  77. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/gui.py +3 -0
  78. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/mail.py +37 -12
  79. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_cli.py +83 -42
  80. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_cli_e2e.py +40 -12
  81. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_cli_run.py +42 -41
  82. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_commands.py +12 -0
  83. execsql2-2.25.1/tests/cli/test_error_location.py +32 -0
  84. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_lint.py +346 -4
  85. execsql2-2.25.1/tests/cli/test_lint_fixtures.py +161 -0
  86. execsql2-2.25.1/tests/cli/test_log_exit_record.py +71 -0
  87. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_profile.py +2 -1
  88. execsql2-2.25.1/tests/cli/test_sigterm.py +105 -0
  89. {execsql2-2.24.0 → execsql2-2.25.1}/tests/conftest.py +1 -1
  90. execsql2-2.25.1/tests/data/lint/conditions_and_blocks.sql +222 -0
  91. execsql2-2.25.1/tests/data/lint/does_not_parse.sql +39 -0
  92. execsql2-2.25.1/tests/data/lint/every_metacommand.sql +289 -0
  93. execsql2-2.25.1/tests/data/lint/invalid.sql +134 -0
  94. execsql2-2.25.1/tests/db/test_copy_new.py +125 -0
  95. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_db_adapters_mocked.py +9 -13
  96. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_db_adapters_mocked_extra.py +43 -3
  97. execsql2-2.25.1/tests/db/test_factory_postgres_encoding.py +27 -0
  98. execsql2-2.25.1/tests/db/test_import_atomic.py +100 -0
  99. execsql2-2.25.1/tests/db/test_import_replacement_quoted.py +22 -0
  100. execsql2-2.25.1/tests/db/test_import_short_rows.py +60 -0
  101. execsql2-2.25.1/tests/db/test_import_timezones.py +68 -0
  102. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_mysql_inprocess.py +1 -4
  103. execsql2-2.25.1/tests/db/test_new_table_checks.py +152 -0
  104. execsql2-2.25.1/tests/db/test_oracle_driver.py +80 -0
  105. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_postgres_inprocess.py +0 -4
  106. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_sqlite_extra.py +11 -11
  107. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_sqlserver_inprocess.py +25 -0
  108. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_transactions.py +0 -15
  109. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_delimited.py +0 -18
  110. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_xlsx.py +1 -1
  111. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_xlsx.py +69 -2
  112. execsql2-2.25.1/tests/importers/test_csv_blank_lines.py +108 -0
  113. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_csv_edge_cases.py +36 -9
  114. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/conftest.py +1 -1
  115. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/test_dsn.py +1 -1
  116. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/test_mysql.py +73 -1
  117. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/test_postgres.py +38 -1
  118. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/test_sqlite.py +1 -1
  119. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_conditions_extra.py +2 -2
  120. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands.py +5 -2
  121. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_data.py +7 -7
  122. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_pg_upsert.py +1 -1
  123. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_row_count.py +8 -5
  124. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/test_sql_scripts.py +2 -0
  125. execsql2-2.25.1/tests/security/test_log_secrets.py +214 -0
  126. execsql2-2.25.1/tests/test_api_errors.py +106 -0
  127. execsql2-2.25.1/tests/test_api_filewriter.py +345 -0
  128. execsql2-2.25.1/tests/test_api_isolation.py +92 -0
  129. execsql2-2.25.1/tests/test_api_subprocess.py +76 -0
  130. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_ast_parser.py +124 -0
  131. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_config.py +2 -12
  132. execsql2-2.25.1/tests/test_date_inference.py +113 -0
  133. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_engine.py +42 -0
  134. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_executor.py +4 -3
  135. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_mail.py +8 -2
  136. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_models.py +2 -2
  137. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_registry.py +16 -0
  138. execsql2-2.25.1/tests/test_tooling_versions.py +38 -0
  139. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_types.py +57 -10
  140. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_auth.py +32 -13
  141. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_auth_extra.py +5 -2
  142. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_datetime.py +64 -0
  143. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_errors.py +22 -0
  144. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_fileio_extra.py +129 -19
  145. execsql2-2.25.1/tests/utils/test_keyring_rules.py +289 -0
  146. execsql2-2.25.1/tests/utils/test_mail_tls.py +192 -0
  147. execsql2-2.25.1/uv.lock +4177 -0
  148. execsql2-2.24.0/.github/dependabot.yml +0 -21
  149. execsql2-2.24.0/docs/api/index.md +0 -85
  150. execsql2-2.24.0/docs/getting-started/installation.md +0 -45
  151. execsql2-2.24.0/tests/test_api_filewriter.py +0 -158
  152. execsql2-2.24.0/uv.lock +0 -3480
  153. {execsql2-2.24.0 → execsql2-2.25.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  154. {execsql2-2.24.0 → execsql2-2.25.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  155. {execsql2-2.24.0 → execsql2-2.25.1}/.gitignore +0 -0
  156. {execsql2-2.24.0 → execsql2-2.25.1}/.pre-commit-hooks.yaml +0 -0
  157. {execsql2-2.24.0 → execsql2-2.25.1}/.python-version +0 -0
  158. {execsql2-2.24.0 → execsql2-2.25.1}/.readthedocs.yaml +0 -0
  159. {execsql2-2.24.0 → execsql2-2.25.1}/LICENSE.txt +0 -0
  160. {execsql2-2.24.0 → execsql2-2.25.1}/NOTICE +0 -0
  161. {execsql2-2.24.0 → execsql2-2.25.1}/SECURITY.md +0 -0
  162. {execsql2-2.24.0 → execsql2-2.25.1}/docs/about/contributors.md +0 -0
  163. {execsql2-2.24.0 → execsql2-2.25.1}/docs/about/copyright.md +0 -0
  164. {execsql2-2.24.0 → execsql2-2.25.1}/docs/api/cli.md +0 -0
  165. {execsql2-2.24.0 → execsql2-2.25.1}/docs/api/db.md +0 -0
  166. {execsql2-2.24.0 → execsql2-2.25.1}/docs/api/exporters.md +0 -0
  167. {execsql2-2.24.0 → execsql2-2.25.1}/docs/api/importers.md +0 -0
  168. {execsql2-2.24.0 → execsql2-2.25.1}/docs/api/metacommands.md +0 -0
  169. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/adding_exporters.md +0 -0
  170. {execsql2-2.24.0 → execsql2-2.25.1}/docs/dev/adding_importers.md +0 -0
  171. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/debugging.md +0 -0
  172. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/documentation.md +0 -0
  173. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/encoding.md +0 -0
  174. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/sql_syntax.md +0 -0
  175. {execsql2-2.24.0 → execsql2-2.25.1}/docs/guides/using_scripts.md +0 -0
  176. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/Compare_planets.png +0 -0
  177. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/actions.png +0 -0
  178. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/actions2.png +0 -0
  179. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/checkboxes.png +0 -0
  180. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/connect.b64 +0 -0
  181. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/connect.png +0 -0
  182. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/create_conf.png +0 -0
  183. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/data_error1_screenshot.jpg +0 -0
  184. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/entry_form.png +0 -0
  185. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/execsql_console.png +0 -0
  186. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/execsql_logo_01.png +0 -0
  187. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/fatals.png +0 -0
  188. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/logo_small.png +0 -0
  189. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/pause_terminal.png +0 -0
  190. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/pause_terminal_sm.b64 +0 -0
  191. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/pause_terminal_sm.png +0 -0
  192. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/prompt_compare.png +0 -0
  193. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/set_build_commands.jpg +0 -0
  194. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/unit_conversions.b64 +0 -0
  195. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/unit_conversions_029.png +0 -0
  196. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/unmatched.png +0 -0
  197. {execsql2-2.24.0 → execsql2-2.25.1}/docs/images/vim_execsql_highlight.png +0 -0
  198. {execsql2-2.24.0 → execsql2-2.25.1}/docs/index.md +0 -0
  199. {execsql2-2.24.0 → execsql2-2.25.1}/docs/reference/substitution_vars.md +0 -0
  200. {execsql2-2.24.0 → execsql2-2.25.1}/extras/plugin-template/README.md +0 -0
  201. {execsql2-2.24.0 → execsql2-2.25.1}/extras/plugin-template/pyproject.toml +0 -0
  202. {execsql2-2.24.0 → execsql2-2.25.1}/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +0 -0
  203. {execsql2-2.24.0 → execsql2-2.25.1}/extras/plugin-template/tests/test_plugin.py.example +0 -0
  204. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/.vscodeignore +0 -0
  205. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/LICENSE.txt +0 -0
  206. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/README.md +0 -0
  207. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/icon.png +0 -0
  208. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/package.json +0 -0
  209. {execsql2-2.24.0 → execsql2-2.25.1}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
  210. {execsql2-2.24.0 → execsql2-2.25.1}/scripts/benchmarks/README.md +0 -0
  211. {execsql2-2.24.0 → execsql2-2.25.1}/scripts/benchmarks/results/.gitignore +0 -0
  212. {execsql2-2.24.0 → execsql2-2.25.1}/scripts/benchmarks/run_benchmarks.py +0 -0
  213. {execsql2-2.24.0 → execsql2-2.25.1}/scripts/generate_vscode_grammar.py +0 -0
  214. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/__init__.py +0 -0
  215. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/__main__.py +0 -0
  216. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/application.py +0 -0
  217. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/__init__.py +0 -0
  218. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/config.py +0 -0
  219. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/format.py +0 -0
  220. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/init.py +0 -0
  221. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/commands/listing.py +0 -0
  222. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/dispatch.py +0 -0
  223. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/cli/help.py +0 -0
  224. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/config_validation.py +0 -0
  225. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/data/__init__.py +0 -0
  226. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/data/script_header.sql +0 -0
  227. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/__init__.py +0 -0
  228. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/db/tiers.py +0 -0
  229. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/debug/__init__.py +0 -0
  230. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/debug/repl.py +0 -0
  231. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exceptions.py +0 -0
  232. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/__init__.py +0 -0
  233. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/base.py +0 -0
  234. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/duckdb.py +0 -0
  235. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/feather.py +0 -0
  236. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/html.py +0 -0
  237. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/json.py +0 -0
  238. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/latex.py +0 -0
  239. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/markdown.py +0 -0
  240. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/ods.py +0 -0
  241. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/parquet.py +0 -0
  242. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/pretty.py +0 -0
  243. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/protocol.py +0 -0
  244. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/raw.py +0 -0
  245. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/sqlite.py +0 -0
  246. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/templates.py +0 -0
  247. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/values.py +0 -0
  248. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/xls.py +0 -0
  249. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/xml.py +0 -0
  250. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/exporters/yaml.py +0 -0
  251. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/gui/__init__.py +0 -0
  252. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/gui/base.py +0 -0
  253. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/gui/console.py +0 -0
  254. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/__init__.py +0 -0
  255. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/feather.py +0 -0
  256. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/json.py +0 -0
  257. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/ods.py +0 -0
  258. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/importers/xls.py +0 -0
  259. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/interactive.py +0 -0
  260. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/__init__.py +0 -0
  261. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/connect.py +0 -0
  262. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/control.py +0 -0
  263. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/dispatch.py +0 -0
  264. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/effects.py +0 -0
  265. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/io.py +0 -0
  266. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/io_export.py +0 -0
  267. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/io_write.py +0 -0
  268. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/script_ext.py +0 -0
  269. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/metacommands/system.py +0 -0
  270. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/py.typed +0 -0
  271. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/__init__.py +0 -0
  272. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/ast.py +0 -0
  273. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/control.py +0 -0
  274. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/script/variables.py +0 -0
  275. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/__init__.py +0 -0
  276. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/color.py +0 -0
  277. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/crypto.py +0 -0
  278. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/numeric.py +0 -0
  279. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/regex.py +0 -0
  280. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/strings.py +0 -0
  281. {execsql2-2.24.0 → execsql2-2.25.1}/src/execsql/utils/timer.py +0 -0
  282. {execsql2-2.24.0 → execsql2-2.25.1}/templates/README.md +0 -0
  283. {execsql2-2.24.0 → execsql2-2.25.1}/templates/config_settings.sqlite +0 -0
  284. {execsql2-2.24.0 → execsql2-2.25.1}/templates/example_config_prompt.sql +0 -0
  285. {execsql2-2.24.0 → execsql2-2.25.1}/templates/make_config_db.sql +0 -0
  286. {execsql2-2.24.0 → execsql2-2.25.1}/templates/md_compare.sql +0 -0
  287. {execsql2-2.24.0 → execsql2-2.25.1}/templates/md_glossary.sql +0 -0
  288. {execsql2-2.24.0 → execsql2-2.25.1}/templates/md_upsert.sql +0 -0
  289. {execsql2-2.24.0 → execsql2-2.25.1}/templates/pg_compare.sql +0 -0
  290. {execsql2-2.24.0 → execsql2-2.25.1}/templates/pg_glossary.sql +0 -0
  291. {execsql2-2.24.0 → execsql2-2.25.1}/templates/pg_upsert.sql +0 -0
  292. {execsql2-2.24.0 → execsql2-2.25.1}/templates/script_template.sql +0 -0
  293. {execsql2-2.24.0 → execsql2-2.25.1}/templates/ss_compare.sql +0 -0
  294. {execsql2-2.24.0 → execsql2-2.25.1}/templates/ss_glossary.sql +0 -0
  295. {execsql2-2.24.0 → execsql2-2.25.1}/templates/ss_upsert.sql +0 -0
  296. {execsql2-2.24.0 → execsql2-2.25.1}/tests/__init__.py +0 -0
  297. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/__init__.py +0 -0
  298. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_cli_surface.py +0 -0
  299. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_config_validate.py +0 -0
  300. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_dispatch.py +0 -0
  301. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_init.py +0 -0
  302. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_manifest.py +0 -0
  303. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_ping.py +0 -0
  304. {execsql2-2.24.0 → execsql2-2.25.1}/tests/cli/test_undeclared_imports.py +0 -0
  305. {execsql2-2.24.0 → execsql2-2.25.1}/tests/data/formatter_shapes/comment_anchoring.sql +0 -0
  306. {execsql2-2.24.0 → execsql2-2.25.1}/tests/data/formatter_shapes/escapes_and_literals.sql +0 -0
  307. {execsql2-2.24.0 → execsql2-2.25.1}/tests/data/formatter_shapes/substitution_and_metacommands.sql +0 -0
  308. {execsql2-2.24.0 → execsql2-2.25.1}/tests/data/formatter_shapes/unparsable_sql.sql +0 -0
  309. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/__init__.py +0 -0
  310. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_access_windows.py +0 -0
  311. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_base.py +0 -0
  312. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_dsn.py +0 -0
  313. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_duckdb.py +0 -0
  314. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_factory.py +0 -0
  315. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_mysql_case_folding.py +0 -0
  316. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_postgres.py +0 -0
  317. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_roundtrip_adapters.py +0 -0
  318. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_sqlite.py +0 -0
  319. {execsql2-2.24.0 → execsql2-2.25.1}/tests/db/test_tiers.py +0 -0
  320. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/__init__.py +0 -0
  321. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/conftest.py +0 -0
  322. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_base.py +0 -0
  323. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_db.py +0 -0
  324. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_duckdb_exporter.py +0 -0
  325. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_exporters.py +0 -0
  326. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_feather.py +0 -0
  327. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_html_extended.py +0 -0
  328. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_html_latex.py +0 -0
  329. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_json.py +0 -0
  330. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_json_extended.py +0 -0
  331. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_latex_extended.py +0 -0
  332. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_markdown.py +0 -0
  333. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_ods.py +0 -0
  334. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_ods_export.py +0 -0
  335. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_parquet.py +0 -0
  336. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_pretty_extended.py +0 -0
  337. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_raw_extended.py +0 -0
  338. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_columnar.py +0 -0
  339. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_dbfile.py +0 -0
  340. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_delimited.py +0 -0
  341. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_json.py +0 -0
  342. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_latex_xml.py +0 -0
  343. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_markup.py +0 -0
  344. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_ods.py +0 -0
  345. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_pretty_raw.py +0 -0
  346. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_template.py +0 -0
  347. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_roundtrip_values.py +0 -0
  348. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_sqlite_exporter.py +0 -0
  349. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_templates.py +0 -0
  350. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_templates_extended.py +0 -0
  351. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_values_extended.py +0 -0
  352. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_xls_xlsx.py +0 -0
  353. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_xml.py +0 -0
  354. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_yaml.py +0 -0
  355. {execsql2-2.24.0 → execsql2-2.25.1}/tests/exporters/test_zip.py +0 -0
  356. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/__init__.py +0 -0
  357. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_backends.py +0 -0
  358. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_backends_extended.py +0 -0
  359. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_compare_stats.py +0 -0
  360. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_compute_row_diffs.py +0 -0
  361. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_desktop_dialogs.py +0 -0
  362. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_format_table.py +0 -0
  363. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_tui_pilot.py +0 -0
  364. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_tui_pilot_complex.py +0 -0
  365. {execsql2-2.24.0 → execsql2-2.25.1}/tests/gui/test_utils_gui_extended.py +0 -0
  366. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/__init__.py +0 -0
  367. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/conftest.py +0 -0
  368. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_base_extended.py +0 -0
  369. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_csv_importer.py +0 -0
  370. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_feather_importer.py +0 -0
  371. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_json_importer.py +0 -0
  372. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_ods_importer.py +0 -0
  373. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_roundtrip_csv.py +0 -0
  374. {execsql2-2.24.0 → execsql2-2.25.1}/tests/importers/test_xls_importer.py +0 -0
  375. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/__init__.py +0 -0
  376. {execsql2-2.24.0 → execsql2-2.25.1}/tests/integration/test_duckdb.py +0 -0
  377. {execsql2-2.24.0 → execsql2-2.25.1}/tests/live_db.py +0 -0
  378. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/__init__.py +0 -0
  379. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_assert.py +0 -0
  380. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_breakpoint.py +0 -0
  381. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_connect.py +0 -0
  382. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_io_export.py +0 -0
  383. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_io_import.py +0 -0
  384. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_connect.py +0 -0
  385. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_extended.py +0 -0
  386. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
  387. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_io.py +0 -0
  388. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
  389. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_script_ext.py +0 -0
  390. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_system.py +0 -0
  391. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_metacommands_system_extra.py +0 -0
  392. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_prompt.py +0 -0
  393. {execsql2-2.24.0 → execsql2-2.25.1}/tests/metacommands/test_show_scripts.py +0 -0
  394. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/__init__.py +0 -0
  395. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/audit_lint_bad.sql +0 -0
  396. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/audit_smoke/sample.json +0 -0
  397. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/audit_smoke/sample.jsonl +0 -0
  398. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/audit_smoke.sql +0 -0
  399. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/config_runtime.sql +0 -0
  400. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/control_flow.sql +0 -0
  401. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/counters_and_locals.sql +0 -0
  402. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/error_handling.sql +0 -0
  403. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/import_options/has_comments.csv +0 -0
  404. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/import_options.sql +0 -0
  405. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/includes/helper.sql +0 -0
  406. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/includes.sql +0 -0
  407. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/io_formats.sql +0 -0
  408. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
  409. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/multi_db.sql +0 -0
  410. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/parquet_feather_roundtrip.sql +0 -0
  411. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/parse_only/parse_tree.sql +0 -0
  412. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/predicates.sql +0 -0
  413. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/scripts.sql +0 -0
  414. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/smoke.sql +0 -0
  415. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/subroutine_loops.sql +0 -0
  416. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/subvars_advanced.sql +0 -0
  417. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/template_export/greeting.tmpl +0 -0
  418. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/template_export.sql +0 -0
  419. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/timer.sql +0 -0
  420. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/transactions.sql +0 -0
  421. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/write_create_table.sql +0 -0
  422. {execsql2-2.24.0 → execsql2-2.25.1}/tests/scripts/fixtures/xlsx_ods_roundtrip.sql +0 -0
  423. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/__init__.py +0 -0
  424. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_env_detection.py +0 -0
  425. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_expansion_bomb.py +0 -0
  426. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_import_regex_hardening.py +0 -0
  427. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_log_redaction.py +0 -0
  428. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_odbc_injection.py +0 -0
  429. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_path_containment.py +0 -0
  430. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_substitution_injection.py +0 -0
  431. {execsql2-2.24.0 → execsql2-2.25.1}/tests/security/test_zip_bomb.py +0 -0
  432. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_api.py +0 -0
  433. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_api_extended.py +0 -0
  434. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_ast.py +0 -0
  435. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_bundled_templates.py +0 -0
  436. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_config_data.py +0 -0
  437. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_config_extended.py +0 -0
  438. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_debug_repl.py +0 -0
  439. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_error_messages.py +0 -0
  440. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_exceptions.py +0 -0
  441. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_executor_inprocess.py +0 -0
  442. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_format.py +0 -0
  443. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_interactive.py +0 -0
  444. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_package.py +0 -0
  445. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_parser.py +0 -0
  446. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_parser_params.py +0 -0
  447. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_plugins.py +0 -0
  448. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_script.py +0 -0
  449. {execsql2-2.24.0 → execsql2-2.25.1}/tests/test_state.py +0 -0
  450. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/__init__.py +0 -0
  451. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_crypto.py +0 -0
  452. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_encodedfile_context.py +0 -0
  453. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_errors_extra.py +0 -0
  454. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_fileio.py +0 -0
  455. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_numeric.py +0 -0
  456. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_regex.py +0 -0
  457. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_strings.py +0 -0
  458. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_timer.py +0 -0
  459. {execsql2-2.24.0 → execsql2-2.25.1}/tests/utils/test_timer_extra.py +0 -0
  460. {execsql2-2.24.0 → execsql2-2.25.1}/zensical.toml +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
 
@@ -38,10 +44,12 @@ jobs:
38
44
  - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
39
45
  with:
40
46
  python-version: "3.13"
41
- cache: "pip"
42
- - run: python -m pip install --upgrade pip
43
- - run: python -m pip install ".[dev]"
44
- - run: mypy src/execsql/
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/
45
53
 
46
54
  formatter-corpus:
47
55
  name: formatter-corpus
@@ -342,6 +350,16 @@ jobs:
342
350
  with:
343
351
  python-version: "3.13"
344
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
345
363
  - name: Build sdist + wheel
346
364
  run: |
347
365
  python -m pip install --upgrade pip
@@ -380,11 +398,12 @@ jobs:
380
398
  uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
381
399
  with:
382
400
  packages-dir: dist
383
- skip-existing: true
384
401
 
385
402
  generate-release:
386
403
  name: Generate GitHub Release
387
- needs: [ build ]
404
+ # After the PyPI upload, so a release is never announced for a
405
+ # version that pip cannot install.
406
+ needs: [ publish ]
388
407
  if: startsWith(github.ref, 'refs/tags/v')
389
408
  runs-on: ubuntu-latest
390
409
  permissions:
@@ -397,75 +416,21 @@ jobs:
397
416
  with:
398
417
  name: ${{ github.event.repository.name }}
399
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
400
429
  - name: Create release
401
430
  uses: softprops/action-gh-release@efb35369e0ad2afab669f228072c1b0d510eae64 # v3.0.3
402
431
  with:
403
432
  draft: false
404
- prerelease: false
433
+ prerelease: ${{ steps.tag.outputs.prerelease }}
405
434
  generate_release_notes: true
406
435
  files: |
407
436
  dist/*
408
-
409
- publish-vscode:
410
- name: Publish VS Code extension 🧩
411
- needs: [ build ]
412
- # Only on a version tag, and only when a Marketplace token is configured.
413
- # Without VSCE_PAT the job is skipped rather than failed, so a release
414
- # still completes for anyone who has not set the secret up.
415
- if: startsWith(github.ref, 'refs/tags/v')
416
- runs-on: ubuntu-latest
417
- permissions:
418
- contents: read
419
- steps:
420
- - name: Checkout
421
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
422
- - name: Check for a Marketplace token
423
- id: gate
424
- # Read through env, never interpolated into the command line.
425
- env:
426
- VSCE_PAT: ${{ secrets.VSCE_PAT }}
427
- run: |
428
- if [ -n "$VSCE_PAT" ]; then
429
- echo "ready=true" >> "$GITHUB_OUTPUT"
430
- else
431
- echo "ready=false" >> "$GITHUB_OUTPUT"
432
- echo "VSCE_PAT is not set — skipping the Marketplace publish." >> "$GITHUB_STEP_SUMMARY"
433
- fi
434
- - name: Setup Python
435
- if: steps.gate.outputs.ready == 'true'
436
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
437
- with:
438
- python-version: "3.13"
439
- # The grammar is generated from the metacommand dispatch table, so it
440
- # is rebuilt here rather than trusted to be current in the tree.
441
- - name: Regenerate the TextMate grammar
442
- if: steps.gate.outputs.ready == 'true'
443
- run: |
444
- python -m pip install --upgrade pip
445
- python -m pip install .
446
- python scripts/generate_vscode_grammar.py
447
- - name: Fail if the committed grammar is stale
448
- if: steps.gate.outputs.ready == 'true'
449
- run: git diff --exit-code -- extras/vscode-execsql/syntaxes/
450
- # The Marketplace refuses a version it already has, so the
451
- # extension version tracks the tag rather than being bumped by hand
452
- # in a second place.
453
- - name: Set the extension version from the tag
454
- if: steps.gate.outputs.ready == 'true'
455
- working-directory: extras/vscode-execsql
456
- run: |
457
- version="${GITHUB_REF_NAME#v}"
458
- python - "$version" <<'PY'
459
- import json, pathlib, sys
460
- p = pathlib.Path("package.json")
461
- data = json.loads(p.read_text())
462
- data["version"] = sys.argv[1]
463
- p.write_text(json.dumps(data, indent=2) + "\n")
464
- print("extension version set to", sys.argv[1])
465
- PY
466
- - name: Publish
467
- if: steps.gate.outputs.ready == 'true'
468
- working-directory: extras/vscode-execsql
469
- run: npx --yes @vscode/vsce@latest publish
470
- env:
471
- VSCE_PAT: ${{ secrets.VSCE_PAT }}
@@ -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
@@ -13,6 +13,82 @@ ______________________________________________________________________
13
13
 
14
14
  ______________________________________________________________________
15
15
 
16
+ ## [2.25.1] - 2026-10-09
17
+
18
+ ### Fixed
19
+
20
+ - **`execsql lint` `V001` / `V002` and nested variable names:** `!!N_!!CHECK_GROUP!!_CHECKS!!` no longer reports `!!N_!!` and `!!_CHECKS!!` as undefined; the inner `!!CHECK_GROUP!!` is checked, and counts as used.
21
+ - **`execsql lint` and `SUB_INI`:** a script whose `SUB_INI` names a FIFO or device (`/dev/zero`) no longer hangs lint, and an INI file that does not parse no longer stops it.
22
+
23
+ ______________________________________________________________________
24
+
25
+ ## [2.25.0] - 2026-10-09
26
+
27
+ ### Added
28
+
29
+ - **`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 `;`.
30
+ - **`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`.
31
+ - **`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`.
32
+ - **`[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.
33
+
34
+ ### Changed
35
+
36
+ - **`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`.
37
+ - **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`.
38
+ - **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.
39
+ - **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.
40
+ - **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.
41
+ - **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.
42
+ - **`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.
43
+ - **Faster start-up:** every `execsql` command and `import execsql` start about 0.7 s sooner.
44
+
45
+ ### Removed
46
+
47
+ - **`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.
48
+
49
+ ### Fixed
50
+
51
+ - **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.
52
+ - **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).
53
+ - **`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`.
54
+ - **`execsql.log` `run_db_file` record** names the database file for SQLite, DuckDB and Access runs.
55
+ - **`execsql.log` no longer shows `-a` values** in the `run` record; it gives how many there were.
56
+ - **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.
57
+ - **Stored passwords (keyring) are saved only after the connection succeeds**, so a mistyped password is no longer stored.
58
+ - **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.
59
+ - **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.
60
+ - **Oracle (`-t o`, `oracle://`) connects with the `oracledb` driver** that `execsql2[oracle]` installs.
61
+ - **`-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.
62
+ - **`-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.
63
+ - **`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`.
64
+ - **`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).
65
+ - **`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.
66
+ - **`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`.
67
+ - **`COPY ... TO NEW` / `REPLACEMENT` no longer holds every source row in memory.**
68
+ - **`IMPORT` / `COPY` into DuckDB that fails part-way keeps no rows**, as on SQLite and PostgreSQL, so a re-run no longer duplicates them.
69
+ - **`IMPORT` of a data line with fewer values than the header** loads the missing values as NULL on every DBMS.
70
+ - **`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.
71
+ - **PostgreSQL `IMPORT` of a quoted file with a blank line** no longer fails with `missing data for column`.
72
+ - **`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`).
73
+ - **`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.
74
+ - **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.
75
+ - **`EXPORT ... AS XLSX`** writes text that starts with `=` as text, not as a formula.
76
+ - **`execsql.run()` from a script without an `if __name__ == "__main__":` guard** no longer runs the script's SQL twice on macOS and Windows.
77
+ - **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.
78
+ - **Repeated `execsql.run()` calls in one process** no longer pile up exit hooks or duplicate plugin metacommands.
79
+ - **`execsql.run()` cleans up when it returns:** its temp files are removed, and a run interrupted with Ctrl-C closes the connection it opened.
80
+ - **`execsql.run()` with `--manifest`** no longer records into a manifest that belongs to another run in the same thread.
81
+ - **`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.
82
+ - **`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.
83
+ - **`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`.
84
+ - **`execsql lint` `V001`** reports a user variable named like a system variable without its `$` (`!!date_tag!!`), and a `SUB` variable written with a `$` (`!!$region!!`).
85
+ - **`execsql lint` `V002` (`unused-variable`)** no longer reports a variable read only by `sub_defined(...)` or `sub_empty(...)`.
86
+ - **`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`.
87
+ - **Install hints in error messages** name the right extra: `formats` for XLSX (not `excel`), and none for Textual, which execsql2 includes.
88
+ - **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"`.
89
+
90
+ ______________________________________________________________________
91
+
16
92
  ## [2.24.0] - 2026-10-01
17
93
 
18
94
  ### Added
@@ -398,7 +474,7 @@ ______________________________________________________________________
398
474
 
399
475
  ### Changed
400
476
 
401
- - **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.
477
+ - **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.)
402
478
 
403
479
  ### Fixed
404
480
 
@@ -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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execsql2
3
- Version: 2.24.0
3
+ Version: 2.25.1
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
@@ -161,7 +161,7 @@ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), whic
161
161
  | Command | What it does | Needs a database? |
162
162
  | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
163
163
  | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
164
- | `execsql lint` | Static analysis: structure, undefined variables, bad targets | No |
164
+ | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
165
165
  | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
166
166
  | `execsql config` | Show every config option, its value, and the file that set it | No |
167
167
  | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
@@ -180,14 +180,14 @@ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), whic
180
180
  `format` and `lint` work on a bare `.sql` file, with no server and no config. Try them first:
181
181
 
182
182
  ```bash
183
- pip install execsql2[formatter]
183
+ uv tool install "execsql2[formatter]" # or: pipx install "execsql2[formatter]"
184
184
 
185
185
  execsql format --check scripts/ # is it formatted?
186
186
  execsql format -i scripts/ # format it
187
187
  execsql lint scripts/ # find problems before they cost you a run
188
188
  ```
189
189
 
190
- `lint` reports unmatched blocks, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
190
+ `lint` reports unmatched blocks, misspelled or malformed metacommands and conditions, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
191
191
 
192
192
  ```text
193
193
  $ execsql lint load_data.sql
@@ -244,11 +244,16 @@ The `PROMPT` metacommand produces a GUI display of the data:
244
244
  ## Installation
245
245
 
246
246
  ```bash
247
- pip install execsql2 # core: SQLite works with no extras
248
- pip install "execsql2[postgres]" # add a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
249
- pip install "execsql2[all]" # everything: all drivers plus all feature extras
247
+ uv tool install execsql2 # core: SQLite works with no extras
248
+ uv tool install "execsql2[postgres]" # with a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
249
+ uv tool install "execsql2[all]" # everything: all drivers plus all feature extras
250
250
  ```
251
251
 
252
+ `pipx install` takes the same arguments. Quote the name when it has extras
253
+ (zsh reports `no matches found` otherwise). To call execsql from Python code,
254
+ add it to that project instead: `uv add "execsql2[postgres]"` or
255
+ `pip install "execsql2[postgres]"` in its virtual environment.
256
+
252
257
  Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more. See the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
253
258
 
254
259
  ## Usage
@@ -309,7 +314,7 @@ silences.
309
314
  | `-c SCRIPT` | Execute inline SQL or metacommand string |
310
315
  | `-a VALUE` | Set substitution variable `$ARG_x` |
311
316
  | `--var NAME=VALUE` | Set the substitution variable `!!NAME!!` |
312
- | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
317
+ | `-v {0,1,2,3}` | GUI level (0=none, 1=password/PAUSE, 2=+HALT and DB selection, 3=console) |
313
318
  | `--config FILE` | Load an explicit config file |
314
319
  | `--dry-run` | Parse the script and report commands without executing |
315
320
  | `--manifest FILE` | Write a JSON record of the run: files read and written, statements, errors |
@@ -360,7 +365,8 @@ result = run(
360
365
  new_db=True,
361
366
  )
362
367
 
363
- # With substitution variables
368
+ # With substitution variables: each key becomes a $ variable,
369
+ # so the script refers to these as !!$SCHEMA!! and !!$DATE!!
364
370
  result = run(
365
371
  script="etl.sql",
366
372
  dsn="sqlite:///data.db",
@@ -371,7 +377,7 @@ result = run(
371
377
  print(result.success) # True
372
378
  print(result.commands_run) # 2
373
379
  print(result.elapsed) # 0.003 (seconds)
374
- print(result.variables) # {"SCHEMA": "public", ...}
380
+ print(result.variables) # {"schema": "public", ...} (names lower-cased, no $)
375
381
  ```
376
382
 
377
383
  Error handling:
@@ -428,7 +434,7 @@ The `execsql format` command normalizes execsql script files: it uppercases meta
428
434
 
429
435
  ```bash
430
436
  # Install with the SQL-reformatting extra
431
- pip install execsql2[formatter]
437
+ uv tool install "execsql2[formatter]"
432
438
 
433
439
  # Format files in place
434
440
  execsql format --in-place scripts/
@@ -445,7 +451,7 @@ execsql format --no-sql --in-place scripts/
445
451
  ```yaml
446
452
  repos:
447
453
  - repo: https://github.com/geocoug/execsql
448
- rev: v2.24.0
454
+ rev: v2.25.1
449
455
  hooks:
450
456
  - id: execsql-format
451
457
  - id: execsql-lint
@@ -30,7 +30,7 @@ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), whic
30
30
  | Command | What it does | Needs a database? |
31
31
  | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------- |
32
32
  | `execsql format` | Normalize keywords, indentation, and SQL layout | No |
33
- | `execsql lint` | Static analysis: structure, undefined variables, bad targets | No |
33
+ | `execsql lint` | Static analysis: structure, unknown metacommands, variables, targets | No |
34
34
  | `execsql run` | Run the script against PostgreSQL, MySQL, SQLite, DuckDB, … | Yes |
35
35
  | `execsql config` | Show every config option, its value, and the file that set it | No |
36
36
  | `execsql list` | Metacommands, encodings, plugins, or the keyword vocabulary | No |
@@ -49,14 +49,14 @@ Scripts are ordinary SQL plus metacommands embedded in comments (`-- !x!`), whic
49
49
  `format` and `lint` work on a bare `.sql` file, with no server and no config. Try them first:
50
50
 
51
51
  ```bash
52
- pip install execsql2[formatter]
52
+ uv tool install "execsql2[formatter]" # or: pipx install "execsql2[formatter]"
53
53
 
54
54
  execsql format --check scripts/ # is it formatted?
55
55
  execsql format -i scripts/ # format it
56
56
  execsql lint scripts/ # find problems before they cost you a run
57
57
  ```
58
58
 
59
- `lint` reports unmatched blocks, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
59
+ `lint` reports unmatched blocks, misspelled or malformed metacommands and conditions, undefined and unused substitution variables, unreachable branches, and `INCLUDE`/`SCRIPT` targets that do not exist: the failures that otherwise surface halfway through a run against a live database:
60
60
 
61
61
  ```text
62
62
  $ execsql lint load_data.sql
@@ -113,11 +113,16 @@ The `PROMPT` metacommand produces a GUI display of the data:
113
113
  ## Installation
114
114
 
115
115
  ```bash
116
- pip install execsql2 # core: SQLite works with no extras
117
- pip install "execsql2[postgres]" # add a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
118
- pip install "execsql2[all]" # everything: all drivers plus all feature extras
116
+ uv tool install execsql2 # core: SQLite works with no extras
117
+ uv tool install "execsql2[postgres]" # with a driver: postgres, mysql, mssql, duckdb, firebird, oracle, odbc
118
+ uv tool install "execsql2[all]" # everything: all drivers plus all feature extras
119
119
  ```
120
120
 
121
+ `pipx install` takes the same arguments. Quote the name when it has extras
122
+ (zsh reports `no matches found` otherwise). To call execsql from Python code,
123
+ add it to that project instead: `uv add "execsql2[postgres]"` or
124
+ `pip install "execsql2[postgres]"` in its virtual environment.
125
+
121
126
  Feature extras cover spreadsheet and Parquet/Feather formats, keyring authentication, PostgreSQL upsert, and more. See the [installation guide](https://execsql2.readthedocs.io/en/latest/getting-started/installation/) for the full list.
122
127
 
123
128
  ## Usage
@@ -178,7 +183,7 @@ silences.
178
183
  | `-c SCRIPT` | Execute inline SQL or metacommand string |
179
184
  | `-a VALUE` | Set substitution variable `$ARG_x` |
180
185
  | `--var NAME=VALUE` | Set the substitution variable `!!NAME!!` |
181
- | `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
186
+ | `-v {0,1,2,3}` | GUI level (0=none, 1=password/PAUSE, 2=+HALT and DB selection, 3=console) |
182
187
  | `--config FILE` | Load an explicit config file |
183
188
  | `--dry-run` | Parse the script and report commands without executing |
184
189
  | `--manifest FILE` | Write a JSON record of the run: files read and written, statements, errors |
@@ -229,7 +234,8 @@ result = run(
229
234
  new_db=True,
230
235
  )
231
236
 
232
- # With substitution variables
237
+ # With substitution variables: each key becomes a $ variable,
238
+ # so the script refers to these as !!$SCHEMA!! and !!$DATE!!
233
239
  result = run(
234
240
  script="etl.sql",
235
241
  dsn="sqlite:///data.db",
@@ -240,7 +246,7 @@ result = run(
240
246
  print(result.success) # True
241
247
  print(result.commands_run) # 2
242
248
  print(result.elapsed) # 0.003 (seconds)
243
- print(result.variables) # {"SCHEMA": "public", ...}
249
+ print(result.variables) # {"schema": "public", ...} (names lower-cased, no $)
244
250
  ```
245
251
 
246
252
  Error handling:
@@ -297,7 +303,7 @@ The `execsql format` command normalizes execsql script files: it uppercases meta
297
303
 
298
304
  ```bash
299
305
  # Install with the SQL-reformatting extra
300
- pip install execsql2[formatter]
306
+ uv tool install "execsql2[formatter]"
301
307
 
302
308
  # Format files in place
303
309
  execsql format --in-place scripts/
@@ -314,7 +320,7 @@ execsql format --no-sql --in-place scripts/
314
320
  ```yaml
315
321
  repos:
316
322
  - repo: https://github.com/geocoug/execsql
317
- rev: v2.24.0
323
+ rev: v2.25.1
318
324
  hooks:
319
325
  - id: execsql-format
320
326
  - id: execsql-lint