From 6c439483256ea534be6863b280f1331258a20494 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Wed, 13 Sep 2023 15:58:09 -0700 Subject: [PATCH] llm.user_dir() creates directory if needed, closes #275 Would have fixed this bug too: - https://github.com/simonw/llm-sentence-transformers/issues/9 --- docs/plugins/plugin-utilities.md | 2 +- llm/__init__.py | 7 +++++-- tests/test_llm.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/plugins/plugin-utilities.md b/docs/plugins/plugin-utilities.md index 44b5e13..347b2c7 100644 --- a/docs/plugins/plugin-utilities.md +++ b/docs/plugins/plugin-utilities.md @@ -9,7 +9,7 @@ LLM stores various pieces of logging and configuration data in a directory on th On macOS this directory is `~/Library/Application Support/io.datasette.llm`, but this will differ on other operating systems. -The `llm.user_dir()` function returns the path to this directory as a `pathlib.Path` object. +The `llm.user_dir()` function returns the path to this directory as a `pathlib.Path` object, after creating that directory if it does not yet exist. Plugins can use this to store their own data in a subdirectory of this directory. diff --git a/llm/__init__.py b/llm/__init__.py index 6c21bbb..4993983 100644 --- a/llm/__init__.py +++ b/llm/__init__.py @@ -188,8 +188,11 @@ def load_keys(): def user_dir(): llm_user_path = os.environ.get("LLM_USER_PATH") if llm_user_path: - return pathlib.Path(llm_user_path) - return pathlib.Path(click.get_app_dir("io.datasette.llm")) + path = pathlib.Path(llm_user_path) + else: + path = pathlib.Path(click.get_app_dir("io.datasette.llm")) + path.mkdir(exist_ok=True, parents=True) + return path def set_alias(alias, model_id_or_alias): diff --git a/tests/test_llm.py b/tests/test_llm.py index 969a713..6a9dd49 100644 --- a/tests/test_llm.py +++ b/tests/test_llm.py @@ -1,5 +1,6 @@ from click.testing import CliRunner import datetime +import llm from llm.cli import cli from llm.migrations import migrate import json @@ -354,3 +355,12 @@ def test_llm_models_options(user_path): result = runner.invoke(cli, ["models", "--options"], catch_exceptions=False) assert result.exit_code == 0 assert EXPECTED_OPTIONS.strip() in result.output + + +def test_llm_user_dir(tmpdir, monkeypatch): + user_dir = str(tmpdir / "u") + monkeypatch.setenv("LLM_USER_PATH", user_dir) + assert not os.path.exists(user_dir) + user_dir2 = llm.user_dir() + assert user_dir == str(user_dir2) + assert os.path.exists(user_dir)