mycli 2.24.0__tar.gz → 2.24.2__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.24.0 → mycli-2.24.2}/.github/workflows/publish.yml +1 -0
- {mycli-2.24.0/mycli.egg-info → mycli-2.24.2}/PKG-INFO +1 -1
- {mycli-2.24.0 → mycli-2.24.2}/changelog.md +19 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/myclirc +3 -3
- {mycli-2.24.0 → mycli-2.24.2}/mycli/sqlcompleter.py +27 -14
- {mycli-2.24.0 → mycli-2.24.2/mycli.egg-info}/PKG-INFO +1 -1
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/scm_version.json +2 -2
- {mycli-2.24.0 → mycli-2.24.2}/test/myclirc +3 -3
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_client.py +1 -1
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_sqlcompleter.py +123 -15
- {mycli-2.24.0 → mycli-2.24.2}/.git-blame-ignore-revs +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/dependabot.yml +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/workflows/ci.yml +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/workflows/lint.yml +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.github/workflows/typecheck.yml +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/.gitignore +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/AGENTS.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/AUTHORS.rst +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/CONTRIBUTING.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/LICENSE.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/MANIFEST.in +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/README.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/SPONSORS.rst +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/key_bindings.rst +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/llm.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/screenshots/main.gif +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/screenshots/tables.png +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/screenshots/total_histogram.png +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/doc/transforms.md +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/docker/Dockerfile +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/docker/resources/test_db-1.0.7.tar.gz +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/AUTHORS +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/SPONSORS +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/TIPS +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/app_state.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/boundary_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/cli_runner.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/clibuffer.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/client.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/client_commands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/client_connection.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/client_query.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/clistyle.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/clitoolbar.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/compat.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/completion_refresher.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/config.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/constants.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/key_bindings.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/kubectl_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/lexer.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/batch.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/checkup.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/completions.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/execute.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/list_dsn.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/main_modes/repl.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/output.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/batch_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/cli_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/completion_engine.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/filepaths.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/hybrid_redirection.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/interactive_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/key_binding_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/polars_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/polars_transform.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/ptoolkit/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/ptoolkit/fzf.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/ptoolkit/history.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/ptoolkit/utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/dbcommands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/delimitercommand.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/dsn_aliases.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/favoritequeries.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/iocommands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/llm.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/main.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/source.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/special/utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/sql_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/sqlresult.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/string_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/tabular_output/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/packages/tabular_output/sql_format.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/password_sources.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/resources/completions/bash/mycli +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/resources/completions/fish/mycli.fish +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/resources/completions/zsh/_mycli +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/schema_prefetcher.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/sqlexecute.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/ssh_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/types.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli/vault.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/SOURCES.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/dependency_links.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/entry_points.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/requires.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/scm_file_list.json +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/mycli.egg-info/top_level.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/pyproject.toml +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/setup.cfg +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/auto_vertical.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/basic_commands.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/connection.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/crud_database.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/crud_table.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/db_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/environment.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/fixture_data/help_commands.txt +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/fixture_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/iocommands.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/named_queries.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/specials.feature +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/__init__.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/auto_vertical.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/basic_commands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/connection.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/crud_database.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/crud_table.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/iocommands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/named_queries.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/specials.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/steps/wrappers.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/features/wrappager.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/mylogin.cnf +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/conftest.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_app_state.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_bash_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_batch_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_boundary_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_checkup.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_cli_runner.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_cli_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_clibuffer.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_client_commands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_client_connection.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_client_query.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_clistyle.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_clitoolbar.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_completer_use_switch.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_completion_engine.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_completion_refresher.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_config.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_delimitercommand.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_dsn_aliases.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_favoritequeries.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_filepaths.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_fish_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_hybrid_redirection.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_interactive_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_key_binding_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_key_bindings.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_kubectl_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_main.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_main_modes_batch.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_main_modes_execute.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_main_modes_list_dsn.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_main_modes_repl.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_naive_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_output.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_password_sources.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_polars_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_polars_transform.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_ptoolkit_fzf.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_ptoolkit_history.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_ptoolkit_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_schema_prefetcher.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_smart_completion_public_schema_only.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_dbcommands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_init.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_iocommands.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_llm.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_main.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_source.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_special_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_sql_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_sqlexecute.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_sqlresult.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_ssh_tunnel.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_string_utils.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_tabular_output.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_vault.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/pytests/test_zsh_completion.py +0 -0
- {mycli-2.24.0 → mycli-2.24.2}/test/utils.py +0 -0
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
2.24.2 (2026/09/12)
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
Bug Fixes
|
|
5
|
+
--------
|
|
6
|
+
* Revert `docker` output-type on ghcr.io images.
|
|
7
|
+
* Set `artifact-metadata: write` in `publish.yml`.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
2.24.1 (2026/09/12)
|
|
12
|
+
==============
|
|
13
|
+
|
|
14
|
+
Bug Fixes
|
|
15
|
+
--------
|
|
16
|
+
* Omitted completion-candidate methods are no longer applied at all.
|
|
17
|
+
* Set `docker` output-type on ghcr.io images.
|
|
18
|
+
|
|
19
|
+
|
|
1
20
|
2.24.0 (2026/09/12)
|
|
2
21
|
==============
|
|
3
22
|
|
|
@@ -9,9 +9,9 @@ show_warnings = False
|
|
|
9
9
|
# possible completions will be listed.
|
|
10
10
|
smart_completion = True
|
|
11
11
|
|
|
12
|
-
# Methods to find completion candidates,
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# Methods to find completion candidates, in priority order. Empty means the
|
|
13
|
+
# default list. Filename matching requires perfect and/or slash_words to be
|
|
14
|
+
# listed. Polars completions uses its own methods.
|
|
15
15
|
# * perfect - exact leading match
|
|
16
16
|
# * regex - ordered charater match with limited intervening spans ("rgx" matches "regex")
|
|
17
17
|
# * under_words - like regex but follows underscores ("uw" matches "under_words")
|
|
@@ -985,7 +985,7 @@ class SQLCompleter(Completer):
|
|
|
985
985
|
if len(set(order)) != len(order) or any(name not in default_order for name in order):
|
|
986
986
|
self.completion_config_errors.append('Invalid completion_match_order; using the default order.')
|
|
987
987
|
order = ()
|
|
988
|
-
self.completion_match_order = order
|
|
988
|
+
self.completion_match_order = order or default_order
|
|
989
989
|
self._match_priorities: dict[int, int] = {
|
|
990
990
|
Fuzziness[name.upper()]: priority for priority, name in enumerate(self.completion_match_order)
|
|
991
991
|
}
|
|
@@ -1337,12 +1337,12 @@ class SQLCompleter(Completer):
|
|
|
1337
1337
|
def find_fuzzy_match(
|
|
1338
1338
|
self,
|
|
1339
1339
|
item: str,
|
|
1340
|
-
pattern: re.Pattern[str],
|
|
1340
|
+
pattern: re.Pattern[str] | None,
|
|
1341
1341
|
under_words_text: list[str],
|
|
1342
1342
|
case_words_text: list[str],
|
|
1343
1343
|
) -> int | None:
|
|
1344
1344
|
for name in self.completion_match_order:
|
|
1345
|
-
if name == 'regex' and pattern.search(item.lower()):
|
|
1345
|
+
if name == 'regex' and pattern is not None and pattern.search(item.lower()):
|
|
1346
1346
|
return Fuzziness.REGEX
|
|
1347
1347
|
if name == 'under_words':
|
|
1348
1348
|
under_words_item = [x for x in item.lower().split('_') if x]
|
|
@@ -1362,17 +1362,22 @@ class SQLCompleter(Completer):
|
|
|
1362
1362
|
collection: Collection[Any],
|
|
1363
1363
|
) -> list[tuple[str, int]]:
|
|
1364
1364
|
completions: list[tuple[str, int]] = []
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1365
|
+
pattern = None
|
|
1366
|
+
if 'regex' in self.completion_match_order:
|
|
1367
|
+
regex = f'.{{0,{self.regex_match_distance}}}?'.join(map(re.escape, text))
|
|
1368
|
+
pattern = re.compile(f'({regex})')
|
|
1369
|
+
under_words_text = [x for x in text.split('_') if x] if 'under_words' in self.completion_match_order else []
|
|
1370
|
+
case_words_text = re.split(_CASE_CHANGE_PAT, last) if 'camel_case' in self.completion_match_order else []
|
|
1369
1371
|
|
|
1370
1372
|
for item in collection:
|
|
1371
1373
|
fuzziness = self.find_fuzzy_match(item, pattern, under_words_text, case_words_text)
|
|
1374
|
+
if 'perfect' in self.completion_match_order and self._matches_prefix(item, text):
|
|
1375
|
+
if fuzziness is None or self._match_priorities[Fuzziness.PERFECT] < self._match_priorities[fuzziness]:
|
|
1376
|
+
fuzziness = Fuzziness.PERFECT
|
|
1372
1377
|
if fuzziness is not None:
|
|
1373
1378
|
completions.append((item, fuzziness))
|
|
1374
1379
|
|
|
1375
|
-
if len(text) >= self.rapidfuzz_min_length:
|
|
1380
|
+
if 'rapidfuzz' in self.completion_match_order and len(text) >= self.rapidfuzz_min_length:
|
|
1376
1381
|
rapidfuzz_matches = rapidfuzz.process.extract(
|
|
1377
1382
|
text,
|
|
1378
1383
|
collection,
|
|
@@ -1397,17 +1402,22 @@ class SQLCompleter(Completer):
|
|
|
1397
1402
|
|
|
1398
1403
|
return completions
|
|
1399
1404
|
|
|
1405
|
+
def _matches_prefix(self, candidate: str, text: str) -> bool:
|
|
1406
|
+
if not text.startswith('`'):
|
|
1407
|
+
candidate = self._strip_backticks(candidate)
|
|
1408
|
+
return candidate.lower().startswith(text)
|
|
1409
|
+
|
|
1400
1410
|
def find_perfect_matches(
|
|
1401
1411
|
self,
|
|
1402
1412
|
text: str,
|
|
1403
1413
|
collection: Collection[Any],
|
|
1404
1414
|
start_only: bool,
|
|
1405
1415
|
) -> list[tuple[str, int]]:
|
|
1416
|
+
if 'perfect' not in self.completion_match_order:
|
|
1417
|
+
return []
|
|
1406
1418
|
completions: list[tuple[str, int]] = []
|
|
1407
|
-
match_end_limit = len(text) if start_only else None
|
|
1408
1419
|
for item in collection:
|
|
1409
|
-
|
|
1410
|
-
if match_point >= 0:
|
|
1420
|
+
if self._matches_prefix(item, text) if start_only else text in item.lower():
|
|
1411
1421
|
completions.append((item, Fuzziness.PERFECT))
|
|
1412
1422
|
return completions
|
|
1413
1423
|
|
|
@@ -1882,7 +1892,7 @@ class SQLCompleter(Completer):
|
|
|
1882
1892
|
tiebreaker = tiebreaker_key(candidate)
|
|
1883
1893
|
if not text_for_len:
|
|
1884
1894
|
return (0, rank, tiebreaker, 0)
|
|
1885
|
-
elif
|
|
1895
|
+
elif self._matches_prefix(candidate, text_for_len):
|
|
1886
1896
|
# Preserve the shorter-prefix fallback for equal frecency scores.
|
|
1887
1897
|
length = -1000 + len(candidate) if self.completion_tiebreaker == 'frecency' else 0
|
|
1888
1898
|
return (0, 0, tiebreaker, length)
|
|
@@ -1929,10 +1939,13 @@ class SQLCompleter(Completer):
|
|
|
1929
1939
|
|
|
1930
1940
|
"""
|
|
1931
1941
|
if '/' in word:
|
|
1932
|
-
|
|
1933
|
-
|
|
1942
|
+
if 'slash_words' in self.completion_match_order:
|
|
1943
|
+
for path in suggest_path_by_prefix(word, sql_only=sql_only):
|
|
1944
|
+
yield (path, Fuzziness.SLASH_WORDS)
|
|
1934
1945
|
return
|
|
1935
1946
|
|
|
1947
|
+
if 'perfect' not in self.completion_match_order:
|
|
1948
|
+
return
|
|
1936
1949
|
# todo position is ignored, but may need to be used
|
|
1937
1950
|
base_path, last_path, position = parse_path(word)
|
|
1938
1951
|
paths = suggest_path(word, sql_only=sql_only)
|
|
@@ -9,9 +9,9 @@ show_warnings = False
|
|
|
9
9
|
# possible completions will be listed.
|
|
10
10
|
smart_completion = True
|
|
11
11
|
|
|
12
|
-
# Methods to find completion candidates,
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# Methods to find completion candidates, in priority order. Empty means the
|
|
13
|
+
# default list. Filename matching requires perfect and/or slash_words to be
|
|
14
|
+
# listed. Polars completions uses its own methods.
|
|
15
15
|
# * perfect - exact leading match
|
|
16
16
|
# * regex - ordered charater match with limited intervening spans ("rgx" matches "regex")
|
|
17
17
|
# * under_words - like regex but follows underscores ("uw" matches "under_words")
|
|
@@ -33,7 +33,7 @@ def test_init_configures_completion_ranking(monkeypatch: pytest.MonkeyPatch, tmp
|
|
|
33
33
|
|
|
34
34
|
cli = MyCli(myclirc=myclirc)
|
|
35
35
|
|
|
36
|
-
assert cli.completer.completion_match_order == ('camel_case', 'under_words'
|
|
36
|
+
assert cli.completer.completion_match_order == ('camel_case', 'under_words')
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
@pytest.mark.parametrize(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# type: ignore
|
|
2
2
|
|
|
3
|
+
from pathlib import Path
|
|
3
4
|
import re
|
|
4
5
|
from types import SimpleNamespace
|
|
5
6
|
from unittest.mock import Mock
|
|
@@ -153,7 +154,7 @@ def test_find_fuzzy_matches_skips_rapidfuzz_for_short_text(monkeypatch) -> None:
|
|
|
153
154
|
raise AssertionError('rapidfuzz should not be called')
|
|
154
155
|
|
|
155
156
|
monkeypatch.setattr(mycli.sqlcompleter.rapidfuzz.process, 'extract', fail_extract)
|
|
156
|
-
completer = SQLCompleter()
|
|
157
|
+
completer = SQLCompleter(completion_match_order=('rapidfuzz',))
|
|
157
158
|
matches = completer.find_fuzzy_matches('sel', 'sel', ['SELECT'])
|
|
158
159
|
|
|
159
160
|
assert matches == []
|
|
@@ -326,7 +327,7 @@ def test_find_matches_supports_substring_matching() -> None:
|
|
|
326
327
|
def test_find_matches_quotes_identifiers_when_text_starts_with_backtick() -> None:
|
|
327
328
|
matches = collect_matches('`us', ['users'])
|
|
328
329
|
|
|
329
|
-
assert matches == [('`users`', Fuzziness.
|
|
330
|
+
assert matches == [('`users`', Fuzziness.PERFECT)]
|
|
330
331
|
|
|
331
332
|
|
|
332
333
|
def test_find_matches_quotes_identifiers_when_cursor_is_inside_backticks() -> None:
|
|
@@ -336,7 +337,7 @@ def test_find_matches_quotes_identifiers_when_cursor_is_inside_backticks() -> No
|
|
|
336
337
|
text_before_cursor='select `uu',
|
|
337
338
|
)
|
|
338
339
|
|
|
339
|
-
assert matches == [('`uuid`', Fuzziness.
|
|
340
|
+
assert matches == [('`uuid`', Fuzziness.PERFECT)]
|
|
340
341
|
|
|
341
342
|
|
|
342
343
|
def test_find_matches_preserves_asterisk_inside_backticks() -> None:
|
|
@@ -346,14 +347,14 @@ def test_find_matches_preserves_asterisk_inside_backticks() -> None:
|
|
|
346
347
|
text_before_cursor='select `*',
|
|
347
348
|
)
|
|
348
349
|
|
|
349
|
-
assert matches == [('*', Fuzziness.
|
|
350
|
+
assert matches == [('*', Fuzziness.PERFECT)]
|
|
350
351
|
|
|
351
352
|
|
|
352
353
|
def test_find_matches_finds_regex_matches() -> None:
|
|
353
354
|
matches = collect_matches('sel', ['SELECT', 'foo_select_bar'])
|
|
354
355
|
|
|
355
356
|
assert matches == [
|
|
356
|
-
('SELECT', Fuzziness.
|
|
357
|
+
('SELECT', Fuzziness.PERFECT),
|
|
357
358
|
('foo_select_bar', Fuzziness.REGEX),
|
|
358
359
|
]
|
|
359
360
|
|
|
@@ -386,7 +387,7 @@ def test_find_matches_skips_rapidfuzz_for_short_text(monkeypatch) -> None:
|
|
|
386
387
|
|
|
387
388
|
matches = collect_matches('sel', ['SELECT'])
|
|
388
389
|
|
|
389
|
-
assert matches == [('SELECT', Fuzziness.
|
|
390
|
+
assert matches == [('SELECT', Fuzziness.PERFECT)]
|
|
390
391
|
|
|
391
392
|
|
|
392
393
|
def test_find_matches_filters_short_rapidfuzz_candidates(monkeypatch) -> None:
|
|
@@ -404,10 +405,10 @@ def test_find_matches_filters_short_rapidfuzz_candidates(monkeypatch) -> None:
|
|
|
404
405
|
@pytest.mark.parametrize(
|
|
405
406
|
('orig_text', 'collection', 'casing', 'expected'),
|
|
406
407
|
[
|
|
407
|
-
('sel', ['SELECT'], 'auto', [('select', Fuzziness.
|
|
408
|
-
('SEL', ['select'], 'auto', [('SELECT', Fuzziness.
|
|
409
|
-
('sel', ['select'], 'upper', [('SELECT', Fuzziness.
|
|
410
|
-
('SEL', ['SELECT'], 'lower', [('select', Fuzziness.
|
|
408
|
+
('sel', ['SELECT'], 'auto', [('select', Fuzziness.PERFECT)]),
|
|
409
|
+
('SEL', ['select'], 'auto', [('SELECT', Fuzziness.PERFECT)]),
|
|
410
|
+
('sel', ['select'], 'upper', [('SELECT', Fuzziness.PERFECT)]),
|
|
411
|
+
('SEL', ['SELECT'], 'lower', [('select', Fuzziness.PERFECT)]),
|
|
411
412
|
],
|
|
412
413
|
)
|
|
413
414
|
def test_find_matches_applies_casing(
|
|
@@ -494,12 +495,119 @@ def test_completion_match_order_defaults_and_validation(order: tuple[str, ...])
|
|
|
494
495
|
def test_completion_match_order_normalizes_partial_list() -> None:
|
|
495
496
|
completer = SQLCompleter(completion_match_order=(' CAMEL_CASE ', 'under_words'))
|
|
496
497
|
|
|
497
|
-
assert completer.completion_match_order == ('camel_case', 'under_words'
|
|
498
|
+
assert completer.completion_match_order == ('camel_case', 'under_words')
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
@pytest.mark.parametrize(
|
|
502
|
+
('method', 'text', 'candidate'),
|
|
503
|
+
[
|
|
504
|
+
('perfect', 'sel', 'select'),
|
|
505
|
+
('regex', 'slt', 'select'),
|
|
506
|
+
('under_words', 'us_de_fu', 'user_defined_function'),
|
|
507
|
+
('camel_case', 'TiZoTrTy', 'TimeZoneTransitionType'),
|
|
508
|
+
('rapidfuzz', 'abcd', 'abce'),
|
|
509
|
+
],
|
|
510
|
+
)
|
|
511
|
+
def test_only_enabled_method_contributes_candidates(method: str, text: str, candidate: str) -> None:
|
|
512
|
+
enabled = SQLCompleter(completion_match_order=(method,))
|
|
513
|
+
disabled = SQLCompleter(completion_match_order=('slash_words',))
|
|
514
|
+
|
|
515
|
+
assert enabled.find_fuzzy_matches(text, text.lower(), [candidate]) == [(candidate, Fuzziness[method.upper()])]
|
|
516
|
+
assert disabled.find_fuzzy_matches(text, text.lower(), [candidate]) == []
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def test_perfect_only_does_not_run_fuzzy_matchers(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
520
|
+
completer = SQLCompleter(completion_match_order=('perfect',))
|
|
521
|
+
monkeypatch.setattr(mycli.sqlcompleter.re, 'compile', pytest.fail)
|
|
522
|
+
monkeypatch.setattr(mycli.sqlcompleter.re, 'split', pytest.fail)
|
|
523
|
+
monkeypatch.setattr(completer, 'word_parts_match', pytest.fail)
|
|
524
|
+
monkeypatch.setattr(mycli.sqlcompleter.rapidfuzz.process, 'extract', pytest.fail)
|
|
525
|
+
|
|
526
|
+
assert completer.find_fuzzy_matches('sele', 'sele', ['select', 'user_select']) == [('select', Fuzziness.PERFECT)]
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
@pytest.mark.parametrize('order', [('perfect', 'regex'), ('regex', 'perfect')])
|
|
530
|
+
def test_enabled_prefix_methods_follow_configured_priority(order: tuple[str, ...]) -> None:
|
|
531
|
+
completer = SQLCompleter(completion_match_order=order)
|
|
532
|
+
|
|
533
|
+
assert list(completer.find_matches('sel', ['select'])) == [('select', Fuzziness[order[0].upper()])]
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@pytest.mark.parametrize('smart', [True, False])
|
|
537
|
+
@pytest.mark.parametrize(('order', 'expected'), [(('perfect',), ['select']), (('slash_words',), [])])
|
|
538
|
+
def test_sql_completion_with_restricted_methods(
|
|
539
|
+
monkeypatch: pytest.MonkeyPatch, smart: bool, order: tuple[str, ...], expected: list[str]
|
|
540
|
+
) -> None:
|
|
541
|
+
completer = make_completer(smart_completion=smart, completion_match_order=order)
|
|
542
|
+
completer.keywords = ['select', 'user_select']
|
|
543
|
+
completer.all_completions = {'select', 'user_select'}
|
|
544
|
+
monkeypatch.setattr(mycli.sqlcompleter, 'suggest_type', lambda *args: [{'type': 'keyword'}])
|
|
545
|
+
|
|
546
|
+
assert [c.text for c in completer.get_completions(Document('sel'), None)] == expected
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def test_nonfuzzy_completion_requires_perfect() -> None:
|
|
550
|
+
completer = SQLCompleter(completion_match_order=('regex',))
|
|
551
|
+
|
|
552
|
+
assert list(completer.find_matches('sel', ['select'], fuzzy=False)) == []
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
@pytest.mark.parametrize('smart', [True, False])
|
|
556
|
+
@pytest.mark.parametrize(('name', 'prefix'), [('order items', 'ord'), ('select', 'SEL')])
|
|
557
|
+
@pytest.mark.parametrize('quote', ['', '`'])
|
|
558
|
+
def test_perfect_only_completes_quoted_table_names(smart: bool, name: str, prefix: str, quote: str) -> None:
|
|
559
|
+
completer = SQLCompleter(smart_completion=smart, completion_match_order=('perfect',))
|
|
560
|
+
completer.extend_schemata('test')
|
|
561
|
+
completer.set_dbname('test')
|
|
562
|
+
completer.extend_relations([(name,)], kind='tables')
|
|
563
|
+
token = quote + prefix
|
|
564
|
+
|
|
565
|
+
matches = list(completer.get_completions(Document(f'SELECT * FROM {token}'), None))
|
|
566
|
+
|
|
567
|
+
assert any(c.text == f'`{name}`' and c.start_position == -len(token) for c in matches)
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
@pytest.mark.parametrize(('name', 'prefix'), [('order total', 'ord'), ('from', 'fro')])
|
|
571
|
+
def test_perfect_only_completes_quoted_column_names(name: str, prefix: str) -> None:
|
|
572
|
+
completer = SQLCompleter(completion_match_order=('perfect',))
|
|
573
|
+
completer.extend_schemata('test')
|
|
574
|
+
completer.set_dbname('test')
|
|
575
|
+
completer.extend_relations([('orders',)], kind='tables')
|
|
576
|
+
completer.extend_columns([('orders', name)], kind='tables')
|
|
577
|
+
|
|
578
|
+
matches = list(completer.get_completions(Document(f'SELECT * FROM orders WHERE {prefix}'), None))
|
|
579
|
+
|
|
580
|
+
assert any(c.text == f'`{name}`' and c.start_position == -len(prefix) for c in matches)
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
@pytest.mark.parametrize('fuzzy', [True, False])
|
|
584
|
+
def test_perfect_only_does_not_match_inside_quoted_names(fuzzy: bool) -> None:
|
|
585
|
+
completer = SQLCompleter(completion_match_order=('perfect',))
|
|
586
|
+
|
|
587
|
+
assert list(completer.find_matches('der', ['`order items`'], fuzzy=fuzzy, start_only=True)) == []
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
@pytest.mark.parametrize(('word', 'order'), [('./fi', ('perfect',)), ('fi', ('slash_words',))])
|
|
591
|
+
def test_disabled_file_methods_do_not_access_filesystem(monkeypatch: pytest.MonkeyPatch, word: str, order: tuple[str, ...]) -> None:
|
|
592
|
+
completer = SQLCompleter(completion_match_order=order)
|
|
593
|
+
monkeypatch.setattr(mycli.sqlcompleter, 'suggest_path_by_prefix', pytest.fail)
|
|
594
|
+
monkeypatch.setattr(mycli.sqlcompleter, 'suggest_path', pytest.fail)
|
|
595
|
+
|
|
596
|
+
assert list(completer.find_files(word)) == []
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
@pytest.mark.parametrize(('word', 'method'), [('./fi', 'slash_words'), ('fi', 'perfect')])
|
|
600
|
+
def test_enabled_file_method_completes_paths(monkeypatch: pytest.MonkeyPatch, tmp_path: Path, word: str, method: str) -> None:
|
|
601
|
+
monkeypatch.chdir(tmp_path)
|
|
602
|
+
(tmp_path / 'file.sql').touch()
|
|
603
|
+
completer = SQLCompleter(completion_match_order=(method,))
|
|
604
|
+
|
|
605
|
+
assert list(completer.find_files(word)) == [('./file.sql' if '/' in word else 'file.sql', Fuzziness[method.upper()])]
|
|
498
606
|
|
|
499
607
|
|
|
500
608
|
@pytest.mark.parametrize('preferred', ['regex', 'under_words', 'camel_case'])
|
|
501
609
|
def test_overlapping_matches_use_configured_priority(preferred: str) -> None:
|
|
502
|
-
completer = SQLCompleter(completion_match_order=(preferred,))
|
|
610
|
+
completer = SQLCompleter(completion_match_order=(preferred, 'perfect'))
|
|
503
611
|
|
|
504
612
|
matches = list(completer.find_matches('al', ['alphabet']))
|
|
505
613
|
|
|
@@ -507,7 +615,7 @@ def test_overlapping_matches_use_configured_priority(preferred: str) -> None:
|
|
|
507
615
|
|
|
508
616
|
|
|
509
617
|
def test_rapidfuzz_can_replace_an_overlapping_category(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
510
|
-
completer = SQLCompleter(completion_match_order=('rapidfuzz',))
|
|
618
|
+
completer = SQLCompleter(completion_match_order=('rapidfuzz', 'regex'))
|
|
511
619
|
monkeypatch.setattr(
|
|
512
620
|
mycli.sqlcompleter.rapidfuzz.process,
|
|
513
621
|
'extract',
|
|
@@ -520,7 +628,7 @@ def test_rapidfuzz_can_replace_an_overlapping_category(monkeypatch: pytest.Monke
|
|
|
520
628
|
@pytest.mark.parametrize('tiebreaker', ['frecency', 'length', 'lexicographic'])
|
|
521
629
|
def test_prefix_priority_precedes_frecency(monkeypatch: pytest.MonkeyPatch, tiebreaker: str) -> None:
|
|
522
630
|
completer = make_completer(
|
|
523
|
-
completion_match_order=('rapidfuzz',), frecency_provider=lambda: {'alpha': 100.0}, completion_tiebreaker=tiebreaker
|
|
631
|
+
completion_match_order=('rapidfuzz', 'regex'), frecency_provider=lambda: {'alpha': 100.0}, completion_tiebreaker=tiebreaker
|
|
524
632
|
)
|
|
525
633
|
monkeypatch.setattr(mycli.sqlcompleter, 'suggest_type', lambda *args: [{'type': 'keyword'}])
|
|
526
634
|
monkeypatch.setattr(completer, 'find_matches', lambda *args, **kwargs: [('alpha', Fuzziness.RAPIDFUZZ), ('prefix', Fuzziness.REGEX)])
|
|
@@ -529,7 +637,7 @@ def test_prefix_priority_precedes_frecency(monkeypatch: pytest.MonkeyPatch, tieb
|
|
|
529
637
|
|
|
530
638
|
|
|
531
639
|
def test_custom_match_priority_sorts_candidates(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
532
|
-
completer = make_completer(completion_match_order=('under_words',))
|
|
640
|
+
completer = make_completer(completion_match_order=('under_words', 'regex'))
|
|
533
641
|
monkeypatch.setattr(mycli.sqlcompleter, 'suggest_type', lambda *args: [{'type': 'keyword'}])
|
|
534
642
|
monkeypatch.setattr(completer, 'find_matches', lambda *args, **kwargs: [('alpha', Fuzziness.REGEX), ('bravo', Fuzziness.UNDER_WORDS)])
|
|
535
643
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|