Skip to content

Release v2.6.0 - #6

Merged
MichailSemoglou merged 13 commits into
mainfrom
feature/v2.6.0
Aug 5, 2026
Merged

Release v2.6.0#6
MichailSemoglou merged 13 commits into
mainfrom
feature/v2.6.0

Conversation

@MichailSemoglou

@MichailSemoglou MichailSemoglou commented Aug 5, 2026

Copy link
Copy Markdown
Owner

What's new

Added

  • Perceptually uniform appearance spaces — ICtCp (ITU-R BT.2100/BT.2124-0, HDR-aware) and CIELAB (CIE76 & CIEDE2000) backends for ranking CVD deficiency severity. Exposed via make_appearance_space(name) factory, get_error_map(appearance=), and compute_dashboard(appearance=).
  • colorcast dashboard CLI subcommand — generate full-resolution CVD accessibility reports with --appearance {cielab,ictcp}.
  • GUI Dashboard ΔE metric dropdown — change the metric and the computation re-runs automatically. Report filenames and titles auto-include the metric label (dashboard_report_ictcp.png).
  • ErrorMap.preferred_metric() — centralizes the priority rule (appearance > CIEDE2000 > chroma) so downstream code stays ignorant of which metric was computed.
  • Shared srgb_to_linear utility in colorcast/utils/color_utils.py — eliminates the duplicate from simulation.py.
  • Minimal dark theme — custom QSS stylesheet with dark canvas, white pill buttons, hairline borders, zero drop shadows.

Fixed

  • Decompression bomb defence — Pillow DecompressionBombError now re-raises instead of falling through to a full decode. Multi-frame stacks rejected before allocation.
  • Config boolean validationColorCastConfig.load() no longer silently accepts JSON booleans for integer-typed fields.
  • GUI stale-completion test — fixed assertion that didn't account for the initial _start_computation call from DashboardDialog.__init__.

Changed

  • CIELABSpace default metric is now CIEDE2000 (was CIE76).
  • _summarize simplified — delegates to ErrorMap.preferred_metric() instead of encoding the priority chain inline.
  • gpu_transfer.py module docstring simplified.

Tests

  • 12 new appearance-space tests (zero-ΔE, monotonicity, PQ helpers, metric names, input validation)
  • 2 new image-loader tests (DecompressionBombError guard, multi-frame rejection)
  • 1 new GUI test (heatmap title includes ΔE metric label)
  • 1 fixed GUI test (stale-completion assertion)
  • 378 passing, 1 skipped (up from 361 in v2.5.0)

Summary by CodeRabbit

  • New Features

    • Added CIELAB and ICtCp appearance-space metrics for perceptual color-difference analysis.
    • Added CLI dashboard reports with selectable metrics and CVD accessibility statistics.
    • Added metric-aware heatmaps, reports, and dashboard controls.
    • Introduced a unified dark GUI theme and responsive layout.
    • Included GUI assets in packaged distributions.
  • Bug Fixes

    • Improved image validation for oversized and multi-frame files.
    • Prevented outdated dashboard results from replacing current results.
  • Documentation

    • Updated release metadata, examples, changelog, and version to 2.6.0.

Introduce an AppearanceSpace ABC with two backends:
- CIELAB (CIE 1976, CIE76 dE*ab or CIEDE2000 dE00 via skimage)
- ICtCp (ITU-R BT.2100, BT.2124-0 dE_ITP, HDR-aware)

The make_appearance_space(name) factory centralizes creation.
Extract the shared srgb_to_linear into colorcast/utils/color_utils.py
so both simulation and appearance can import it without duplication.

Add **/.DS_Store to .gitignore to catch nested macOS junk.

12 tests cover identical-image zero-dE, monotonicity, PQ/linear
helpers, metric names, and input validation.
Add appearance_delta / appearance_delta_name fields to ErrorMap
and a preferred_metric() method that centralizes the priority rule
(appearance > CIEDE2000 > chroma).  get_error_map() accepts an
appearance= keyword; compute_dashboard() passes it through.

New CLI subcommand colorcast dashboard IMAGE --appearance ictcp.
GUI Dashboard dialog gains a dE-metric dropdown that re-triggers
computation.  Report filenames and titles auto-include the metric
label (e.g. dashboard_report_ictcp.png).

Fix a GUI test that did not account for the initial _start_computation
call from DashboardDialog.__init__, causing it to see 3 pending
requests instead of 2.
…rejection

- _get_image_dimensions: catch and re-raise Pillow DecompressionBombError
  so oversized images stop at header read instead of triggering a full
  decode fallback.  Restore Pillow.MAX_IMAGE_PIXELS to its original value
  after the header check.
- Extract _read_image_array for single-frame validation; reject
  multi-frame stacks (ndim > 3 or ambiguous channel count).
- Add tests for DecompressionBombError propagation and multi-frame
  detection via skimage/imread monkeypatching.
ColorCastConfig.load() now rejects JSON booleans for integer-typed
fields (bool is a subclass of int, so isinstance alone was not enough).
Floats are still accepted for integer fields because JSON cannot
distinguish them.
Add chevron-down.png for combo-box dropdown arrows.
Wire MANIFEST.in and pyproject.toml to ship assets/ in sdists.

Also pin mypy python_version to 3.10 to match the project's
minimum supported Python.
- README test metrics: 378 passing, 1 skipped (up from 361)
- README new features: appearance spaces, dashboard CLI, GUI theme
- README CLI and Python API examples for appearance + dashboard
- CHANGELOG [2.6.0] entries covering all prior commits
- Replace dashboard_report.png with metric-labelled ICtCp variant
- Update interface screenshots to reflect the new dark theme
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89993fca-c6d3-4391-816b-2483e064461c

📥 Commits

Reviewing files that changed from the base of the PR and between 3e45f1c and 1f45671.

📒 Files selected for processing (6)
  • colorcast/analysis/dashboard.py
  • colorcast/analysis/error_map.py
  • colorcast/gui.py
  • colorcast/processing/image_loader.py
  • tests/test_appearance.py
  • tests/test_gui.py
📝 Walkthrough

Walkthrough

ColorCast 2.6.0 adds CIELAB and ICtCp appearance metrics to analysis, error maps, dashboards, CLI, and GUI workflows. It also hardens image loading, centralizes sRGB conversion, updates the GUI theme, packages GUI assets, and updates release metadata.

Changes

Appearance metrics and analysis

Layer / File(s) Summary
Appearance-space backends
colorcast/analysis/appearance.py, colorcast/analysis/__init__.py, tests/test_appearance.py
Adds CIELAB and ICtCp spaces, multiple ΔE metrics, validation, factory selection, exports, and tests.
Metric-aware error maps and reports
colorcast/analysis/error_map.py, colorcast/analysis/dashboard.py
Stores appearance deltas and uses preferred metrics for summaries, heatmaps, and report captions.

CLI and GUI

Layer / File(s) Summary
CLI and asynchronous dashboard surfaces
colorcast/__main__.py, colorcast/gui.py, tests/test_gui.py, README.md
Adds the dashboard command and GUI metric selection, asynchronous computation, stale-result handling, and metric-specific reports.
GUI application shell
colorcast/gui.py
Adds the dark theme, responsive layout, styled controls and dialogs, worker-signal retention, and startup configuration.

Supporting changes

Layer / File(s) Summary
Validated image loading
colorcast/processing/image_loader.py, tests/test_image_loading.py
Adds synchronized header checks, pixel limits, multi-frame rejection, channel validation, and shared decoding.
Shared utilities and validation
colorcast/utils/color_utils.py, colorcast/processing/simulation.py, colorcast/processing/gpu_transfer.py, colorcast/utils/config.py
Centralizes sRGB linearization, updates simulation usage, clarifies GPU behavior, and consolidates type validation.
Release metadata and packaging
.gitignore, .zenodo.json, CHANGELOG.md, CITATION.cff, MANIFEST.in, pyproject.toml, colorcast/_version.py, docs/index.rst, README.md
Updates version metadata and release documentation, packages GUI assets, and adds ignore rules.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant cmd_dashboard
  participant load_image
  participant compute_dashboard
  participant report_generator
  CLI->>cmd_dashboard: select image and appearance space
  cmd_dashboard->>load_image: load input image
  cmd_dashboard->>compute_dashboard: calculate deficiency metrics
  compute_dashboard-->>cmd_dashboard: return dashboard result
  cmd_dashboard->>report_generator: write metric-labeled report
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the primary change as the v2.6.0 release.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/v2.6.0

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
colorcast/processing/image_loader.py (1)

