Skip to content

Commit 2ceffe6

Browse files
committed
Add support for URI style database names
SQLite accepts URI style db names: * https://docs.python.org/3/library/sqlite3.html#sqlite3-uri-tricks * https://www.sqlite.org/c3ref/open.html#urifilenameexamples This is particularly useful for opening databases in read-only mode (also with multiple connections, when using `cache=shared`). Although, this might be a corner case for `litecli` it'll help my use-case of embedding litecli in a personal app.
1 parent f3d11dc commit 2ceffe6

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

litecli/sqlexecute.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,26 @@ def connect(self, database=None):
6868
db = database or self.dbname
6969
_logger.debug("Connection DB Params: \n\tdatabase: %r", db)
7070

71-
db_name = os.path.expanduser(db)
72-
db_dir_name = os.path.dirname(os.path.abspath(db_name))
73-
if not os.path.exists(db_dir_name):
74-
raise Exception("Path does not exist: {}".format(db_dir_name))
71+
if db.startswith("file:"):
72+
uri = True
73+
db_name = db
74+
db_filename, *_ = db_name[5:].split("?", 1)
75+
else:
76+
uri = False
77+
db_filename = db_name = os.path.expanduser(db)
78+
db_dir_name = os.path.dirname(os.path.abspath(db_filename))
79+
if not os.path.exists(db_dir_name):
80+
raise Exception("Path does not exist: {}".format(db_dir_name))
7581

76-
conn = sqlite3.connect(database=db_name, isolation_level=None)
82+
conn = sqlite3.connect(database=db_name, isolation_level=None, uri=uri)
7783
conn.text_factory = lambda x: x.decode("utf-8", "backslashreplace")
7884
if self.conn:
7985
self.conn.close()
8086

8187
self.conn = conn
8288
# Update them after the connection is made to ensure that it was a
8389
# successful connection.
84-
self.dbname = db
90+
self.dbname = db_filename
8591

8692
def run(self, statement):
8793
"""Execute the sql in the database and return the results. The results

tests/test_main.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
from unittest.mock import patch
77

88
import click
9+
import pytest
910
from click.testing import CliRunner
1011

1112
from litecli.main import cli, LiteCli
1213
from litecli.packages.special.main import COMMANDS as SPECIAL_COMMANDS
13-
from utils import dbtest, run
14+
from utils import dbtest, run, create_db, db_connection
1415

1516
test_dir = os.path.abspath(os.path.dirname(__file__))
1617
project_dir = os.path.dirname(test_dir)
@@ -330,3 +331,30 @@ def test_get_prompt(mock_datetime):
330331
# 12. Windows path
331332
lc.connect("C:\\Users\\litecli\\litecli_test.db")
332333
assert lc.get_prompt(r"\d") == "C:\\Users\\litecli\\litecli_test.db"
334+
335+
336+
@pytest.mark.parametrize(
337+
"uri, expected_dbname",
338+
[
339+
("file:{tmp_path}/test.db", "{tmp_path}/test.db"),
340+
("file:{tmp_path}/test.db?mode=ro", "{tmp_path}/test.db"),
341+
("file:{tmp_path}/test.db?mode=ro&cache=shared", "{tmp_path}/test.db"),
342+
],
343+
)
344+
def test_file_uri(tmp_path, uri, expected_dbname):
345+
"""
346+
Test that `file:` URIs are correctly handled
347+
ref:
348+
https://docs.python.org/3/library/sqlite3.html#sqlite3-uri-tricks
349+
https://www.sqlite.org/c3ref/open.html#urifilenameexamples
350+
"""
351+
# - ensure db exists
352+
db_path = tmp_path / "test.db"
353+
create_db(db_path)
354+
db_connection(db_path)
355+
uri = uri.format(tmp_path=tmp_path)
356+
357+
lc = LiteCli()
358+
lc.connect(uri)
359+
360+
assert lc.get_prompt(r"\d") == expected_dbname.format(tmp_path=tmp_path)

0 commit comments

Comments
 (0)