execsql2 2.11.0__tar.gz → 2.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/project_context.md +27 -8
- {execsql2-2.11.0 → execsql2-2.12.0}/CHANGELOG.md +40 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/CLAUDE.md +2 -2
- {execsql2-2.11.0 → execsql2-2.12.0}/PKG-INFO +5 -2
- {execsql2-2.11.0 → execsql2-2.12.0}/README.md +4 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/about/divergence.md +49 -8
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/debugging.md +41 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/pyproject.toml +3 -3
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/cli/__init__.py +6 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/cli/lint.py +1 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/cli/run.py +18 -12
- execsql2-2.12.0/src/execsql/debug/__init__.py +6 -0
- execsql2-2.12.0/src/execsql/debug/repl.py +472 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/xlsx.py +5 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/yaml.py +2 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/__init__.py +1 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/control.py +4 -10
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/debug.py +1 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/dispatch.py +1 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/script/engine.py +15 -5
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/state.py +2 -2
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/gui.py +26 -4
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_profile.py +52 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/gui/test_backends.py +422 -0
- execsql2-2.12.0/tests/importers/test_csv_importer.py +436 -0
- execsql2-2.12.0/tests/metacommands/test_breakpoint.py +980 -0
- execsql2-2.12.0/tests/metacommands/test_io_export.py +1377 -0
- execsql2-2.12.0/tests/metacommands/test_io_import.py +1585 -0
- execsql2-2.12.0/tests/metacommands/test_metacommands_data.py +802 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_extended.py +362 -3
- {execsql2-2.11.0 → execsql2-2.12.0}/uv.lock +1 -1
- execsql2-2.11.0/src/execsql/metacommands/debug_repl.py +0 -288
- execsql2-2.11.0/tests/importers/test_csv_importer.py +0 -193
- execsql2-2.11.0/tests/metacommands/test_breakpoint.py +0 -524
- execsql2-2.11.0/tests/metacommands/test_metacommands_data.py +0 -381
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/dba.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/herald.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/inspector.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/oracle.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/patcher.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/qa.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/agents/scribe.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/code-oracle.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/migrate.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/review-changes.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/test-module.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/update-changelog.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/commands/where-is.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.claude/state/status.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.github/workflows/ci-cd.yml +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.gitignore +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.pre-commit-config.yaml +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.pre-commit-hooks.yaml +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.python-version +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/.readthedocs.yaml +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/CONTRIBUTING.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/LICENSE.txt +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/NOTICE +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/SECURITY.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/about/contributors.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/about/copyright.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/cli.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/db.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/exporters.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/importers.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/index.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/api/metacommands.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/dev/adding_db_adapters.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/dev/adding_exporters.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/dev/adding_importers.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/dev/adding_metacommands.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/dev/architecture.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/getting-started/installation.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/getting-started/requirements.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/getting-started/syntax.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/documentation.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/encoding.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/examples.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/formatter.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/logging.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/sql_syntax.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/usage.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/guides/using_scripts.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/Compare_planets.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/actions.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/actions2.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/checkboxes.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/connect.b64 +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/connect.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/create_conf.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/data_error1_screenshot.jpg +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/entry_form.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/execsql_console.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/execsql_logo_01.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/fatals.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/logo_small.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/pause_terminal.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/pause_terminal_sm.b64 +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/pause_terminal_sm.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/prompt_compare.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/set_build_commands.jpg +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/unit_conversions.b64 +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/unit_conversions_029.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/unmatched.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/images/vim_execsql_highlight.png +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/index.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/reference/configuration.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/reference/metacommands.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/reference/security.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/docs/reference/substitution_vars.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/extras/vscode-execsql/README.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/extras/vscode-execsql/package.json +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/extras/vscode-execsql/syntaxes/execsql.tmLanguage.json +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/justfile +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/scripts/generate_vscode_grammar.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/__main__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/cli/dsn.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/cli/help.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/config.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/constants.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/access.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/dsn.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/duckdb.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/factory.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/firebird.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/mysql.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/oracle.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/postgres.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/sqlite.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/db/sqlserver.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exceptions.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/delimited.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/duckdb.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/feather.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/html.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/json.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/latex.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/markdown.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/ods.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/parquet.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/pretty.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/protocol.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/raw.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/sqlite.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/templates.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/values.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/xls.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/xml.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/exporters/zip.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/format.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/gui/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/gui/base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/gui/console.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/gui/desktop.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/gui/tui.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/csv.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/feather.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/ods.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/importers/xls.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/conditions.py +1 -1
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/connect.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/data.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/io.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/io_export.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/io_fileops.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/io_import.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/io_write.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/prompt.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/script_ext.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/metacommands/system.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/models.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/parser.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/py.typed +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/script/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/script/control.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/script/variables.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/types.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/auth.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/crypto.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/datetime.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/errors.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/fileio.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/mail.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/numeric.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/regex.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/strings.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/src/execsql/utils/timer.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/README.md +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/config_settings.sqlite +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/example_config_prompt.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/execsql.conf +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/make_config_db.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/md_compare.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/md_glossary.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/md_upsert.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/pg_compare.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/pg_glossary.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/pg_upsert.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/script_template.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/ss_compare.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/ss_glossary.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/templates/ss_upsert.sql +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_cli.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_cli_e2e.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_cli_run.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_lint.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/cli/test_ping.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/conftest.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_duckdb.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_factory.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_postgres.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_sqlite.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/db/test_sqlite_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_base.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_db.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_delimited.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_duckdb_exporter.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_exporters.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_feather.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_html_latex.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_json.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_markdown.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_ods.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_parquet.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_sqlite_exporter.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_templates.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_xls_xlsx.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_xlsx.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_xml.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_yaml.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/exporters/test_zip.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/gui/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/importers/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/importers/test_feather_importer.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/importers/test_ods_importer.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/importers/test_xls_importer.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/conftest.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/test_dsn.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/test_duckdb.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/test_mysql.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/test_postgres.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/integration/test_sqlite.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_assert.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_connect.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_connect.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_fileops_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_io.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_io_write_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_script_ext.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_system.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_metacommands_system_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/metacommands/test_row_count.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_config.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_config_data.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_constants.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_engine.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_error_messages.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_exceptions.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_format.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_mail.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_models.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_package.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_parser.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_registry.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_script.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_state.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/test_types.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/__init__.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_auth.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_auth_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_crypto.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_datetime.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_errors.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_errors_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_fileio.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_fileio_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_numeric.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_regex.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_strings.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_timer.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/tests/utils/test_timer_extra.py +0 -0
- {execsql2-2.11.0 → execsql2-2.12.0}/zensical.toml +0 -0
|
@@ -67,6 +67,9 @@ src/execsql/ # active codebase — all new work goes here
|
|
|
67
67
|
importers/
|
|
68
68
|
__init__.py
|
|
69
69
|
base.py / csv.py / ods.py / xls.py / feather.py
|
|
70
|
+
debug/
|
|
71
|
+
__init__.py # debug package
|
|
72
|
+
repl.py # x_breakpoint, _debug_repl, REPL helpers (BREAKPOINT metacommand)
|
|
70
73
|
metacommands/
|
|
71
74
|
__init__.py # DISPATCH_TABLE, format/db constants, re-exports all handlers
|
|
72
75
|
dispatch.py # build_dispatch_table() — all mcl.add() regex registrations
|
|
@@ -189,10 +192,10 @@ Triggered on: push to `main`, any tag `v*.*.*`, pull requests.
|
|
|
189
192
|
|
|
190
193
|
## Versioning
|
|
191
194
|
|
|
192
|
-
`bump-my-version` manages versions. Current: `2.
|
|
195
|
+
`bump-my-version` manages versions. Current: `2.11.0`. Bump commands:
|
|
193
196
|
|
|
194
|
-
- `just bump-patch` → 2.
|
|
195
|
-
- `just bump-minor` → 2.
|
|
197
|
+
- `just bump-patch` → 2.11.0 → 2.11.1
|
|
198
|
+
- `just bump-minor` → 2.11.0 → 2.12.0
|
|
196
199
|
Bumps commit + tag. Pre-commit hook runs `uv lock` + stages `uv.lock`.
|
|
197
200
|
|
|
198
201
|
## Ruff Config
|
|
@@ -254,16 +257,32 @@ the foreseeable future.
|
|
|
254
257
|
| Dispatch optimization already in place (verified) | 2.5.0 | 2026-04 |
|
|
255
258
|
| PostgreSQL integration tests (9 tests, CI Docker) | 2.5.0 | 2026-04 |
|
|
256
259
|
| MySQL integration tests (9 tests, CI Docker) | 2.5.0 | 2026-04 |
|
|
260
|
+
| `RuntimeContext` refactor + module proxy | 2.6.0 | 2026-04 |
|
|
261
|
+
| `noqa` cleanup (180 suppressions removed) | 2.6.0 | 2026-04 |
|
|
262
|
+
| Coverage raised to 86% (3010 tests) | 2.6.0 | 2026-04 |
|
|
263
|
+
| Markdown, YAML, XLSX export formats | 2.7.0 | 2026-04 |
|
|
264
|
+
| `ASSERT` metacommand | 2.8.0 | 2026-04 |
|
|
265
|
+
| `--dry-run` variable expansion | 2.8.0 | 2026-04 |
|
|
266
|
+
| `--profile` per-statement timing | 2.8.0 | 2026-04 |
|
|
267
|
+
| `--ping` connectivity test | 2.9.0 | 2026-04 |
|
|
268
|
+
| `--lint` static script analysis | 2.9.0 | 2026-04 |
|
|
269
|
+
| Configuration docs audit (6 fixes) | 2.9.0 | 2026-04 |
|
|
270
|
+
| `ROW_COUNT_GT/GTE/EQ/LT` conditionals | 2.10.0 | 2026-04 |
|
|
271
|
+
| `BREAKPOINT` debug REPL with step mode | 2.10.0 | 2026-04 |
|
|
272
|
+
| Error messages restored (script location, command) | 2.11.0 | 2026-04 |
|
|
273
|
+
| 16-item codebase analysis fix sweep | 2.11.x | 2026-04 |
|
|
257
274
|
|
|
258
275
|
______________________________________________________________________
|
|
259
276
|
|
|
260
|
-
### v2.6
|
|
277
|
+
### Completed milestone detail (v2.6–v2.11)
|
|
261
278
|
|
|
262
|
-
|
|
263
|
-
- [x] **`noqa` cleanup in `metacommands/__init__.py`** — removed all 180 redundant `# noqa` comments; `__all__` already satisfies ruff F401.
|
|
264
|
-
- [x] **Coverage push to 86%** — 403 new tests (3010 total) covering `db/base.py` (55→99%), `metacommands/connect.py` (36→100%), `script/engine.py` (77→95%), `exporters/delimited.py` (76→95%). Remaining gap to 90% is in GUI, ODS, and import handlers.
|
|
279
|
+
#### v2.6 — Architecture & Internal Quality
|
|
265
280
|
|
|
266
|
-
|
|
281
|
+
- [x] `state.py` → `RuntimeContext` refactor
|
|
282
|
+
- [x] `noqa` cleanup in `metacommands/__init__.py`
|
|
283
|
+
- [x] Coverage push to 86%
|
|
284
|
+
|
|
285
|
+
#### v2.7 — New Export/Import Formats
|
|
267
286
|
|
|
268
287
|
- [x] **Parquet import** — already existed as `IMPORT TO table FROM PARQUET file` (verified present).
|
|
269
288
|
- [x] **YAML export** — `FORMAT YAML` via PyYAML, list-of-dicts with native type preservation.
|
|
@@ -13,6 +13,46 @@ ______________________________________________________________________
|
|
|
13
13
|
|
|
14
14
|
______________________________________________________________________
|
|
15
15
|
|
|
16
|
+
## [2.12.0] - 2026-04-01
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Debug REPL `.where` / `.w` command — shows current script file, line number, and the upcoming statement text (truncated to 120 chars). The entry banner now includes the location (`[Breakpoint] myscript.sql:42`) and `_print_where()` is called automatically on REPL entry via `BREAKPOINT` or step mode.
|
|
21
|
+
- Debug REPL `.set VAR VAL` / `.s VAR VAL` command — sets or updates a substitution variable interactively during a `BREAKPOINT` session. Prints a confirmation line (`VAR = VAL`) on success; prints an error if substitution variables are not initialised.
|
|
22
|
+
- Debug REPL ANSI color output — horizontal rule separators, colored labels ("Breakpoint"/"Step" in bold yellow, filename:line in cyan, type tags in dim green), cyan variable names, dim `=` signs, red error messages, bold SQL column headers, and dim row-count and table borders. Color is auto-detected via TTY and suppressed when `NO_COLOR` or `EXECSQL_NO_COLOR` environment variables are set. Falls back to plain text in non-interactive contexts (CI, piped output). Help text is also colorized with cyan command names and consistent column alignment.
|
|
23
|
+
- Debug REPL shortcut aliases — `.h` for `.help`, `.v` for `.vars`, `.v all` for `.vars all`.
|
|
24
|
+
- Debug REPL step mode banner — when the REPL is re-entered via `.next` / step mode, the entry banner now shows "Step" instead of "Breakpoint" to make it clear the pause is from stepping rather than an explicit `BREAKPOINT` metacommand.
|
|
25
|
+
- `--profile-limit N` CLI option — controls how many top statements appear in the `--profile` timing summary (default: 20). The "not shown" footer message now includes the active limit for clarity.
|
|
26
|
+
- Test coverage raised from 86% to 91% — 274 new tests across `metacommands/io_import.py`, `metacommands/io_export.py`, `metacommands/control.py`, `metacommands/data.py`, `importers/csv.py`, and `gui/console.py`. Coverage floor raised from 85% to 90% in `pyproject.toml`.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- `execsql.debug.repl` is now a dedicated package (`src/execsql/debug/repl.py`); previously the REPL lived at `execsql.metacommands.debug_repl`. Internal import paths have been updated throughout. No public API change.
|
|
31
|
+
|
|
32
|
+
______________________________________________________________________
|
|
33
|
+
|
|
34
|
+
## [2.11.1] - 2026-04-01
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- `x_assert` crash when `exec_log` is None — added null guard on `log_user_msg()` call.
|
|
39
|
+
- `--ping` version-query loop exiting prematurely — `break` was at wrong indentation, skipping fallback queries when the first query returned no rows.
|
|
40
|
+
- `CONSOLE SET WIDTH/HEIGHT` crash — `gui_console_width()`/`gui_console_height()` restored as setter functions with GUI console propagation.
|
|
41
|
+
- `$ERROR_MESSAGE` now contains full `errmsg()` (with script location and timestamp) for non-halting errors.
|
|
42
|
+
- Non-halting SQL and metacommand errors now logged to exec_log.
|
|
43
|
+
- `x_debug_log_subvars` log format — was printing full tuple instead of name/value for local variables.
|
|
44
|
+
- Dead `endloop()` removed from `control.py` — `state.endloop()` is canonical.
|
|
45
|
+
- YAML `append=True` now emits `---` document separator for valid multi-document streams.
|
|
46
|
+
- REPL dot-command parsing consistency between dispatcher and exit-check.
|
|
47
|
+
- `__delattr__` on state proxy uses cached `_DEFAULT_CTX` instead of allocating per call.
|
|
48
|
+
- `write_query_to_xlsx` single-sheet now updates `export_metadata`.
|
|
49
|
+
- `isinstance()` used instead of `type()` equality in `MetaCommandList.add()`.
|
|
50
|
+
- Module docstrings in `conditions.py` and `control.py` moved before imports.
|
|
51
|
+
- FEATHER divergence doc corrected — `polars` only, not `polars + pyarrow`.
|
|
52
|
+
- README pre-commit rev updated to `v2.11.0`; options table completed.
|
|
53
|
+
|
|
54
|
+
______________________________________________________________________
|
|
55
|
+
|
|
16
56
|
## [2.11.0] - 2026-04-01
|
|
17
57
|
|
|
18
58
|
### Added
|
|
@@ -37,13 +37,13 @@ A multi-agent system where specialized agents collaborate to improve, extend, de
|
|
|
37
37
|
1. **Research** — Oracle investigates codebase, finds relevant code paths and impact
|
|
38
38
|
1. **Plan** — DBA synthesizes research into implementation approach, aligns with human
|
|
39
39
|
1. **Implement** — Patcher writes code, Oracle advises on architecture
|
|
40
|
-
1. **Test** — QA writes/runs tests, verifies coverage stays above
|
|
40
|
+
1. **Test** — QA writes/runs tests, verifies coverage stays above 90%
|
|
41
41
|
1. **Document** — Scribe updates docs, Herald updates changelog
|
|
42
42
|
1. **Review** — Inspector does final code review before human merge
|
|
43
43
|
|
|
44
44
|
## Constraints
|
|
45
45
|
|
|
46
|
-
- Coverage floor (
|
|
46
|
+
- Coverage floor (90%) must be maintained — QA blocks any change that drops it
|
|
47
47
|
- Backwards compatibility with upstream execsql v1.130.1 unless explicitly approved
|
|
48
48
|
- No destructive git operations without human approval
|
|
49
49
|
- Agents should always read `.claude/project_context.md` before starting work
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: execsql2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.12.0
|
|
4
4
|
Summary: Runs a SQL script against a PostgreSQL, SQLite, MariaDB/MySQL, DuckDB, Firebird, MS-Access, MS-SQL-Server, or Oracle database, or an ODBC DSN. Provides metacommands to import and export data, copy data between databases, conditionally execute SQL and metacommands, and dynamically alter SQL and metacommands with substitution variables.
|
|
5
5
|
Project-URL: Repository, https://github.com/geocoug/execsql
|
|
6
6
|
Project-URL: Issues, https://github.com/geocoug/execsql/issues
|
|
@@ -220,8 +220,11 @@ execsql script.sql # read connection from config file
|
|
|
220
220
|
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
221
221
|
| `-w` | Skip password prompt when a username is supplied |
|
|
222
222
|
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
223
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
223
224
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
224
225
|
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
226
|
+
| `--ping` | Test database connectivity and exit |
|
|
227
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
225
228
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
226
229
|
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
227
230
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
@@ -298,7 +301,7 @@ execsql-format --check scripts/
|
|
|
298
301
|
```yaml
|
|
299
302
|
repos:
|
|
300
303
|
- repo: https://github.com/geocoug/execsql
|
|
301
|
-
rev: v2.
|
|
304
|
+
rev: v2.11.0
|
|
302
305
|
hooks:
|
|
303
306
|
- id: execsql-format
|
|
304
307
|
args: [--in-place]
|
|
@@ -110,8 +110,11 @@ execsql script.sql # read connection from config file
|
|
|
110
110
|
| `-v {0,1,2,3}` | GUI level (0=none, 1=password, 2=selection, 3=full) |
|
|
111
111
|
| `-w` | Skip password prompt when a username is supplied |
|
|
112
112
|
| `--dsn URL` | Connection string (e.g. `postgresql://user:pass@host/db`) |
|
|
113
|
+
| `--output-dir DIR` | Default base directory for EXPORT output files |
|
|
113
114
|
| `--dry-run` | Parse the script and report commands without executing |
|
|
114
115
|
| `--lint` | Static analysis: check structure and warn on issues (no DB) |
|
|
116
|
+
| `--ping` | Test database connectivity and exit |
|
|
117
|
+
| `--profile` | Show per-statement timing summary after execution |
|
|
115
118
|
| `--progress` | Show a progress bar for long-running IMPORT operations |
|
|
116
119
|
| `--debug` | Start in step-through debug mode (REPL pauses before each stmt) |
|
|
117
120
|
| `--dump-keywords` | Print metacommand keywords as JSON and exit |
|
|
@@ -188,7 +191,7 @@ execsql-format --check scripts/
|
|
|
188
191
|
```yaml
|
|
189
192
|
repos:
|
|
190
193
|
- repo: https://github.com/geocoug/execsql
|
|
191
|
-
rev: v2.
|
|
194
|
+
rev: v2.11.0
|
|
192
195
|
hooks:
|
|
193
196
|
- id: execsql-format
|
|
194
197
|
args: [--in-place]
|
|
@@ -24,7 +24,8 @@ ______________________________________________________________________
|
|
|
24
24
|
| `--gui-framework` | Select GUI backend: `tkinter` (default) or `textual` (terminal UI). |
|
|
25
25
|
| `--debug` | Start in step-through debug mode. The debug REPL pauses before each statement, as if `BREAKPOINT` were at the top with `.next` always active. |
|
|
26
26
|
| `--dry-run` | Parse the script and print the full command list without connecting to a database or executing anything. Substitution variables already populated at parse time (env vars, `--assign-arg` values, built-in start-time vars) are expanded in the output; execution-time variables (`$DB_NAME`, `$CURRENT_TIME`, etc.) remain unexpanded. |
|
|
27
|
-
| `--profile` | Record wall-clock time for each SQL and metacommand statement. After the script completes, print a summary table sorted by elapsed time (descending), showing time, percentage of total, source location, command type, and a command preview.
|
|
27
|
+
| `--profile` | Record wall-clock time for each SQL and metacommand statement. After the script completes, print a summary table sorted by elapsed time (descending), showing time, percentage of total, source location, command type, and a command preview. |
|
|
28
|
+
| `--profile-limit N` | Number of top statements to display in the `--profile` summary (default: 20). Remaining statements are counted and noted in the output footer. |
|
|
28
29
|
| `--ping` | Test database connectivity and exit. Connects using the supplied connection parameters, queries for the server version, and prints a one-line success message (exit 0) or the error (exit 1). No script file argument is required. |
|
|
29
30
|
| `--lint` | Parse the script and perform static analysis without connecting to a database. Reports unmatched IF/ENDIF, LOOP/END LOOP, and BEGIN BATCH/END BATCH blocks (errors), potentially undefined `!!$VAR!!` references (warnings), and missing INCLUDE file targets (warnings). Exits 0 if no errors, 1 if errors found. |
|
|
30
31
|
|
|
@@ -33,19 +34,19 @@ ______________________________________________________________________
|
|
|
33
34
|
| Format | Description |
|
|
34
35
|
| ----------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
35
36
|
| `PARQUET` | Export query or table results to Apache Parquet via `polars`. |
|
|
36
|
-
| `FEATHER` | Export to Apache Feather/IPC via `polars`
|
|
37
|
+
| `FEATHER` | Export to Apache Feather/IPC via `polars` (upstream used `pandas` + `pyarrow`). |
|
|
37
38
|
| `YAML` | Export query or table results as a YAML sequence of mappings via `PyYAML`. |
|
|
38
39
|
| `MARKDOWN` / `MD` | Export query or table results as a GitHub-Flavored Markdown (GFM) pipe table. Pure Python, no optional dependencies. |
|
|
39
40
|
| `XLSX` | Export query or table results to an Excel XLSX workbook via `openpyxl` (single or multi-sheet). |
|
|
40
41
|
|
|
41
42
|
### Metacommands
|
|
42
43
|
|
|
43
|
-
| Metacommand | Description
|
|
44
|
-
| ---------------------- |
|
|
45
|
-
| `ASSERT` | Evaluate a condition and raise an error (halting the script) if it is false. Supports all IF conditions. Optional quoted failure message. Skipped in false IF blocks.
|
|
46
|
-
| `BREAKPOINT` | Pause script execution and drop into an interactive debug REPL.
|
|
47
|
-
| `CONFIG SHOW_PROGRESS` | Enable the Rich progress bar for IMPORT operations at runtime.
|
|
48
|
-
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file.
|
|
44
|
+
| Metacommand | Description |
|
|
45
|
+
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
46
|
+
| `ASSERT` | Evaluate a condition and raise an error (halting the script) if it is false. Supports all IF conditions. Optional quoted failure message. Skipped in false IF blocks. |
|
|
47
|
+
| `BREAKPOINT` | Pause script execution and drop into an interactive debug REPL. See [Debugging](#debugging) below for full details. |
|
|
48
|
+
| `CONFIG SHOW_PROGRESS` | Enable the Rich progress bar for IMPORT operations at runtime. |
|
|
49
|
+
| `CONFIG LOG_SQL` | Enable SQL query audit logging — writes executed SQL to the log file. |
|
|
49
50
|
|
|
50
51
|
### Conditional Tests
|
|
51
52
|
|
|
@@ -106,6 +107,46 @@ New options in `execsql.conf`:
|
|
|
106
107
|
| `py.typed` marker | PEP 561 marker enabling downstream static type checking. |
|
|
107
108
|
| Structured keyword registry | `--dump-keywords` introspects the dispatch table and outputs JSON used by the grammar generator and test suite. |
|
|
108
109
|
|
|
110
|
+
### Debugging { #debugging }
|
|
111
|
+
|
|
112
|
+
execsql2 adds a full interactive debugging system that has no equivalent in upstream execsql.
|
|
113
|
+
|
|
114
|
+
**`BREAKPOINT` metacommand** — insert `-- !x! BREAKPOINT` anywhere in a script to pause execution and drop into a debug REPL. The REPL provides a `execsql debug>` prompt where you can inspect state and interact with the database before resuming.
|
|
115
|
+
|
|
116
|
+
**`--debug` CLI flag** — start the script in step-through mode, pausing before every statement as if `BREAKPOINT` were inserted at the top with `.next` always active.
|
|
117
|
+
|
|
118
|
+
**REPL commands** (all dot-prefixed to avoid collisions with variable names and SQL):
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
| ---------------------- | ------------------------------------------------------------------------- |
|
|
122
|
+
| `.continue` / `.c` | Resume normal script execution |
|
|
123
|
+
| `.abort` / `.q` | Halt the script with exit status 1 |
|
|
124
|
+
| `.vars` / `.v` | List all user, system, local, and counter variables (grouped by type) |
|
|
125
|
+
| `.vars all` / `.v all` | Include environment variables (`&`) in the listing |
|
|
126
|
+
| `.next` / `.n` | Execute the next statement, then pause again (step mode) |
|
|
127
|
+
| `.where` / `.w` | Show the current script file, line number, and upcoming statement text |
|
|
128
|
+
| `.stack` | Show the command-list stack (script name, cursor position, nesting depth) |
|
|
129
|
+
| `.set VAR VAL` / `.s` | Set or update a substitution variable; prints confirmation on success |
|
|
130
|
+
| `.help` / `.h` | Show available commands |
|
|
131
|
+
|
|
132
|
+
**Non-prefixed input** is interpreted as either a variable lookup or ad-hoc SQL:
|
|
133
|
+
|
|
134
|
+
| Input | Behavior |
|
|
135
|
+
| ------------------------------ | -------------------------------------------------------------------------------- |
|
|
136
|
+
| `logfile` | Print the value of the `logfile` substitution variable |
|
|
137
|
+
| `$ARG_1` | Print the value of a system/built-in variable |
|
|
138
|
+
| `SELECT count(*) FROM orders;` | Execute SQL against the current database and pretty-print the results in a table |
|
|
139
|
+
|
|
140
|
+
**Key behaviors:**
|
|
141
|
+
|
|
142
|
+
- **Non-interactive safety** — `BREAKPOINT` is silently skipped when `sys.stdin` is not a TTY (CI pipelines, piped input, cron). Scripts never hang in automation.
|
|
143
|
+
- **Ad-hoc SQL** — any input ending with `;` is executed against the current database connection using the same cursor and transaction state as the script. Queries return a formatted table; DML statements (INSERT, UPDATE, DELETE) execute and commit/rollback according to the current autocommit and batch settings.
|
|
144
|
+
- **Variable inspection** — bare names look up user-defined variables (e.g., `logfile`); sigil-prefixed names look up system (`$`), environment (`&`), local (`~`), or counter (`@`) variables. If a `$`-prefixed name isn't found, the REPL strips the sigil and retries (since `SUB` stores keys without a prefix).
|
|
145
|
+
- **Step mode** — `.next` executes exactly one statement then re-enters the REPL. When stepping, the entry banner shows "Step" instead of "Breakpoint" to distinguish stepping from an explicit `BREAKPOINT`. Combined with `.where`, `.vars`, and SQL queries, this allows line-by-line script debugging with full state visibility.
|
|
146
|
+
- **Location display** — on entry to the REPL (via `BREAKPOINT` or step mode) the banner shows a horizontal rule with the label ("Breakpoint" or "Step"), the current filename and line number, and the upcoming statement. Use `.where` (or `.w`) at any time to re-display this information.
|
|
147
|
+
- **ANSI color output** — the REPL uses ANSI color on TTY outputs: bold yellow for section labels, cyan for filenames and variable names, dim for separators and `=` signs, red for error messages, bold for SQL column headers, and dim italic for `NULL` values. Color is suppressed when `NO_COLOR` or `EXECSQL_NO_COLOR` environment variables are set, or when the output stream is not a TTY.
|
|
148
|
+
- **Readline support** — on platforms where `readline` is available (macOS, Linux), the REPL supports arrow-key history navigation and line editing.
|
|
149
|
+
|
|
109
150
|
______________________________________________________________________
|
|
110
151
|
|
|
111
152
|
## Changed Behavior
|
|
@@ -38,6 +38,47 @@ DEBUG WRITE <script_name> [[APPEND] TO <filename>]
|
|
|
38
38
|
|
|
39
39
|
This is an alias for the [WRITE SCRIPT](../reference/metacommands.md#write_script) metacommand.
|
|
40
40
|
|
|
41
|
+
# Interactive Debug REPL (BREAKPOINT)
|
|
42
|
+
|
|
43
|
+
Insert `-- !x! BREAKPOINT` anywhere in a script to pause execution and drop into the interactive debug REPL:
|
|
44
|
+
|
|
45
|
+
```sql
|
|
46
|
+
-- !x! BREAKPOINT
|
|
47
|
+
SELECT * FROM orders WHERE status = 'pending';
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The REPL prints the current file name, line number, and the upcoming statement when it opens:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
[Breakpoint] myscript.sql:42 — Script paused. Type '.help' for commands, '.c' to resume.
|
|
54
|
+
myscript.sql:42 (sql)
|
|
55
|
+
→ SELECT * FROM orders WHERE status = 'pending';
|
|
56
|
+
execsql debug>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Available commands:**
|
|
60
|
+
|
|
61
|
+
| Command | Shortcut | Description |
|
|
62
|
+
| -------------- | -------- | ------------------------------------------------------------------------- |
|
|
63
|
+
| `.continue` | `.c` | Resume normal script execution |
|
|
64
|
+
| `.abort` | `.q` | Halt the script with exit status 1 |
|
|
65
|
+
| `.vars` | `.v` | List user, system, local, and counter substitution variables |
|
|
66
|
+
| `.vars all` | `.v all` | Include environment variables (`&`) in the listing |
|
|
67
|
+
| `.next` | `.n` | Execute the next statement, then pause again (step mode) |
|
|
68
|
+
| `.where` | `.w` | Re-display the current script location and upcoming statement |
|
|
69
|
+
| `.stack` | | Show the command-list stack (script name, cursor position, nesting depth) |
|
|
70
|
+
| `.set VAR VAL` | `.s` | Set or update a substitution variable |
|
|
71
|
+
| `.help` | `.h` | Show available commands |
|
|
72
|
+
|
|
73
|
+
Anything not starting with `.` is treated as a variable lookup or SQL:
|
|
74
|
+
|
|
75
|
+
- A bare name (e.g. `logfile`) prints the value of that substitution variable.
|
|
76
|
+
- Any input ending with `;` is executed as SQL against the current database (expects columns returned, e.g. SELECT).
|
|
77
|
+
|
|
78
|
+
The `--debug` CLI flag starts execution in step mode, pausing before every statement.
|
|
79
|
+
|
|
80
|
+
In non-interactive environments (CI, piped input) `BREAKPOINT` is silently skipped so automated pipelines are never blocked.
|
|
81
|
+
|
|
41
82
|
The ON ERROR_HALT metacommands allow custom reporting (or cleanup) actions to be taken when errors occur.
|
|
42
83
|
|
|
43
84
|
Setting the configuration setting [write_warnings](../reference/configuration.md#write_warnings) to "Yes" can also assist with debugging by displaying conditions that may result from errors in the script.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execsql2"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.12.0"
|
|
8
8
|
description = "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."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = { file = "LICENSE.txt" }
|
|
@@ -158,7 +158,7 @@ skip-magic-trailing-comma = false
|
|
|
158
158
|
line-ending = "auto"
|
|
159
159
|
|
|
160
160
|
[tool.bumpversion]
|
|
161
|
-
current_version = "2.
|
|
161
|
+
current_version = "2.12.0"
|
|
162
162
|
commit = true
|
|
163
163
|
commit_args = "--no-verify"
|
|
164
164
|
tag = true
|
|
@@ -182,7 +182,7 @@ addopts = [
|
|
|
182
182
|
"--cov=execsql",
|
|
183
183
|
"--cov-branch",
|
|
184
184
|
"--cov-report=xml",
|
|
185
|
-
"--cov-fail-under=
|
|
185
|
+
"--cov-fail-under=90",
|
|
186
186
|
"--strict-markers",
|
|
187
187
|
"--strict-config",
|
|
188
188
|
"--color=yes",
|
|
@@ -278,6 +278,11 @@ def main(
|
|
|
278
278
|
"--profile",
|
|
279
279
|
help="Record per-statement execution times and print a timing summary after the script completes.",
|
|
280
280
|
),
|
|
281
|
+
profile_limit: int = typer.Option(
|
|
282
|
+
20,
|
|
283
|
+
"--profile-limit",
|
|
284
|
+
help="Number of top statements to show in the --profile timing summary (default: 20).",
|
|
285
|
+
),
|
|
281
286
|
debug: bool = typer.Option(
|
|
282
287
|
False,
|
|
283
288
|
"--debug",
|
|
@@ -449,6 +454,7 @@ def main(
|
|
|
449
454
|
output_dir=output_dir,
|
|
450
455
|
progress=progress,
|
|
451
456
|
profile=profile,
|
|
457
|
+
profile_limit=profile_limit,
|
|
452
458
|
ping=ping,
|
|
453
459
|
lint=lint,
|
|
454
460
|
debug=debug,
|
|
@@ -194,7 +194,7 @@ def _lint_cmdlist(
|
|
|
194
194
|
for cmd in cmdlist.cmdlist:
|
|
195
195
|
src = cmd.source
|
|
196
196
|
lno = cmd.line_no
|
|
197
|
-
stmt = cmd.command.statement
|
|
197
|
+
stmt = cmd.command.statement
|
|
198
198
|
|
|
199
199
|
if cmd.command_type == "sql":
|
|
200
200
|
# SQL statements: check for variable references only
|
|
@@ -8,6 +8,7 @@ and drives the main execution loop. Separated from argument parsing
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
import atexit
|
|
11
|
+
from typing import Any
|
|
11
12
|
import datetime
|
|
12
13
|
import getpass
|
|
13
14
|
import os
|
|
@@ -70,12 +71,14 @@ def _print_dry_run(cmdlist: object) -> None:
|
|
|
70
71
|
# ---------------------------------------------------------------------------
|
|
71
72
|
|
|
72
73
|
|
|
73
|
-
def _print_profile(profile_data: list[tuple]) -> None:
|
|
74
|
+
def _print_profile(profile_data: list[tuple], limit: int = 20) -> None:
|
|
74
75
|
"""Print a per-statement timing summary to stdout.
|
|
75
76
|
|
|
76
77
|
Args:
|
|
77
78
|
profile_data: List of ``(source, line_no, command_type, elapsed_secs,
|
|
78
79
|
command_text_preview)`` tuples collected during execution.
|
|
80
|
+
limit: Maximum number of top statements to display (default: 20).
|
|
81
|
+
All statements are included in totals regardless of this value.
|
|
79
82
|
"""
|
|
80
83
|
if not profile_data:
|
|
81
84
|
_console.print("[dim]Profile: no statements recorded.[/dim]")
|
|
@@ -84,9 +87,9 @@ def _print_profile(profile_data: list[tuple]) -> None:
|
|
|
84
87
|
total_secs = sum(row[3] for row in profile_data)
|
|
85
88
|
n = len(profile_data)
|
|
86
89
|
|
|
87
|
-
# Sort descending by elapsed time; show top
|
|
90
|
+
# Sort descending by elapsed time; show top `limit` (or all if <= limit).
|
|
88
91
|
sorted_data = sorted(profile_data, key=lambda r: r[3], reverse=True)
|
|
89
|
-
display = sorted_data[:
|
|
92
|
+
display = sorted_data[:limit]
|
|
90
93
|
|
|
91
94
|
_console.print()
|
|
92
95
|
_console.print(f"[bold cyan]Profile:[/bold cyan] {n} statement{'s' if n != 1 else ''} in {total_secs:.3f}s")
|
|
@@ -114,10 +117,10 @@ def _print_profile(profile_data: list[tuple]) -> None:
|
|
|
114
117
|
f"{preview_short}",
|
|
115
118
|
)
|
|
116
119
|
|
|
117
|
-
if len(sorted_data) >
|
|
118
|
-
omitted = len(sorted_data) -
|
|
120
|
+
if len(sorted_data) > limit:
|
|
121
|
+
omitted = len(sorted_data) - limit
|
|
119
122
|
_console.print(
|
|
120
|
-
f"[dim] ... {omitted} more statement{'s' if omitted != 1 else ''} not shown (top
|
|
123
|
+
f"[dim] ... {omitted} more statement{'s' if omitted != 1 else ''} not shown (top {limit} by time)[/dim]",
|
|
121
124
|
)
|
|
122
125
|
|
|
123
126
|
_console.print()
|
|
@@ -128,7 +131,7 @@ def _print_profile(profile_data: list[tuple]) -> None:
|
|
|
128
131
|
# ---------------------------------------------------------------------------
|
|
129
132
|
|
|
130
133
|
|
|
131
|
-
def _ping_db(db) -> None:
|
|
134
|
+
def _ping_db(db: Any) -> None:
|
|
132
135
|
"""Test connectivity for *db*, print connection details, and exit.
|
|
133
136
|
|
|
134
137
|
Attempts to execute ``SELECT version()`` (or ``SELECT sqlite_version()``
|
|
@@ -156,7 +159,7 @@ def _ping_db(db) -> None:
|
|
|
156
159
|
curs.close()
|
|
157
160
|
if row and row[0]:
|
|
158
161
|
version_str = str(row[0]).split("\n")[0].strip()
|
|
159
|
-
|
|
162
|
+
break
|
|
160
163
|
except Exception:
|
|
161
164
|
continue
|
|
162
165
|
|
|
@@ -212,6 +215,7 @@ def _run(
|
|
|
212
215
|
output_dir: str | None = None,
|
|
213
216
|
progress: bool = False,
|
|
214
217
|
profile: bool = False,
|
|
218
|
+
profile_limit: int = 20,
|
|
215
219
|
ping: bool = False,
|
|
216
220
|
lint: bool = False,
|
|
217
221
|
debug: bool = False,
|
|
@@ -551,7 +555,7 @@ def _run(
|
|
|
551
555
|
if debug:
|
|
552
556
|
_state.step_mode = True
|
|
553
557
|
|
|
554
|
-
_execute_script_direct(conf, profile=profile)
|
|
558
|
+
_execute_script_direct(conf, profile=profile, profile_limit=profile_limit)
|
|
555
559
|
|
|
556
560
|
|
|
557
561
|
# ---------------------------------------------------------------------------
|
|
@@ -610,7 +614,7 @@ def _execute_script_textual_console(conf: ConfigData) -> None:
|
|
|
610
614
|
_state.exec_log.log_exit_end()
|
|
611
615
|
|
|
612
616
|
|
|
613
|
-
def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
617
|
+
def _execute_script_direct(conf: ConfigData, *, profile: bool = False, profile_limit: int = 20) -> None:
|
|
614
618
|
"""Run runscripts() in the current (main) thread — used when Textual is not active.
|
|
615
619
|
|
|
616
620
|
Args:
|
|
@@ -618,6 +622,8 @@ def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
|
618
622
|
profile: When ``True``, print a per-statement timing summary after the
|
|
619
623
|
script completes. Timing data must already have been activated on
|
|
620
624
|
``_state.profile_data`` before this function is called.
|
|
625
|
+
profile_limit: Maximum number of top statements to display in the
|
|
626
|
+
profile summary (default: 20).
|
|
621
627
|
"""
|
|
622
628
|
import execsql.state as _state
|
|
623
629
|
import execsql.utils.gui as _gui
|
|
@@ -644,7 +650,7 @@ def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
|
644
650
|
gui_console_off()
|
|
645
651
|
_state.exec_log.log_status_info(f"{_state.cmds_run} commands run")
|
|
646
652
|
if profile and _state.profile_data is not None:
|
|
647
|
-
_print_profile(_state.profile_data)
|
|
653
|
+
_print_profile(_state.profile_data, limit=profile_limit)
|
|
648
654
|
sys.exit(exc.code)
|
|
649
655
|
except ConfigError:
|
|
650
656
|
raise
|
|
@@ -672,7 +678,7 @@ def _execute_script_direct(conf: ConfigData, *, profile: bool = False) -> None:
|
|
|
672
678
|
gui_console_off()
|
|
673
679
|
_state.exec_log.log_status_info(f"{_state.cmds_run} commands run")
|
|
674
680
|
if profile and _state.profile_data is not None:
|
|
675
|
-
_print_profile(_state.profile_data)
|
|
681
|
+
_print_profile(_state.profile_data, limit=profile_limit)
|
|
676
682
|
_state.exec_log.log_exit_end()
|
|
677
683
|
|
|
678
684
|
|