mycli 2.4.0__tar.gz → 2.5.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.
- {mycli-2.4.0 → mycli-2.5.1}/.github/workflows/ci.yml +12 -12
- {mycli-2.4.0 → mycli-2.5.1}/.github/workflows/lint.yml +1 -1
- {mycli-2.4.0 → mycli-2.5.1}/.github/workflows/publish.yml +14 -14
- {mycli-2.4.0 → mycli-2.5.1}/.github/workflows/typecheck.yml +3 -3
- {mycli-2.4.0/mycli.egg-info → mycli-2.5.1}/PKG-INFO +10 -4
- {mycli-2.4.0 → mycli-2.5.1}/README.md +3 -2
- {mycli-2.4.0 → mycli-2.5.1}/changelog.md +23 -0
- mycli-2.5.1/doc/transforms.md +98 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/client_connection.py +28 -8
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main_modes/repl.py +50 -9
- {mycli-2.4.0 → mycli-2.5.1}/mycli/myclirc +9 -3
- mycli-2.5.1/mycli/packages/polars_transform.py +220 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/__init__.py +2 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/iocommands.py +5 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/types.py +7 -0
- {mycli-2.4.0 → mycli-2.5.1/mycli.egg-info}/PKG-INFO +10 -4
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/SOURCES.txt +3 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/requires.txt +7 -1
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/scm_file_list.json +3 -0
- mycli-2.5.1/mycli.egg-info/scm_version.json +8 -0
- {mycli-2.4.0 → mycli-2.5.1}/pyproject.toml +7 -1
- {mycli-2.4.0 → mycli-2.5.1}/test/features/environment.py +10 -1
- {mycli-2.4.0 → mycli-2.5.1}/test/myclirc +9 -3
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_client_connection.py +8 -2
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_main_modes_repl.py +277 -0
- mycli-2.5.1/test/pytests/test_polars_transform.py +405 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_iocommands.py +13 -0
- mycli-2.4.0/mycli.egg-info/scm_version.json +0 -8
- {mycli-2.4.0 → mycli-2.5.1}/.git-blame-ignore-revs +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/.github/dependabot.yml +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/.gitignore +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/AGENTS.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/AUTHORS.rst +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/CONTRIBUTING.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/LICENSE.txt +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/MANIFEST.in +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/SPONSORS.rst +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/doc/key_bindings.rst +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/doc/llm.md +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/doc/screenshots/main.gif +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/doc/screenshots/tables.png +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/AUTHORS +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/SPONSORS +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/TIPS +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/app_state.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/cli_runner.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/clibuffer.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/client.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/client_commands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/client_query.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/clistyle.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/clitoolbar.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/compat.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/completion_refresher.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/config.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/constants.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/key_bindings.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/lexer.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main_modes/batch.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main_modes/checkup.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main_modes/execute.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/main_modes/list_dsn.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/output.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/batch_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/cli_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/completion_engine.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/filepaths.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/hybrid_redirection.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/interactive_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/key_binding_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/ptoolkit/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/ptoolkit/fzf.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/ptoolkit/history.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/ptoolkit/utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/dbcommands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/delimitercommand.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/dsn_aliases.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/favoritequeries.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/llm.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/main.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/special/utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/sql_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/sqlresult.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/string_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/tabular_output/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/packages/tabular_output/sql_format.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/password_sources.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/schema_prefetcher.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/sqlcompleter.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/sqlexecute.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/ssh_tunnel.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli/vault.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/dependency_links.txt +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/entry_points.txt +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/mycli.egg-info/top_level.txt +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/setup.cfg +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/auto_vertical.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/basic_commands.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/connection.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/crud_database.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/crud_table.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/db_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/fixture_data/help_commands.txt +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/fixture_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/iocommands.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/named_queries.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/specials.feature +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/__init__.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/auto_vertical.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/basic_commands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/connection.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/crud_database.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/crud_table.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/iocommands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/named_queries.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/specials.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/steps/wrappers.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/features/wrappager.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/mylogin.cnf +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/conftest.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_app_state.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_batch_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_checkup.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_cli_runner.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_cli_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_clibuffer.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_client.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_client_commands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_client_query.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_clistyle.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_clitoolbar.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_completer_use_switch.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_completion_engine.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_completion_refresher.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_config.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_delimitercommand.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_dsn_aliases.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_favoritequeries.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_filepaths.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_hybrid_redirection.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_interactive_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_key_binding_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_key_bindings.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_lexer.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_main.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_main_modes_batch.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_main_modes_execute.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_main_modes_list_dsn.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_naive_completion.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_output.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_password_sources.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_ptoolkit_fzf.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_ptoolkit_history.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_ptoolkit_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_schema_prefetcher.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_smart_completion_public_schema_only.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_dbcommands.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_init.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_llm.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_main.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_special_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_sql_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_sqlcompleter.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_sqlexecute.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_sqlresult.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_ssh_tunnel.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_string_utils.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_tabular_output.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/pytests/test_vault.py +0 -0
- {mycli-2.4.0 → mycli-2.5.1}/test/utils.py +0 -0
|
@@ -22,14 +22,14 @@ jobs:
|
|
|
22
22
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
23
23
|
|
|
24
24
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
26
|
|
|
27
|
-
- uses: astral-sh/setup-uv@
|
|
27
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
28
28
|
with:
|
|
29
29
|
version: "latest"
|
|
30
30
|
|
|
31
31
|
- name: Set up Python ${{ matrix.python-version }}
|
|
32
|
-
uses: actions/setup-python@
|
|
32
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
33
33
|
with:
|
|
34
34
|
python-version: ${{ matrix.python-version }}
|
|
35
35
|
|
|
@@ -64,14 +64,14 @@ jobs:
|
|
|
64
64
|
python-version: ["3.14"]
|
|
65
65
|
|
|
66
66
|
steps:
|
|
67
|
-
- uses: actions/checkout@
|
|
67
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
68
68
|
|
|
69
|
-
- uses: astral-sh/setup-uv@
|
|
69
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
70
70
|
with:
|
|
71
71
|
version: "latest"
|
|
72
72
|
|
|
73
73
|
- name: Set up Python ${{ matrix.python-version }}
|
|
74
|
-
uses: actions/setup-python@
|
|
74
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
75
75
|
with:
|
|
76
76
|
python-version: ${{ matrix.python-version }}
|
|
77
77
|
|
|
@@ -114,14 +114,14 @@ jobs:
|
|
|
114
114
|
python-version: ['3.14']
|
|
115
115
|
|
|
116
116
|
steps:
|
|
117
|
-
- uses: actions/checkout@
|
|
117
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
118
118
|
|
|
119
|
-
- uses: astral-sh/setup-uv@
|
|
119
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
120
120
|
with:
|
|
121
121
|
version: 'latest'
|
|
122
122
|
|
|
123
123
|
- name: Set up Python ${{ matrix.python-version }}
|
|
124
|
-
uses: actions/setup-python@
|
|
124
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
125
125
|
with:
|
|
126
126
|
python-version: ${{ matrix.python-version }}
|
|
127
127
|
|
|
@@ -217,14 +217,14 @@ jobs:
|
|
|
217
217
|
runs-on: ubuntu-latest
|
|
218
218
|
|
|
219
219
|
steps:
|
|
220
|
-
- uses: actions/checkout@
|
|
220
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
221
221
|
|
|
222
|
-
- uses: astral-sh/setup-uv@
|
|
222
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
223
223
|
with:
|
|
224
224
|
version: "latest"
|
|
225
225
|
|
|
226
226
|
- name: Set up Python ${{ matrix.python-version }}
|
|
227
|
-
uses: actions/setup-python@
|
|
227
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
228
228
|
with:
|
|
229
229
|
python-version: '3.14'
|
|
230
230
|
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
20
|
- name: Check out Git repository
|
|
21
|
-
uses: actions/checkout@
|
|
21
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
22
|
|
|
23
23
|
- name: Run ruff check
|
|
24
24
|
uses: astral-sh/ruff-action@278981a28ce3188b1e39527901f38254bf3aac89 # v4.1.0
|
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
|
|
14
14
|
steps:
|
|
15
|
-
- uses: actions/checkout@
|
|
15
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
16
16
|
|
|
17
17
|
- name: Require release changelog form
|
|
18
18
|
run: |
|
|
@@ -28,13 +28,13 @@ jobs:
|
|
|
28
28
|
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
29
29
|
|
|
30
30
|
steps:
|
|
31
|
-
- uses: actions/checkout@
|
|
32
|
-
- uses: astral-sh/setup-uv@
|
|
31
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
32
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
33
33
|
with:
|
|
34
34
|
version: "latest"
|
|
35
35
|
|
|
36
36
|
- name: Set up Python ${{ matrix.python-version }}
|
|
37
|
-
uses: actions/setup-python@
|
|
37
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
38
38
|
with:
|
|
39
39
|
python-version: ${{ matrix.python-version }}
|
|
40
40
|
|
|
@@ -72,14 +72,14 @@ jobs:
|
|
|
72
72
|
python-version: ["3.14"]
|
|
73
73
|
|
|
74
74
|
steps:
|
|
75
|
-
- uses: actions/checkout@
|
|
75
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
76
76
|
|
|
77
|
-
- uses: astral-sh/setup-uv@
|
|
77
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
78
78
|
with:
|
|
79
79
|
version: "latest"
|
|
80
80
|
|
|
81
81
|
- name: Set up Python ${{ matrix.python-version }}
|
|
82
|
-
uses: actions/setup-python@
|
|
82
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
83
83
|
with:
|
|
84
84
|
python-version: ${{ matrix.python-version }}
|
|
85
85
|
|
|
@@ -122,14 +122,14 @@ jobs:
|
|
|
122
122
|
python-version: ['3.14']
|
|
123
123
|
|
|
124
124
|
steps:
|
|
125
|
-
- uses: actions/checkout@
|
|
125
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
126
126
|
|
|
127
|
-
- uses: astral-sh/setup-uv@
|
|
127
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
128
128
|
with:
|
|
129
129
|
version: 'latest'
|
|
130
130
|
|
|
131
131
|
- name: Set up Python ${{ matrix.python-version }}
|
|
132
|
-
uses: actions/setup-python@
|
|
132
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
133
133
|
with:
|
|
134
134
|
python-version: ${{ matrix.python-version }}
|
|
135
135
|
|
|
@@ -225,13 +225,13 @@ jobs:
|
|
|
225
225
|
needs: [tests, tests-macos, tests-windows, tests-wsl]
|
|
226
226
|
|
|
227
227
|
steps:
|
|
228
|
-
- uses: actions/checkout@
|
|
229
|
-
- uses: astral-sh/setup-uv@
|
|
228
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
229
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
230
230
|
with:
|
|
231
231
|
version: "latest"
|
|
232
232
|
|
|
233
233
|
- name: Set up Python
|
|
234
|
-
uses: actions/setup-python@
|
|
234
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
235
235
|
with:
|
|
236
236
|
python-version: '3.14'
|
|
237
237
|
|
|
@@ -262,4 +262,4 @@ jobs:
|
|
|
262
262
|
name: python-packages
|
|
263
263
|
path: dist/
|
|
264
264
|
- name: Publish to PyPI
|
|
265
|
-
uses: pypa/gh-action-pypi-publish@
|
|
265
|
+
uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
|
|
@@ -18,14 +18,14 @@ jobs:
|
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
20
|
- name: Check out Git repository
|
|
21
|
-
uses: actions/checkout@
|
|
21
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
22
|
|
|
23
23
|
- name: Set up Python
|
|
24
|
-
uses: actions/setup-python@
|
|
24
|
+
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
25
25
|
with:
|
|
26
26
|
python-version: '3.14'
|
|
27
27
|
|
|
28
|
-
- uses: astral-sh/setup-uv@
|
|
28
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
29
29
|
with:
|
|
30
30
|
version: 'latest'
|
|
31
31
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mycli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.1
|
|
4
4
|
Summary: CLI for MySQL Database. With auto-completion and syntax highlighting.
|
|
5
5
|
Author: Mycli Core Team
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -36,8 +36,11 @@ Requires-Dist: llm~=0.30.0; extra == "llm"
|
|
|
36
36
|
Requires-Dist: pydantic_core~=2.41.5; extra == "llm"
|
|
37
37
|
Requires-Dist: setuptools==82.*; extra == "llm"
|
|
38
38
|
Requires-Dist: pip==26.*; extra == "llm"
|
|
39
|
+
Provides-Extra: dataframe
|
|
40
|
+
Requires-Dist: polars~=1.42.1; extra == "dataframe"
|
|
41
|
+
Requires-Dist: altair~=6.2.2; extra == "dataframe"
|
|
39
42
|
Provides-Extra: all
|
|
40
|
-
Requires-Dist: mycli[llm]; extra == "all"
|
|
43
|
+
Requires-Dist: mycli[dataframe,llm]; extra == "all"
|
|
41
44
|
Provides-Extra: dev
|
|
42
45
|
Requires-Dist: behave~=1.3.3; extra == "dev"
|
|
43
46
|
Requires-Dist: coverage~=7.13.4; extra == "dev"
|
|
@@ -53,6 +56,8 @@ Requires-Dist: pydantic_core~=2.41.5; extra == "dev"
|
|
|
53
56
|
Requires-Dist: setuptools==82.*; extra == "dev"
|
|
54
57
|
Requires-Dist: pip==26.*; extra == "dev"
|
|
55
58
|
Requires-Dist: ruff~=0.15.0; extra == "dev"
|
|
59
|
+
Requires-Dist: polars~=1.42.1; extra == "dev"
|
|
60
|
+
Requires-Dist: altair~=6.2.2; extra == "dev"
|
|
56
61
|
Dynamic: license-file
|
|
57
62
|
|
|
58
63
|
# mycli
|
|
@@ -64,8 +69,8 @@ A command line client for MySQL with auto-completion and syntax highlighting.
|
|
|
64
69
|
Homepage: [https://mycli.net](https://mycli.net)
|
|
65
70
|
Documentation: [https://mycli.net/docs](https://mycli.net/docs)
|
|
66
71
|
|
|
67
|
-

|
|
68
|
-

|
|
72
|
+

|
|
73
|
+

|
|
69
74
|
|
|
70
75
|
Mycli is compatible with MySQL, MariaDB, Percona, TiDB, and Apache Doris.
|
|
71
76
|
|
|
@@ -128,6 +133,7 @@ Features
|
|
|
128
133
|
* Pretty print tabular data (with colors!).
|
|
129
134
|
* Support for SSL connections
|
|
130
135
|
* Shell-style trailing redirects with `$>`, `$>>` and `$|` operators.
|
|
136
|
+
* [Polars](https://pola.rs) dataframe [transforms](doc/transforms.md) with `.|` and Parquet saves with `.>`.
|
|
131
137
|
* Support for querying LLMs with context derived from your schema using `/llm`.
|
|
132
138
|
* Support for storing passwords in the system keyring.
|
|
133
139
|
|
|
@@ -7,8 +7,8 @@ A command line client for MySQL with auto-completion and syntax highlighting.
|
|
|
7
7
|
Homepage: [https://mycli.net](https://mycli.net)
|
|
8
8
|
Documentation: [https://mycli.net/docs](https://mycli.net/docs)
|
|
9
9
|
|
|
10
|
-

|
|
11
|
-

|
|
10
|
+

|
|
11
|
+

|
|
12
12
|
|
|
13
13
|
Mycli is compatible with MySQL, MariaDB, Percona, TiDB, and Apache Doris.
|
|
14
14
|
|
|
@@ -71,6 +71,7 @@ Features
|
|
|
71
71
|
* Pretty print tabular data (with colors!).
|
|
72
72
|
* Support for SSL connections
|
|
73
73
|
* Shell-style trailing redirects with `$>`, `$>>` and `$|` operators.
|
|
74
|
+
* [Polars](https://pola.rs) dataframe [transforms](doc/transforms.md) with `.|` and Parquet saves with `.>`.
|
|
74
75
|
* Support for querying LLMs with context derived from your schema using `/llm`.
|
|
75
76
|
* Support for storing passwords in the system keyring.
|
|
76
77
|
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
2.5.1 (2026/07/22)
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
Documentation
|
|
5
|
+
---------
|
|
6
|
+
* Attempt to make `README.md` images display on PyPi.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
2.5.0 (2026/07/22)
|
|
10
|
+
==============
|
|
11
|
+
|
|
12
|
+
Features
|
|
13
|
+
---------
|
|
14
|
+
* Configurable sources of credentials to save to the keyring.
|
|
15
|
+
* Trailing operator `.|` to transform query results as dataframes.
|
|
16
|
+
* Trailing operator `.>` to save query results as parquet files.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
Internal
|
|
20
|
+
---------
|
|
21
|
+
* Don't modify checked-in `test/myclirc` in the behave test suite.
|
|
22
|
+
|
|
23
|
+
|
|
1
24
|
2.4.0 (2026/07/18)
|
|
2
25
|
==============
|
|
3
26
|
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Transforms with Polars Dataframes
|
|
2
|
+
|
|
3
|
+
## Installing
|
|
4
|
+
|
|
5
|
+
Install mycli with dataframe support using:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install --upgrade 'mycli[dataframe]'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or install the Polars and Altair libraries separately.
|
|
12
|
+
|
|
13
|
+
## BETA STATUS
|
|
14
|
+
|
|
15
|
+
Dataframe transforms are new and experimental. The interface and functionality
|
|
16
|
+
may still change.
|
|
17
|
+
|
|
18
|
+
Here are some known limitations:
|
|
19
|
+
|
|
20
|
+
* transforms can't be mixed with `$|` shell redirection
|
|
21
|
+
* multiple transform steps are not permitted
|
|
22
|
+
* the Altair library is provided, but plots can't yet be displayed
|
|
23
|
+
* results from `UNION`s may be unable to be transformed
|
|
24
|
+
|
|
25
|
+
And there are inherent limitations to the post-processing model: the entire
|
|
26
|
+
SQL result must be transferred from the server and loaded into local memory.
|
|
27
|
+
|
|
28
|
+
## Transforming
|
|
29
|
+
|
|
30
|
+
In the interactive REPL, append the `.|` operator and a Python expression to a
|
|
31
|
+
single SQL statement. The Python expression receives
|
|
32
|
+
|
|
33
|
+
* `df`, a Polars `DataFrame`
|
|
34
|
+
* `pl`, the Polars module
|
|
35
|
+
* `alt`, the Altair module
|
|
36
|
+
|
|
37
|
+
Spaces may be required around the operator.
|
|
38
|
+
|
|
39
|
+
Transform example:
|
|
40
|
+
|
|
41
|
+
```sql
|
|
42
|
+
SELECT * FROM orders .| df.group_by('customer_id').len();
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
which is equivalent to this native SQL:
|
|
46
|
+
|
|
47
|
+
```sql
|
|
48
|
+
SELECT customer_id, COUNT(1) AS len FROM orders GROUP BY customer_id;
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Transform expressions run with normal Python privileges, and expressions
|
|
52
|
+
should not be run from untrusted sources. If the transform operation
|
|
53
|
+
returns a Polars `DataFrame` or `Series`, the result is rendered by mycli
|
|
54
|
+
as tabular output; other return types currently give a warning and cannot
|
|
55
|
+
be displayed.
|
|
56
|
+
|
|
57
|
+
Transform expressions are useful for operations such as medians which
|
|
58
|
+
cannot be done (or are simply awkward) in SQL. Example:
|
|
59
|
+
|
|
60
|
+
```sql
|
|
61
|
+
SELECT * FROM orders .| df.describe();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Saving
|
|
65
|
+
|
|
66
|
+
A query result, transformed `DataFrame`, or transformed `Series` can be
|
|
67
|
+
written directly to Parquet with the `.>` operator.
|
|
68
|
+
|
|
69
|
+
Save example:
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
SELECT * FROM orders .> orders.parquet;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The `.>` operator must be last, requires a `.parquet` destination, and
|
|
76
|
+
overwrites any existing file. Spaces may be required around the operator.
|
|
77
|
+
Destination paths containing whitespace must be quoted. A successful write
|
|
78
|
+
reports its destination and row count.
|
|
79
|
+
|
|
80
|
+
When `post_redirect_command` is set in `~/.myclirc`, the given command runs
|
|
81
|
+
after a successful Parquet save.
|
|
82
|
+
|
|
83
|
+
`.>` cannot be combined with `\x`, `\G`, or `\g` special display terminators.
|
|
84
|
+
|
|
85
|
+
## Combining
|
|
86
|
+
|
|
87
|
+
Parquet saves may be combined with dataframe transforms. Again, `.>` must
|
|
88
|
+
be the last operator.
|
|
89
|
+
|
|
90
|
+
Combined transform and save example:
|
|
91
|
+
|
|
92
|
+
```sql
|
|
93
|
+
SELECT * FROM orders .| df.group_by('customer_id').len() .> customer_counts.parquet;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```sql
|
|
97
|
+
SELECT * FROM orders .| df['order_id'] .> order_ids.parquet;
|
|
98
|
+
```
|
|
@@ -80,6 +80,7 @@ class ClientConnectionMixin:
|
|
|
80
80
|
user_connection_config = self.config_without_package_defaults.get('connection', {})
|
|
81
81
|
self.keepalive_ticks = keepalive_ticks
|
|
82
82
|
self.ssh_tunnel = None
|
|
83
|
+
self.selected_password = None
|
|
83
84
|
|
|
84
85
|
int_port = port and int(port)
|
|
85
86
|
if not int_port:
|
|
@@ -92,6 +93,11 @@ class ClientConnectionMixin:
|
|
|
92
93
|
else:
|
|
93
94
|
password_source_precedence = ['prompt']
|
|
94
95
|
|
|
96
|
+
if self.config.get('main', {}).get('keyring_sources'):
|
|
97
|
+
keyring_sources = self.config.get('main').as_list('keyring_sources')
|
|
98
|
+
else:
|
|
99
|
+
keyring_sources = []
|
|
100
|
+
|
|
95
101
|
if ssh_jump:
|
|
96
102
|
remote_host = host or DEFAULT_HOST
|
|
97
103
|
remote_port = int_port or DEFAULT_PORT
|
|
@@ -185,9 +191,9 @@ class ClientConnectionMixin:
|
|
|
185
191
|
if use_keyring and not reset_keyring:
|
|
186
192
|
password_candidates.add_loader('keyring', lambda: keyring.get_password(keyring_domain, keyring_identifier))
|
|
187
193
|
|
|
188
|
-
selected_password = password_candidates.resolve(password_source_precedence)
|
|
189
|
-
passwd = selected_password.value if selected_password is not None else None
|
|
190
|
-
keyring_retrieved_cleanly = selected_password is not None and selected_password.source == 'keyring'
|
|
194
|
+
self.selected_password = password_candidates.resolve(password_source_precedence)
|
|
195
|
+
passwd = self.selected_password.value if self.selected_password is not None else None
|
|
196
|
+
keyring_retrieved_cleanly = self.selected_password is not None and self.selected_password.source == 'keyring'
|
|
191
197
|
|
|
192
198
|
# prompt for password if requested by user
|
|
193
199
|
if passwd == EMPTY_PASSWORD_FLAG_SENTINEL:
|
|
@@ -253,15 +259,25 @@ class ClientConnectionMixin:
|
|
|
253
259
|
connection_info['port'] = int_port
|
|
254
260
|
connection_info['socket'] = socket
|
|
255
261
|
|
|
256
|
-
def _update_keyring(
|
|
262
|
+
def _update_keyring(
|
|
263
|
+
password: str | None,
|
|
264
|
+
password_source: str | None,
|
|
265
|
+
keyring_retrieved_cleanly: bool,
|
|
266
|
+
):
|
|
257
267
|
if not password:
|
|
258
268
|
return
|
|
269
|
+
if password_source not in keyring_sources:
|
|
270
|
+
return
|
|
259
271
|
if reset_keyring or (use_keyring and not keyring_retrieved_cleanly):
|
|
260
272
|
try:
|
|
261
273
|
saved_pw = keyring.get_password(keyring_domain, keyring_identifier)
|
|
262
274
|
if password != saved_pw or reset_keyring:
|
|
263
275
|
keyring.set_password(keyring_domain, keyring_identifier, password)
|
|
264
|
-
click.secho(
|
|
276
|
+
click.secho(
|
|
277
|
+
f'Password from source: "{password_source}" '
|
|
278
|
+
f'saved to the system keyring at {keyring_domain}/{keyring_identifier}',
|
|
279
|
+
err=True,
|
|
280
|
+
)
|
|
265
281
|
except Exception as e:
|
|
266
282
|
click.secho(f'Password not saved to the system keyring: {e}', err=True, fg='red')
|
|
267
283
|
|
|
@@ -273,7 +289,11 @@ class ClientConnectionMixin:
|
|
|
273
289
|
) -> None:
|
|
274
290
|
try:
|
|
275
291
|
if keyring_save_eligible:
|
|
276
|
-
_update_keyring(
|
|
292
|
+
_update_keyring(
|
|
293
|
+
connection_info["password"],
|
|
294
|
+
self.selected_password.source if self.selected_password else None,
|
|
295
|
+
keyring_retrieved_cleanly=keyring_retrieved_cleanly,
|
|
296
|
+
)
|
|
277
297
|
self.sqlexecute = SQLExecute(**connection_info)
|
|
278
298
|
except pymysql.OperationalError as e1:
|
|
279
299
|
if e1.args[0] == HANDSHAKE_ERROR and ssl is not None and ssl.get("mode", None) == "auto":
|
|
@@ -295,8 +315,8 @@ class ClientConnectionMixin:
|
|
|
295
315
|
f"Enter password for {user}", hide_input=True, show_default=False, default='', type=str, err=True
|
|
296
316
|
),
|
|
297
317
|
)
|
|
298
|
-
|
|
299
|
-
connection_info["password"] =
|
|
318
|
+
self.selected_password = password_candidates.resolve(['fallback'])
|
|
319
|
+
connection_info["password"] = self.selected_password.value if self.selected_password else None
|
|
300
320
|
keyring_retrieved_cleanly = False
|
|
301
321
|
_connect(
|
|
302
322
|
retry_password=True,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from collections.abc import Iterable
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
import functools
|
|
@@ -14,7 +15,7 @@ import subprocess
|
|
|
14
15
|
import sys
|
|
15
16
|
import time
|
|
16
17
|
import traceback
|
|
17
|
-
from typing import TYPE_CHECKING, Any
|
|
18
|
+
from typing import TYPE_CHECKING, Any
|
|
18
19
|
from xml.parsers.expat import ExpatError
|
|
19
20
|
|
|
20
21
|
import click
|
|
@@ -61,6 +62,13 @@ from mycli.packages.key_binding_utils import (
|
|
|
61
62
|
handle_clip_command,
|
|
62
63
|
handle_editor_command,
|
|
63
64
|
)
|
|
65
|
+
from mycli.packages.polars_transform import (
|
|
66
|
+
PolarsTransform,
|
|
67
|
+
PolarsTransformError,
|
|
68
|
+
parse_polars_transform,
|
|
69
|
+
prepare_polars_transform,
|
|
70
|
+
run_polars_transform,
|
|
71
|
+
)
|
|
64
72
|
from mycli.packages.ptoolkit.history import FileHistoryWithTimestamp
|
|
65
73
|
from mycli.packages.special.utils import format_uptime, get_ssl_version, get_uptime, get_warning_count
|
|
66
74
|
from mycli.packages.sql_utils import (
|
|
@@ -420,7 +428,7 @@ def _get_continuation(
|
|
|
420
428
|
def _output_results(
|
|
421
429
|
mycli: 'MyCli',
|
|
422
430
|
state: ReplState,
|
|
423
|
-
results:
|
|
431
|
+
results: Iterable[SQLResult],
|
|
424
432
|
start: float,
|
|
425
433
|
) -> None:
|
|
426
434
|
sqlexecute = mycli.sqlexecute
|
|
@@ -687,7 +695,15 @@ def _one_iteration(
|
|
|
687
695
|
if not text:
|
|
688
696
|
return
|
|
689
697
|
|
|
690
|
-
|
|
698
|
+
original_text = text
|
|
699
|
+
try:
|
|
700
|
+
polars_pipeline = parse_polars_transform(text)
|
|
701
|
+
except PolarsTransformError as exc:
|
|
702
|
+
mycli.echo(str(exc), err=True, fg='red')
|
|
703
|
+
return
|
|
704
|
+
if polars_pipeline is not None:
|
|
705
|
+
text = polars_pipeline.sql
|
|
706
|
+
elif is_redirect_command(text):
|
|
691
707
|
sql_part, command_part, file_operator_part, file_part = get_redirect_components(text)
|
|
692
708
|
text = sql_part or ''
|
|
693
709
|
try:
|
|
@@ -719,19 +735,41 @@ def _one_iteration(
|
|
|
719
735
|
successful = False
|
|
720
736
|
try:
|
|
721
737
|
mycli.logger.debug('sql: %r', text)
|
|
738
|
+
polars_transform: PolarsTransform | None = (
|
|
739
|
+
prepare_polars_transform(text, polars_pipeline.expression) if polars_pipeline is not None else None
|
|
740
|
+
)
|
|
741
|
+
query_history_text = original_text if polars_transform is not None else text
|
|
722
742
|
special.write_tee(mycli.last_prompt_message, nl=False)
|
|
723
|
-
special.write_tee(
|
|
724
|
-
mycli.log_query(
|
|
743
|
+
special.write_tee(query_history_text)
|
|
744
|
+
mycli.log_query(query_history_text)
|
|
725
745
|
|
|
726
746
|
start = time.time()
|
|
727
747
|
results = sqlexecute.run(text)
|
|
728
748
|
mycli.main_formatter.query = text
|
|
729
749
|
mycli.redirect_formatter.query = text
|
|
730
750
|
mycli.explorer_formatter.query = text
|
|
751
|
+
if polars_transform is not None:
|
|
752
|
+
assert polars_pipeline is not None
|
|
753
|
+
if polars_pipeline.parquet_path is None:
|
|
754
|
+
polars_result = run_polars_transform(polars_transform, results)
|
|
755
|
+
else:
|
|
756
|
+
polars_result = run_polars_transform(polars_transform, results, polars_pipeline.parquet_path)
|
|
757
|
+
if polars_pipeline.parquet_path is None:
|
|
758
|
+
if polars_pipeline.output_mode == 'explorer':
|
|
759
|
+
special.set_explorer_output(True)
|
|
760
|
+
elif polars_pipeline.output_mode == 'expanded':
|
|
761
|
+
special.set_expanded_output(True)
|
|
762
|
+
_output_results(mycli, state, iter([polars_result]), start)
|
|
763
|
+
if polars_pipeline.parquet_path is not None:
|
|
764
|
+
special.run_post_redirect_hook(
|
|
765
|
+
mycli.post_redirect_command,
|
|
766
|
+
polars_pipeline.parquet_path,
|
|
767
|
+
)
|
|
768
|
+
else:
|
|
769
|
+
_output_results(mycli, state, results, start)
|
|
770
|
+
special.unset_once_if_written(mycli.post_redirect_command)
|
|
771
|
+
special.flush_pipe_once_if_written(mycli.post_redirect_command)
|
|
731
772
|
successful = True
|
|
732
|
-
_output_results(mycli, state, results, start)
|
|
733
|
-
special.unset_once_if_written(mycli.post_redirect_command)
|
|
734
|
-
special.flush_pipe_once_if_written(mycli.post_redirect_command)
|
|
735
773
|
except pymysql.err.InterfaceError:
|
|
736
774
|
if not mycli.reconnect():
|
|
737
775
|
return
|
|
@@ -764,6 +802,9 @@ def _one_iteration(
|
|
|
764
802
|
mycli.echo('Did not get a connection id, skip cancelling query', err=True, fg='red')
|
|
765
803
|
except NotImplementedError:
|
|
766
804
|
mycli.echo('Not Yet Implemented.', fg='yellow')
|
|
805
|
+
except PolarsTransformError as exc:
|
|
806
|
+
mycli.logger.error('sql: %r, error: %r', text, exc)
|
|
807
|
+
mycli.echo(str(exc), err=True, fg='red')
|
|
767
808
|
except pymysql.OperationalError as e1:
|
|
768
809
|
mycli.logger.debug('Exception: %r', e1)
|
|
769
810
|
if e1.args[0] == ER_MUST_CHANGE_PASSWORD:
|
|
@@ -814,7 +855,7 @@ def _one_iteration(
|
|
|
814
855
|
if mycli.logfile is False:
|
|
815
856
|
mycli.echo('Warning: This query was not logged.', err=True, fg='red')
|
|
816
857
|
|
|
817
|
-
query = Query(text, successful, state.mutating)
|
|
858
|
+
query = Query(original_text if polars_pipeline is not None else text, successful, state.mutating)
|
|
818
859
|
mycli.query_history.append(query)
|
|
819
860
|
|
|
820
861
|
|
|
@@ -93,9 +93,10 @@ numeric_alignment = right
|
|
|
93
93
|
# to hex rendering if not possible.
|
|
94
94
|
binary_display = hex
|
|
95
95
|
|
|
96
|
-
# A command to run after a successful
|
|
97
|
-
# with
|
|
98
|
-
#
|
|
96
|
+
# A command to run after a successful Parquet save with ".>" or shell output
|
|
97
|
+
# redirect with "$>". The sequence "{}" will be replaced by the escaped
|
|
98
|
+
# destination filename. Mac example: echo {} | pbcopy.
|
|
99
|
+
# Escaping is not reliable/safe on Windows.
|
|
99
100
|
post_redirect_command =
|
|
100
101
|
|
|
101
102
|
# Syntax coloring style. Possible values (many support the "-dark" suffix):
|
|
@@ -232,6 +233,11 @@ password_sources = prompt, literal, file, environment, dsn, boundary, vault, log
|
|
|
232
233
|
# Recommended: auto
|
|
233
234
|
use_keyring = False
|
|
234
235
|
|
|
236
|
+
# Comma-separated password sources eligible to be saved in the keyring.
|
|
237
|
+
# Valid choices: same as password_sources (above).
|
|
238
|
+
# use_keyring must be True or auto.
|
|
239
|
+
keyring_sources = prompt, literal, file, environment, dsn, login_path, fallback
|
|
240
|
+
|
|
235
241
|
[editor]
|
|
236
242
|
|
|
237
243
|
# Command line to invoke for /edit, instead of respecting the $VISUAL/$EDITOR
|