From 091e8ab9944ace6c61c857a75304b97b5827ee4b Mon Sep 17 00:00:00 2001 From: IlyaKhalafi Date: Wed, 14 Oct 2026 08:51:38 +0000 Subject: [PATCH] Preserve empty database plugin overrides Closes #3000 --- datasette/app.py | 4 +++- docs/writing_plugins.rst | 2 ++ tests/test_plugins.py | 41 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/datasette/app.py b/datasette/app.py index b2cb24b7..04d0202d 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -1491,7 +1491,9 @@ class Datasette: # fallback to db_config or top-level config, in that order, if needed if table_plugin_config is None and fallback: - return db_plugin_config or self._plugin_config_top(plugin_name) + if db_plugin_config is not None: + return db_plugin_config + return self._plugin_config_top(plugin_name) return table_plugin_config diff --git a/docs/writing_plugins.rst b/docs/writing_plugins.rst index bbefe344..68507d4c 100644 --- a/docs/writing_plugins.rst +++ b/docs/writing_plugins.rst @@ -302,6 +302,8 @@ If it cannot find the requested configuration at the table layer, it will fall b In this case, the above code would return that configuration for ANY table within the ``sf-trees`` database. +An explicit empty dictionary at the database or table layer counts as configuration and prevents fallback to the next layer. + The plugin configuration could also be set at the top level of ``datasette.yaml``: .. [[[cog diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 58e154a2..973744a5 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -301,6 +301,47 @@ async def test_plugin_config(ds_client): assert None is ds_client.ds.plugin_config("unknown-plugin") +@pytest.mark.parametrize( + "database_plugins,table_plugins,fallback,expected", + [ + ({"example": {}}, {}, True, {}), + ({"example": {"setting": "database"}}, {}, True, {"setting": "database"}), + ({}, {}, True, {"setting": "top"}), + ({"example": None}, {}, True, {"setting": "top"}), + ( + {"example": {}}, + {"example": {"setting": "table"}}, + True, + {"setting": "table"}, + ), + ({"example": {"setting": "database"}}, {"example": {}}, True, {}), + ({"example": {}}, {}, False, None), + ({"example": {}}, {"example": {}}, False, {}), + ], +) +def test_plugin_config_table_fallback_preserves_empty_database_config( + database_plugins, table_plugins, fallback, expected +): + datasette = Datasette( + config={ + "plugins": {"example": {"setting": "top"}}, + "databases": { + "example_db": { + "plugins": database_plugins, + "tables": {"items": {"plugins": table_plugins}}, + } + }, + } + ) + + assert ( + datasette.plugin_config( + "example", database="example_db", table="items", fallback=fallback + ) + == expected + ) + + @pytest.mark.asyncio async def test_plugin_config_env(ds_client, monkeypatch): monkeypatch.setenv("FOO_ENV", "FROM_ENVIRONMENT")