Skip to content

napari/settings: replace single checkbox with per-output retention group + presets (Slice 3 of #245) #248

Description

@aelefebv

Parent PRD

#245

What to build

Replace the single "Remove intermediate files" checkbox in the napari Settings widget with a new collapsible per-output retention group, and update SettingsConfig to carry a frozenset[str] of drop keys instead of a bool:

  1. SettingsConfig schema change: replace remove_intermediates: bool with cleanup_drop_keys: frozenset[str] (default-factory frozenset). Update to_config to populate it from the new widget; update apply_config to push it into the new widget.
  2. New widget composition (in nellie_napari/nellie_settings.py): a QGroupBox titled "Intermediate file retention," default-collapsed, placed where the old single checkbox lived. Composition:
    • A horizontal preset radio row at top: "Keep everything" (default-selected), "Masks + CSVs only," "CSVs only," "Custom" (auto-selected when individual toggles diverge from a named preset; not user-clickable).
    • Below the radio: stage-grouped checkbox subgroups under headers Filter, Label, Network, Markers, Tracking, Voxel reassignment, Hierarchy, Pipeline input. The 14 checkboxes correspond exactly to the 14 keys in DROPPABLE_KEYS. Each checkbox label has the form Friendly Name (raw_key) — see PRD §Implementation Decisions for the stage-to-key mapping.
    • Checkbox semantics: checked = drop, unchecked = keep. Tooltips on each checkbox list consumer stages.
  3. Preset radio behavior: clicking a preset sets the per-output checkbox states to match the preset's drop set. Toggling any individual checkbox flips the radio to "Custom" automatically.
  4. Remove the old remove_intermediates_checkbox — its layout slot is reclaimed by the new group. The new group sits in the same subprocessor_layout1 position (or however the new layout best fits).

This slice does NOT touch nellie_napari/nellie_processor.py — that wiring is filed as Slice 4.

Acceptance criteria

  • SettingsConfig.cleanup_drop_keys: frozenset[str] field exists; default is frozenset(). SettingsConfig.remove_intermediates field is gone.
  • to_config() returns cleanup_drop_keys as frozenset[str] populated from the per-output checkbox states (collect keys whose checkbox is checked).
  • apply_config(config) sets per-output checkboxes from config.cleanup_drop_keys and selects the preset radio that matches the loaded drop set (or "Custom" if none).
  • All 14 checkboxes are present, exactly one per key in DROPPABLE_KEYS, grouped under the 8 stage headers per the PRD's mapping. Friendly labels include the raw key in parens.
  • Tooltip on each checkbox lists at least one consumer stage (see PRD §User stories Now works for single volume inputs for morphological analysis #10).
  • Selecting "Keep everything" preset → all 14 checkboxes unchecked → drop set is empty.
  • Selecting "CSVs only" preset → all 14 checkboxes checked → drop set is DROPPABLE_KEYS.
  • Selecting "Masks + CSVs only" preset → checkboxes for im_instance_label, im_branch_label_reassigned, im_obj_label_reassigned, im_path are unchecked; the other 10 are checked → drop set is MASKS_AND_CSVS_PRESET.
  • Toggling any single checkbox after selecting a named preset switches the preset radio to "Custom."
  • New tests (in tests/test_napari_settings.py, creating the file if it does not exist; use qtbot fixture from pytest-qt if available, otherwise minimal direct-instantiation tests):
    • test_settings_config_default_cleanup_drop_keys_is_empty_frozenset.
    • test_apply_config_then_to_config_round_trip — parametrize over each preset.
    • test_widget_preset_radio_reflects_loaded_drop_set — apply each preset; assert the matching radio is selected; apply a non-preset drop set; assert "Custom" is selected.
    • test_widget_toggle_after_preset_switches_to_custom — apply KEEP_EVERYTHING_PRESET; toggle one checkbox; assert "Custom" is selected.
  • pytest tests/test_napari_settings.py -q passes.
  • All other tests (pytest -q --ignore=tests/test_*_perf.py) still pass — no regression.

Blocked by

User stories addressed

From PRD #245:

  • User story 1 (per-output toggles for masks-only retention).
  • User story 2 (one-click "CSVs only" preset).
  • User story 3 (backward-compat preset name recognizable).
  • User story 4 ("Custom" preset auto-selected on divergence).
  • User story 9 (default = "Keep everything").
  • User story 10 (tooltips list consumer stages).
  • User story 13 (im_path in its own "Pipeline input" group).
  • User story 14 (collapsible group, default-collapsed).
  • User story 15 (preset radio at top).
  • User story 16 ("Custom" auto-flip).

Wiki context

  • wiki/napari-plugin/ — current widget structure for reference.
  • wiki/pipeline.md — stage→output mapping that the UI groups follow.
  • wiki/decisions/0014-intermediates-policy-frozenset.md — the API-shape decision and the rationale behind frozenset[str] + presets-as-constants.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions