From 862944bc38381ea4cb23fe050e0481c4a7495447 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 4 Jul 2026 18:13:50 +0000 Subject: [PATCH] drop-table and drop-view now refuse to drop the wrong object type drop-table on a view name silently dropped the view, and drop-view on a table name silently dropped the table, because both used db[name].drop() which dispatches on the actual object type. They now use db.table() / db.view() and exit with an explanatory error pointing at the correct command. --ignore still exits cleanly but no longer drops anything. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01UnLnhsH25Nnv7LHhekUfPd --- sqlite_utils/cli.py | 19 ++++++++++++++++--- tests/test_cli.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index f15850d..d51ba7b 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -14,6 +14,7 @@ from sqlite_utils.db import ( DEFAULT, DescIndex, NoTable, + NoView, quote_identifier, ) from sqlite_utils.plugins import ensure_plugins_loaded, pm, get_plugins @@ -1725,7 +1726,13 @@ def drop_table(path, table, ignore, load_extension): _register_db_for_cleanup(db) _load_extensions(db, load_extension) try: - db[table].drop(ignore=ignore) + db.table(table).drop(ignore=ignore) + except NoTable: + # A view exists with this name + if not ignore: + raise click.ClickException( + '"{}" is a view, not a table - use drop-view to drop it'.format(table) + ) except OperationalError: raise click.ClickException('Table "{}" does not exist'.format(table)) @@ -1797,8 +1804,14 @@ def drop_view(path, view, ignore, load_extension): _register_db_for_cleanup(db) _load_extensions(db, load_extension) try: - db[view].drop(ignore=ignore) - except OperationalError: + db.view(view).drop(ignore=ignore) + except NoView: + if ignore: + return + if view in db.table_names(): + raise click.ClickException( + '"{}" is a table, not a view - use drop-table to drop it'.format(view) + ) raise click.ClickException('View "{}" does not exist'.format(view)) diff --git a/tests/test_cli.py b/tests/test_cli.py index 565fbc2..02c00ab 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1467,6 +1467,24 @@ def test_drop_table_error(): assert result.exit_code == 0 +def test_drop_table_on_view_errors(): + runner = CliRunner() + with runner.isolated_filesystem(): + db = Database("test.db") + db["t"].insert({"id": 1}) + db.create_view("v", "select * from t") + result = runner.invoke(cli.cli, ["drop-table", "test.db", "v"]) + assert result.exit_code == 1 + assert 'Error: "v" is a view, not a table - use drop-view to drop it' == ( + result.output.strip() + ) + assert "v" in db.view_names() + # --ignore exits cleanly but must still not drop the view + result = runner.invoke(cli.cli, ["drop-table", "test.db", "v", "--ignore"]) + assert result.exit_code == 0 + assert "v" in db.view_names() + + def test_drop_view(): runner = CliRunner() with runner.isolated_filesystem(): @@ -1485,6 +1503,23 @@ def test_drop_view(): assert "hello" not in db.view_names() +def test_drop_view_on_table_errors(): + runner = CliRunner() + with runner.isolated_filesystem(): + db = Database("test.db") + db["t"].insert({"id": 1}) + result = runner.invoke(cli.cli, ["drop-view", "test.db", "t"]) + assert result.exit_code == 1 + assert 'Error: "t" is a table, not a view - use drop-table to drop it' == ( + result.output.strip() + ) + assert "t" in db.table_names() + # --ignore exits cleanly but must still not drop the table + result = runner.invoke(cli.cli, ["drop-view", "test.db", "t", "--ignore"]) + assert result.exit_code == 0 + assert "t" in db.table_names() + + def test_drop_view_error(): runner = CliRunner() with runner.isolated_filesystem():