From 50e0e10efb63dc248ffd83a36862df2f5d5b8876 Mon Sep 17 00:00:00 2001 From: Pierre Raybaut <1311787+PierreRaybaut@users.noreply.github.com> Date: Fri, 30 Oct 2026 06:35:00 +0100 Subject: [PATCH 1/2] fix(config): stop persisting the plot watermark path DataLabOptions set watermark_image_path to the absolute path of the watermark image of the running installation, but the field kept the "view" category inherited from SigimaX, so it was written to the user configuration and, on the next start, overrode the value of whichever DataLab read this configuration. Installations sharing it (e.g. DataLab installed in several Python environments) displayed the watermark of the first one, no watermark once it was removed, and a blurry one on high-DPI screens when it predated the @2x images. - options: the watermark path is now uncategorized application branding, like the splash screen image, hence never persisted. - persistence: OBSOLETE_INI_OPTIONS lists the INI options written by earlier versions that are removed when the configuration is loaded ([view] watermark_image_path, written by DataLab 1.3). - Regression test: a stale watermark path is ignored, removed from the INI file and not written back. Assisted-by: Claude Opus 5.5 --- datalab/config/options.py | 4 ++ datalab/config/persistence.py | 31 ++++++++++++++++ .../backbone/config_persistence_unit_test.py | 37 +++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/datalab/config/options.py b/datalab/config/options.py index 0c4946d8c..792ad8cfe 100644 --- a/datalab/config/options.py +++ b/datalab/config/options.py @@ -620,6 +620,10 @@ def __init__(self) -> None: self.watermark_image_path.set( configtools.get_image_file_path("DataLab-watermark.png") ) + # The watermark path depends on the running installation: persisting it + # would make other installations sharing the user configuration (e.g. in + # another Python environment) display this one's image. + self.watermark_image_path.category = "" self.app_docurl.set(__docurl__) self.app_homeurl.set(__homeurl__) self.app_supporturl.set(__supporturl__) diff --git a/datalab/config/persistence.py b/datalab/config/persistence.py index 83d58f9fd..4beb48d5d 100644 --- a/datalab/config/persistence.py +++ b/datalab/config/persistence.py @@ -117,10 +117,18 @@ def _default_conf() -> UserConfig: "app_copyright", "splash_image_path", "splash_show_progress", + "watermark_image_path", "datetime_format", } ) +#: ``(section, key)`` INI options written by earlier versions that must no longer +#: be read, and are removed when the configuration is loaded. +OBSOLETE_INI_OPTIONS: tuple[tuple[str, str], ...] = ( + # Absolute path of the installation that wrote it (DataLab 1.3) + ("view", "watermark_image_path"), +) + def get_ini_location(options: DataLabOptions, name: str) -> tuple[str, str] | None: """Return the ``(section, ini_key)`` INI location of an option field. @@ -210,6 +218,25 @@ def remove_persisted_option( return True +def remove_obsolete_ini_options(conf: UserConfig) -> bool: + """Remove the INI options listed in :data:`OBSOLETE_INI_OPTIONS`. + + Args: + conf: The ``UserConfig`` INI backend to clean up. + + Returns: + True if at least one option was removed, False otherwise. + """ + removed = False + for section, key in OBSOLETE_INI_OPTIONS: + if conf.has_option(section, key): + conf.remove_option(section, key) + removed = True + if removed: + conf.save() + return removed + + def _iter_persisted_field_names(options: DataLabOptions): """Yield persisted (categorized) option field names in category order.""" for _category, names in options.fields_by_category().items(): @@ -308,6 +335,9 @@ def load_options_from_ini( ) -> None: """Load all mapped option values from the INI backend into the container. + Obsolete options (see :data:`OBSOLETE_INI_OPTIONS`) are removed from the + backend. + Args: options: The DataLab options container to populate. conf: The ``UserConfig`` INI backend to read from (defaults to the @@ -319,6 +349,7 @@ def load_options_from_ini( if location is None: continue _load_field(options, conf, field_name, *location) + remove_obsolete_ini_options(conf) def save_options_to_ini( diff --git a/datalab/tests/backbone/config_persistence_unit_test.py b/datalab/tests/backbone/config_persistence_unit_test.py index 60fe1b355..1529027f6 100644 --- a/datalab/tests/backbone/config_persistence_unit_test.py +++ b/datalab/tests/backbone/config_persistence_unit_test.py @@ -13,6 +13,7 @@ import guidata.dataset as gds import pytest +from guidata import configtools from sigimax.utils import conf as confmod from sigimax.utils.conf import AppUserConfig @@ -21,6 +22,7 @@ from datalab.config.persistence import ( CONF_VERSION, DataLabUserConfig, + IniOptionStore, atomic_save_configuration, get_ini_location, get_uncategorized_fields, @@ -46,6 +48,14 @@ def _make_conf() -> AppUserConfig: return conf +def _make_file_conf(tmp_path, monkeypatch) -> DataLabUserConfig: + """Return a DataLab INI backend whose file is written in ``tmp_path``.""" + conf = DataLabUserConfig({}) + monkeypatch.setattr(conf, "get_path", lambda basename: str(tmp_path / basename)) + conf.set_application("DataLab_pytest", CONF_VERSION, load=False) + return conf + + def test_legacy_configuration_migrates_without_modifying_source( tmp_path, monkeypatch ) -> None: @@ -142,6 +152,33 @@ def test_uncategorized_option_has_no_persisted_location() -> None: assert not remove_persisted_option(options, "app_name", conf) +def test_watermark_path_is_not_persisted(tmp_path, monkeypatch) -> None: + """The watermark of the running installation is always used. + + DataLab 1.3 persisted the absolute path of its own watermark image: other + installations sharing the user configuration displayed this image, and none + once this installation was removed. + """ + conf = _make_file_conf(tmp_path, monkeypatch) + stale_path = str(tmp_path / "removed_install" / "DataLab-watermark.png") + conf.set("view", "watermark_image_path", stale_path) + options = DataLabOptions() + assert get_ini_location(options, "watermark_image_path") is None + + load_options_from_ini(options, conf) + + expected = configtools.get_image_file_path("DataLab-watermark.png") + assert options.watermark_image_path.get() == expected + assert not conf.has_option("view", "watermark_image_path") + ini_text = Path(conf.filename()).read_text(encoding="utf-8") + assert "watermark_image_path" not in ini_text + + options.attach_store(IniOptionStore(options, conf)) + options.watermark_image_path.set(stale_path) + save_options_to_ini(options, conf) + assert not conf.has_option("view", "watermark_image_path") + + def test_round_trip_across_types() -> None: """Values of various types round-trip through the INI backend.""" conf = _make_conf() From ba07e094d937c78776c00caf78ce2783286af18c Mon Sep 17 00:00:00 2001 From: Pierre Raybaut <1311787+PierreRaybaut@users.noreply.github.com> Date: Fri, 30 Oct 2026 06:35:03 +0100 Subject: [PATCH 2/2] docs: plot watermark path (release notes, translations) Add the 1.4.0 bug-fix note on the watermark of empty plots read from another installation sharing the user configuration, and its French translation. Assisted-by: Claude Opus 5.5 --- doc/locale/fr/LC_MESSAGES/release_notes/release_1.04.po | 6 ++++++ doc/release_notes/release_1.04.md | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/doc/locale/fr/LC_MESSAGES/release_notes/release_1.04.po b/doc/locale/fr/LC_MESSAGES/release_notes/release_1.04.po index c265c7f10..5a97d9108 100644 --- a/doc/locale/fr/LC_MESSAGES/release_notes/release_1.04.po +++ b/doc/locale/fr/LC_MESSAGES/release_notes/release_1.04.po @@ -496,6 +496,12 @@ msgstr "Correction du flou de l'écran de démarrage, du logo DataLab de la page msgid "Fixed most of the text of the user interface (welcome page, object properties, panel tabs, dialog boxes, ...) keeping its 100% size with a Windows display scaling greater than 100% (e.g., 125%), while menus and the status bar were enlarged. All the text now follows the display scaling and the Windows text size setting, and uses the standard font of Windows applications (\"Segoe UI\"). This affected DataLab running with Qt 5, like the standalone application (requires guidata ≥ 3.16.1)" msgstr "Correction de la majeure partie du texte de l'interface (page d'accueil, propriétés des objets, onglets des panneaux, boîtes de dialogue, ...) qui conservait sa taille à 100 % avec une mise à l'échelle de l'affichage Windows supérieure à 100 % (par exemple 125 %), alors que les menus et la barre d'état étaient agrandis. Tout le texte suit désormais la mise à l'échelle de l'affichage et le réglage de la taille du texte de Windows, et utilise la police standard des applications Windows (« Segoe UI »). Cela concernait DataLab exécuté avec Qt 5, comme l'application autonome (nécessite guidata ≥ 3.16.1)" +msgid "**Plot watermark:**" +msgstr "**Filigrane des graphiques :**" + +msgid "Fixed the watermark of empty plots being read from another installation of DataLab sharing the same user configuration (e.g., DataLab installed in another Python environment): the watermark disappeared once this other installation was removed, and stayed blurry on high-DPI screens when it was an older version. The watermark of the running DataLab is now always used" +msgstr "Correction du filigrane des graphiques vides, qui était lu dans une autre installation de DataLab partageant la même configuration utilisateur (par exemple DataLab installé dans un autre environnement Python) : le filigrane disparaissait une fois cette autre installation supprimée, et restait flou sur les écrans haute résolution lorsqu'il s'agissait d'une version plus ancienne. Le filigrane du DataLab en cours d'exécution est désormais toujours utilisé" + msgid "**Signal display:**" msgstr "**Affichage des signaux :**" diff --git a/doc/release_notes/release_1.04.md b/doc/release_notes/release_1.04.md index c8601618b..d84bc45c6 100644 --- a/doc/release_notes/release_1.04.md +++ b/doc/release_notes/release_1.04.md @@ -217,6 +217,10 @@ See the [HDF5 browser guide](../features/common/h5browser.rst) for scientific ob * Fixed the splash screen, the DataLab logo of the welcome page and of the guided tour, and the watermark of empty plots being blurry with a Windows display scaling greater than 100% (e.g., 125%): they are now displayed at the resolution of the screen * Fixed most of the text of the user interface (welcome page, object properties, panel tabs, dialog boxes, ...) keeping its 100% size with a Windows display scaling greater than 100% (e.g., 125%), while menus and the status bar were enlarged. All the text now follows the display scaling and the Windows text size setting, and uses the standard font of Windows applications ("Segoe UI"). This affected DataLab running with Qt 5, like the standalone application (requires guidata ≥ 3.16.1) +**Plot watermark:** + +* Fixed the watermark of empty plots being read from another installation of DataLab sharing the same user configuration (e.g., DataLab installed in another Python environment): the watermark disappeared once this other installation was removed, and stayed blurry on high-DPI screens when it was an older version. The watermark of the running DataLab is now always used + **Signal display:** * Fixed auto downsampling of signals (**Settings > Visualization > Signals**) only starting above 5 times the configured maximum number of points: with the default value of 100,000 points, signals of a few hundred thousand points were drawn in full, which slowed down the display. Signals with more points than the maximum are now downsampled so that at most this number of points is drawn, and the Settings dialog and the documentation now give the actual default value (100,000 instead of 10,000) (fixes [Issue #455](https://github.com/DataLab-Platform/DataLab/issues/455))