258-263: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve InvalidImageFormatError from _read_image_array.

_read_image_array raises InvalidImageFormatError for unsupported frame stacks and channel layouts. The generic handler converts that expected validation result into ImageLoadError. This conflicts with the documented public exception contract.

Proposed fix
     try:
         img = img_as_float(_read_image_array(path))
+    except InvalidImageFormatError:
+        raise
     except OSError as e:
         raise ImageLoadError(f"Failed to read image file: {e}") from e
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@colorcast/processing/image_loader.py` around lines 258 - 263, Update the
exception handling around _read_image_array in the image-loading flow to let
InvalidImageFormatError propagate unchanged before the generic Exception handler
runs. Preserve the existing ImageLoadError wrapping for other unexpected errors
and the OSError handling.
colorcast/analysis/error_map.py (1)

270-274: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale inline comment about NaN.

Line 274 now assigns None when compute_dE00 is false. The comment on lines 272-273 still states that the result contains NaN values. The class docstring at line 88 was updated to None. Align this comment.

📝 Proposed comment fix
     # -- CIEDE2000 chromaticity error -----------------------------------------
     # Compute dE00 with L* pinned to 50 to isolate chromaticity contribution.
-    # By default this optional output is disabled, so the result contains
-    # NaN values instead of a computed metric.
+    # By default this optional output is disabled, so the field is left as
+    # ``None`` instead of holding a computed metric.
     chroma_error_dE00 = _compute_chroma_error_dE00(orig_lab, sim_lab) if compute_dE00 else None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@colorcast/analysis/error_map.py` around lines 270 - 274, Update the inline
comment above chroma_error_dE00 to state that the optional output is disabled by
assigning None when compute_dE00 is false, replacing the stale reference to NaN;
leave the _compute_chroma_error_dE00 assignment unchanged.
colorcast/gui.py (1)

1010-1022: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Remove the stale chroma-loss naming.

Line 1019 now renders em.preferred_metric(), which can be the appearance ΔE, CIEDE2000, or the Euclidean chroma error. The comment on lines 1010-1011 still describes the chroma_error field.

The placeholder cell titles in _build_ui have the same problem. They read "Chroma Loss (P)" until line 1022 replaces them with _heatmap_title. Until the first result arrives, the dialog shows a metric name the user did not select.

