From 423ae7093e43f35083b918336bce2a33ec852903 Mon Sep 17 00:00:00 2001 From: Roland Walker Date: Fri, 2 Oct 2026 07:21:15 -0400 Subject: [PATCH] prefer forward-slash /commands in pytest tests also finding a few cases in user feedback where backslash was used. Some tests still use backslash of course, since it is still supported. --- changelog.md | 1 + mycli/key_bindings.py | 4 +- mycli/main_modes/checkup.py | 4 +- mycli/main_modes/repl.py | 2 +- mycli/packages/special/iocommands.py | 8 +-- test/pytests/test_checkup.py | 4 +- test/pytests/test_client_commands.py | 2 +- test/pytests/test_completion_engine.py | 62 ++++++++++++------- test/pytests/test_hybrid_redirection.py | 2 +- test/pytests/test_key_bindings.py | 4 +- test/pytests/test_main.py | 12 ++-- test/pytests/test_main_modes_repl.py | 22 +++---- ...est_smart_completion_public_schema_only.py | 37 +++++------ test/pytests/test_special_dbcommands.py | 12 ++-- test/pytests/test_special_init.py | 2 +- test/pytests/test_special_iocommands.py | 54 ++++++++-------- test/pytests/test_special_llm.py | 40 ++++++------ test/pytests/test_special_main.py | 24 +++---- test/pytests/test_sql_utils.py | 16 ++--- 19 files changed, 165 insertions(+), 147 deletions(-) diff --git a/changelog.md b/changelog.md index e828b77e6..6ae5b4487 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,7 @@ Internal * Replace `pyfzf` dependency with internal implementation. * Use the `uv` outside of the `tox` environment when testing. * Use forward-slash forms of special commands in the behave test suite. +* Use forward-slash forms of special commands in the pytest test suite. v2.27.0 (2026/09/29) diff --git a/mycli/key_bindings.py b/mycli/key_bindings.py index 6fb8ef206..02546c80d 100644 --- a/mycli/key_bindings.py +++ b/mycli/key_bindings.py @@ -43,9 +43,9 @@ def print_f1_help(): app.print_text('\n') app.print_text([ ('', 'Inline help — type "'), - ('bold', 'help'), + ('bold', '/help'), ('', '" or "'), - ('bold', r'\?'), + ('bold', r'/?'), ('', '"\n'), ]) app.print_text([ diff --git a/mycli/main_modes/checkup.py b/mycli/main_modes/checkup.py index 2333ad166..c00442dc3 100644 --- a/mycli/main_modes/checkup.py +++ b/mycli/main_modes/checkup.py @@ -71,8 +71,8 @@ def _environment_checkup() -> None: print('\n### Environment variables:\n') table = [] for variable, purpose in [ - ('EDITOR', r'optional for \edit and C-x C-e'), - ('VISUAL', r'optional for \edit and C-x C-e'), + ('EDITOR', r'optional for /edit and C-x C-e'), + ('VISUAL', r'optional for /edit and C-x C-e'), ]: if value := os.environ.get(variable): table.append([f'${variable}', value, purpose]) diff --git a/mycli/main_modes/repl.py b/mycli/main_modes/repl.py index 77aa5389b..f11a7fd4d 100644 --- a/mycli/main_modes/repl.py +++ b/mycli/main_modes/repl.py @@ -1144,7 +1144,7 @@ def _tips_picker() -> str: except FileNotFoundError: pass - return random.choice(tips) if tips else r'\? or "help" for help!' + return random.choice(tips) if tips else r'/? or /help for help!' def _configure_editor(mycli: 'MyCli') -> None: diff --git a/mycli/packages/special/iocommands.py b/mycli/packages/special/iocommands.py index 4b3f206ad..ca659de2a 100644 --- a/mycli/packages/special/iocommands.py +++ b/mycli/packages/special/iocommands.py @@ -650,7 +650,7 @@ def subst_favorite_query_args(query: str, args: list[str]) -> list[str | None]: def save_favorite_query(arg: str, **_) -> list[SQLResult]: """Save a new favorite query.""" - usage = "Syntax: \\fs name query.\n\n" + FavoriteQueries.instance.usage + usage = "Syntax: /fs name query.\n\n" + FavoriteQueries.instance.usage return _save_favorite_query(arg, usage) @@ -704,7 +704,7 @@ def is_favorite_save_command(statement: str) -> bool: ) def delete_favorite_query(arg: str, **_) -> list[SQLResult]: """Delete an existing favorite query.""" - usage = "Syntax: \\fd name.\n\n" + FavoriteQueries.instance.usage + usage = "Syntax: /fd name.\n\n" + FavoriteQueries.instance.usage return _delete_favorite_query(arg, usage) @@ -804,7 +804,7 @@ def _edit_dsn_alias(alias: str) -> list[SQLResult]: ) def execute_system_command(arg: str, **_) -> list[SQLResult]: """Execute a system shell command.""" - usage = "Syntax: system [-r] [command].\n-r denotes \"raw\" mode, in which output is passed through without formatting." + usage = "Syntax: /system [-r] [command].\n-r denotes \"raw\" mode, in which output is passed through without formatting." IMPLICIT_RAW_MODE_COMMANDS = { 'clear', @@ -1088,7 +1088,7 @@ def flush_pipe_once_if_written( completion_snippet='run query every N seconds', ) def watch_query(arg: str, **kwargs) -> Generator[SQLResult, None, None]: - usage = """Syntax: watch [sec] [-c] query. + usage = """Syntax: /watch [sec] [-c] query. * sec: The interval at the query will be repeated, in seconds. By default: 5. * -c: Clears the screen between every iteration. diff --git a/test/pytests/test_checkup.py b/test/pytests/test_checkup.py index a27e8ef76..74297ae1c 100644 --- a/test/pytests/test_checkup.py +++ b/test/pytests/test_checkup.py @@ -107,8 +107,8 @@ def test_environment_checkup(monkeypatch, capsys) -> None: assert '### Environment variables:' in output rows = [line.split() for line in output.splitlines()] - assert ['$EDITOR', 'vim', 'optional', 'for', r'\edit', 'and', 'C-x', 'C-e'] in rows - assert ['$VISUAL', 'UNSET', 'optional', 'for', r'\edit', 'and', 'C-x', 'C-e'] in rows + assert ['$EDITOR', 'vim', 'optional', 'for', r'/edit', 'and', 'C-x', 'C-e'] in rows + assert ['$VISUAL', 'UNSET', 'optional', 'for', r'/edit', 'and', 'C-x', 'C-e'] in rows def test_configuration_checkup_missing_file(capsys) -> None: diff --git a/test/pytests/test_client_commands.py b/test/pytests/test_client_commands.py index 24d70469e..b8e142d12 100644 --- a/test/pytests/test_client_commands.py +++ b/test/pytests/test_client_commands.py @@ -237,7 +237,7 @@ def test_config_command_returns_unquoted_configobj_value(monkeypatch: pytest.Mon assert special.execute(None, '/config search SHOW_WARNINGS') == config_result assert special.execute(None, r'\config search SHOW_WARNINGS') == config_result with pytest.raises(special.CommandNotFound, match='Command not found: select'): - special.execute(None, r'select 1 \config get main.show_warnings') + special.execute(None, r'select 1 /config get main.show_warnings') def test_config_edit_opens_user_config_for_slash_and_backslash_commands( diff --git a/test/pytests/test_completion_engine.py b/test/pytests/test_completion_engine.py index c85614cb5..ec77b5f5c 100644 --- a/test/pytests/test_completion_engine.py +++ b/test/pytests/test_completion_engine.py @@ -939,21 +939,21 @@ def test_suggest_type_handles_parser_results_shorter_than_cursor(monkeypatch): @pytest.mark.parametrize( ('text', 'expected'), [ - ('\\', [{'type': 'special'}]), + ('/', [{'type': 'special'}]), ('use ', [{'type': 'database'}]), ('connect ', [{'type': 'database'}]), - ('\\u ', [{'type': 'database'}]), - ('\\r ', [{'type': 'database'}]), + ('/use ', [{'type': 'database'}]), + ('/connect ', [{'type': 'database'}]), ('tableformat ', [{'type': 'table_format'}]), ('redirectformat ', [{'type': 'table_format'}]), - ('\\T ', [{'type': 'table_format'}]), - ('\\Tr ', [{'type': 'table_format'}]), - ('\\f ', [{'type': 'favoritequery'}]), - ('\\fs ', [{'type': 'favoritequery'}]), - ('\\fd ', [{'type': 'favoritequery'}]), + ('/tableformat ', [{'type': 'table_format'}]), + ('/redirectformat ', [{'type': 'table_format'}]), + ('/f ', [{'type': 'favoritequery'}]), + ('/fs ', [{'type': 'favoritequery'}]), + ('/fd ', [{'type': 'favoritequery'}]), ('/f report', [{'type': 'favoritequery'}]), ('/f report ', [{'type': 'favoritequery_template_key', 'name': 'report', 'used_keys': set()}]), - ('\\f report --u', [{'type': 'favoritequery_template_key', 'name': 'report', 'used_keys': set()}]), + ('/f report --u', [{'type': 'favoritequery_template_key', 'name': 'report', 'used_keys': set()}]), ('/f report -', [{'type': 'favoritequery_template_key', 'name': 'report', 'used_keys': set()}]), ('/f report --', [{'type': 'favoritequery_template_key', 'name': 'report', 'used_keys': set()}]), ('/f report -- ', []), @@ -976,10 +976,10 @@ def test_suggest_type_handles_parser_results_shorter_than_cursor(monkeypatch): ), ('/f report -- --user', []), ('/f report --user="henry', []), - ('\\dt ', [{'type': 'table', 'schema': []}, {'type': 'view', 'schema': []}, {'type': 'schema'}]), - ('\\dt+ ', [{'type': 'table', 'schema': []}, {'type': 'view', 'schema': []}, {'type': 'schema'}]), + ('/dt ', [{'type': 'table', 'schema': []}, {'type': 'view', 'schema': []}, {'type': 'schema'}]), + ('/dt+ ', [{'type': 'table', 'schema': []}, {'type': 'view', 'schema': []}, {'type': 'schema'}]), ( - '\\. ', + '/. ', [ { 'type': 'special_subcommand', @@ -1123,10 +1123,10 @@ def test_suggest_type_handles_parser_results_shorter_than_cursor(monkeypatch): ('/once ', [{'type': 'file_name', 'all_files': True}]), ('tee ', [{'type': 'file_name', 'all_files': True}]), ('/tee ', [{'type': 'file_name', 'all_files': True}]), - ('\\e ', [{'type': 'file_name'}]), - ('\\edit ', [{'type': 'file_name'}]), - ('\\llm ', [{'type': 'llm'}]), - ('\\ai ', [{'type': 'llm'}]), + ('/e ', [{'type': 'file_name'}]), + ('/edit ', [{'type': 'file_name'}]), + ('/llm ', [{'type': 'llm'}]), + ('/ai ', [{'type': 'llm'}]), ('/config ', [{'type': 'special_subcommand', 'subcommands': ['help', 'get', 'search', 'edit']}]), ('/config g', [{'type': 'special_subcommand', 'subcommands': ['help', 'get', 'search', 'edit']}]), ('/config s', [{'type': 'special_subcommand', 'subcommands': ['help', 'get', 'search', 'edit']}]), @@ -1220,6 +1220,22 @@ def test_suggest_special(text, expected): assert suggest_special(text) == expected +@pytest.mark.parametrize('command', [r'\u', '/u', r'\r', '/r']) +@pytest.mark.parametrize('argument', ['', 'my']) +def test_short_connection_commands_suggest_databases(command: str, argument: str) -> None: + text = f'{command} {argument}' + + assert suggest_type(text, text) == [{'type': 'database'}] + + +@pytest.mark.parametrize('command', [r'\T', '/T', r'\Tr', '/Tr']) +@pytest.mark.parametrize('argument', ['', 'cs']) +def test_short_format_commands_suggest_table_formats(command: str, argument: str) -> None: + text = f'{command} {argument}' + + assert suggest_type(text, text) == [{'type': 'table_format'}] + + @pytest.mark.parametrize( ('text', 'query'), [ @@ -2053,10 +2069,10 @@ def test_after_as(expression): @pytest.mark.parametrize( "expression", [ - "\\. ", - "select 1; \\. ", - "select 1;\\. ", - "select 1 ; \\. ", + "/. ", + "select 1; /. ", + "select 1;/. ", + "select 1 ; /. ", "source ", "truncate table test; source ", "truncate table test ; source ", @@ -2068,9 +2084,9 @@ def test_source_is_file(expression): special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) suggestions = suggest_type(expression, expression) assert suggestions == [ @@ -2082,7 +2098,7 @@ def test_source_is_file(expression): @pytest.mark.parametrize( "expression", [ - "\\f ", + "/f ", ], ) def test_favorite_name_suggestion(expression): diff --git a/test/pytests/test_hybrid_redirection.py b/test/pytests/test_hybrid_redirection.py index 80b91192b..e24b99ec8 100644 --- a/test/pytests/test_hybrid_redirection.py +++ b/test/pytests/test_hybrid_redirection.py @@ -153,7 +153,7 @@ def test_file_redirect_ignores_trailing_sql_comments(operator: str, filename: st 'SELECT 1', None, operator[1:], - filename.strip('\'"'), + filename.strip('"').strip("'"), ) diff --git a/test/pytests/test_key_bindings.py b/test/pytests/test_key_bindings.py index 2843e7dc9..da8ddac34 100644 --- a/test/pytests/test_key_bindings.py +++ b/test/pytests/test_key_bindings.py @@ -189,9 +189,9 @@ def test_print_f1_help_prints_inline_help_and_docs_url(monkeypatch) -> None: '\n', [ ('', 'Inline help — type "'), - ('bold', 'help'), + ('bold', '/help'), ('', '" or "'), - ('bold', r'\?'), + ('bold', r'/?'), ('', '"\n'), ], [ diff --git a/test/pytests/test_main.py b/test/pytests/test_main.py index dd8dcefde..c10203027 100644 --- a/test/pytests/test_main.py +++ b/test/pytests/test_main.py @@ -391,7 +391,7 @@ def test_reconnect_no_database(executor, capsys): None, None, ) - sql = "\\r" + sql = "/connect" result = next(mycli.packages.special.execute(executor, sql)) stdout, _stderr = capsys.readouterr() assert result.status is None @@ -417,7 +417,7 @@ def test_reconnect_with_different_database(executor): database_1 = TEST_DATABASE database_2 = DEFAULT_DATABASE sql_1 = f"use {database_1}" - sql_2 = f"\\r {database_2}" + sql_2 = f"/connect {database_2}" _result_1 = next(mycli.packages.special.execute(executor, sql_1)) result_2 = next(mycli.packages.special.execute(executor, sql_2)) expected = f'You are now connected to database "{database_2}" as user "{USER}"' @@ -441,9 +441,9 @@ def test_reconnect_with_same_database(executor): None, ) database = DEFAULT_DATABASE - sql = f"\\u {database}" + sql = f"/use {database}" result = next(mycli.packages.special.execute(executor, sql)) - sql = f"\\r {database}" + sql = f"/connect {database}" result = next(mycli.packages.special.execute(executor, sql)) expected = f'You are already connected to database "{database}" as user "{USER}"' assert expected in result.status @@ -501,7 +501,7 @@ def test_prompt_socket_short_host(executor): def test_enable_show_warnings(executor): mycli = MyCli() mycli.register_special_commands() - sql = "\\W" + sql = "/warnings" result = run(executor, sql) assert result[0]["status"] == "Show warnings enabled." @@ -510,7 +510,7 @@ def test_enable_show_warnings(executor): def test_disable_show_warnings(executor): mycli = MyCli() mycli.register_special_commands() - sql = "\\w" + sql = "/nowarnings" result = run(executor, sql) assert result[0]["status"] == "Show warnings disabled." diff --git a/test/pytests/test_main_modes_repl.py b/test/pytests/test_main_modes_repl.py index 4327b9b50..0761dc49a 100644 --- a/test/pytests/test_main_modes_repl.py +++ b/test/pytests/test_main_modes_repl.py @@ -290,10 +290,10 @@ def test_complete_while_typing_filter_covers_threshold_and_word_rules(monkeypatc monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='source x/'))) assert repl_mode.complete_while_typing_filter() is False - monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='\\. abc'))) + monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='/. abc'))) assert repl_mode.complete_while_typing_filter() is True - monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='\\. a/'))) + monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='/. a/'))) assert repl_mode.complete_while_typing_filter() is False monkeypatch.setattr(repl_mode, 'get_app', lambda: SimpleNamespace(current_buffer=SimpleNamespace(text='select abc'))) @@ -425,7 +425,7 @@ def test_repl_picker_helpers_cover_present_and_missing_resources(monkeypatch: py monkeypatch.setattr(repl_mode.resources, 'files', lambda package: FakeResourceTree({})) assert repl_mode._contributors_picker() == 'our contributors' assert repl_mode._sponsors_picker() == 'our sponsors' - assert repl_mode._tips_picker() == r'\? or "help" for help!' + assert repl_mode._tips_picker() == r'/? or /help for help!' def test_configure_editor_uses_configured_editor(monkeypatch: pytest.MonkeyPatch) -> None: @@ -1583,7 +1583,7 @@ def test_one_iteration_covers_llm_paths(monkeypatch: pytest.MonkeyPatch) -> None click_output: list[str] = [] monkeypatch.setattr(repl_mode.click, 'echo', lambda message='', **kwargs: click_output.append(str(message))) monkeypatch.setattr(repl_mode.special, 'is_timing_enabled', lambda: True) - monkeypatch.setattr(repl_mode.special, 'is_llm_command', lambda text: text.startswith('\\llm')) + monkeypatch.setattr(repl_mode.special, 'is_llm_command', lambda text: text.startswith('/llm')) class FakeSQLExecute: def __init__(self) -> None: @@ -1599,7 +1599,7 @@ def run(self, text: str) -> Iterator[SQLResult]: lambda text, cur, dbname, field_truncate, section_truncate: ('context', 'select 1', 1.25), ) cli = make_repl_cli(FakeSQLExecute()) - cli.prompt_session = FakePromptSession(['\\llm ask', 'select 1']) + cli.prompt_session = FakePromptSession(['/llm ask', 'select 1']) repl_mode._one_iteration( cli, repl_mode.ReplState(), @@ -1608,7 +1608,7 @@ def run(self, text: str) -> Iterator[SQLResult]: assert cli.output_calls[0][0] == ['None', 'ran:select 1'] cli_finish = make_repl_cli(FakeSQLExecute()) - cli_finish.prompt_session = FakePromptSession(['\\llm finish']) + cli_finish.prompt_session = FakePromptSession(['/llm finish']) cli_finish.format_sqlresult = lambda result, **kwargs: iter([result.status_plain or 'row']) monkeypatch.setattr( repl_mode.special, @@ -1619,7 +1619,7 @@ def run(self, text: str) -> Iterator[SQLResult]: assert cli_finish.output_calls[0][0] == ['done'] cli_empty = make_repl_cli(FakeSQLExecute()) - cli_empty.prompt_session = FakePromptSession(['\\llm empty']) + cli_empty.prompt_session = FakePromptSession(['/llm empty']) monkeypatch.setattr( repl_mode.special, 'handle_llm', @@ -1629,7 +1629,7 @@ def run(self, text: str) -> Iterator[SQLResult]: assert cli_empty.output_calls == [] cli_err = make_repl_cli(FakeSQLExecute()) - cli_err.prompt_session = FakePromptSession(['\\llm err']) + cli_err.prompt_session = FakePromptSession(['/llm err']) monkeypatch.setattr( repl_mode.special, 'handle_llm', @@ -1639,7 +1639,7 @@ def run(self, text: str) -> Iterator[SQLResult]: assert 'llm boom' in cli_err.echo_calls[-1] cli_interrupt = make_repl_cli(FakeSQLExecute()) - cli_interrupt.prompt_session = FakePromptSession(['\\llm stop']) + cli_interrupt.prompt_session = FakePromptSession(['/llm stop']) monkeypatch.setattr( repl_mode.special, 'handle_llm', @@ -1649,7 +1649,7 @@ def run(self, text: str) -> Iterator[SQLResult]: assert cli_interrupt.output_calls == [] cli_quiet = make_repl_cli(FakeSQLExecute()) - cli_quiet.prompt_session = FakePromptSession(['\\llm quiet', 'select 2']) + cli_quiet.prompt_session = FakePromptSession(['/llm quiet', 'select 2']) monkeypatch.setattr(repl_mode.special, 'is_timing_enabled', lambda: False) monkeypatch.setattr( repl_mode.special, @@ -1671,7 +1671,7 @@ def run(self, text: str) -> Iterator[SQLResult]: ("set password = 'newpass'", True), ('quit', True), ('exit', True), - ('\\q', True), + ('/q', True), ('SELECT 1', False), ('DROP TABLE t', False), ('USE mydb', False), diff --git a/test/pytests/test_smart_completion_public_schema_only.py b/test/pytests/test_smart_completion_public_schema_only.py index a2b29f555..2cc405ec3 100644 --- a/test/pytests/test_smart_completion_public_schema_only.py +++ b/test/pytests/test_smart_completion_public_schema_only.py @@ -89,9 +89,9 @@ def test_use_database_completion(completer, complete_event): special.register_special_command( ..., 'use', - '\\u [database]', + '/use [database]', 'Change to a new database.', - aliases=[special.SpecialCommandAlias('\\u', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/use', case_sensitive=False)], ) result = completer.get_completions(Document(text=text, cursor_position=position), complete_event) assert list(result) == [ @@ -101,12 +101,13 @@ def test_use_database_completion(completer, complete_event): def test_special_name_completion(completer, complete_event): - text = "\\d" - position = len("\\d") + text = "/d" + position = len("/d") result = completer.get_completions(Document(text=text, cursor_position=position), complete_event) assert list(result) == [ - Completion(text="\\dt", start_position=-2, display_meta='list or describe tables'), - Completion(text="\\dsn", start_position=-2, display_meta='manage saved DSNs'), + Completion(text="/dt", start_position=-2, display_meta='list or describe tables'), + Completion(text="/dsn", start_position=-2, display_meta='manage saved DSNs'), + Completion(text="/delimiter", start_position=-2, display_meta='set end-of-statement delimiter'), ] @@ -879,9 +880,9 @@ def test_file_name_completion(completer, complete_event, text, expected): special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event)) expected = [Completion(txt, pos) for txt, pos in expected] @@ -922,9 +923,9 @@ def test_source_eager_completion(completer, complete_event, tmp_path, monkeypatc special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event)) success = True @@ -951,9 +952,9 @@ def test_source_completion_advances_into_nested_directories(completer, complete_ special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) text = 'source doc/' @@ -992,9 +993,9 @@ def test_file_commands_complete_slash_separated_prefixes( special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) path_prefix = './dir/sub/exa' @@ -1013,9 +1014,9 @@ def test_source_completion_quotes_paths_with_spaces(completer, complete_event, t special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) text = 'source spaced' @@ -1072,9 +1073,9 @@ def test_source_leading_dot_suggestions_completion(completer, complete_event, tm special.register_special_command( ..., 'source', - '\\. ', + '/. ', 'Execute commands from file.', - aliases=[special.SpecialCommandAlias('\\.', case_sensitive=False)], + aliases=[special.SpecialCommandAlias('/.', case_sensitive=False)], ) result = list(completer.get_completions(Document(text=text, cursor_position=position), complete_event)) success = True diff --git a/test/pytests/test_special_dbcommands.py b/test/pytests/test_special_dbcommands.py index 1f348a5c6..7c703a7c1 100644 --- a/test/pytests/test_special_dbcommands.py +++ b/test/pytests/test_special_dbcommands.py @@ -70,7 +70,7 @@ def fetchone(self): def test_list_tables_verbose_preserves_field_results(): - """Test that \\dt+ table_name returns SHOW FIELDS results, not SHOW CREATE TABLE results. + """Test that /dt+ table_name returns SHOW FIELDS results, not SHOW CREATE TABLE results. This is a regression test for a bug where the cursor was reused for SHOW CREATE TABLE, which overwrote the SHOW FIELDS results. @@ -111,7 +111,7 @@ def fetchone_side_effect(): cur.fetchall.side_effect = fetchall_side_effect cur.fetchone.side_effect = fetchone_side_effect - # Call list_tables with command_verbosity=True (simulating \dt+ table_name) + # Call list_tables with command_verbosity=True (simulating /dt+ table_name) results = list_tables(cur, arg='test_table', command_verbosity=True) assert len(results) == 1 @@ -132,17 +132,17 @@ def fetchone_side_effect(): def test_u_suggests_databases(): - suggestions = suggest_type("\\u ", "\\u ") + suggestions = suggest_type("/use ", "/use ") assert sorted_dicts(suggestions) == sorted_dicts([{"type": "database"}]) def test_describe_table(): - suggestions = suggest_type("\\dt", "\\dt ") + suggestions = suggest_type("/dt", "/dt ") assert sorted_dicts(suggestions) == sorted_dicts([{"type": "table", "schema": []}, {"type": "view", "schema": []}, {"type": "schema"}]) def test_list_or_show_create_tables(): - suggestions = suggest_type("\\dt+", "\\dt+ ") + suggestions = suggest_type("/dt+", "/dt+ ") assert sorted_dicts(suggestions) == sorted_dicts([{"type": "table", "schema": []}, {"type": "view", "schema": []}, {"type": "schema"}]) @@ -216,7 +216,7 @@ def test_ping_rejects_arguments_without_contacting_server() -> None: def test_ping_command_registration() -> None: - command = special_main.COMMANDS[r'\ping'] + command = special_main.COMMANDS[r'/ping'] assert command.handler is ping assert command.usage == '/ping' diff --git a/test/pytests/test_special_init.py b/test/pytests/test_special_init.py index 31631c5cc..b6532bbcb 100644 --- a/test/pytests/test_special_init.py +++ b/test/pytests/test_special_init.py @@ -85,7 +85,7 @@ def test_special_init_uses_llm_implementation_when_enabled(load_special: Callabl def test_special_init_uses_llm_stubs_when_disabled(load_special: Callable[[bool], ModuleType]) -> None: special = load_special(True) - assert special.is_llm_command(r'\llm prompt') is False + assert special.is_llm_command(r'/llm prompt') is False with pytest.raises(special.FinishIteration) as handle_exc: special.handle_llm(cast_args := object()) with pytest.raises(special.FinishIteration) as sql_exc: diff --git a/test/pytests/test_special_iocommands.py b/test/pytests/test_special_iocommands.py index 1a7a9f7d7..86ed1124d 100644 --- a/test/pytests/test_special_iocommands.py +++ b/test/pytests/test_special_iocommands.py @@ -219,17 +219,17 @@ def test_editor_command(monkeypatch): assert mycli.packages.special.editor_command(r"hello\e") assert mycli.packages.special.editor_command(r"hello\edit") - assert mycli.packages.special.editor_command(r"\e hello") - assert mycli.packages.special.editor_command(r"\edit hello") + assert mycli.packages.special.editor_command(r"/e hello") + assert mycli.packages.special.editor_command(r"/edit hello") assert mycli.packages.special.editor_command('/edit') assert not mycli.packages.special.editor_command(r"HELP \e") assert not mycli.packages.special.editor_command(r"help \edit\g") assert not mycli.packages.special.editor_command(r"hello") - assert not mycli.packages.special.editor_command(r"\ehello") - assert not mycli.packages.special.editor_command(r"\edithello") + assert not mycli.packages.special.editor_command(r"/ehello") + assert not mycli.packages.special.editor_command(r"/edithello") - assert mycli.packages.special.get_filename(r"\e filename") == "filename" + assert mycli.packages.special.get_filename(r"/e filename") == "filename" assert mycli.packages.special.get_editor_query('/edit') == '' if os.name != "nt": @@ -290,37 +290,37 @@ def test_tee_command_error(): def test_favorite_query(favorite_queries_instance) -> None: with db_connection().cursor() as cur: query = 'select "✔"' - mycli.packages.special.execute(cur, f"\\fs check {query}") - assert next(mycli.packages.special.execute(cur, "\\f check")).preamble == "> " + query + mycli.packages.special.execute(cur, f"/fs check {query}") + assert next(mycli.packages.special.execute(cur, "/f check")).preamble == "> " + query @dbtest @pytest.mark.skipif(os.name == "nt", reason="Bug: fails on Windows, needs fixing, singleton of FQ not working right") def test_special_favorite_query(favorite_queries_instance) -> None: with db_connection().cursor() as cur: - query = r'\?' - mycli.packages.special.execute(cur, rf"\fs special {query}") - assert (r'\G', None, r'\G', 'Display results vertically.') in next(mycli.packages.special.execute(cur, r'\f special')).rows + query = '/help' + mycli.packages.special.execute(cur, f"/fs special {query}") + assert (r'\G', None, r'\G', 'Display results vertically.') in next(mycli.packages.special.execute(cur, r'/f special')).rows def test_once_command(): with pytest.raises(TypeError): - mycli.packages.special.execute(None, "\\once") + mycli.packages.special.execute(None, "/once") with pytest.raises(OSError): - mycli.packages.special.execute(None, "\\once /proc/access-denied") + mycli.packages.special.execute(None, "/once /proc/access-denied") mycli.packages.special.write_once("hello world") # write without file set # keep Windows from locking the file with delete=False with tempfile.NamedTemporaryFile(prefix=TEMPFILE_PREFIX, delete=False) as f: - mycli.packages.special.execute(None, "\\once " + f.name) + mycli.packages.special.execute(None, "/once " + f.name) mycli.packages.special.write_once("hello world") if os.name == "nt": assert f.read() == b"hello world\r\n" else: assert f.read() == b"hello world\n" - mycli.packages.special.execute(None, "\\once -o " + f.name) + mycli.packages.special.execute(None, "/once -o " + f.name) mycli.packages.special.write_once("hello world line 1") mycli.packages.special.write_once("hello world line 2") f.seek(0) @@ -338,20 +338,20 @@ def test_once_command(): def test_pipe_once_command(): with pytest.raises(IOError): - mycli.packages.special.execute(None, "\\pipe_once") + mycli.packages.special.execute(None, "/pipe_once") with pytest.raises(OSError): - mycli.packages.special.execute(None, "\\pipe_once /proc/access-denied") + mycli.packages.special.execute(None, "/pipe_once /proc/access-denied") mycli.packages.special.write_pipe_once("select 1") mycli.packages.special.flush_pipe_once_if_written(None) if os.name == "nt": - mycli.packages.special.execute(None, '\\pipe_once python -c "import sys; print(len(sys.stdin.read().strip()))"') + mycli.packages.special.execute(None, '/pipe_once python -c "import sys; print(len(sys.stdin.read().strip()))"') mycli.packages.special.write_once("hello world") mycli.packages.special.flush_pipe_once_if_written(None) else: with tempfile.NamedTemporaryFile(prefix=TEMPFILE_PREFIX) as f: - mycli.packages.special.execute(None, "\\pipe_once tee " + f.name) + mycli.packages.special.execute(None, "/pipe_once tee " + f.name) mycli.packages.special.write_pipe_once("hello world") mycli.packages.special.flush_pipe_once_if_written(None) f.seek(0) @@ -548,7 +548,7 @@ def test_disable_show_warnings_updates_special_state() -> None: def test_editor_helpers_strip_commands() -> None: - assert iocommands.get_filename(r'\edit ') is None + assert iocommands.get_filename(r'/edit ') is None assert iocommands.get_filename('select 1') is None assert iocommands.get_editor_query(r' select * from style\edit\e ') == 'select * from style' @@ -600,10 +600,10 @@ def fake_edit(text: str, extension: str) -> str: def test_clip_helpers_and_clipboard(monkeypatch) -> None: - assert iocommands.clip_command(r'\clip select 1') + assert iocommands.clip_command(r'/clip select 1') assert iocommands.clip_command(r'select 1 \clip') assert not iocommands.clip_command(r'select 1') - assert iocommands.get_clip_query(r'\clip select 1\clip') == ' select 1' + assert iocommands.get_clip_query(r'/clip select 1\clip') == ' select 1' copied: list[str] = [] monkeypatch.setattr(iocommands.pyperclip, 'copy', lambda text: copied.append(text)) @@ -1507,14 +1507,14 @@ def test_list_substitute_save_delete_and_redirect_state(tmp_path: Path, monkeypa assert iocommands.subst_favorite_query_args('select 1', ['x']) == [None, 'query does not have substitution parameter $1:\n select 1'] assert iocommands.subst_favorite_query_args('select $1, $2', ['x']) == [None, 'missing substitution for $2 in query:\n select x, $2'] - assert iocommands.save_favorite_query('', cur=None)[0].status == 'Syntax: \\fs name query.\n\n' + populated_favorites.usage + assert iocommands.save_favorite_query('', cur=None)[0].status == 'Syntax: /fs name query.\n\n' + populated_favorites.usage assert iocommands.save_favorite_query('onlyname', cur=None)[0].status == ( - 'Syntax: \\fs name query.\n\n' + populated_favorites.usage + ' Err: Both name and query are required.' + 'Syntax: /fs name query.\n\n' + populated_favorites.usage + ' Err: Both name and query are required.' ) assert iocommands.save_favorite_query('saved select 2', cur=None)[0].status == 'Saved.' assert populated_favorites.saved == [('saved', 'select 2')] - assert iocommands.delete_favorite_query('', cur=None)[0].status == 'Syntax: \\fd name.\n\n' + populated_favorites.usage + assert iocommands.delete_favorite_query('', cur=None)[0].status == 'Syntax: /fd name.\n\n' + populated_favorites.usage assert iocommands.delete_favorite_query('saved', cur=None)[0].status == 'saved: Deleted.' assert populated_favorites.deleted == ['saved'] @@ -1746,7 +1746,7 @@ def test_dsn_command_shows_usage_for_help_and_unknown_subcommands(monkeypatch) - def test_execute_system_command_usage_parse_and_cd(monkeypatch) -> None: - usage = 'Syntax: system [-r] [command].\n-r denotes "raw" mode, in which output is passed through without formatting.' + usage = 'Syntax: /system [-r] [command].\n-r denotes "raw" mode, in which output is passed through without formatting.' assert iocommands.execute_system_command('')[0].status == usage assert iocommands.execute_system_command('-r')[0].status == usage @@ -1991,10 +1991,10 @@ def test_flush_pipe_once_timeout_and_nonzero_exit(monkeypatch, tmp_path: Path) - def test_watch_query_usage_and_destructive_cancel(monkeypatch) -> None: usage_results = list(iocommands.watch_query('', cur=SequenceCursor([None]))) - assert usage_results[0].status and usage_results[0].status.startswith('Syntax: watch') + assert usage_results[0].status and usage_results[0].status.startswith('Syntax: /watch') usage_missing_statement = list(iocommands.watch_query('5 -c', cur=SequenceCursor([None]))) - assert usage_missing_statement[0].status and usage_missing_statement[0].status.startswith('Syntax: watch') + assert usage_missing_statement[0].status and usage_missing_statement[0].status.startswith('Syntax: /watch') secho_calls: list[str] = [] monkeypatch.setattr(iocommands, 'confirm_destructive_query', lambda keywords, statement: False) diff --git a/test/pytests/test_special_llm.py b/test/pytests/test_special_llm.py index 9ca281505..4f1fb0105 100644 --- a/test/pytests/test_special_llm.py +++ b/test/pytests/test_special_llm.py @@ -230,10 +230,10 @@ def fake_run_external_cmd_missing(*args, **kwargs): @patch("mycli.packages.special.llm.llm") def test_llm_command_without_args(mock_llm, executor): r""" - Invoking \llm without any arguments should print the usage and raise FinishIteration. + Invoking /llm without any arguments should print the usage and raise FinishIteration. """ assert mock_llm is not None - test_text = r"\llm" + test_text = "/llm" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) # Should return usage message when no args provided @@ -243,10 +243,10 @@ def test_llm_command_without_args(mock_llm, executor): @patch("mycli.packages.special.llm.llm") def test_llm_command_with_help_subcommand(mock_llm, executor): r""" - Invoking \llm with "help" should print the usage and raise FinishIteration. + Invoking /llm with "help" should print the usage and raise FinishIteration. """ assert mock_llm is not None - test_text = r"\llm help" + test_text = r"/llm help" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) # Should return usage message when "help" subcommand or variant is provided @@ -259,7 +259,7 @@ def test_llm_command_with_c_flag(mock_run_cmd, mock_llm, executor): string = "Hello, no SQL today." # Suppose the LLM returns some text without fenced SQL mock_run_cmd.return_value = (0, string) - test_text = r"\llm -c 'Something?'" + test_text = r"/llm -c 'Something?'" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) # Expect raw output when no SQL fence found @@ -273,7 +273,7 @@ def test_llm_command_with_c_flag_and_fenced_sql(mock_run_cmd, mock_llm, executor sql_text = "SELECT * FROM users;" fenced = f"Here you go:\n```sql\n{sql_text}\n```" mock_run_cmd.return_value = (0, fenced) - test_text = r"\llm -c 'Rewrite SQL'" + test_text = r"/llm -c 'Rewrite SQL'" result, sql, duration = handle_llm(test_text, executor, 'mysql', 0, 0) # Without verbosity, result is empty, sql extracted assert sql == sql_text @@ -285,7 +285,7 @@ def test_llm_command_with_c_flag_and_fenced_sql(mock_run_cmd, mock_llm, executor @patch("mycli.packages.special.llm.run_external_cmd") def test_llm_command_known_subcommand(mock_run_cmd, mock_llm, executor): # 'models' is a known subcommand - test_text = r"\llm models" + test_text = r"/llm models" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) mock_run_cmd.assert_called_once_with("llm", "models", restart_cli=False) @@ -295,7 +295,7 @@ def test_llm_command_known_subcommand(mock_run_cmd, mock_llm, executor): @patch("mycli.packages.special.llm.llm") @patch("mycli.packages.special.llm.run_external_cmd") def test_llm_command_with_help_flag(mock_run_cmd, mock_llm, executor): - test_text = r"\llm --help" + test_text = r"/llm --help" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) mock_run_cmd.assert_called_once_with("llm", "--help", restart_cli=False) @@ -305,7 +305,7 @@ def test_llm_command_with_help_flag(mock_run_cmd, mock_llm, executor): @patch("mycli.packages.special.llm.llm") @patch("mycli.packages.special.llm.run_external_cmd") def test_llm_command_with_install_flag(mock_run_cmd, mock_llm, executor): - test_text = r"\llm install openai" + test_text = r"/llm install openai" with pytest.raises(llm_module.FinishIteration) as exc_info: handle_llm(test_text, executor, 'mysql', 0, 0) mock_run_cmd.assert_called_once_with("llm", "install", "openai", restart_cli=True) @@ -317,10 +317,10 @@ def test_llm_command_with_install_flag(mock_run_cmd, mock_llm, executor): @patch("mycli.packages.special.llm.sql_using_llm") def test_llm_command_with_prompt(mock_sql_using_llm, mock_ensure_template, mock_llm, executor): r""" - \llm prompt 'question' should use template and call sql_using_llm + /llm prompt 'question' should use template and call sql_using_llm """ mock_sql_using_llm.return_value = ("CTX", "SELECT 1;") - test_text = r"\llm prompt 'Test?'" + test_text = r"/llm prompt 'Test?'" context, sql, duration = handle_llm(test_text, executor, 'mysql', 0, 0) mock_ensure_template.assert_called_once() mock_sql_using_llm.assert_called() @@ -334,10 +334,10 @@ def test_llm_command_with_prompt(mock_sql_using_llm, mock_ensure_template, mock_ @patch("mycli.packages.special.llm.sql_using_llm") def test_llm_command_question_with_context(mock_sql_using_llm, mock_ensure_template, mock_llm, executor): r""" - \llm 'question' treats as prompt and returns SQL + /llm 'question' treats as prompt and returns SQL """ mock_sql_using_llm.return_value = ("CTX2", "SELECT 2;") - test_text = r"\llm 'Top 10?'" + test_text = r"/llm 'Top 10?'" context, sql, duration = handle_llm(test_text, executor, 'mysql', 0, 0) mock_ensure_template.assert_called_once() mock_sql_using_llm.assert_called() @@ -351,10 +351,10 @@ def test_llm_command_question_with_context(mock_sql_using_llm, mock_ensure_templ @patch("mycli.packages.special.llm.sql_using_llm") def test_llm_command_question_verbose(mock_sql_using_llm, mock_ensure_template, mock_llm, executor): r""" - \llm+ returns verbose context and SQL + /llm+ returns verbose context and SQL """ mock_sql_using_llm.return_value = ("NO_CTX", "SELECT 42;") - test_text = r"\llm- 'Succinct?'" + test_text = r"/llm- 'Succinct?'" context, sql, duration = handle_llm(test_text, executor, 'mysql', 0, 0) assert context == "" assert sql == "SELECT 42;" @@ -365,7 +365,7 @@ def test_handle_llm_without_dependencies(executor, monkeypatch) -> None: monkeypatch.setattr(llm_module, "LLM_IMPORTED", False) with pytest.raises(llm_module.FinishIteration) as exc_info: - handle_llm(r"\llm anything", executor, "mysql", 0, 0) + handle_llm(r"/llm anything", executor, "mysql", 0, 0) assert exc_info.value.results == [SQLResult(preamble=NEED_DEPENDENCIES)] @@ -376,12 +376,12 @@ def test_handle_llm_wraps_context_errors(mock_llm, executor, monkeypatch) -> Non monkeypatch.setattr(llm_module, "ensure_mycli_template", lambda: (_ for _ in ()).throw(ValueError("bad template"))) with pytest.raises(RuntimeError, match="bad template"): - handle_llm(r"\llm 'Top 10?'", executor, "mysql", 0, 0) + handle_llm(r"/llm 'Top 10?'", executor, "mysql", 0, 0) def test_is_llm_command(): # Valid llm command variants - for cmd in ["\\llm", "\\ai"]: + for cmd in ["/llm", "/ai"]: assert is_llm_command(cmd + " 'x'") # Invalid commands assert not is_llm_command("select * from table;") @@ -537,10 +537,10 @@ class DummyCursor: # Test handle_llm supports registered command names without args -@pytest.mark.parametrize("prefix", [r"\llm", r"\ai"]) +@pytest.mark.parametrize("prefix", ["/llm", "/ai"]) def test_handle_llm_registered_aliases_without_args(prefix, executor, monkeypatch): assert prefix in COMMANDS - assert COMMANDS[prefix].handler is COMMANDS[r"\llm"].handler + assert COMMANDS[prefix].handler is COMMANDS["/llm"].handler assert COMMANDS[prefix].command == r"\llm" monkeypatch.setattr(llm_module, "llm", object()) with pytest.raises(llm_module.FinishIteration) as exc_info: diff --git a/test/pytests/test_special_main.py b/test/pytests/test_special_main.py index 861b0594f..42a59dca1 100644 --- a/test/pytests/test_special_main.py +++ b/test/pytests/test_special_main.py @@ -62,8 +62,8 @@ def load_isolated_special_main(module_name: str) -> ModuleType: ('sql', 'expected'), [ ('help select', ('help', special_main.CommandVerbosity.NORMAL, 'select')), - (r'\llm+ prompt', (r'\llm', special_main.CommandVerbosity.VERBOSE, 'prompt')), - (r'\llm- prompt', (r'\llm', special_main.CommandVerbosity.SUCCINCT, 'prompt')), + (r'/llm+ prompt', (r'/llm', special_main.CommandVerbosity.VERBOSE, 'prompt')), + (r'/llm- prompt', (r'/llm', special_main.CommandVerbosity.SUCCINCT, 'prompt')), ('help spaced ', ('help', special_main.CommandVerbosity.NORMAL, 'spaced')), ], ) @@ -87,7 +87,7 @@ def handler() -> None: 'Demo', 'demo', 'Description', - aliases=[special_main.SpecialCommandAlias('\\d', case_sensitive=False)], + aliases=[special_main.SpecialCommandAlias(r'\d', case_sensitive=False)], completion_snippet='Manage demos.', ) @@ -99,11 +99,11 @@ def handler() -> None: arg_type=special_main.ArgType.PARSED_QUERY, hidden=False, case_sensitive=False, - aliases=[special_main.SpecialCommandAlias('\\d', case_sensitive=False)], + aliases=[special_main.SpecialCommandAlias(r'\d', case_sensitive=False)], backslash_only=False, completion_snippet='Manage demos.', ) - assert special_main.COMMANDS['\\d'] == special_main.SpecialCommand( + assert special_main.COMMANDS['/d'] == special_main.SpecialCommand( handler, 'Demo', 'demo', @@ -129,11 +129,11 @@ def test_register_special_command_tracks_case_insensitive_commands(restore_comma 'Demo', 'demo', 'Description', - aliases=[special_main.SpecialCommandAlias('\\d', case_sensitive=False)], + aliases=[special_main.SpecialCommandAlias(r'\d', case_sensitive=False)], ) assert special_main.CASE_SENSITIVE_COMMANDS == set() - assert special_main.CASE_INSENSITIVE_COMMANDS == {'demo', '/demo', '\\d', '/d'} + assert special_main.CASE_INSENSITIVE_COMMANDS == {'demo', '/demo', r'\d', '/d'} def test_special_command_decorator_registers_case_sensitive_command(restore_commands: None) -> None: @@ -348,7 +348,7 @@ def test_show_help_lists_only_visible_commands(restore_commands: None) -> None: 'visible', '/visible', 'Visible command', - aliases=[special_main.SpecialCommandAlias('\\v', case_sensitive=False)], + aliases=[special_main.SpecialCommandAlias(r'\v', case_sensitive=False)], completion_snippet='Complete visible.', ) special_main.register_special_command(lambda: None, 'hidden', 'hidden', 'Hidden command', hidden=True) @@ -454,8 +454,8 @@ def test_reload_special_main_without_llm_support(monkeypatch) -> None: isolated_main = load_isolated_special_main('test_special_main_without_llm') try: assert isolated_main.LLM_IMPORTED is False - assert r'\llm' not in isolated_main.COMMANDS - assert r'\ai' not in isolated_main.COMMANDS + assert r'/llm' not in isolated_main.COMMANDS + assert r'/ai' not in isolated_main.COMMANDS finally: sys.modules.pop('test_special_main_without_llm', None) @@ -474,7 +474,7 @@ def fake_import(name, globals=None, locals=None, fromlist=(), level=0): # noqa: isolated_main = load_isolated_special_main('test_special_main_import_error') try: assert isolated_main.LLM_IMPORTED is False - assert r'\llm' not in isolated_main.COMMANDS - assert r'\ai' not in isolated_main.COMMANDS + assert r'/llm' not in isolated_main.COMMANDS + assert r'/ai' not in isolated_main.COMMANDS finally: sys.modules.pop('test_special_main_import_error', None) diff --git a/test/pytests/test_sql_utils.py b/test/pytests/test_sql_utils.py index 1be26ef10..41c7e39e8 100644 --- a/test/pytests/test_sql_utils.py +++ b/test/pytests/test_sql_utils.py @@ -156,7 +156,7 @@ def test_extract_tables_from_complete_statements_cte(): # this would confuse plain extract_tables() per #1122 def test_extract_tables_from_multiple_complete_statements(): - tables = extract_tables_from_complete_statements(r'\T sql-insert; SELECT * FROM my_table AS m WHERE m.a > 5') + tables = extract_tables_from_complete_statements(r'/tableformat sql-insert; SELECT * FROM my_table AS m WHERE m.a > 5') assert tables == [(None, 'my_table', 'm')] @@ -518,8 +518,8 @@ def test_is_dropping_database_skips_statements_without_enough_keywords(): ('alter table foo add column bar int;', True), ('create table foo (id int);', True), ('use foo;', True), - ('\\r foo localhost root', True), - ('\\u foo', True), + ('/connect foo localhost root', True), + ('/use foo', True), ('connect foo localhost root', True), ('drop table foo;', True), ('rename table foo to bar;', True), @@ -544,9 +544,9 @@ def split(self): [ ('select 1;', False), ('use foo;', True), - ('\\u foo', True), - ('\\r', False), - ('\\r foo localhost root', True), + ('/use foo', True), + ('/connect', False), + ('/connect foo localhost root', True), ('connect', False), ('connect foo localhost root', True), ], @@ -597,7 +597,7 @@ def test_find_password_after_eq_returns_none_for_non_string_token() -> None: (' ', ('quit', None)), ('quit', ('quit', None)), ('exit', ('quit', None)), - ('\\q', ('quit', None)), + ('/quit', ('quit', None)), ("ALTER USER 'root'@'localhost' IDENTIFIED BY 'new'", ('alter_user', 'new')), ('ALTER USER root IDENTIFIED WITH mysql_native_password', ('alter_user', None)), ("SET PASSWORD = 'newpass'", ('set_password', 'newpass')), @@ -619,7 +619,7 @@ def test_classify_sandbox_statement(text: str, expected: tuple[str | None, str | ("set password = 'newpass'", True), ('quit', True), ('exit', True), - ('\\q', True), + ('/quit', True), ('SELECT 1', False), ('DROP TABLE t', False), ('USE mydb', False),