execsql2 2.15.11__tar.gz → 2.16.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.
- {execsql2-2.15.11 → execsql2-2.16.1}/.gitignore +3 -2
- {execsql2-2.15.11 → execsql2-2.16.1}/CHANGELOG.md +78 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/PKG-INFO +93 -27
- {execsql2-2.15.11 → execsql2-2.16.1}/README.md +92 -26
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/about/contributors.md +3 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/about/divergence.md +83 -36
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/exporters.md +6 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/importers.md +2 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/index.md +45 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/dev/adding_metacommands.md +25 -13
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/dev/architecture.md +51 -8
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/getting-started/installation.md +2 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/getting-started/syntax.md +18 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/examples.md +303 -76
- execsql2-2.16.1/docs/guides/logging.md +106 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/reference/configuration.md +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/reference/substitution_vars.md +12 -8
- execsql2-2.16.1/extras/plugin-template/README.md +71 -0
- execsql2-2.16.1/extras/plugin-template/pyproject.toml +22 -0
- execsql2-2.16.1/extras/plugin-template/src/execsql_plugin_YOURNAME/__init__.py +96 -0
- execsql2-2.16.1/extras/plugin-template/tests/test_plugin.py.example +110 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/pyproject.toml +5 -3
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/__init__.py +4 -0
- execsql2-2.16.1/src/execsql/api.py +580 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/cli/__init__.py +106 -0
- execsql2-2.16.1/src/execsql/cli/lint_ast.py +439 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/cli/run.py +431 -263
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/config.py +10 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/access.py +1 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/dsn.py +3 -2
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/duckdb.py +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/factory.py +3 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/firebird.py +2 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/mysql.py +2 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/oracle.py +2 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/postgres.py +2 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/sqlite.py +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/sqlserver.py +3 -2
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/base.py +6 -4
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/delimited.py +11 -3
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/pretty.py +9 -12
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/__init__.py +3 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/connect.py +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/control.py +8 -14
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/debug.py +6 -4
- execsql2-2.16.1/src/execsql/metacommands/io_export.py +325 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/io_fileops.py +7 -13
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/io_write.py +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/script_ext.py +8 -5
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/upsert.py +40 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/models.py +8 -12
- execsql2-2.16.1/src/execsql/plugins.py +414 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/script/__init__.py +36 -12
- execsql2-2.16.1/src/execsql/script/ast.py +562 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/script/engine.py +59 -368
- execsql2-2.16.1/src/execsql/script/executor.py +926 -0
- execsql2-2.16.1/src/execsql/script/parser.py +663 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/script/variables.py +11 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/state.py +118 -44
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/crypto.py +14 -10
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/errors.py +31 -8
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/mail.py +15 -12
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_cli.py +163 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_cli_run.py +18 -151
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_profile.py +4 -4
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/conftest.py +16 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_db_adapters_mocked.py +3 -4
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_dsn.py +5 -6
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_base.py +15 -13
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands.py +4 -3
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_extended.py +8 -37
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_fileops_extra.py +4 -20
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_io.py +5 -21
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_script_ext.py +5 -11
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/scripts/fixtures/control_flow.sql +5 -0
- execsql2-2.16.1/tests/scripts/fixtures/parse_only/parse_tree.sql +541 -0
- execsql2-2.16.1/tests/test_api.py +303 -0
- execsql2-2.16.1/tests/test_ast.py +552 -0
- execsql2-2.16.1/tests/test_ast_parser.py +829 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_config_data.py +2 -2
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_config_extended.py +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_engine.py +15 -630
- execsql2-2.16.1/tests/test_executor.py +1128 -0
- execsql2-2.16.1/tests/test_plugins.py +213 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_script.py +8 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_state.py +108 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_errors_extra.py +4 -4
- {execsql2-2.15.11 → execsql2-2.16.1}/uv.lock +1 -1
- {execsql2-2.15.11 → execsql2-2.16.1}/zensical.toml +40 -2
- execsql2-2.15.11/docs/guides/logging.md +0 -103
- execsql2-2.15.11/src/execsql/metacommands/io_export.py +0 -523
- {execsql2-2.15.11 → execsql2-2.16.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.pre-commit-config.yaml +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.python-version +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/.readthedocs.yaml +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/CONTRIBUTING.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/LICENSE.txt +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/NOTICE +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/SECURITY.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/about/copyright.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/cli.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/db.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/api/metacommands.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/debugging.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/documentation.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/encoding.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/formatter.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/usage.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/actions.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/actions2.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/checkboxes.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/connect.b64 +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/connect.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/create_conf.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/entry_form.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/execsql_console.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/fatals.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/logo_small.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/unmatched.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/index.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/reference/metacommands.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/docs/reference/security.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/justfile +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/__main__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/cli/help.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/cli/lint.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/db/base.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/debug/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/debug/repl.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exceptions.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/xlsx.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/yaml.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/format.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/gui/base.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/gui/console.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/base.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/json.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/conditions.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/dispatch.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/parser.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/py.typed +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/script/control.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/types.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/gui.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/README.md +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/config_settings.sqlite +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/execsql.conf +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/make_config_db.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/md_compare.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/md_glossary.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/md_upsert.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/pg_compare.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/pg_glossary.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/pg_upsert.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/script_template.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/ss_compare.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/ss_glossary.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/templates/ss_upsert.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_lint.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/cli/test_ping.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_base.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_factory.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_postgres.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_db.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_html_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_json.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_json_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_latex_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_pretty_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_raw_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_templates_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_values_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/gui/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/gui/test_backends.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/gui/test_compare_stats.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/gui/test_compute_row_diffs.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_base_extended.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_csv_edge_cases.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_csv_importer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_json_importer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/conftest.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_breakpoint.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_io_export.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_io_import.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_data.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_pg_upsert.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/scripts/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/scripts/fixtures/io_roundtrip.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/scripts/fixtures/smoke.sql +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/scripts/test_sql_scripts.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_config.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_debug_repl.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_error_messages.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_exceptions.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_format.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_mail.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_models.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_package.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_parser.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_registry.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/test_types.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/__init__.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_auth.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_errors.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_regex.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_strings.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_timer.py +0 -0
- {execsql2-2.15.11 → execsql2-2.16.1}/tests/utils/test_timer_extra.py +0 -0
|
@@ -13,6 +13,84 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.16.1] - 2026-04-30
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- AST executor now correctly handles `~` (local) and `+` (outer-scope) substitution variables inside SCRIPT blocks. Previously, `-- !x! SUB ~var value` inside a SCRIPT body would write to a disconnected scope, causing the variable to be invisible to subsequent SQL statements and producing spurious "potential un-substituted variable" warnings. The fix pushes proper `CommandList` frames onto `commandliststack` at script and top-level boundaries, bridging the AST executor with the legacy metacommand handlers (`x_sub`, `x_rm_sub`, `xf_sub_defined`, `SUB_LOCAL`, prompt handlers, REPL `.vars`/`.stack`, etc.).
|
|
21
|
+
- EXECUTE SCRIPT argument expressions (e.g., `val=!!#parent_param!!`) are now expanded in the caller's scope before the child script frame is created, fixing nested script calls that pass `~` or `#` variables as arguments.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- `RuntimeContext` is now stored in `threading.local()` instead of a module-level global, making `_state.foo` access thread-safe. Each thread gets its own isolated context via lazy initialization. The `active_context` context manager is now safe for concurrent use across threads. Enables future PARALLEL blocks and concurrent `from execsql import run` calls.
|
|
26
|
+
- `_run()` in `cli/run.py` decomposed into 8 standalone functions: `_seed_early_subvars()`, `_load_config()`, `_seed_script_subvars()`, `_load_script()`, `_apply_dsn()`, `_apply_cli_options()`, `_route_positionals()`, and `_setup_logging()`. Reduces `_run()` from ~380 lines to ~150 lines of orchestration with zero behavioral change.
|
|
27
|
+
|
|
28
|
+
______________________________________________________________________
|
|
29
|
+
|
|
30
|
+
## [2.16.0] - 2026-04-29
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- `--parse-tree` CLI flag: parse a script into an Abstract Syntax Tree and print a visual tree structure showing block nesting (IF/LOOP/BATCH/SCRIPT), source line ranges, compound conditions (ANDIF/ORIF), and all metacommands. Requires no database connection or configuration.
|
|
35
|
+
- AST parser module (`execsql.script.parser`) with `parse_script()` and `parse_string()` entry points. Produces a structured `Script` tree with typed nodes for all block constructs (IfBlock, LoopBlock, BatchBlock, ScriptBlock, SqlBlock, IncludeDirective).
|
|
36
|
+
- AST node definitions (`execsql.script.ast`) with `format_tree()` for human-readable tree output.
|
|
37
|
+
- AST-based execution engine is now the default (and only) engine. Scripts are parsed into a tree of typed nodes, then walked for execution. INCLUDE'd files are parsed and executed natively with circular-include detection. Control flow (IF/LOOP/BATCH) is driven by tree structure.
|
|
38
|
+
- `active_context()` context manager in `execsql.state` for installing an isolated `RuntimeContext` as the active global context within a `with` block.
|
|
39
|
+
- Plugin system (`execsql.plugins`) for extending execsql with custom metacommands, export formats, and import formats via Python entry points. Entry point groups: `execsql.metacommands`, `execsql.exporters`, `execsql.importers`. Plugins are discovered automatically at startup.
|
|
40
|
+
- `--list-plugins` CLI flag to show all discovered plugins and exit.
|
|
41
|
+
- Python library API: `from execsql import run` for programmatic script execution from notebooks, pipelines, and applications. Returns a `ScriptResult` with success/failure, command count, timing, errors, and final variable state. Supports DSN connection strings, pre-existing connections, substitution variables, and error control. Full RuntimeContext isolation between calls.
|
|
42
|
+
- AST `Comment` node: the parser now preserves SQL comments in the tree. Consecutive single-line `--` comments are grouped into one node; `/* */` block comments are captured as single nodes. The `--parse-tree` output includes `<CMT>` tagged comment nodes.
|
|
43
|
+
- `--parse-tree` visual improvements: color-coded type tags (`<SQL>`, `<CMD>`, `<CMT>`, `<IF>`, `<LOOP>`, etc.), dimmed line numbers, and content truncation for cleaner output.
|
|
44
|
+
- Deprecation warning emitted when `enc_password` is used in config files, advising users to switch to keyring or environment variables.
|
|
45
|
+
- Sensitive environment variables (`*SECRET*`, `*TOKEN*`, `*PASSWORD*`, etc.) are now filtered from automatic substitution variable exposure.
|
|
46
|
+
|
|
47
|
+
### Changed
|
|
48
|
+
|
|
49
|
+
- **Execution engine replaced.** The legacy flat command-list engine has been replaced by the AST-based executor. Scripts are now parsed into a tree of typed nodes and executed by walking the tree. INCLUDE'd files are parsed and executed natively with circular-include detection. All metacommands, SQL, and control flow work identically. This change is transparent to users.
|
|
50
|
+
- **BREAK outside LOOP is now an error.** `BREAK` outside a loop block now raises an error (exit 1) instead of being silently ignored. This catches script bugs that were previously unreported.
|
|
51
|
+
- `--lint` now uses the AST parser for structural validation. Unmatched IF/LOOP/BATCH/SCRIPT blocks are caught at parse time with precise source line ranges. No database connection or runtime state initialization is required. All prior lint checks (variable analysis, INCLUDE file existence, EXECUTE SCRIPT resolution, SUB_INI reading) are preserved.
|
|
52
|
+
- Export format dispatch logic (`EXPORT` and `EXPORT QUERY` metacommands) refactored from duplicated ~180-line if/elif chains into shared `_dispatch_format()` function, eliminating code duplication and fixing missing zip-compatibility checks for `EXPORT QUERY`.
|
|
53
|
+
- `MailSpec.send()` refactored: extracted `_expand()` helper to replace 12 repetitive substitution lines.
|
|
54
|
+
- Default database type changed from Access (`-t a`) to SQLite (`-t l`). Upstream defaulted to Access, which requires Windows and pyodbc. Users targeting Access databases should pass `-t a` explicitly.
|
|
55
|
+
|
|
56
|
+
### Fixed
|
|
57
|
+
|
|
58
|
+
- **[Critical]** `WriteSpec.write()` and `MailSpec.send()` error-recovery paths crashed because `SubVarSet.substitute_all()` returns `(str, bool)` but callers treated the return as a plain string. All 14 call sites now unpack the tuple correctly.
|
|
59
|
+
- **[Critical]** Error-recovery fallback in `WriteSpec.write()` and `io_write` called `.encode()` producing bytes passed to `sys.stdout.write()` which expects `str`. Removed the `.encode()` calls.
|
|
60
|
+
- `WriteSpec.write()` no longer crashes with `IndexError` when `commandliststack` is empty during early initialization errors.
|
|
61
|
+
- SQL injection vector in `exec_cmd()` across all 8 database adapters — stored procedure/function/view names are now quoted with `quote_identifier()`.
|
|
62
|
+
- `DSN` and `SQL Server` adapters no longer encode SQL strings to bytes before execution.
|
|
63
|
+
- Duplicate tuple entries in export format checks (`"txt-and"` and `"text-and"` each appeared twice).
|
|
64
|
+
- Database adapters now clear `self.password` after successful connection, reducing credential exposure window.
|
|
65
|
+
- Removed unused `_DEFAULT_CTX = RuntimeContext()` allocation in `state.py`.
|
|
66
|
+
- Version bump commits no longer skip pre-commit hooks (`--no-verify` removed from bumpversion config).
|
|
67
|
+
- `SubVarSet.substitute_all()` now enforces a 100-iteration depth limit to prevent infinite loops from cyclic variable references. The per-statement guard in the executor already had this protection, but direct callers (e.g. config loading) did not.
|
|
68
|
+
- `ConfigData.export_output_dir` is now declared in `__init__` with a default of `None` instead of being dynamically added in the CLI entry point.
|
|
69
|
+
- `Encrypt.ky` key table is now an immutable `MappingProxyType` instead of a mutable class-level dict.
|
|
70
|
+
- `JsonDatatype` attributes are now declared as class variables in the class body instead of assigned externally after class definition.
|
|
71
|
+
- `minimal_conf` test fixture expanded with commonly needed attributes (`import_encoding`, `script_encoding`, `export_output_dir`, `write_prefix`, `write_suffix`, `fold_col_hdrs`, `trim_col_hdrs`, etc.) to reduce ad-hoc attribute additions in individual tests.
|
|
72
|
+
|
|
73
|
+
### Documentation
|
|
74
|
+
|
|
75
|
+
- Fixed false `$ENV:` prefix claim in substitution variables reference — feature does not exist.
|
|
76
|
+
- Documented environment variable filtering (SECRET, TOKEN, PASSWORD, etc.) in substitution variables reference.
|
|
77
|
+
- Added missing exporter API docs (markdown, yaml, xlsx) and importer API docs (json).
|
|
78
|
+
- Added 8 missing CLI flags to README Options table (-b, -e, -g, -i, -o, -s, -y, -z).
|
|
79
|
+
- Added missing installation extras ([upsert], [firebird], [oracle]) to README and installation guide.
|
|
80
|
+
- Fixed broken `PROMPT.md` link in logging guide.
|
|
81
|
+
- Added explicit `{ #exampleN }` anchors to all 34 examples for reliable cross-referencing.
|
|
82
|
+
- Updated architecture doc: corrected metacommand count (~225), export format count (20+), added debug/notebook/server/lsp packages to module map.
|
|
83
|
+
- Updated metacommand developer guide to reflect io.py split into io_export.py, io_import.py, io_write.py, io_fileops.py.
|
|
84
|
+
- Noted SQLite as the default database type in syntax reference.
|
|
85
|
+
|
|
86
|
+
### Removed
|
|
87
|
+
|
|
88
|
+
- `--ast` / `--no-ast` CLI flag — the AST executor is now the only execution engine; no opt-out.
|
|
89
|
+
- Legacy flat command-list execution engine (`_parse_script_lines`, `read_sqlfile`, `read_sqlstring`, `runscripts`, `ScriptFile`, `CommandListWhileLoop`, `CommandListUntilLoop`, `ScriptExecSpec.execute()`).
|
|
90
|
+
- Legacy `_execute_script_direct()` function and `_execute_include_legacy()` fallback path.
|
|
91
|
+
|
|
92
|
+
______________________________________________________________________
|
|
93
|
+
|
|
16
94
|
## [2.15.11] - 2026-04-27
|
|
17
95
|
|
|
18
96
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.16.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
|
|
@@ -173,7 +173,8 @@ pip install execsql2[oracle] # Oracle (oracledb)
|
|
|
173
173
|
pip install execsql2[odbc] # ODBC DSN (pyodbc)
|
|
174
174
|
|
|
175
175
|
# Feature bundles
|
|
176
|
-
pip install execsql2[formats]
|
|
176
|
+
pip install execsql2[formats] # ODS, Excel, Jinja2, Feather, Parquet, HDF5
|
|
177
|
+
pip install execsql2[upsert] # pg-upsert for PostgreSQL upsert operations
|
|
177
178
|
pip install execsql2[auth] # OS keyring integration
|
|
178
179
|
pip install execsql2[auth-plaintext] # Keyring + plaintext file backend (headless Linux)
|
|
179
180
|
pip install execsql2[auth-encrypted] # Keyring + encrypted file backend (headless Linux)
|
|
@@ -219,31 +220,41 @@ execsql script.sql # read connection from config file
|
|
|
219
220
|
|
|
220
221
|
## Options
|
|
221
222
|
|
|
222
|
-
| Flag
|
|
223
|
-
|
|
|
224
|
-
| `-t {p,m,s,l,k,a,f,o,d}`
|
|
225
|
-
| `-u USER`
|
|
226
|
-
| `-p PORT`
|
|
227
|
-
| `-a VALUE`
|
|
228
|
-
| `-
|
|
229
|
-
| `-
|
|
230
|
-
| `-
|
|
231
|
-
| `-
|
|
232
|
-
| `-
|
|
233
|
-
| `-
|
|
234
|
-
| `-
|
|
235
|
-
| `-
|
|
236
|
-
|
|
|
237
|
-
|
|
|
238
|
-
| `--
|
|
239
|
-
| `--
|
|
240
|
-
|
|
|
241
|
-
|
|
|
242
|
-
| `--
|
|
243
|
-
|
|
|
244
|
-
| `--
|
|
245
|
-
| `--
|
|
246
|
-
| `--
|
|
223
|
+
| Flag | Description |
|
|
224
|
+
| ------------------------------------- | ---------------------------------------------------------------- |
|
|
225
|
+
| `-t {p,m,s,l,k,a,f,o,d}` | Database type |
|
|
226
|
+
| `-u USER` | Database username |
|
|
227
|
+
| `-p PORT` | Server port |
|
|
228
|
+
| `-a VALUE` | Set substitution variable `$ARG_x` |
|
|
229
|
+
| `-b` / `--boolean-int` | Treat integers 0 and 1 as boolean values |
|
|
230
|
+
| `-c SCRIPT` | Execute inline SQL or metacommand string |
|
|
231
|
+
| `-d` | Auto-create export directories |
|
|
232
|
+
| `-e ENCODING` / `--database-encoding` | Character encoding used in the database |
|
|
233
|
+
| `-f ENCODING` | Script file encoding (default: UTF-8) |
|
|
234
|
+
| `-g ENCODING` / `--output-encoding` | Encoding for WRITE and EXPORT output |
|
|
235
|
+
| `-i ENCODING` / `--import-encoding` | Encoding for data files used with IMPORT |
|
|
236
|
+
| `-l` | Write run log to `~/execsql.log` |
|
|
237
|
+
| `-m` | List metacommands and exit |
|
|
238
|
+
| `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
|
|
239
|
+
| `-o` / `--online-help` | Open the online documentation in the default browser |
|
|
240
|
+
| `-s N` / `--scan-lines` | Lines to scan for IMPORT format detection (0 = scan entire file) |
|
|
241
|
+
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
242
|
+
| `-w` | Skip password prompt when a username is supplied |
|
|
243
|
+
| `-y` / `--encodings` | List available encoding names and exit |
|
|
244
|
+
| `-z KB` / `--import-buffer` | Import buffer size in KB (default: 32) |
|
|
245
|
+
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
246
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
247
|
+
| `--dry-run` | Parse the script and report commands without executing |
|
|
248
|
+
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
249
|
+
| `--parse-tree` | Print the script's AST structure and exit (no DB) |
|
|
250
|
+
| `--list-plugins` | List discovered plugins and exit |
|
|
251
|
+
| `--ping` | Test database connectivity and exit |
|
|
252
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
253
|
+
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
254
|
+
| `--config FILE` | Load an explicit config file (highest priority after CLI args) |
|
|
255
|
+
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
256
|
+
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
257
|
+
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
247
258
|
|
|
248
259
|
Run `execsql --help` for the full option list, or `execsql -m` to list all metacommands.
|
|
249
260
|
|
|
@@ -260,6 +271,61 @@ Run `execsql --help` for the full option list, or `execsql -m` to list all metac
|
|
|
260
271
|
- Display query results in a GUI dialog; optionally prompt the user to select a row, enter a value, or submit a form.
|
|
261
272
|
- Write status messages or tabular output to the console or a file during execution.
|
|
262
273
|
- Automatically log each run, recording databases used, scripts executed, and user responses.
|
|
274
|
+
- Extend with custom metacommands, exporters, and importers via the plugin system.
|
|
275
|
+
|
|
276
|
+
# Library API
|
|
277
|
+
|
|
278
|
+
execsql can be used as a Python library for programmatic script execution:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
from execsql import run
|
|
282
|
+
|
|
283
|
+
# Execute a script file
|
|
284
|
+
result = run(script="pipeline.sql", dsn="postgresql://user:pass@host/db")
|
|
285
|
+
|
|
286
|
+
# Execute inline SQL
|
|
287
|
+
result = run(
|
|
288
|
+
sql="CREATE TABLE t (id INT);\nINSERT INTO t VALUES (1);",
|
|
289
|
+
dsn="sqlite:///my.db",
|
|
290
|
+
new_db=True,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
# With substitution variables
|
|
294
|
+
result = run(
|
|
295
|
+
script="etl.sql",
|
|
296
|
+
dsn="sqlite:///data.db",
|
|
297
|
+
variables={"SCHEMA": "public", "DATE": "2026-01-01"},
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# Check results
|
|
301
|
+
print(result.success) # True
|
|
302
|
+
print(result.commands_run) # 2
|
|
303
|
+
print(result.elapsed) # 0.003 (seconds)
|
|
304
|
+
print(result.variables) # {"SCHEMA": "public", ...}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
Error handling:
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
result = run(sql="SELECT * FROM nonexistent;", dsn="sqlite:///:memory:")
|
|
311
|
+
if not result.success:
|
|
312
|
+
for err in result.errors:
|
|
313
|
+
print(f"{err.source}:{err.line}: {err.message}")
|
|
314
|
+
|
|
315
|
+
# Or raise on failure
|
|
316
|
+
result.raise_on_error() # raises ExecSqlError
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Use a pre-existing database connection instead of a DSN:
|
|
320
|
+
|
|
321
|
+
```python
|
|
322
|
+
from execsql.db.factory import db_SQLite
|
|
323
|
+
conn = db_SQLite("my.db", new_db=True)
|
|
324
|
+
result = run(sql="SELECT 1;", connection=conn)
|
|
325
|
+
# run() does NOT close this connection — you manage its lifecycle
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Each call to `run()` uses an isolated `RuntimeContext`, so multiple calls do not share state.
|
|
263
329
|
|
|
264
330
|
# An Illustration
|
|
265
331
|
|
|
@@ -51,7 +51,8 @@ pip install execsql2[oracle] # Oracle (oracledb)
|
|
|
51
51
|
pip install execsql2[odbc] # ODBC DSN (pyodbc)
|
|
52
52
|
|
|
53
53
|
# Feature bundles
|
|
54
|
-
pip install execsql2[formats]
|
|
54
|
+
pip install execsql2[formats] # ODS, Excel, Jinja2, Feather, Parquet, HDF5
|
|
55
|
+
pip install execsql2[upsert] # pg-upsert for PostgreSQL upsert operations
|
|
55
56
|
pip install execsql2[auth] # OS keyring integration
|
|
56
57
|
pip install execsql2[auth-plaintext] # Keyring + plaintext file backend (headless Linux)
|
|
57
58
|
pip install execsql2[auth-encrypted] # Keyring + encrypted file backend (headless Linux)
|
|
@@ -97,31 +98,41 @@ execsql script.sql # read connection from config file
|
|
|
97
98
|
|
|
98
99
|
## Options
|
|
99
100
|
|
|
100
|
-
| Flag
|
|
101
|
-
|
|
|
102
|
-
| `-t {p,m,s,l,k,a,f,o,d}`
|
|
103
|
-
| `-u USER`
|
|
104
|
-
| `-p PORT`
|
|
105
|
-
| `-a VALUE`
|
|
106
|
-
| `-
|
|
107
|
-
| `-
|
|
108
|
-
| `-
|
|
109
|
-
| `-
|
|
110
|
-
| `-
|
|
111
|
-
| `-
|
|
112
|
-
| `-
|
|
113
|
-
| `-
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
| `--
|
|
117
|
-
| `--
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
| `--
|
|
121
|
-
|
|
|
122
|
-
| `--
|
|
123
|
-
| `--
|
|
124
|
-
| `--
|
|
101
|
+
| Flag | Description |
|
|
102
|
+
| ------------------------------------- | ---------------------------------------------------------------- |
|
|
103
|
+
| `-t {p,m,s,l,k,a,f,o,d}` | Database type |
|
|
104
|
+
| `-u USER` | Database username |
|
|
105
|
+
| `-p PORT` | Server port |
|
|
106
|
+
| `-a VALUE` | Set substitution variable `$ARG_x` |
|
|
107
|
+
| `-b` / `--boolean-int` | Treat integers 0 and 1 as boolean values |
|
|
108
|
+
| `-c SCRIPT` | Execute inline SQL or metacommand string |
|
|
109
|
+
| `-d` | Auto-create export directories |
|
|
110
|
+
| `-e ENCODING` / `--database-encoding` | Character encoding used in the database |
|
|
111
|
+
| `-f ENCODING` | Script file encoding (default: UTF-8) |
|
|
112
|
+
| `-g ENCODING` / `--output-encoding` | Encoding for WRITE and EXPORT output |
|
|
113
|
+
| `-i ENCODING` / `--import-encoding` | Encoding for data files used with IMPORT |
|
|
114
|
+
| `-l` | Write run log to `~/execsql.log` |
|
|
115
|
+
| `-m` | List metacommands and exit |
|
|
116
|
+
| `-n` | Create a new SQLite or PostgreSQL database if it does not exist |
|
|
117
|
+
| `-o` / `--online-help` | Open the online documentation in the default browser |
|
|
118
|
+
| `-s N` / `--scan-lines` | Lines to scan for IMPORT format detection (0 = scan entire file) |
|
|
119
|
+
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
120
|
+
| `-w` | Skip password prompt when a username is supplied |
|
|
121
|
+
| `-y` / `--encodings` | List available encoding names and exit |
|
|
122
|
+
| `-z KB` / `--import-buffer` | Import buffer size in KB (default: 32) |
|
|
123
|
+
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
124
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
125
|
+
| `--dry-run` | Parse the script and report commands without executing |
|
|
126
|
+
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
127
|
+
| `--parse-tree` | Print the script's AST structure and exit (no DB) |
|
|
128
|
+
| `--list-plugins` | List discovered plugins and exit |
|
|
129
|
+
| `--ping` | Test database connectivity and exit |
|
|
130
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
131
|
+
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
132
|
+
| `--config FILE` | Load an explicit config file (highest priority after CLI args) |
|
|
133
|
+
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
134
|
+
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
135
|
+
| `--gui-framework {tkinter,textual}` | GUI framework for interactive prompts |
|
|
125
136
|
|
|
126
137
|
Run `execsql --help` for the full option list, or `execsql -m` to list all metacommands.
|
|
127
138
|
|
|
@@ -138,6 +149,61 @@ Run `execsql --help` for the full option list, or `execsql -m` to list all metac
|
|
|
138
149
|
- Display query results in a GUI dialog; optionally prompt the user to select a row, enter a value, or submit a form.
|
|
139
150
|
- Write status messages or tabular output to the console or a file during execution.
|
|
140
151
|
- Automatically log each run, recording databases used, scripts executed, and user responses.
|
|
152
|
+
- Extend with custom metacommands, exporters, and importers via the plugin system.
|
|
153
|
+
|
|
154
|
+
# Library API
|
|
155
|
+
|
|
156
|
+
execsql can be used as a Python library for programmatic script execution:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from execsql import run
|
|
160
|
+
|
|
161
|
+
# Execute a script file
|
|
162
|
+
result = run(script="pipeline.sql", dsn="postgresql://user:pass@host/db")
|
|
163
|
+
|
|
164
|
+
# Execute inline SQL
|
|
165
|
+
result = run(
|
|
166
|
+
sql="CREATE TABLE t (id INT);\nINSERT INTO t VALUES (1);",
|
|
167
|
+
dsn="sqlite:///my.db",
|
|
168
|
+
new_db=True,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# With substitution variables
|
|
172
|
+
result = run(
|
|
173
|
+
script="etl.sql",
|
|
174
|
+
dsn="sqlite:///data.db",
|
|
175
|
+
variables={"SCHEMA": "public", "DATE": "2026-01-01"},
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Check results
|
|
179
|
+
print(result.success) # True
|
|
180
|
+
print(result.commands_run) # 2
|
|
181
|
+
print(result.elapsed) # 0.003 (seconds)
|
|
182
|
+
print(result.variables) # {"SCHEMA": "public", ...}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Error handling:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
result = run(sql="SELECT * FROM nonexistent;", dsn="sqlite:///:memory:")
|
|
189
|
+
if not result.success:
|
|
190
|
+
for err in result.errors:
|
|
191
|
+
print(f"{err.source}:{err.line}: {err.message}")
|
|
192
|
+
|
|
193
|
+
# Or raise on failure
|
|
194
|
+
result.raise_on_error() # raises ExecSqlError
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Use a pre-existing database connection instead of a DSN:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from execsql.db.factory import db_SQLite
|
|
201
|
+
conn = db_SQLite("my.db", new_db=True)
|
|
202
|
+
result = run(sql="SELECT 1;", connection=conn)
|
|
203
|
+
# run() does NOT close this connection — you manage its lifecycle
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Each call to `run()` uses an isolated `RuntimeContext`, so multiple calls do not share state.
|
|
141
207
|
|
|
142
208
|
# An Illustration
|
|
143
209
|
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
# Contributors
|
|
2
2
|
|
|
3
|
+
R. Dreas Nielsen
|
|
4
|
+
: Original author of [execsql](https://execsql.readthedocs.io/) (v1.0 through v1.130.1). Designed and implemented the metacommand language, substitution variable system, database adapters, export/import framework, GUI prompt system, and all core functionality that execsql2 is built on.
|
|
5
|
+
|
|
3
6
|
Elizabeth Shea
|
|
4
7
|
: Brainstorming, testing, coding of the conditional expression parser, coding of the 'with arguments' and 'with parameters' clauses of the [SCRIPT](../reference/metacommands.md#beginscript) metacommand, coding of the WHILE and UNTIL clauses of the [EXECUTE SCRIPT](../reference/metacommands.md#executescript) metacommand, coding of [deferred variable substitution](../reference/substitution_vars.md#deferred_substitution), corrections to the [PROMPT ENTRY_FORM](../reference/metacommands.md#prompt_entry) metacommand, examples, implementation of the ["+" prefix](../reference/substitution_vars.md#outer_scope_referent) for substitution variables, and other minor corrections.
|