mycli 2.6.1__tar.gz → 2.8.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.
Files changed (182) hide show
  1. {mycli-2.6.1 → mycli-2.8.0}/.github/workflows/publish.yml +1 -1
  2. {mycli-2.6.1 → mycli-2.8.0}/MANIFEST.in +1 -0
  3. {mycli-2.6.1/mycli.egg-info → mycli-2.8.0}/PKG-INFO +28 -21
  4. {mycli-2.6.1 → mycli-2.8.0}/changelog.md +55 -0
  5. {mycli-2.6.1 → mycli-2.8.0}/mycli/TIPS +10 -0
  6. {mycli-2.6.1 → mycli-2.8.0}/mycli/client.py +5 -1
  7. {mycli-2.6.1 → mycli-2.8.0}/mycli/client_commands.py +1 -1
  8. {mycli-2.6.1 → mycli-2.8.0}/mycli/client_query.py +1 -0
  9. {mycli-2.6.1 → mycli-2.8.0}/mycli/clistyle.py +1 -0
  10. {mycli-2.6.1 → mycli-2.8.0}/mycli/completion_refresher.py +5 -0
  11. {mycli-2.6.1 → mycli-2.8.0}/mycli/main_modes/checkup.py +34 -21
  12. {mycli-2.6.1 → mycli-2.8.0}/mycli/main_modes/repl.py +11 -3
  13. {mycli-2.6.1 → mycli-2.8.0}/mycli/myclirc +7 -0
  14. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/completion_engine.py +25 -5
  15. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/iocommands.py +4 -4
  16. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/main.py +11 -11
  17. mycli-2.8.0/mycli/resources/completions/zsh/_mycli +66 -0
  18. {mycli-2.6.1 → mycli-2.8.0}/mycli/schema_prefetcher.py +8 -0
  19. {mycli-2.6.1 → mycli-2.8.0}/mycli/sqlcompleter.py +63 -7
  20. {mycli-2.6.1 → mycli-2.8.0}/mycli/sqlexecute.py +19 -0
  21. {mycli-2.6.1 → mycli-2.8.0/mycli.egg-info}/PKG-INFO +28 -21
  22. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/SOURCES.txt +3 -1
  23. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/requires.txt +12 -20
  24. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/scm_file_list.json +3 -1
  25. mycli-2.8.0/mycli.egg-info/scm_version.json +8 -0
  26. {mycli-2.6.1 → mycli-2.8.0}/pyproject.toml +36 -23
  27. {mycli-2.6.1 → mycli-2.8.0}/test/features/environment.py +4 -18
  28. {mycli-2.6.1 → mycli-2.8.0}/test/myclirc +7 -0
  29. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_checkup.py +18 -10
  30. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_client.py +30 -0
  31. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_client_query.py +12 -2
  32. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_clistyle.py +12 -1
  33. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_completer_use_switch.py +3 -0
  34. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_completion_engine.py +33 -4
  35. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_completion_refresher.py +4 -0
  36. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_main_modes_repl.py +17 -3
  37. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_naive_completion.py +13 -0
  38. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_schema_prefetcher.py +11 -0
  39. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_smart_completion_public_schema_only.py +113 -0
  40. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_main.py +3 -3
  41. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_sqlcompleter.py +39 -0
  42. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_sqlexecute.py +39 -0
  43. mycli-2.8.0/test/pytests/test_zsh_completion.py +118 -0
  44. mycli-2.6.1/mycli.egg-info/scm_version.json +0 -8
  45. {mycli-2.6.1 → mycli-2.8.0}/.git-blame-ignore-revs +0 -0
  46. {mycli-2.6.1 → mycli-2.8.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  47. {mycli-2.6.1 → mycli-2.8.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  48. {mycli-2.6.1 → mycli-2.8.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  49. {mycli-2.6.1 → mycli-2.8.0}/.github/dependabot.yml +0 -0
  50. {mycli-2.6.1 → mycli-2.8.0}/.github/workflows/ci.yml +0 -0
  51. {mycli-2.6.1 → mycli-2.8.0}/.github/workflows/lint.yml +0 -0
  52. {mycli-2.6.1 → mycli-2.8.0}/.github/workflows/typecheck.yml +0 -0
  53. {mycli-2.6.1 → mycli-2.8.0}/.gitignore +0 -0
  54. {mycli-2.6.1 → mycli-2.8.0}/AGENTS.md +0 -0
  55. {mycli-2.6.1 → mycli-2.8.0}/AUTHORS.rst +0 -0
  56. {mycli-2.6.1 → mycli-2.8.0}/CONTRIBUTING.md +0 -0
  57. {mycli-2.6.1 → mycli-2.8.0}/LICENSE.txt +0 -0
  58. {mycli-2.6.1 → mycli-2.8.0}/README.md +0 -0
  59. {mycli-2.6.1 → mycli-2.8.0}/SPONSORS.rst +0 -0
  60. {mycli-2.6.1 → mycli-2.8.0}/doc/key_bindings.rst +0 -0
  61. {mycli-2.6.1 → mycli-2.8.0}/doc/llm.md +0 -0
  62. {mycli-2.6.1 → mycli-2.8.0}/doc/screenshots/main.gif +0 -0
  63. {mycli-2.6.1 → mycli-2.8.0}/doc/screenshots/tables.png +0 -0
  64. {mycli-2.6.1 → mycli-2.8.0}/doc/screenshots/total_histogram.png +0 -0
  65. {mycli-2.6.1 → mycli-2.8.0}/doc/transforms.md +0 -0
  66. {mycli-2.6.1 → mycli-2.8.0}/mycli/AUTHORS +0 -0
  67. {mycli-2.6.1 → mycli-2.8.0}/mycli/SPONSORS +0 -0
  68. {mycli-2.6.1 → mycli-2.8.0}/mycli/__init__.py +0 -0
  69. {mycli-2.6.1 → mycli-2.8.0}/mycli/app_state.py +0 -0
  70. {mycli-2.6.1 → mycli-2.8.0}/mycli/cli_runner.py +0 -0
  71. {mycli-2.6.1 → mycli-2.8.0}/mycli/clibuffer.py +0 -0
  72. {mycli-2.6.1 → mycli-2.8.0}/mycli/client_connection.py +0 -0
  73. {mycli-2.6.1 → mycli-2.8.0}/mycli/clitoolbar.py +0 -0
  74. {mycli-2.6.1 → mycli-2.8.0}/mycli/compat.py +0 -0
  75. {mycli-2.6.1 → mycli-2.8.0}/mycli/config.py +0 -0
  76. {mycli-2.6.1 → mycli-2.8.0}/mycli/constants.py +0 -0
  77. {mycli-2.6.1 → mycli-2.8.0}/mycli/key_bindings.py +0 -0
  78. {mycli-2.6.1 → mycli-2.8.0}/mycli/lexer.py +0 -0
  79. {mycli-2.6.1 → mycli-2.8.0}/mycli/main.py +0 -0
  80. {mycli-2.6.1 → mycli-2.8.0}/mycli/main_modes/batch.py +0 -0
  81. {mycli-2.6.1 → mycli-2.8.0}/mycli/main_modes/execute.py +0 -0
  82. {mycli-2.6.1 → mycli-2.8.0}/mycli/main_modes/list_dsn.py +0 -0
  83. {mycli-2.6.1 → mycli-2.8.0}/mycli/output.py +0 -0
  84. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/__init__.py +0 -0
  85. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/batch_utils.py +0 -0
  86. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/cli_utils.py +0 -0
  87. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/filepaths.py +0 -0
  88. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/hybrid_redirection.py +0 -0
  89. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/interactive_utils.py +0 -0
  90. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/key_binding_utils.py +0 -0
  91. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/polars_transform.py +0 -0
  92. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/ptoolkit/__init__.py +0 -0
  93. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/ptoolkit/fzf.py +0 -0
  94. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/ptoolkit/history.py +0 -0
  95. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/ptoolkit/utils.py +0 -0
  96. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/__init__.py +0 -0
  97. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/dbcommands.py +0 -0
  98. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/delimitercommand.py +0 -0
  99. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/dsn_aliases.py +0 -0
  100. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/favoritequeries.py +0 -0
  101. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/llm.py +0 -0
  102. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/special/utils.py +0 -0
  103. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/sql_utils.py +0 -0
  104. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/sqlresult.py +0 -0
  105. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/string_utils.py +0 -0
  106. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/tabular_output/__init__.py +0 -0
  107. {mycli-2.6.1 → mycli-2.8.0}/mycli/packages/tabular_output/sql_format.py +0 -0
  108. {mycli-2.6.1 → mycli-2.8.0}/mycli/password_sources.py +0 -0
  109. {mycli-2.6.1 → mycli-2.8.0}/mycli/ssh_tunnel.py +0 -0
  110. {mycli-2.6.1 → mycli-2.8.0}/mycli/types.py +0 -0
  111. {mycli-2.6.1 → mycli-2.8.0}/mycli/vault.py +0 -0
  112. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/dependency_links.txt +0 -0
  113. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/entry_points.txt +0 -0
  114. {mycli-2.6.1 → mycli-2.8.0}/mycli.egg-info/top_level.txt +0 -0
  115. {mycli-2.6.1 → mycli-2.8.0}/setup.cfg +0 -0
  116. {mycli-2.6.1 → mycli-2.8.0}/test/__init__.py +0 -0
  117. {mycli-2.6.1 → mycli-2.8.0}/test/features/__init__.py +0 -0
  118. {mycli-2.6.1 → mycli-2.8.0}/test/features/auto_vertical.feature +0 -0
  119. {mycli-2.6.1 → mycli-2.8.0}/test/features/basic_commands.feature +0 -0
  120. {mycli-2.6.1 → mycli-2.8.0}/test/features/connection.feature +0 -0
  121. {mycli-2.6.1 → mycli-2.8.0}/test/features/crud_database.feature +0 -0
  122. {mycli-2.6.1 → mycli-2.8.0}/test/features/crud_table.feature +0 -0
  123. {mycli-2.6.1 → mycli-2.8.0}/test/features/db_utils.py +0 -0
  124. {mycli-2.6.1 → mycli-2.8.0}/test/features/fixture_data/help_commands.txt +0 -0
  125. {mycli-2.6.1 → mycli-2.8.0}/test/features/fixture_utils.py +0 -0
  126. {mycli-2.6.1 → mycli-2.8.0}/test/features/iocommands.feature +0 -0
  127. {mycli-2.6.1 → mycli-2.8.0}/test/features/named_queries.feature +0 -0
  128. {mycli-2.6.1 → mycli-2.8.0}/test/features/specials.feature +0 -0
  129. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/__init__.py +0 -0
  130. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/auto_vertical.py +0 -0
  131. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/basic_commands.py +0 -0
  132. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/connection.py +0 -0
  133. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/crud_database.py +0 -0
  134. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/crud_table.py +0 -0
  135. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/iocommands.py +0 -0
  136. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/named_queries.py +0 -0
  137. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/specials.py +0 -0
  138. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/utils.py +0 -0
  139. {mycli-2.6.1 → mycli-2.8.0}/test/features/steps/wrappers.py +0 -0
  140. {mycli-2.6.1 → mycli-2.8.0}/test/features/wrappager.py +0 -0
  141. {mycli-2.6.1 → mycli-2.8.0}/test/mylogin.cnf +0 -0
  142. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/conftest.py +0 -0
  143. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_app_state.py +0 -0
  144. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_batch_utils.py +0 -0
  145. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_cli_runner.py +0 -0
  146. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_cli_utils.py +0 -0
  147. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_clibuffer.py +0 -0
  148. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_client_commands.py +0 -0
  149. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_client_connection.py +0 -0
  150. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_clitoolbar.py +0 -0
  151. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_config.py +0 -0
  152. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_delimitercommand.py +0 -0
  153. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_dsn_aliases.py +0 -0
  154. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_favoritequeries.py +0 -0
  155. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_filepaths.py +0 -0
  156. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_hybrid_redirection.py +0 -0
  157. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_interactive_utils.py +0 -0
  158. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_key_binding_utils.py +0 -0
  159. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_key_bindings.py +0 -0
  160. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_lexer.py +0 -0
  161. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_main.py +0 -0
  162. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_main_modes_batch.py +0 -0
  163. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_main_modes_execute.py +0 -0
  164. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_main_modes_list_dsn.py +0 -0
  165. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_output.py +0 -0
  166. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_password_sources.py +0 -0
  167. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_polars_transform.py +0 -0
  168. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_ptoolkit_fzf.py +0 -0
  169. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_ptoolkit_history.py +0 -0
  170. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_ptoolkit_utils.py +0 -0
  171. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_dbcommands.py +0 -0
  172. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_init.py +0 -0
  173. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_iocommands.py +0 -0
  174. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_llm.py +0 -0
  175. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_special_utils.py +0 -0
  176. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_sql_utils.py +0 -0
  177. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_sqlresult.py +0 -0
  178. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_ssh_tunnel.py +0 -0
  179. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_string_utils.py +0 -0
  180. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_tabular_output.py +0 -0
  181. {mycli-2.6.1 → mycli-2.8.0}/test/pytests/test_vault.py +0 -0
  182. {mycli-2.6.1 → mycli-2.8.0}/test/utils.py +0 -0
@@ -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@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
265
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -1,4 +1,5 @@
1
1
  include LICENSE.txt *.md *.rst doc/screenshots/*
2
+ recursive-include mycli/resources/completions *
2
3
  recursive-include test *.cnf
3
4
  recursive-include test *.feature
4
5
  recursive-include test *.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mycli
3
- Version: 2.6.1
3
+ Version: 2.8.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
@@ -9,22 +9,37 @@ Project-URL: Documentation, https://mycli.net/docs
9
9
  Project-URL: Source, https://github.com/dbcli/mycli
10
10
  Project-URL: Issues, https://github.com/dbcli/mycli/issues
11
11
  Project-URL: Changelog, https://github.com/dbcli/mycli/blob/main/changelog.md
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Programming Language :: Python :: 3.14
23
+ Classifier: Programming Language :: SQL
24
+ Classifier: Topic :: Database
25
+ Classifier: Topic :: Database :: Front-Ends
26
+ Classifier: Topic :: Software Development
12
27
  Requires-Python: >=3.10
13
28
  Description-Content-Type: text/markdown
14
29
  License-File: LICENSE.txt
15
30
  License-File: AUTHORS.rst
16
- Requires-Dist: click~=8.3.1
31
+ Requires-Dist: click~=8.4.2
17
32
  Requires-Dist: clickdc~=0.1.1
18
- Requires-Dist: cryptography~=46.0.5
19
- Requires-Dist: Pygments~=2.19.2
33
+ Requires-Dist: cryptography~=49.0.0
34
+ Requires-Dist: Pygments~=2.20.0
20
35
  Requires-Dist: prompt_toolkit<4.0.0,>=3.0.41
21
36
  Requires-Dist: PyMySQL~=1.1.2
22
37
  Requires-Dist: sqlparse<0.6.0,>=0.3.0
23
- Requires-Dist: sqlglot~=30.8.0
24
- Requires-Dist: sqlglotc~=30.8.0
38
+ Requires-Dist: sqlglot~=30.12.0
39
+ Requires-Dist: sqlglotc~=30.12.0
25
40
  Requires-Dist: configobj~=5.0.9
26
- Requires-Dist: cli_helpers[styles]~=2.15.0
27
- Requires-Dist: wcwidth~=0.6.0
41
+ Requires-Dist: cli_helpers[styles]~=2.15.1
42
+ Requires-Dist: wcwidth~=0.8.2
28
43
  Requires-Dist: pyperclip~=1.11.0
29
44
  Requires-Dist: pycryptodomex~=3.23.0
30
45
  Requires-Dist: pyfzf~=0.3.1
@@ -32,10 +47,9 @@ Requires-Dist: rapidfuzz~=3.14.3
32
47
  Requires-Dist: keyring~=25.7.0
33
48
  Requires-Dist: yaspin~=3.4.0
34
49
  Provides-Extra: llm
35
- Requires-Dist: llm~=0.30.0; extra == "llm"
36
- Requires-Dist: pydantic_core~=2.41.5; extra == "llm"
37
- Requires-Dist: setuptools==82.*; extra == "llm"
38
- Requires-Dist: pip==26.*; extra == "llm"
50
+ Requires-Dist: llm~=0.31.1; extra == "llm"
51
+ Requires-Dist: setuptools==83.*; extra == "llm"
52
+ Requires-Dist: pip~=26.1.2; extra == "llm"
39
53
  Provides-Extra: dataframe
40
54
  Requires-Dist: polars~=1.42.1; extra == "dataframe"
41
55
  Requires-Dist: altair~=6.2.2; extra == "dataframe"
@@ -45,21 +59,14 @@ Requires-Dist: mycli[dataframe,llm]; extra == "all"
45
59
  Provides-Extra: dev
46
60
  Requires-Dist: behave~=1.3.3; extra == "dev"
47
61
  Requires-Dist: coverage~=7.13.4; extra == "dev"
48
- Requires-Dist: mypy~=1.19.1; extra == "dev"
62
+ Requires-Dist: mypy~=2.3.0; extra == "dev"
49
63
  Requires-Dist: pexpect~=4.9.0; extra == "dev"
50
- Requires-Dist: pytest~=9.0.2; extra == "dev"
64
+ Requires-Dist: pytest~=9.1.1; extra == "dev"
51
65
  Requires-Dist: pytest-cov~=7.0.0; extra == "dev"
52
66
  Requires-Dist: pytest-random-order~=1.2.0; extra == "dev"
53
67
  Requires-Dist: tox~=4.35.0; extra == "dev"
54
68
  Requires-Dist: pdbpp~=0.11.7; extra == "dev"
55
- Requires-Dist: llm~=0.30.0; extra == "dev"
56
- Requires-Dist: pydantic_core~=2.41.5; extra == "dev"
57
- Requires-Dist: setuptools==82.*; extra == "dev"
58
- Requires-Dist: pip==26.*; extra == "dev"
59
69
  Requires-Dist: ruff~=0.15.0; extra == "dev"
60
- Requires-Dist: polars~=1.42.1; extra == "dev"
61
- Requires-Dist: altair~=6.2.2; extra == "dev"
62
- Requires-Dist: vl-convert-python~=1.9.0; extra == "dev"
63
70
  Dynamic: license-file
64
71
 
65
72
  # mycli
@@ -1,3 +1,58 @@
1
+ 2.8.0 (2026/07/31)
2
+ ==============
3
+
4
+ Features
5
+ ---------
6
+ * Render tab literals as four spaces in the REPL.
7
+ * Let cursor shape respond to vi modes: _eg_ bar for insert mode.
8
+ * Add zsh completions which can complete DSN aliases.
9
+
10
+
11
+ Internal
12
+ ---------
13
+ * Add Trove classifiers for PyPi.
14
+ * Don't let behave tests refer to real home-directory resources.
15
+
16
+
17
+ 2.7.0 (2026/07/25)
18
+ ==============
19
+
20
+ Features
21
+ ---------
22
+ * Show purpose in tabular `--checkup` output.
23
+ * Add optional dependencies to `--checkup`.
24
+ * Improve completions for `/command`s.
25
+ * Highlight indexed columns in completions with a suffix and/or a text style.
26
+
27
+
28
+ Bugfixes
29
+ ---------
30
+ * Ignoring `min_completion_trigger` only applies to first token after `/`.
31
+
32
+
33
+ Documentation
34
+ ---------
35
+ * Add `.|` and `.>` to TIPS.
36
+
37
+
38
+ Internal
39
+ ---------
40
+ * Update `cli_helpers` dependency to v2.15.1
41
+ * Update `click` to v8.4.2
42
+ * Update `cryptography` to v49.0.0
43
+ * Update `pygments` to v2.20.0
44
+ * Update `llm` to v0.31.1
45
+ * Update `setuptools` to v83.x
46
+ * Update `pip` to v26.1.2
47
+ * Update `pytest` to v9.1.1
48
+ * Add dependency cooldown period
49
+ * Exclude `cli_helpers` and `openai` from cooldown
50
+ * Update `sqlglot`/`sqlglotc` to v30.12.0
51
+ * Update `wcwidth` to v0.8.2
52
+ * Remove duplication in dev dependencies.
53
+ * Update `mypy` to v2.3.0.
54
+
55
+
1
56
  2.6.1 (2026/07/24)
2
57
  ==============
3
58
 
@@ -144,6 +144,8 @@ display output in an interactive explorer \x at the end of a query!
144
144
 
145
145
  run SQL scripts in batch mode using the standard input!
146
146
 
147
+ indexed columns are tagged with a "*" in completion menus!
148
+
147
149
  ###
148
150
  ### keystrokes
149
151
  ###
@@ -301,3 +303,11 @@ redirect query output to a CSV file with "$> <filename>"!
301
303
  append query output to a CSV file with "$>> <filename>"!
302
304
 
303
305
  run a command after shell redirects with "post_redirect_command" in ~/.myclirc!
306
+
307
+ ###
308
+ ### transforms
309
+ ###
310
+
311
+ transform or plot query output with a dataframe using ".| df"!
312
+
313
+ save query output to a Parquet file with ".> output.parquet"!
@@ -183,6 +183,7 @@ class MyCli(AppStateMixin, OutputMixin, ClientCommandsMixin, ClientConnectionMix
183
183
  self.initialize_logging()
184
184
 
185
185
  keyword_casing = c["main"].get("keyword_casing", "auto")
186
+ indexed_column_suffix = c['main'].get('indexed_column_suffix', '')
186
187
 
187
188
  self.highlight_preview = c['search'].as_bool('highlight_preview')
188
189
 
@@ -191,7 +192,10 @@ class MyCli(AppStateMixin, OutputMixin, ClientCommandsMixin, ClientConnectionMix
191
192
  # Initialize completer.
192
193
  self.smart_completion = c["main"].as_bool("smart_completion")
193
194
  self.completer = SQLCompleter(
194
- self.smart_completion, supported_formats=self.main_formatter.supported_formats, keyword_casing=keyword_casing
195
+ self.smart_completion,
196
+ supported_formats=self.main_formatter.supported_formats,
197
+ keyword_casing=keyword_casing,
198
+ indexed_column_suffix=indexed_column_suffix,
195
199
  )
196
200
  self._completer_lock = threading.Lock()
197
201
 
@@ -52,7 +52,7 @@ class ClientCommandsMixin:
52
52
  "rehash",
53
53
  "/rehash",
54
54
  "Refresh auto-completions.",
55
- arg_type=ArgType.NO_QUERY,
55
+ arg_type=ArgType.NO_ARGUMENT,
56
56
  aliases=[SpecialCommandAlias("\\#", case_sensitive=False)],
57
57
  )
58
58
  special.register_special_command(
@@ -52,6 +52,7 @@ class ClientQueryMixin:
52
52
  "smart_completion": self.smart_completion,
53
53
  "supported_formats": self.main_formatter.supported_formats,
54
54
  "keyword_casing": self.completer.keyword_casing,
55
+ "indexed_column_suffix": self.completer.indexed_column_suffix,
55
56
  },
56
57
  )
57
58
 
@@ -15,6 +15,7 @@ logger = logging.getLogger(__name__)
15
15
  TOKEN_TO_PROMPT_STYLE: dict[Token, str] = {
16
16
  Token.Menu.Completions.Completion.Current: "completion-menu.completion.current",
17
17
  Token.Menu.Completions.Completion: "completion-menu.completion",
18
+ Token.Menu.Completions.Completion.Indexed: "completion-menu.completion.indexed",
18
19
  Token.Menu.Completions.Meta.Current: "completion-menu.meta.completion.current",
19
20
  Token.Menu.Completions.Meta: "completion-menu.meta.completion",
20
21
  Token.Menu.Completions.MultiColumnMeta: "completion-menu.multi-column-meta",
@@ -167,6 +167,11 @@ def refresh_tables(completer: SQLCompleter, executor: SQLExecute) -> None:
167
167
  completer.extend_columns(table_columns_dbresult, kind="tables")
168
168
 
169
169
 
170
+ @refresher("indexed_columns")
171
+ def refresh_indexed_columns(completer: SQLCompleter, executor: SQLExecute) -> None:
172
+ completer.extend_indexed_columns(executor.indexed_columns())
173
+
174
+
170
175
  @refresher("foreign_keys")
171
176
  def refresh_foreign_keys(completer: SQLCompleter, executor: SQLExecute) -> None:
172
177
  completer.extend_foreign_keys(executor.foreign_keys())
@@ -6,6 +6,8 @@ import sys
6
6
  import urllib.error
7
7
  import urllib.request
8
8
 
9
+ from tabulate import tabulate
10
+
9
11
  from mycli.constants import REPO_URL
10
12
 
11
13
  PYPI_API_BASE = 'https://pypi.org/pypi'
@@ -24,15 +26,20 @@ def pypi_api_fetch(fragment: str) -> dict:
24
26
 
25
27
  def _dependencies_checkup() -> None:
26
28
  print('\n### Key Python dependencies:\n')
27
- for dependency in [
28
- 'cli_helpers',
29
- 'click',
30
- 'prompt_toolkit',
31
- 'pygments',
32
- 'pymysql',
33
- 'sqlglot',
34
- 'sqlglotc',
35
- 'tabulate',
29
+ table = []
30
+ for dependency, purpose in [
31
+ ('cli_helpers', 'required'),
32
+ ('click', 'required'),
33
+ ('prompt_toolkit', 'required'),
34
+ ('pygments', 'required'),
35
+ ('pymysql', 'required'),
36
+ ('sqlglot', 'required'),
37
+ ('sqlglotc', 'required'),
38
+ ('tabulate', 'required'),
39
+ ('llm', 'optional for /llm command'),
40
+ ('polars', 'optional for .| operator'),
41
+ ('altair', 'optional for .| operator'),
42
+ ('vl-convert-python', 'optional for .| operator'),
36
43
  ]:
37
44
  try:
38
45
  installed_version = importlib.metadata.version(dependency)
@@ -40,32 +47,38 @@ def _dependencies_checkup() -> None:
40
47
  installed_version = None
41
48
  pypi_profile = pypi_api_fetch(f'/{dependency}/json')
42
49
  latest_version = pypi_profile.get('info', {}).get('version', None)
43
- print(f'{dependency} version {installed_version} (latest {latest_version})')
50
+ table.append([dependency, installed_version, latest_version, purpose])
51
+ print(tabulate(table, headers=['library', 'version', 'latest', 'purpose']))
44
52
 
45
53
 
46
54
  def _executables_checkup() -> None:
47
55
  print('\n### External executables:\n')
48
- for executable in [
49
- 'less',
50
- 'fzf',
51
- 'pygmentize',
56
+ table = []
57
+ for executable, purpose in [
58
+ ('less', 'required for paging'),
59
+ ('fzf', r'optional for history search and \x'),
60
+ ('pygmentize', 'optional for history search'),
52
61
  ]:
62
+ # executable, purpose = external
53
63
  if shutil.which(executable):
54
- print(f'The "{executable}" executable was found — good!')
64
+ table.append([executable, 'found', purpose])
55
65
  else:
56
- print(f'The recommended "{executable}" executable was not found — some functionality will suffer.')
66
+ table.append([executable, 'MISSING', purpose])
67
+ print(tabulate(table, headers=['executable', 'status', 'purpose']))
57
68
 
58
69
 
59
70
  def _environment_checkup() -> None:
60
71
  print('\n### Environment variables:\n')
61
- for variable in [
62
- 'EDITOR',
63
- 'VISUAL',
72
+ table = []
73
+ for variable, purpose in [
74
+ ('EDITOR', r'optional for \edit and C-x C-e'),
75
+ ('VISUAL', r'optional for \edit and C-x C-e'),
64
76
  ]:
65
77
  if value := os.environ.get(variable):
66
- print(f'The ${variable} environment variable was set to "{value}" — good!')
78
+ table.append([f'${variable}', value, purpose])
67
79
  else:
68
- print(f'The ${variable} environment variable was not set — some functionality will suffer.')
80
+ table.append([f'${variable}', 'UNSET', purpose])
81
+ print(tabulate(table, headers=['variable', 'setting', 'purpose']))
69
82
 
70
83
 
71
84
  def _configuration_checkup(mycli) -> None:
@@ -23,6 +23,7 @@ import prompt_toolkit
23
23
  from prompt_toolkit.application.current import get_app
24
24
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory, ThreadedAutoSuggest
25
25
  from prompt_toolkit.completion import DynamicCompleter
26
+ from prompt_toolkit.cursor_shapes import CursorShape, ModalCursorShapeConfig
26
27
  from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode
27
28
  from prompt_toolkit.filters import Condition, has_focus, is_done
28
29
  from prompt_toolkit.formatted_text import (
@@ -33,7 +34,11 @@ from prompt_toolkit.formatted_text import (
33
34
  to_plain_text,
34
35
  )
35
36
  from prompt_toolkit.key_binding import KeyBindings
36
- from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor
37
+ from prompt_toolkit.layout.processors import (
38
+ ConditionalProcessor,
39
+ HighlightMatchingBracketProcessor,
40
+ TabsProcessor,
41
+ )
37
42
  from prompt_toolkit.lexers import PygmentsLexer
38
43
  from prompt_toolkit.output import ColorDepth
39
44
  from prompt_toolkit.shortcuts import CompleteStyle, PromptSession
@@ -112,7 +117,7 @@ def complete_while_typing_filter() -> bool:
112
117
  return True
113
118
  app = get_app()
114
119
  text = app.current_buffer.text.lstrip()
115
- if text.startswith('/') and not text.startswith('/*'):
120
+ if text.startswith('/') and not text.startswith('/*') and ' ' not in text:
116
121
  return True
117
122
  text_len = len(text)
118
123
  if text_len < MIN_COMPLETION_TRIGGER:
@@ -583,7 +588,9 @@ def _build_prompt_session(
583
588
  ConditionalProcessor(
584
589
  processor=HighlightMatchingBracketProcessor(chars='[](){}'),
585
590
  filter=has_focus(DEFAULT_BUFFER) & ~is_done,
586
- )
591
+ ),
592
+ # renders tab as four spaces rather than ^I control character
593
+ TabsProcessor(char1=' ', char2=' '),
587
594
  ],
588
595
  tempfile_suffix='.sql',
589
596
  completer=DynamicCompleter(lambda: mycli.completer),
@@ -599,6 +606,7 @@ def _build_prompt_session(
599
606
  enable_system_prompt=True,
600
607
  enable_suspend=True,
601
608
  editing_mode=editing_mode,
609
+ cursor=ModalCursorShapeConfig() if editing_mode == EditingMode.VI else CursorShape.BLOCK,
602
610
  search_ignore_case=True,
603
611
  )
604
612
 
@@ -9,6 +9,12 @@ show_warnings = False
9
9
  # possible completions will be listed.
10
10
  smart_completion = True
11
11
 
12
+ # Text appended to indexed column names in the completion menu. This text is
13
+ # not inserted into the query. Leave empty to disable the marker. Quote values
14
+ # containing spaces, commas, or comment characters.
15
+ # Alternative: ' [indexed]'
16
+ indexed_column_suffix = *
17
+
12
18
  # Minimum characters typed before offering completion suggestions. Forward
13
19
  # slash for a command is an exception which always offers completions.
14
20
  # Suggestion: 3.
@@ -411,6 +417,7 @@ default_username_field = username
411
417
  # Completion menus
412
418
  completion-menu.completion.current = 'bg:#ffffff #000000'
413
419
  completion-menu.completion = 'bg:#008888 #ffffff'
420
+ completion-menu.completion.indexed = 'bg:#008888 #ffffff'
414
421
  completion-menu.meta.completion.current = 'bg:#44aaaa #000000'
415
422
  completion-menu.meta.completion = 'bg:#448888 #ffffff'
416
423
  completion-menu.multi-column-meta = 'bg:#aaffff #000000'
@@ -71,6 +71,10 @@ def _keyword_suggestions() -> list[Suggestion]:
71
71
  return [{'type': 'keyword'}]
72
72
 
73
73
 
74
+ def _special_suggestions() -> list[Suggestion]:
75
+ return [{'type': 'special'}]
76
+
77
+
74
78
  def _keyword_and_special_suggestions() -> list[Suggestion]:
75
79
  return [{'type': 'keyword'}, {'type': 'special'}]
76
80
 
@@ -144,8 +148,11 @@ def _emit_none_token(_ctx: SuggestContext) -> list[Suggestion]:
144
148
  return _keyword_suggestions()
145
149
 
146
150
 
147
- def _emit_blank_token(_ctx: SuggestContext) -> list[Suggestion]:
148
- return _keyword_and_special_suggestions()
151
+ def _emit_blank_token(ctx: SuggestContext) -> list[Suggestion]:
152
+ if ctx.text_before_cursor.startswith('/'):
153
+ return _special_suggestions()
154
+ else:
155
+ return _keyword_and_special_suggestions()
149
156
 
150
157
 
151
158
  def _emit_star(_ctx: SuggestContext) -> list[Suggestion]:
@@ -793,7 +800,8 @@ def suggest_special(text: str) -> list[dict[str, Any]]:
793
800
  {"type": "view", "schema": []},
794
801
  {"type": "schema"},
795
802
  ]
796
- elif cmd.lower() in [
803
+
804
+ if cmd.lower() in [
797
805
  r'\.',
798
806
  r'/.',
799
807
  'source',
@@ -806,14 +814,16 @@ def suggest_special(text: str) -> list[dict[str, Any]]:
806
814
  '/tee',
807
815
  ]:
808
816
  return [{"type": "file_name"}]
817
+
809
818
  # todo: why is \edit case-sensitive?
810
- elif cmd in [
819
+ if cmd in [
811
820
  r'\e',
812
821
  '/e',
813
822
  r'\edit',
814
823
  '/edit',
815
824
  ]:
816
825
  return [{"type": "file_name"}]
826
+
817
827
  if cmd in ["\\llm", "/llm", "\\ai", "/ai"]:
818
828
  return [{"type": "llm"}]
819
829
 
@@ -828,7 +838,17 @@ def suggest_special(text: str) -> list[dict[str, Any]]:
828
838
  return []
829
839
  return [{'type': 'special_subcommand', 'subcommands': list(DSN_SUBCOMMANDS)}]
830
840
 
831
- return [{"type": "keyword"}, {"type": "special"}]
841
+ if cmd.lower() in [
842
+ 'help',
843
+ '/help',
844
+ r'\help',
845
+ '?',
846
+ '/?',
847
+ r'\?',
848
+ ]:
849
+ return [{"type": "keyword"}, {"type": "special"}]
850
+
851
+ return []
832
852
 
833
853
 
834
854
  def suggest_based_on_last_token(
@@ -98,7 +98,7 @@ def is_show_warnings_enabled() -> bool:
98
98
  'warnings',
99
99
  '/warnings',
100
100
  'Enable automatic warnings display.',
101
- arg_type=ArgType.NO_QUERY,
101
+ arg_type=ArgType.NO_ARGUMENT,
102
102
  case_sensitive=True,
103
103
  aliases=[SpecialCommandAlias('\\W', case_sensitive=True)],
104
104
  )
@@ -113,7 +113,7 @@ def enable_show_warnings() -> Generator[SQLResult, None, None]:
113
113
  'nowarnings',
114
114
  '/nowarnings',
115
115
  'Disable automatic warnings display.',
116
- arg_type=ArgType.NO_QUERY,
116
+ arg_type=ArgType.NO_ARGUMENT,
117
117
  case_sensitive=True,
118
118
  aliases=[SpecialCommandAlias('\\w', case_sensitive=True)],
119
119
  )
@@ -152,7 +152,7 @@ def set_pager(arg: str, **_) -> list[SQLResult]:
152
152
  "nopager",
153
153
  "/nopager",
154
154
  "Disable pager; print to stdout.",
155
- arg_type=ArgType.NO_QUERY,
155
+ arg_type=ArgType.NO_ARGUMENT,
156
156
  case_sensitive=True,
157
157
  aliases=[SpecialCommandAlias("\\n", case_sensitive=True)],
158
158
  )
@@ -165,7 +165,7 @@ def disable_pager() -> list[SQLResult]:
165
165
  "\\timing",
166
166
  "/timing",
167
167
  "Toggle timing of queries.",
168
- arg_type=ArgType.NO_QUERY,
168
+ arg_type=ArgType.NO_ARGUMENT,
169
169
  case_sensitive=True,
170
170
  aliases=[SpecialCommandAlias("\\t", case_sensitive=True)],
171
171
  )
@@ -27,7 +27,7 @@ CASE_INSENSITIVE_COMMANDS: set[str] = set()
27
27
 
28
28
 
29
29
  class ArgType(Enum):
30
- NO_QUERY = 0
30
+ NO_ARGUMENT = 0
31
31
  PARSED_QUERY = 1
32
32
  RAW_QUERY = 2
33
33
 
@@ -205,7 +205,7 @@ def execute(cur: Cursor, sql: str) -> list[SQLResult]:
205
205
  if command.lower().startswith(("help", "/help", "\\?", "/?", "?")) and arg:
206
206
  return show_keyword_help(cur=cur, arg=arg)
207
207
 
208
- if special_cmd.arg_type == ArgType.NO_QUERY:
208
+ if special_cmd.arg_type == ArgType.NO_ARGUMENT:
209
209
  return special_cmd.handler()
210
210
  elif special_cmd.arg_type == ArgType.PARSED_QUERY:
211
211
  return special_cmd.handler(cur=cur, arg=arg, command_verbosity=(command_verbosity == CommandVerbosity.VERBOSE))
@@ -219,7 +219,7 @@ def execute(cur: Cursor, sql: str) -> list[SQLResult]:
219
219
  "help",
220
220
  "/help [term]",
221
221
  "Show this table, or search for help on a term.",
222
- arg_type=ArgType.NO_QUERY,
222
+ arg_type=ArgType.NO_ARGUMENT,
223
223
  aliases=[SpecialCommandAlias("\\?", case_sensitive=False), SpecialCommandAlias("?", case_sensitive=False)],
224
224
  )
225
225
  def show_help(*_args) -> list[SQLResult]:
@@ -283,7 +283,7 @@ def show_keyword_help(cur: Cursor, arg: str) -> list[SQLResult]:
283
283
  return _show_mysql_help(cur, keyword)
284
284
 
285
285
 
286
- @special_command('\\bug', '/bug', 'File a bug on GitHub.', arg_type=ArgType.NO_QUERY)
286
+ @special_command('\\bug', '/bug', 'File a bug on GitHub.', arg_type=ArgType.NO_ARGUMENT)
287
287
  def file_bug(*_args) -> list[SQLResult]:
288
288
  webbrowser.open_new_tab(ISSUES_URL)
289
289
  return [SQLResult(status=f'{ISSUES_URL} — press "New Issue"')]
@@ -293,14 +293,14 @@ def file_bug(*_args) -> list[SQLResult]:
293
293
  "exit",
294
294
  "/exit",
295
295
  "Exit.",
296
- arg_type=ArgType.NO_QUERY,
296
+ arg_type=ArgType.NO_ARGUMENT,
297
297
  aliases=[SpecialCommandAlias("\\q", case_sensitive=False)],
298
298
  )
299
299
  @special_command(
300
300
  "quit",
301
301
  "/quit",
302
302
  "Quit.",
303
- arg_type=ArgType.NO_QUERY,
303
+ arg_type=ArgType.NO_ARGUMENT,
304
304
  aliases=[SpecialCommandAlias("\\q", case_sensitive=False)],
305
305
  )
306
306
  def quit_(*_args):
@@ -311,7 +311,7 @@ def quit_(*_args):
311
311
  "\\edit",
312
312
  "/edit <filename> | <query>\\edit",
313
313
  "Edit query with editor (uses $VISUAL or $EDITOR).",
314
- arg_type=ArgType.NO_QUERY,
314
+ arg_type=ArgType.NO_ARGUMENT,
315
315
  case_sensitive=True,
316
316
  aliases=[SpecialCommandAlias("\\e", case_sensitive=True)],
317
317
  )
@@ -319,14 +319,14 @@ def quit_(*_args):
319
319
  "\\clip",
320
320
  "/clip | <query>\\clip",
321
321
  "Copy query to the system clipboard.",
322
- arg_type=ArgType.NO_QUERY,
322
+ arg_type=ArgType.NO_ARGUMENT,
323
323
  case_sensitive=True,
324
324
  )
325
325
  @special_command(
326
326
  "\\G",
327
327
  "<query>\\G",
328
328
  "Display query results vertically.",
329
- arg_type=ArgType.NO_QUERY,
329
+ arg_type=ArgType.NO_ARGUMENT,
330
330
  case_sensitive=True,
331
331
  backslash_only=True,
332
332
  )
@@ -334,7 +334,7 @@ def quit_(*_args):
334
334
  "\\g",
335
335
  "<query>\\g",
336
336
  "Display query results (mnemonic: go).",
337
- arg_type=ArgType.NO_QUERY,
337
+ arg_type=ArgType.NO_ARGUMENT,
338
338
  case_sensitive=True,
339
339
  backslash_only=True,
340
340
  )
@@ -342,7 +342,7 @@ def quit_(*_args):
342
342
  "\\x",
343
343
  "<query>\\x",
344
344
  "Display query results in an explorer rather than a pager.",
345
- arg_type=ArgType.NO_QUERY,
345
+ arg_type=ArgType.NO_ARGUMENT,
346
346
  case_sensitive=True,
347
347
  backslash_only=True,
348
348
  )