Skip to content

Commit 76fb4c5

Browse files
authored
Merge pull request #221 from dbcli/amjith/sqlean-optional
Amjith/sqlean optional
2 parents 4d0db17 + 9350ff9 commit 76fb4c5

17 files changed

Lines changed: 69 additions & 50 deletions

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
### Features
44

5-
*
5+
* Replace sqlite3 library with [sqlean](https://antonz.org/sqlean/). It's a drop-in replacement for sqlite3.
66

77
### Bug Fixes
88

9-
*
9+
* Fix missing sqlite extensions using sqlean. Note. support only limited set of extensions. [(#119)](https://github.com/dbcli/litecli/issues/119)
1010

1111

1212
## 1.15.0 - 2025-03-15

README.md

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,7 @@ If you already know how to install python packages, then you can install it via
1616
You might need sudo on linux.
1717

1818
```
19-
$ pip install -U litecli
20-
```
21-
22-
The package is also available on Arch Linux through AUR in two versions: [litecli](https://aur.archlinux.org/packages/litecli/) is based the latest release (git tag) and [litecli-git](https://aur.archlinux.org/packages/litecli-git/) is based on the master branch of the git repo. You can install them manually or with an AUR helper such as `yay`:
23-
24-
```
25-
$ yay -S litecli
26-
```
27-
28-
or
29-
30-
```
31-
$ yay -S litecli-git
19+
$ pip install -U litecli[sqlean]
3220
```
3321

3422
For MacOS users, you can also use Homebrew to install it:

litecli/main.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
from collections import namedtuple
1212
from datetime import datetime
1313
from io import open
14-
from sqlite3 import OperationalError, sqlite_version
14+
15+
try:
16+
from sqlean import OperationalError, sqlite_version
17+
except ImportError:
18+
from sqlite3 import OperationalError, sqlite_version
1519
from time import time
1620

1721
import click
@@ -260,7 +264,7 @@ def initialize_logging(self):
260264
)
261265
return
262266

263-
formatter = logging.Formatter("%(asctime)s (%(process)d/%(threadName)s) " "%(name)s %(levelname)s - %(message)s")
267+
formatter = logging.Formatter("%(asctime)s (%(process)d/%(threadName)s) %(name)s %(levelname)s - %(message)s")
264268

265269
handler.setFormatter(formatter)
266270

@@ -361,7 +365,7 @@ def run_cli(self):
361365
else:
362366
history = None
363367
self.echo(
364-
'Error: Unable to open the history file "{}". ' "Your query history will not be saved.".format(history_file),
368+
'Error: Unable to open the history file "{}". Your query history will not be saved.'.format(history_file),
365369
err=True,
366370
fg="red",
367371
)
@@ -452,7 +456,7 @@ def one_iteration(text=None):
452456
if context:
453457
click.echo("LLM Reponse:")
454458
click.echo(context)
455-
click.echo('---')
459+
click.echo("---")
456460
click.echo(f"Time: {duration:.2f} seconds")
457461
text = self.prompt_app.prompt(default=sql)
458462
except KeyboardInterrupt:
@@ -927,7 +931,7 @@ def cli(
927931

928932
litecli.connect(database)
929933

930-
litecli.logger.debug("Launch Params: \n" "\tdatabase: %r", database)
934+
litecli.logger.debug("Launch Params: \n\tdatabase: %r", database)
931935

932936
# --execute argument
933937
if execute:

litecli/packages/prompt_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def confirm_destructive_query(queries):
1616
* False if the query is destructive and the user doesn't want to proceed.
1717
1818
"""
19-
prompt_text = "You're about to run a destructive command.\n" "Do you want to proceed? (y/n)"
19+
prompt_text = "You're about to run a destructive command.\nDo you want to proceed? (y/n)"
2020
if is_destructive(queries) and sys.stdin.isatty():
2121
return prompt(prompt_text, type=bool)
2222

litecli/packages/special/dbcommands.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ def list_tables(cur, arg=None, arg_type=PARSED_QUERY, verbose=False):
2727
args = ("{0}%".format(arg),)
2828
query = """
2929
SELECT name FROM sqlite_master
30-
WHERE type IN ('table','view') AND name LIKE ? AND name NOT LIKE 'sqlite_%'
30+
WHERE type IN ('table','view') AND name LIKE ? AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
3131
ORDER BY 1
3232
"""
3333
else:
3434
args = tuple()
3535
query = """
3636
SELECT name FROM sqlite_master
37-
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'
37+
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
3838
ORDER BY 1
3939
"""
4040

@@ -69,14 +69,14 @@ def list_views(cur, arg=None, arg_type=PARSED_QUERY, verbose=False):
6969
args = ("{0}%".format(arg),)
7070
query = """
7171
SELECT name FROM sqlite_master
72-
WHERE type = 'view' AND name LIKE ? AND name NOT LIKE 'sqlite_%'
72+
WHERE type = 'view' AND name LIKE ? AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
7373
ORDER BY 1
7474
"""
7575
else:
7676
args = tuple()
7777
query = """
7878
SELECT name FROM sqlite_master
79-
WHERE type = 'view' AND name NOT LIKE 'sqlite_%'
79+
WHERE type = 'view' AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
8080
ORDER BY 1
8181
"""
8282
log.debug(query)
@@ -124,6 +124,7 @@ def show_schema(cur, arg=None, **_):
124124

125125
return [(None, tables, headers, status)]
126126

127+
127128
@special_command(
128129
".databases",
129130
".databases",
@@ -142,6 +143,7 @@ def list_databases(cur, **_):
142143
else:
143144
return [(None, None, None, "")]
144145

146+
145147
@special_command(
146148
".indexes",
147149
".indexes [tablename]",

litecli/packages/special/llm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def ensure_litecli_template(replace=False):
194194
run_external_cmd("llm", PROMPT, "--save", "litecli")
195195
return
196196

197+
197198
@export
198199
def handle_llm(text, cur) -> Tuple[str, Optional[str], float]:
199200
"""This function handles the special command `\\llm`.
@@ -307,7 +308,7 @@ def sql_using_llm(cur, question=None, verbose=False) -> Tuple[str, Optional[str]
307308
"""
308309
tables_query = """
309310
SELECT name FROM sqlite_master
310-
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'
311+
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
311312
ORDER BY 1
312313
"""
313314
click.echo("Preparing schema information to feed the llm")

litecli/sqlexecute.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import logging
2-
import sqlite3
2+
33
from contextlib import closing
4-
from sqlite3 import OperationalError
4+
5+
try:
6+
import sqlean as sqlite3
7+
from sqlean import OperationalError
8+
9+
sqlite3.extensions.enable_all()
10+
except ImportError:
11+
import sqlite3
12+
from sqlite3 import OperationalError
513
from litecli.packages.special.utils import check_if_sqlitedotcommand
614

715
import sqlparse
@@ -25,15 +33,15 @@ class SQLExecute(object):
2533
tables_query = """
2634
SELECT name
2735
FROM sqlite_master
28-
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'
36+
WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' AND name NOT LIKE 'sqlean_%'
2937
ORDER BY 1
3038
"""
3139

3240
table_columns_query = """
3341
SELECT m.name as tableName, p.name as columnName
3442
FROM sqlite_master m
3543
JOIN pragma_table_info((m.name)) p
36-
WHERE m.type IN ('table','view') AND m.name NOT LIKE 'sqlite_%'
44+
WHERE m.type IN ('table','view') AND m.name NOT LIKE 'sqlite_%' AND m.name NOT LIKE 'sqlean_%'
3745
ORDER BY tableName, columnName
3846
"""
3947

@@ -58,7 +66,7 @@ def __init__(self, database):
5866

5967
def connect(self, database=None):
6068
db = database or self.dbname
61-
_logger.debug("Connection DB Params: \n" "\tdatabase: %r", db)
69+
_logger.debug("Connection DB Params: \n\tdatabase: %r", db)
6270

6371
db_name = os.path.expanduser(db)
6472
db_dir_name = os.path.dirname(os.path.abspath(db_name))

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ litecli = "litecli.main:cli"
3333

3434
[project.optional-dependencies]
3535
ai = ["llm"]
36+
sqlean = ["sqlean-py>=3.47.0"]
3637

3738
dev = [
3839
"behave>=1.2.6",

release.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def checklist(questions):
100100
action="store_true",
101101
dest="confirm_steps",
102102
default=False,
103-
help=("Confirm every step. If the step is not " "confirmed, it will be skipped."),
103+
help=("Confirm every step. If the step is not confirmed, it will be skipped."),
104104
)
105105
parser.add_option(
106106
"-d",

tests/test_dbspecial.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from litecli.packages.completion_engine import suggest_type
21
from test_completion_engine import sorted_dicts
3-
from litecli.packages.special.utils import format_uptime
4-
from litecli.packages.special.utils import check_if_sqlitedotcommand
5-
from utils import run, dbtest, assert_result_equal
2+
from utils import assert_result_equal, dbtest, run
3+
4+
from litecli.packages.completion_engine import suggest_type
5+
from litecli.packages.special.utils import check_if_sqlitedotcommand, format_uptime
66

77

88
def test_import_first_argument():

0 commit comments

Comments
 (0)