From 83f8bc2eaa102189d0a21aa4d68542d9957ed948 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Mon, 24 Nov 2025 09:44:34 -0800 Subject: [PATCH] A bunch of minor fixes --- docs/changelog.rst | 2 +- docs/cli-reference.rst | 1 + docs/cli.rst | 2 +- sqlite_utils/cli.py | 16 +++++----------- sqlite_utils/db.py | 11 +++++++++-- tests/test_cli.py | 4 ++-- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index abe2cc5..b4af0f9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -111,7 +111,7 @@ This release introduces a new :ref:`plugin system `. Read more about th 3.32 (2023-05-21) ----------------- -- New experimental ``sqlite-utils tui`` interface for interactively building command-line invocations, powered by `Trogon `__. This requires an optional dependency, installed using ``sqlite-utils install trogon``. (:issue:`545`) +- New experimental ``sqlite-utils tui`` interface for interactively building command-line invocations, powered by `Trogon `__. This requires an optional dependency, installed using ``sqlite-utils install trogon``. There is a screenshot :ref:`in the documentation `. (:issue:`545`) - ``sqlite-utils analyze-tables`` command (:ref:`documentation `) now has a ``--common-limit 20`` option for changing the number of common/least-common values shown for each column. (:issue:`544`) - ``sqlite-utils analyze-tables --no-most`` and ``--no-least`` options for disabling calculation of most-common and least-common values. - If a column contains only ``null`` values, ``analyze-tables`` will no longer attempt to calculate the most common and least common values for that column. (:issue:`547`) diff --git a/docs/cli-reference.rst b/docs/cli-reference.rst index df1fc3d..2c52c0a 100644 --- a/docs/cli-reference.rst +++ b/docs/cli-reference.rst @@ -65,6 +65,7 @@ This page lists the ``--help`` for every ``sqlite-utils`` CLI sub-command. "create-spatial-index": "cli_spatialite_indexes", "install": "cli_install", "uninstall": "cli_uninstall", + "tui": "cli_tui", } commands.sort(key = lambda command: go_first.index(command) if command in go_first else 999) cog.out("\n") diff --git a/docs/cli.rst b/docs/cli.rst index 8cf8df3..f6a11ef 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -1301,7 +1301,7 @@ You can set the ``SQLITE_UTILS_DETECT_TYPES`` environment variable if you want ` If a CSV or TSV file includes empty cells, like this one: -:: +.. code-block:: csv name,age,weight Cleo,6, diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index d2eedbb..9c7128e 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -962,7 +962,7 @@ def insert_upsert_implementation( db = sqlite_utils.Database(path) _load_extensions(db, load_extension) if functions: - _maybe_register_functions(db, functions) + _register_functions_from_multiple(db, functions) if (delimiter or quotechar or sniff or no_headers) and not tsv: csv = True if (nl + csv + tsv) >= 2: @@ -1800,7 +1800,7 @@ def query( db.register_fts4_bm25() if functions: - _maybe_register_functions(db, functions) + _register_functions_from_multiple(db, functions) _execute_query( db, @@ -2002,7 +2002,7 @@ def memory( db.register_fts4_bm25() if functions: - _maybe_register_functions(db, functions) + _register_functions_from_multiple(db, functions) if return_db: return db @@ -3306,16 +3306,10 @@ def _register_functions(db, functions): db.register_function(value, name=name) -def _value_or_none(value): - if getattr(value, "__class__", None).__name__ == "Sentinel": - return None - return value - - -def _maybe_register_functions(db, functions_list): +def _register_functions_from_multiple(db, functions_list): + """Register functions from multiple --functions arguments.""" if not functions_list: return for functions in functions_list: - functions = _value_or_none(functions) if isinstance(functions, str) and functions.strip(): _register_functions(db, functions) diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index f524e13..8939a68 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -237,36 +237,43 @@ if pd: class AlterError(Exception): "Error altering table" + pass class NoObviousTable(Exception): "Could not tell which table this operation refers to" + pass class NoTable(Exception): "Specified table does not exist" + pass class BadPrimaryKey(Exception): "Table does not have a single obvious primary key" + pass class NotFoundError(Exception): "Record not found" + pass class PrimaryKeyRequired(Exception): "Primary key needs to be specified" + pass class InvalidColumns(Exception): "Specified columns do not exist" + pass @@ -3203,7 +3210,7 @@ class Table(Queryable): :param not_null: Set of strings specifying columns that should be ``NOT NULL``. :param defaults: Dictionary specifying default values for specific columns. :param hash_id: Name of a column to create and use as a primary key, where the - value of thet primary key will be derived as a SHA1 hash of the other column values + value of that primary key will be derived as a SHA1 hash of the other column values in the record. ``hash_id="id"`` is a common column name used for this. :param alter: Boolean, should any missing columns be added automatically? :param ignore: Boolean, if a record already exists with this primary key, ignore this insert. @@ -3852,7 +3859,7 @@ def jsonify_if_needed(value): def resolve_extracts( - extracts: Optional[Union[Dict[str, str], List[str], Tuple[str]]] + extracts: Optional[Union[Dict[str, str], List[str], Tuple[str]]], ) -> dict: if extracts is None: extracts = {} diff --git a/tests/test_cli.py b/tests/test_cli.py index 4c3ca71..f32ddb4 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -987,7 +987,7 @@ def test_query_json_with_json_cols(db_path): @pytest.mark.parametrize( "content,is_binary", - [(b"\x00\x0Fbinary", True), ("this is text", False), (1, False), (1.5, False)], + [(b"\x00\x0fbinary", True), ("this is text", False), (1, False), (1.5, False)], ) def test_query_raw(db_path, content, is_binary): Database(db_path)["files"].insert({"content": content}) @@ -1002,7 +1002,7 @@ def test_query_raw(db_path, content, is_binary): @pytest.mark.parametrize( "content,is_binary", - [(b"\x00\x0Fbinary", True), ("this is text", False), (1, False), (1.5, False)], + [(b"\x00\x0fbinary", True), ("this is text", False), (1, False), (1.5, False)], ) def test_query_raw_lines(db_path, content, is_binary): Database(db_path)["files"].insert_all({"content": content} for _ in range(3))