Skip to content

Commit 8906f57

Browse files
committed
Hack to support reuse of memory command, closes #643
1 parent 4c26288 commit 8906f57

File tree

4 files changed

+65
-2
lines changed

4 files changed

+65
-2
lines changed

docs/plugins.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,31 @@ Example implementation:
115115
"Say hello world"
116116
click.echo("Hello world!")
117117
118+
New commands implemented by plugins can invoke existing commands using the `context.invoke <https://click.palletsprojects.com/en/stable/api/#click.Context.invoke>`__ mechanism.
119+
120+
As a special niche feature, if your plugin needs to import some files and then act against an in-memory database containing those files you can forward to the :ref:`sqlite-utils memory command <cli_memory>` and then access a named in-memory database called ``sqlite_utils_memory`` like this:
121+
122+
.. code-block:: python
123+
124+
from contextlib import redirect_stdout
125+
import io
126+
127+
@cli.command()
128+
@click.pass_context
129+
@click.argument(
130+
"paths",
131+
type=click.Path(file_okay=True, dir_okay=False, allow_dash=True),
132+
required=False,
133+
nargs=-1,
134+
)
135+
def show_schema_for_files(ctx, paths):
136+
from sqlite_utils.cli import memory
137+
with redirect_stdout(io.StringIO()):
138+
ctx.invoke(memory, paths=paths, sql="select 1")
139+
db = sqlite_utils.Database(memory_name="sqlite_utils_memory")
140+
# Now do something with that database
141+
click.echo(db.schema)
142+
118143
.. _plugins_hooks_prepare_connection:
119144

120145
prepare_connection(conn)

sqlite_utils/cli.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1815,6 +1815,10 @@ def query(
18151815
)
18161816

18171817

1818+
# So named memory db "sqlite_utils_memory" isn't dropped when it goes out of scope
1819+
_sqlite_utils_memory_db = []
1820+
1821+
18181822
@cli.command()
18191823
@click.argument(
18201824
"paths",
@@ -1921,7 +1925,14 @@ def memory(
19211925
\b
19221926
sqlite-utils memory animals.csv --schema
19231927
"""
1924-
db = sqlite_utils.Database(memory=True)
1928+
if getattr(sys, "_sqlite_utils_memory_test", False) or not getattr(
1929+
sys, "_called_from_test", False
1930+
):
1931+
db = sqlite_utils.Database(memory_name="sqlite_utils_memory")
1932+
_sqlite_utils_memory_db.append(db)
1933+
else:
1934+
db = sqlite_utils.Database(memory=True)
1935+
19251936
# If --dump or --save or --analyze used but no paths detected, assume SQL query is a path:
19261937
if (dump or save or schema or analyze) and not paths:
19271938
paths = [sql]
@@ -1954,6 +1965,7 @@ def memory(
19541965
rows = tracker.wrap(rows)
19551966
if flatten:
19561967
rows = (_flatten(row) for row in rows)
1968+
19571969
db[file_table].insert_all(rows, alter=True)
19581970
if tracker is not None:
19591971
db[file_table].transform(types=tracker.types)
@@ -1964,6 +1976,7 @@ def memory(
19641976
for view_name in view_names:
19651977
if not db[view_name].exists():
19661978
db.create_view(view_name, "select * from [{}]".format(file_table))
1979+
19671980
if fp:
19681981
fp.close()
19691982

sqlite_utils/db.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ def __init__(
325325
execute_plugins: bool = True,
326326
strict: bool = False,
327327
):
328+
self.memory_name = None
329+
self.memory = False
328330
assert (filename_or_conn is not None and (not memory and not memory_name)) or (
329331
filename_or_conn is None and (memory or memory_name)
330332
), "Either specify a filename_or_conn or pass memory=True"
@@ -335,8 +337,11 @@ def __init__(
335337
uri=True,
336338
check_same_thread=False,
337339
)
340+
self.memory = True
341+
self.memory_name = memory_name
338342
elif memory or filename_or_conn == ":memory:":
339343
self.conn = sqlite3.connect(":memory:")
344+
self.memory = True
340345
elif isinstance(filename_or_conn, (str, pathlib.Path)):
341346
if recreate and os.path.exists(filename_or_conn):
342347
try:

tests/test_cli_memory.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
2-
32
import pytest
3+
import sys
44
from click.testing import CliRunner
55

66
from sqlite_utils import Database, cli
@@ -305,3 +305,23 @@ def test_memory_functions():
305305
)
306306
assert result.exit_code == 0
307307
assert result.output.strip() == '[{"hello()": "Hello"}]'
308+
309+
310+
@pytest.mark.parametrize("enabled", (False, True))
311+
def test_memory_named_database_hack(enabled):
312+
# https://github.com/simonw/sqlite-utils/issues/643
313+
sys._sqlite_utils_memory_test = enabled
314+
try:
315+
result = CliRunner().invoke(
316+
cli.cli,
317+
["memory", "-", "--analyze"],
318+
input="id,name\n1,Cleo\n2,Bants",
319+
)
320+
assert result.exit_code == 0
321+
db = Database(memory_name="sqlite_utils_memory")
322+
if enabled:
323+
assert db.table_names() == ["stdin"]
324+
else:
325+
assert db.table_names() == []
326+
finally:
327+
sys._sqlite_utils_memory_test = False

0 commit comments

Comments
 (0)