mycli 2.3.0__tar.gz → 2.5.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.
Potentially problematic release.
This version of mycli might be problematic. Click here for more details.
- {mycli-2.3.0 → mycli-2.5.0}/.github/workflows/ci.yml +12 -12
- {mycli-2.3.0 → mycli-2.5.0}/.github/workflows/lint.yml +1 -1
- {mycli-2.3.0 → mycli-2.5.0}/.github/workflows/publish.yml +14 -14
- {mycli-2.3.0 → mycli-2.5.0}/.github/workflows/typecheck.yml +3 -3
- {mycli-2.3.0 → mycli-2.5.0}/AGENTS.md +2 -0
- {mycli-2.3.0/mycli.egg-info → mycli-2.5.0}/PKG-INFO +8 -2
- {mycli-2.3.0 → mycli-2.5.0}/README.md +1 -0
- {mycli-2.3.0 → mycli-2.5.0}/changelog.md +36 -0
- mycli-2.5.0/doc/transforms.md +98 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/TIPS +2 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/cli_runner.py +37 -19
- {mycli-2.3.0 → mycli-2.5.0}/mycli/client.py +8 -2
- {mycli-2.3.0 → mycli-2.5.0}/mycli/client_connection.py +47 -24
- {mycli-2.3.0 → mycli-2.5.0}/mycli/clitoolbar.py +13 -13
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main.py +0 -9
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main_modes/repl.py +59 -10
- {mycli-2.3.0 → mycli-2.5.0}/mycli/myclirc +25 -3
- mycli-2.5.0/mycli/packages/polars_transform.py +220 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/__init__.py +2 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/iocommands.py +5 -0
- mycli-2.5.0/mycli/password_sources.py +77 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/types.py +7 -0
- {mycli-2.3.0 → mycli-2.5.0/mycli.egg-info}/PKG-INFO +8 -2
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/SOURCES.txt +5 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/requires.txt +7 -1
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/scm_file_list.json +5 -0
- mycli-2.5.0/mycli.egg-info/scm_version.json +8 -0
- {mycli-2.3.0 → mycli-2.5.0}/pyproject.toml +7 -1
- {mycli-2.3.0 → mycli-2.5.0}/test/features/environment.py +10 -1
- {mycli-2.3.0 → mycli-2.5.0}/test/myclirc +25 -3
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_cli_runner.py +94 -9
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_client.py +32 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_client_connection.py +117 -50
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_clitoolbar.py +3 -3
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_main.py +33 -22
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_main_modes_repl.py +301 -0
- mycli-2.5.0/test/pytests/test_password_sources.py +81 -0
- mycli-2.5.0/test/pytests/test_polars_transform.py +405 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_iocommands.py +17 -2
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_tabular_output.py +4 -1
- mycli-2.3.0/mycli.egg-info/scm_version.json +0 -8
- {mycli-2.3.0 → mycli-2.5.0}/.git-blame-ignore-revs +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/.github/dependabot.yml +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/.gitignore +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/AUTHORS.rst +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/CONTRIBUTING.md +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/LICENSE.txt +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/MANIFEST.in +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/SPONSORS.rst +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/doc/key_bindings.rst +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/doc/llm.md +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/doc/screenshots/main.gif +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/doc/screenshots/tables.png +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/AUTHORS +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/SPONSORS +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/app_state.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/clibuffer.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/client_commands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/client_query.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/clistyle.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/compat.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/completion_refresher.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/config.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/constants.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/key_bindings.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/lexer.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main_modes/batch.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main_modes/checkup.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main_modes/execute.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/main_modes/list_dsn.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/output.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/batch_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/cli_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/completion_engine.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/filepaths.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/hybrid_redirection.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/interactive_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/key_binding_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/ptoolkit/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/ptoolkit/fzf.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/ptoolkit/history.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/ptoolkit/utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/dbcommands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/delimitercommand.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/dsn_aliases.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/favoritequeries.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/llm.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/main.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/special/utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/sql_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/sqlresult.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/string_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/tabular_output/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/packages/tabular_output/sql_format.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/schema_prefetcher.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/sqlcompleter.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/sqlexecute.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/ssh_tunnel.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli/vault.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/dependency_links.txt +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/entry_points.txt +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/mycli.egg-info/top_level.txt +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/setup.cfg +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/auto_vertical.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/basic_commands.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/connection.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/crud_database.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/crud_table.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/db_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/fixture_data/help_commands.txt +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/fixture_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/iocommands.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/named_queries.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/specials.feature +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/__init__.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/auto_vertical.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/basic_commands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/connection.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/crud_database.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/crud_table.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/iocommands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/named_queries.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/specials.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/steps/wrappers.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/features/wrappager.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/mylogin.cnf +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/conftest.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_app_state.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_batch_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_checkup.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_cli_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_clibuffer.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_client_commands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_client_query.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_clistyle.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_completer_use_switch.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_completion_engine.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_completion_refresher.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_config.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_delimitercommand.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_dsn_aliases.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_favoritequeries.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_filepaths.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_hybrid_redirection.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_interactive_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_key_binding_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_key_bindings.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_lexer.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_main_modes_batch.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_main_modes_execute.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_main_modes_list_dsn.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_naive_completion.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_output.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_ptoolkit_fzf.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_ptoolkit_history.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_ptoolkit_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_schema_prefetcher.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_smart_completion_public_schema_only.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_dbcommands.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_init.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_llm.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_main.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_special_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_sql_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_sqlcompleter.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_sqlexecute.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_sqlresult.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_ssh_tunnel.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_string_utils.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/test/pytests/test_vault.py +0 -0
- {mycli-2.3.0 → mycli-2.5.0}/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
|
|
|
@@ -48,6 +48,8 @@ A command line client for MySQL with auto-completion and syntax highlighting.
|
|
|
48
48
|
├── mycli/packages/sqlresult.py # the `SQLResult` dataclass for holding responses
|
|
49
49
|
├── mycli/packages/string_utils.py # generic string utilities
|
|
50
50
|
├── mycli/packages/tabular_output/ # extends cli_helper with additional output formats
|
|
51
|
+
├── mycli/password_sources.py # password sources and precedence
|
|
52
|
+
├── mycli/ssh_tunnel.py # connecting over a tunnel with `--ssh-jump`
|
|
51
53
|
├── mycli/schema_prefetcher.py # background prefetcher for multi-schema auto-completion
|
|
52
54
|
├── mycli/sqlcompleter.py # offers SQL completions
|
|
53
55
|
├── mycli/sqlexecute.py # runs SQL queries
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mycli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.0
|
|
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
|
|
@@ -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
|
|
|
@@ -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,39 @@
|
|
|
1
|
+
2.5.0 (2026/07/22)
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
Features
|
|
5
|
+
---------
|
|
6
|
+
* Configurable sources of credentials to save to the keyring.
|
|
7
|
+
* Trailing operator `.|` to transform query results as dataframes.
|
|
8
|
+
* Trailing operator `.>` to save query results as parquet files.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
Internal
|
|
12
|
+
---------
|
|
13
|
+
* Don't modify checked-in `test/myclirc` in the behave test suite.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
2.4.0 (2026/07/18)
|
|
17
|
+
==============
|
|
18
|
+
|
|
19
|
+
Features
|
|
20
|
+
---------
|
|
21
|
+
* Make password sources and precedence configurable.
|
|
22
|
+
* Ability to deselect fallback interactive password prompt.
|
|
23
|
+
* Add `\e` prompt/toolbar format string for edit mode.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Bug Fixes
|
|
27
|
+
---------
|
|
28
|
+
* Don't create `~/.myclirc` if the user adopted the XDG layout for myclirc.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
Internal
|
|
32
|
+
---------
|
|
33
|
+
* Make flaky `/watch` test even more lenient for CI.
|
|
34
|
+
* Add missing file to `AGENTS.md` project layout.
|
|
35
|
+
|
|
36
|
+
|
|
1
37
|
2.3.0 (2026/07/16)
|
|
2
38
|
==============
|
|
3
39
|
|
|
@@ -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
|
+
```
|
|
@@ -288,6 +288,8 @@ set editor_command = "code --wait" in ~/.myclirc to edit queries using VS Code!
|
|
|
288
288
|
|
|
289
289
|
set up an interactive output explorer using the "[explorer]" section of ~/.myclirc!
|
|
290
290
|
|
|
291
|
+
customize password sources/precedence with "password_sources" in ~/.myclirc!
|
|
292
|
+
|
|
291
293
|
###
|
|
292
294
|
### redirection
|
|
293
295
|
###
|
|
@@ -15,6 +15,7 @@ from mycli.main_modes.checkup import main_checkup
|
|
|
15
15
|
from mycli.main_modes.execute import main_execute_from_cli
|
|
16
16
|
from mycli.main_modes.list_dsn import main_list_dsn
|
|
17
17
|
from mycli.packages.cli_utils import is_valid_connection_scheme
|
|
18
|
+
from mycli.password_sources import PasswordCandidates
|
|
18
19
|
from mycli.vault import (
|
|
19
20
|
DEFAULT_VAULT_EXECUTABLE,
|
|
20
21
|
DEFAULT_VAULT_PASSWORD_FIELD,
|
|
@@ -165,10 +166,15 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
|
|
|
165
166
|
database = cli_args.dbname or cli_args.database
|
|
166
167
|
|
|
167
168
|
dsn_uri = None
|
|
169
|
+
dsn_password: str | None = None
|
|
168
170
|
|
|
169
171
|
# Treat the database argument as a DSN alias only if it matches a configured alias
|
|
170
172
|
# todo why is port tested but not socket?
|
|
171
|
-
truthy_password =
|
|
173
|
+
truthy_password = (
|
|
174
|
+
cli_args.password not in (None, EMPTY_PASSWORD_FLAG_SENTINEL)
|
|
175
|
+
or cli_args.password_file is not None
|
|
176
|
+
or os.environ.get('MYSQL_PWD') is not None
|
|
177
|
+
)
|
|
172
178
|
if (
|
|
173
179
|
database
|
|
174
180
|
and "://" not in database
|
|
@@ -235,9 +241,6 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
|
|
|
235
241
|
database = dsn_database
|
|
236
242
|
if not cli_args.user and dsn_user is not None:
|
|
237
243
|
cli_args.user = dsn_user
|
|
238
|
-
# todo: rationalize the behavior of empty-string passwords here
|
|
239
|
-
if not cli_args.password and dsn_password is not None:
|
|
240
|
-
cli_args.password = dsn_password
|
|
241
244
|
if not cli_args.host:
|
|
242
245
|
cli_args.host = dsn_host
|
|
243
246
|
if not cli_args.port:
|
|
@@ -364,25 +367,40 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
|
|
|
364
367
|
use_keyring = str_to_bool(cli_args.use_keyring)
|
|
365
368
|
reset_keyring = False
|
|
366
369
|
|
|
367
|
-
|
|
370
|
+
password_candidates = PasswordCandidates()
|
|
371
|
+
if cli_args.password == EMPTY_PASSWORD_FLAG_SENTINEL:
|
|
372
|
+
password_candidates.add_value('prompt', cli_args.password)
|
|
373
|
+
elif cli_args.password is not None:
|
|
374
|
+
password_candidates.add_value('literal', cli_args.password)
|
|
375
|
+
if cli_args.password_file:
|
|
376
|
+
password_candidates.add_loader('file', lambda: main_module.get_password_from_file(cli_args.password_file))
|
|
377
|
+
if os.environ.get('MYSQL_PWD') is not None:
|
|
378
|
+
password_candidates.add_value('environment', os.environ.get('MYSQL_PWD'))
|
|
379
|
+
if dsn_password is not None:
|
|
380
|
+
password_candidates.add_value('dsn', dsn_password)
|
|
381
|
+
|
|
382
|
+
if cli_args.vault_secret:
|
|
383
|
+
vault_secret = cli_args.vault_secret
|
|
368
384
|
vault_config = mycli.config.get('vault_beta', {})
|
|
369
385
|
vault_address = cli_args.vault_address or os.environ.get('VAULT_ADDR') or vault_config.get('address') or None
|
|
370
386
|
vault_mount = cli_args.vault_mount or vault_config.get('default_mount') or None
|
|
371
387
|
vault_field = cli_args.vault_password_field or vault_config.get('default_password_field') or DEFAULT_VAULT_PASSWORD_FIELD
|
|
372
388
|
vault_executable = vault_config.get('vault_executable') or DEFAULT_VAULT_EXECUTABLE
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
389
|
+
|
|
390
|
+
def load_vault_password() -> str | None:
|
|
391
|
+
try:
|
|
392
|
+
return get_field_from_vault(
|
|
393
|
+
vault_field,
|
|
394
|
+
vault_secret,
|
|
395
|
+
executable=vault_executable,
|
|
396
|
+
mount=vault_mount,
|
|
397
|
+
address=vault_address,
|
|
398
|
+
)
|
|
399
|
+
except VaultError as exc:
|
|
400
|
+
click.secho(f'Error reading password from Vault: {exc}', err=True, fg='red')
|
|
401
|
+
sys.exit(1)
|
|
402
|
+
|
|
403
|
+
password_candidates.add_loader('vault', load_vault_password)
|
|
386
404
|
|
|
387
405
|
if cli_args.user is None and cli_args.vault_secret:
|
|
388
406
|
vault_config = mycli.config.get('vault_beta', {})
|
|
@@ -409,7 +427,7 @@ def run_from_cli_args(cli_args: 'CliArgs', client_factory: ClientFactory) -> Non
|
|
|
409
427
|
mycli.connect(
|
|
410
428
|
database=database,
|
|
411
429
|
user=vault_username if cli_args.user is None else cli_args.user,
|
|
412
|
-
|
|
430
|
+
password_candidates=password_candidates,
|
|
413
431
|
host=cli_args.host,
|
|
414
432
|
port=cli_args.port,
|
|
415
433
|
socket=cli_args.socket,
|
|
@@ -58,9 +58,9 @@ class MyCli(AppStateMixin, OutputMixin, ClientCommandsMixin, ClientConnectionMix
|
|
|
58
58
|
|
|
59
59
|
# check XDG_CONFIG_HOME exists and not an empty string
|
|
60
60
|
xdg_config_home = os.environ.get("XDG_CONFIG_HOME", "~/.config")
|
|
61
|
+
xdg_config_file = os.path.join(os.path.expanduser(xdg_config_home), "mycli", "myclirc")
|
|
61
62
|
system_config_files: list[str | IO[str]] = [
|
|
62
63
|
"/etc/myclirc",
|
|
63
|
-
os.path.join(os.path.expanduser(xdg_config_home), "mycli", "myclirc"),
|
|
64
64
|
]
|
|
65
65
|
|
|
66
66
|
def __init__(
|
|
@@ -72,7 +72,7 @@ class MyCli(AppStateMixin, OutputMixin, ClientCommandsMixin, ClientConnectionMix
|
|
|
72
72
|
login_path: str | None = None,
|
|
73
73
|
auto_vertical_output: bool = False,
|
|
74
74
|
warn: bool | None = None,
|
|
75
|
-
myclirc: str =
|
|
75
|
+
myclirc: str | None = None,
|
|
76
76
|
show_warnings: bool | None = None,
|
|
77
77
|
cli_verbosity: int = 0,
|
|
78
78
|
) -> None:
|
|
@@ -87,6 +87,12 @@ class MyCli(AppStateMixin, OutputMixin, ClientCommandsMixin, ClientConnectionMix
|
|
|
87
87
|
self.sandbox_mode: bool = False
|
|
88
88
|
self.checkpoint: IO | None = None
|
|
89
89
|
|
|
90
|
+
if myclirc is None:
|
|
91
|
+
if os.path.exists(self.xdg_config_file):
|
|
92
|
+
myclirc = self.xdg_config_file
|
|
93
|
+
else:
|
|
94
|
+
myclirc = '~/.myclirc'
|
|
95
|
+
|
|
90
96
|
# Load config.
|
|
91
97
|
config_files: list[str | IO[str]] = self.system_config_files + [myclirc]
|
|
92
98
|
|