📝 Proposed fix
-        # Chroma-loss heatmaps — use the chroma_error field rendered as
-        # a grayscale hot image
+        # Metric heatmaps — render the preferred per-pixel metric as a
+        # grayscale hot image and retitle the cell with the metric label.
         for key, deficiency in [

Also make the placeholder titles metric-neutral in _build_ui:

-            (2, 0, "heatmap_protanopia", "Chroma Loss (P)"),
-            (2, 1, "heatmap_deuteranopia", "Chroma Loss (D)"),
-            (2, 2, "heatmap_tritanopia", "Chroma Loss (T)"),
+            (2, 0, "heatmap_protanopia", "ΔE (P)"),
+            (2, 1, "heatmap_deuteranopia", "ΔE (D)"),
+            (2, 2, "heatmap_tritanopia", "ΔE (T)"),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@colorcast/gui.py` around lines 1010 - 1022, Remove the stale chroma-loss
wording from the heatmap comment near the loop using em.preferred_metric(),
describing it instead as the selected error metric. In _build_ui, replace the
placeholder “Chroma Loss” titles for the protanopia, deuteranopia, and
tritanopia heatmaps with metric-neutral titles that do not imply a specific
metric.
🧹 Nitpick comments (3)
colorcast/analysis/dashboard.py (1)

266-272: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Rename the chroma_error parameter to match the generalized metric.

The docstring on line 267 now says "metric heatmap". Callers at line 240 pass em.preferred_metric(), which can be the appearance ΔE, CIEDE2000, or the Euclidean chroma error. The parameter name chroma_error no longer describes the value.

♻️ Proposed rename
-def _show_heatmap(ax, chroma_error: np.ndarray) -> None:
+def _show_heatmap(ax, metric: np.ndarray) -> None:
     """Render a metric heatmap on a Matplotlib axis."""
-    vmax = float(chroma_error.max())
+    vmax = float(metric.max())
     if vmax < 1e-6:
-        ax.imshow(np.zeros_like(chroma_error), cmap="hot", vmin=0, vmax=1)
+        ax.imshow(np.zeros_like(metric), cmap="hot", vmin=0, vmax=1)
     else:
-        ax.imshow(chroma_error / vmax, cmap="hot", vmin=0, vmax=1)
+        ax.imshow(metric / vmax, cmap="hot", vmin=0, vmax=1)
     ax.axis("off")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@colorcast/analysis/dashboard.py` around lines 266 - 272, Rename the
_show_heatmap parameter from chroma_error to a generalized metric name, and
update all references within the function, including the vmax calculation,
zero-array fallback, and normalization expression; preserve the existing
rendering behavior for any preferred metric.
tests/test_appearance.py (1)

86-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for make_appearance_space and the "linear" transfer function.

make_appearance_space is a new public export. The CLI and the GUI both depend on it. No test covers it, including the ValueError branch for an unknown name.

The "linear" transfer function path is also untested. A test there would catch the in-place mutation flagged in colorcast/analysis/appearance.py.

💚 Proposed additional tests
def test_make_appearance_space_returns_expected_types() -> None:
    from colorcast.analysis.appearance import make_appearance_space

    assert isinstance(make_appearance_space("cielab"), CIELABSpace)
    assert isinstance(make_appearance_space("ICtCp"), ICtCpSpace)


def test_make_appearance_space_rejects_unknown_name() -> None:
    from colorcast.analysis.appearance import make_appearance_space

    with pytest.raises(ValueError, match="unsupported appearance space"):
        make_appearance_space("oklab")


def test_ictcp_linear_transfer_does_not_mutate_source_array() -> None:
    rgb = np.random.rand(4, 4, 3).astype(np.float64)
    original = rgb.copy()

    ICtCpSpace(transfer_function="linear").from_rgb(rgb)

    np.testing.assert_array_equal(rgb, original)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_appearance.py` around lines 86 - 111, Add tests in
tests/test_appearance.py covering make_appearance_space: verify “cielab” and
“ICtCp” return CIELABSpace and ICtCpSpace, and unknown names raise ValueError
matching “unsupported appearance space”. Also test
ICtCpSpace(transfer_function="linear").from_rgb does not mutate the source RGB
array by comparing it with a copy after conversion.
tests/test_gui.py (1)

239-256: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen the stale-completion assertion and use monkeypatch for the class attribute.

Two points.

First, lines 239-244 patch DashboardDialog._start_computation on the class directly. The finally block restores it, so the test is correct. The test at line 210 already uses monkeypatch.setattr for the same attribute. Use monkeypatch here too, and call monkeypatch.undo() after construction.

Second, the assertion on lines 255-256 only proves that None stays None. The test name states that a stale completion does not mutate the current result. Seed dialog._result with a sentinel first, then assert the sentinel survives the stale callback.

💚 Proposed test changes
-        # Suppress the initial _start_computation call from __init__ so the
-        # test controls exactly how many requests are queued.
-        _original_start = DashboardDialog._start_computation
-        DashboardDialog._start_computation = lambda self: None
-        try:
-            dialog = DashboardDialog(np.random.rand(8, 8, 3).astype(np.float32))
-        finally:
-            DashboardDialog._start_computation = _original_start
+        # Suppress the initial _start_computation call from __init__ so the
+        # test controls exactly how many requests are queued.
+        monkeypatch.setattr(DashboardDialog, "_start_computation", lambda self: None)
+        dialog = DashboardDialog(np.random.rand(8, 8, 3).astype(np.float32))
+        monkeypatch.undo()
+        monkeypatch.setattr(gui_module, "_run_in_thread", fake_run)
 
         monkeypatch.setattr(dialog, "_populate_results", lambda: None)
+
+        # Seed a current result so a stale completion has something to clobber.
+        sentinel = object()
+        dialog._result = sentinel
 
         dialog._start_computation()
         dialog._start_computation()
         assert len(pending) == 2
 
         pending[0][0]()
         pending[0][1]()
 
-        assert dialog._result is None
+        assert dialog._result is sentinel
         assert dialog._error is None

Note that monkeypatch.undo() reverts every patch, so reapply the _run_in_thread patch afterwards as shown.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_gui.py` around lines 239 - 256, Update the test around
DashboardDialog._start_computation to use monkeypatch.setattr instead of direct
class assignment, call monkeypatch.undo() after constructing the dialog, and
reapply the existing _run_in_thread patch afterward if needed. Before invoking
the stale completion callbacks, assign dialog._result a sentinel value and
assert that the sentinel remains unchanged, while preserving the existing _error
assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@colorcast/analysis/appearance.py`:
- Around line 249-254: Update the linear branch of _rgb_to_ictcp to create an
independent float64 copy of rgb before the in-place peak_luminance scaling,
while preserving the existing srgb branch and conversion behavior.

In `@colorcast/gui.py`:
- Around line 60-61: Update the QSS template usages of `@CHEVRON_DOWN`@, including
the references near the drop-down styling and related rules, so the substituted
filesystem path is enclosed in quotes within url(). Keep _CHEVRON_PATH unchanged
and ensure every occurrence produces valid QSS when the path contains spaces.
- Around line 955-961: Update the appearance combo-box setup and selection flow
around _appearance_combo so each item stores its appearance-space id as item
data, then use currentData() instead of matching display text in the space_name
assignment. Preserve the existing CIELAB fallback when no combo box data is
available, and pass the selected id to make_appearance_space.

In `@colorcast/processing/image_loader.py`:
- Around line 93-100: Update the exception handling in _get_image_dimensions in
image_loader.py so DecompressionBombWarning is handled before the generic
fallback and does not reach the broad Exception branch. Mirror the existing
DecompressionBombError path by re-raising or converting DecompressionBombWarning
to ValidationError, while leaving the OSError/ValueError pass-through and the
logger.warning fallback for unrelated exceptions unchanged.

---

Outside diff comments:
In `@colorcast/analysis/error_map.py`:
- Around line 270-274: Update the inline comment above chroma_error_dE00 to
state that the optional output is disabled by assigning None when compute_dE00
is false, replacing the stale reference to NaN; leave the
_compute_chroma_error_dE00 assignment unchanged.

In `@colorcast/gui.py`:
- Around line 1010-1022: Remove the stale chroma-loss wording from the heatmap
comment near the loop using em.preferred_metric(), describing it instead as the
selected error metric. In _build_ui, replace the placeholder “Chroma Loss”
titles for the protanopia, deuteranopia, and tritanopia heatmaps with
metric-neutral titles that do not imply a specific metric.

In `@colorcast/processing/image_loader.py`:
- Around line 258-263: Update the exception handling around _read_image_array in
the image-loading flow to let InvalidImageFormatError propagate unchanged before
the generic Exception handler runs. Preserve the existing ImageLoadError
wrapping for other unexpected errors and the OSError handling.

---

Nitpick comments:
In `@colorcast/analysis/dashboard.py`:
- Around line 266-272: Rename the _show_heatmap parameter from chroma_error to a
generalized metric name, and update all references within the function,
including the vmax calculation, zero-array fallback, and normalization
expression; preserve the existing rendering behavior for any preferred metric.

In `@tests/test_appearance.py`:
- Around line 86-111: Add tests in tests/test_appearance.py covering
make_appearance_space: verify “cielab” and “ICtCp” return CIELABSpace and
ICtCpSpace, and unknown names raise ValueError matching “unsupported appearance
space”. Also test ICtCpSpace(transfer_function="linear").from_rgb does not
mutate the source RGB array by comparing it with a copy after conversion.

In `@tests/test_gui.py`:
- Around line 239-256: Update the test around DashboardDialog._start_computation
to use monkeypatch.setattr instead of direct class assignment, call
monkeypatch.undo() after constructing the dialog, and reapply the existing
_run_in_thread patch afterward if needed. Before invoking the stale completion
callbacks, assign dialog._result a sentinel value and assert that the sentinel
remains unchanged, while preserving the existing _error assertion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7cf61ea8-458f-4755-91f8-fb6b2f0d0e75

📥 Commits

Reviewing files that changed from the base of the PR and between b75f9b5 and 6bc3e38.

⛔ Files ignored due to path filters (7)
  • colorcast/assets/chevron-down.png is excluded by !**/*.png
  • imgs/CVD-Accessibility-Dashboard.png is excluded by !**/*.png
  • imgs/Compare-Transfer-Methods.png is excluded by !**/*.png
  • imgs/dashboard_report.png is excluded by !**/*.png
  • imgs/dashboard_report_ICtCp.png is excluded by !**/*.png
  • imgs/interface.png is excluded by !**/*.png
  • imgs/interface_2.png is excluded by !**/*.png
📒 Files selected for processing (23)
  • .gitignore
  • .zenodo.json
  • CHANGELOG.md
  • CITATION.cff
  • MANIFEST.in
  • README.md
  • colorcast/__main__.py
  • colorcast/_version.py
  • colorcast/analysis/__init__.py
  • colorcast/analysis/appearance.py
  • colorcast/analysis/dashboard.py
  • colorcast/analysis/error_map.py
  • colorcast/gui.py
  • colorcast/processing/gpu_transfer.py
  • colorcast/processing/image_loader.py
  • colorcast/processing/simulation.py
  • colorcast/utils/color_utils.py
  • colorcast/utils/config.py
  • docs/index.rst
  • pyproject.toml
  • tests/test_appearance.py
  • tests/test_gui.py
  • tests/test_image_loading.py

Comment thread colorcast/analysis/appearance.py
Comment thread colorcast/gui.py
Comment thread colorcast/gui.py Outdated
Comment thread colorcast/processing/image_loader.py
- appearance.py: make a full copy before in-place peak-luminance scaling
  in the linear branch so the caller's array is not mutated.
- gui.py: wrap chevron asset path in url() quotes so QSS survives
  paths with spaces; use combo-box itemData/currentData instead of
  text matching for appearance-space selection.
- image_loader.py: catch DecompressionBombWarning and convert it to
  DecompressionBombError before it reaches the generic Exception
  fallback; preserve cause chain with from e.
- dashboard.py: rename _show_heatmap parameter from chroma_error to
  metric to reflect that it accepts any preferred metric.
- test_gui.py: use monkeypatch.setattr instead of direct class assignment
  for _start_computation; add sentinel check to verify stale completions
  do not mutate the current result.
- test_appearance.py: add make_appearance_space type/error tests and
  ICtCpSpace linear-transfer non-mutation test.
- image_loader.py: let InvalidImageFormatError propagate unchanged
  before the generic Exception handler wraps other errors.
- error_map.py: update stale NaN comment to reflect that the optional
  chroma_error_dE00 field is left as None, not populated with NaN.
- gui.py: rename Chroma Loss heatmap titles to metric-neutral
  Error Metric labels; update heatmap comment to reference
  preferred_metric() instead of chroma_error.
@MichailSemoglou
MichailSemoglou merged commit 757d420 into main Aug 5, 2026
7 checks passed
@MichailSemoglou
MichailSemoglou deleted the feature/v2.6.0 branch August 5, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant