Skip to content

Commit c791a31

Browse files
committed
Make square braces only return tables, not views
Breaking change for 4.0: db["name"] now only returns Table objects, never View objects. This improves type safety since views lack methods like .insert(). Use db.view("view_name") to access views explicitly. Closes #699
1 parent 8d74ffc commit c791a31

File tree

6 files changed

+18
-15
lines changed

6 files changed

+18
-15
lines changed

sqlite_utils/cli.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
BadMultiValues,
1313
DescIndex,
1414
NoTable,
15+
NoView,
1516
quote_identifier,
1617
)
1718
from sqlite_utils.plugins import pm, get_plugins
@@ -1796,9 +1797,10 @@ def drop_view(path, view, ignore, load_extension):
17961797
_register_db_for_cleanup(db)
17971798
_load_extensions(db, load_extension)
17981799
try:
1799-
db[view].drop(ignore=ignore)
1800-
except OperationalError:
1801-
raise click.ClickException('View "{}" does not exist'.format(view))
1800+
db.view(view).drop(ignore=ignore)
1801+
except NoView:
1802+
if not ignore:
1803+
raise click.ClickException('View "{}" does not exist'.format(view))
18021804

18031805

18041806
@cli.command()

sqlite_utils/db.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -445,15 +445,15 @@ def tracer(
445445
finally:
446446
self._tracer = prev_tracer
447447

448-
def __getitem__(self, table_name: str) -> Union["Table", "View"]:
448+
def __getitem__(self, table_name: str) -> "Table":
449449
"""
450450
``db[table_name]`` returns a :class:`.Table` object for the table with the specified name.
451451
If the table does not exist yet it will be created the first time data is inserted into it.
452452
453+
Use ``db.view(view_name)`` to access views.
454+
453455
:param table_name: The name of the table
454456
"""
455-
if table_name in self.view_names():
456-
return self.view(table_name)
457457
return self.table(table_name)
458458

459459
def __repr__(self) -> str:
@@ -1206,9 +1206,9 @@ def create_view(
12061206
return self
12071207
elif replace:
12081208
# If SQL is the same, do nothing
1209-
if create_sql == self[name].schema:
1209+
if create_sql == self.view(name).schema:
12101210
return self
1211-
self[name].drop()
1211+
self.view(name).drop()
12121212
self.execute(create_sql)
12131213
return self
12141214

tests/test_cli.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,8 @@ def test_create_view():
13671367
)
13681368
assert result.exit_code == 0
13691369
assert (
1370-
'CREATE VIEW "version" AS select sqlite_version()' == db["version"].schema
1370+
'CREATE VIEW "version" AS select sqlite_version()'
1371+
== db.view("version").schema
13711372
)
13721373

13731374

@@ -1404,7 +1405,7 @@ def test_create_view_ignore():
14041405
assert result.exit_code == 0
14051406
assert (
14061407
'CREATE VIEW "version" AS select sqlite_version() + 1'
1407-
== db["version"].schema
1408+
== db.view("version").schema
14081409
)
14091410

14101411

@@ -1425,7 +1426,8 @@ def test_create_view_replace():
14251426
)
14261427
assert result.exit_code == 0
14271428
assert (
1428-
'CREATE VIEW "version" AS select sqlite_version()' == db["version"].schema
1429+
'CREATE VIEW "version" AS select sqlite_version()'
1430+
== db.view("version").schema
14291431
)
14301432

14311433

tests/test_create.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ def test_drop(fresh_db):
10821082
def test_drop_view(fresh_db):
10831083
fresh_db.create_view("foo_view", "select 1")
10841084
assert ["foo_view"] == fresh_db.view_names()
1085-
assert None is fresh_db["foo_view"].drop()
1085+
assert None is fresh_db.view("foo_view").drop()
10861086
assert [] == fresh_db.view_names()
10871087

10881088

@@ -1093,7 +1093,7 @@ def test_drop_ignore(fresh_db):
10931093
# Testing view is harder, we need to create it in order
10941094
# to get a View object, then drop it twice
10951095
fresh_db.create_view("foo_view", "select 1")
1096-
view = fresh_db["foo_view"]
1096+
view = fresh_db.view("foo_view")
10971097
assert isinstance(view, View)
10981098
view.drop()
10991099
with pytest.raises(sqlite3.OperationalError):

tests/test_fts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ def test_enable_fts_error_message_on_views():
424424
db = Database(memory=True)
425425
db.create_view("hello", "select 1 + 1")
426426
with pytest.raises(NotImplementedError) as e:
427-
db["hello"].enable_fts() # type: ignore[call-arg]
427+
db.view("hello").enable_fts() # type: ignore[call-arg]
428428
assert e.value.args[0] == "enable_fts() is supported on tables but not on views"
429429

430430

tests/test_tracer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def test_tracer():
1515
("select name from sqlite_master where type = 'view'", None),
1616
("select name from sqlite_master where type = 'table'", None),
1717
("select name from sqlite_master where type = 'view'", None),
18-
("select name from sqlite_master where type = 'view'", None),
1918
("select name from sqlite_master where type = 'table'", None),
2019
("select name from sqlite_master where type = 'view'", None),
2120
('CREATE TABLE "dogs" (\n "name" TEXT\n);\n ', None),

0 commit comments

Comments
 (0)