Plugins: a theme plugin switched off or removed at run time stays in the theme picker, and a removed one breaks export #609

Closed
opened 2026-10-01 10:48:21 +00:00 by tiagoagueda · 0 comments
Owner

Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading what the registry undoes when a plugin goes away.

Checked again on 2026-10-01 against main at 0a5cad587: still present. The code is now at plugins/installing.py:1072-1088 (_forget_metadata_cache); catch_up and the other files have not moved.

Related to #228, which made installs, removals and switch-offs take effect without a restart (registry.catch_up) and stopped rejected plugins registering templates and themes (§5), but did not undo what a plugin that was loaded registered once it is switched off or removed.

Loading a plugin registers its document themes (documents.themes._from_plugins), its templates/ directory, its locale/ directory and, when its logo is first shown, a cached copy of the logo. When the record's stamp moves, catch_up clears registry._cache and reloads the plugins that are still on; nothing removes what the others registered. themes.forget is called only from tests, and logos.forget likewise.

  • Where: plugins/registry.py:237-271 (catch_up: _cache.clear(); activate(); …invalidate_caches()); plugins/installing.py:1246-1262 (_forget_metadata_cache, which only refreshes the registry); documents/themes.py:125 and :150-155 (_from_plugins, forget); plugins/logos.py:51 and :172-177 (_cache, forget); plugins/themes.py:38, :52-69; plugins/locale.py:22, :73-97.
  • What happens:
    1. An administrator switches off a plugin that provides a document theme. In every process, including the one that made the change, themes.for_kind still lists it, so the CV and letter theme pickers still offer it and template_for (documents/themes.py:218-231) still resolves documents set in it to the plugin's templates, which still render because the template directory is still on DIRS.
    2. If the plugin is removed instead, its files are gone but the theme is still registered, so template_for does not fall back to the default as it would after a restart (find(name) or find(DEFAULT)), and Export reaches render_to_string with a template that no longer exists: TemplateDoesNotExist, a 500. That is the failure the documents/themes.py docstring says the registry exists to prevent.
    3. An upgraded plugin keeps its old logo until the process restarts, although logo_for's docstring (plugins/logos.py:128-129) says "installing one rebuilds the registry" as the reason the cache is safe.
  • Why it matters: the plugins page says a switch-off or removal takes effect now; for a theme plugin it does not, and a removal turns a working export into a server error until every process restarts. A stale locale path or template directory costs little on its own (Postulo's own come first, and a missing directory is skipped), but they are the same leak.
  • Fix: keep, per plugin distribution, what loading it registered (theme names, template directory, locale directory, logo key). In catch_up and in _forget_metadata_cache, after the reload, forget the themes and logos of every plugin that is no longer loaded and drop its template and locale paths (then _forget_the_engines() and reset trans_real._translations). Clear logos._cache on every rebuild. Correct the register_locale_dir docstring (plugins/locale.py:76-80), which says registration happens "at start-up and never during a request": since #228 catch_up re-runs _load_third_party, and so this, inside whichever request first notices the change.

Done when

  • A test in tests/test_document_themes.py registers a theme plugin, switches it off (moves the record stamp), calls registry.plugins(...), and asserts its theme is gone from themes.for_kind and that template_for falls back to the default; a test in tests/test_plugin_logos.py asserts the logo cache is empty after a rebuild.
Found on 2026-09-29 in a read-only review of postulo at 95348908d, reading what the registry undoes when a plugin goes away. Checked again on 2026-10-01 against `main` at `0a5cad587`: still present. The code is now at `plugins/installing.py:1072-1088` (`_forget_metadata_cache`); `catch_up` and the other files have not moved. Related to #228, which made installs, removals and switch-offs take effect without a restart (`registry.catch_up`) and stopped rejected plugins registering templates and themes (§5), but did not undo what a plugin that *was* loaded registered once it is switched off or removed. Loading a plugin registers its document themes (`documents.themes._from_plugins`), its `templates/` directory, its `locale/` directory and, when its logo is first shown, a cached copy of the logo. When the record's stamp moves, `catch_up` clears `registry._cache` and reloads the plugins that are still on; nothing removes what the others registered. `themes.forget` is called only from tests, and `logos.forget` likewise. - **Where:** `plugins/registry.py:237-271` (`catch_up`: `_cache.clear(); activate(); …invalidate_caches()`); `plugins/installing.py:1246-1262` (`_forget_metadata_cache`, which only refreshes the registry); `documents/themes.py:125` and `:150-155` (`_from_plugins`, `forget`); `plugins/logos.py:51` and `:172-177` (`_cache`, `forget`); `plugins/themes.py:38`, `:52-69`; `plugins/locale.py:22`, `:73-97`. - **What happens:** 1. An administrator switches off a plugin that provides a document theme. In every process, including the one that made the change, `themes.for_kind` still lists it, so the CV and letter theme pickers still offer it and `template_for` (`documents/themes.py:218-231`) still resolves documents set in it to the plugin's templates, which still render because the template directory is still on `DIRS`. 2. If the plugin is removed instead, its files are gone but the theme is still registered, so `template_for` does not fall back to the default as it would after a restart (`find(name) or find(DEFAULT)`), and *Export* reaches `render_to_string` with a template that no longer exists: `TemplateDoesNotExist`, a 500. That is the failure the `documents/themes.py` docstring says the registry exists to prevent. 3. An upgraded plugin keeps its old logo until the process restarts, although `logo_for`'s docstring (`plugins/logos.py:128-129`) says "installing one rebuilds the registry" as the reason the cache is safe. - **Why it matters:** the plugins page says a switch-off or removal takes effect now; for a theme plugin it does not, and a removal turns a working export into a server error until every process restarts. A stale locale path or template directory costs little on its own (Postulo's own come first, and a missing directory is skipped), but they are the same leak. - **Fix:** keep, per plugin distribution, what loading it registered (theme names, template directory, locale directory, logo key). In `catch_up` and in `_forget_metadata_cache`, after the reload, forget the themes and logos of every plugin that is no longer loaded and drop its template and locale paths (then `_forget_the_engines()` and reset `trans_real._translations`). Clear `logos._cache` on every rebuild. Correct the `register_locale_dir` docstring (`plugins/locale.py:76-80`), which says registration happens "at start-up and never during a request": since #228 `catch_up` re-runs `_load_third_party`, and so this, inside whichever request first notices the change. ## Done when - A test in `tests/test_document_themes.py` registers a theme plugin, switches it off (moves the record stamp), calls `registry.plugins(...)`, and asserts its theme is gone from `themes.for_kind` and that `template_for` falls back to the default; a test in `tests/test_plugin_logos.py` asserts the logo cache is empty after a rebuild.
tiagoagueda added this to the 0.6.0 milestone 2026-10-01 10:48:21 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#609
No description provided.