Skip to content

refactor: typing and api - #5

Open
TomasBalak wants to merge 8 commits into
refactor/gitlab-to-github-migrationfrom
refactor/typing-and-api
Open

TomasBalak wants to merge 8 commits into
refactor/gitlab-to-github-migrationfrom
refactor/typing-and-api

Conversation

@TomasBalak

@TomasBalak TomasBalak commented Jun 9, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This PR fixes typing issues, unifies return value naming across all QC modules, migrates to the refactored staining library API, and replaces deprecated scikit-image functions.

Note

This PR is a part of a two-stage PR based on #2. The original PR was split in order to be more "review-friendly." This PR should be merged after PR #4 is merged.

Changes

Typing System

  • Add FloatingPointImage type alias (NDArray[np.float64])
  • Extend BlurScore, FoldArtifacts, ResidualArtifacts TypedDicts with
    number_of_examined_pixels and number_of_flagged_pixels fields
  • Update NDArray type hints across all modules for better type safety

API Consistency

  • Residual artifacts: rename coverage_mask → artifacts_per_pixel, replace coverage (float ratio) with raw pixel counts number_of_examined_pixels / number_of_flagged_pixels
  • Fold detection: rename produced mask folding → folding_per_pixel
  • Blur score: add number_of_examined_pixels / number_of_flagged_pixels to return dictionaries; rename internal blur_score_per_pixel variable to blur_score_pooled to avoid shadowing return key

Staining Library API Migration

  • ColorConversion.RGB2HER → StandardConversions.RGB2HER
  • ConversionType → ConversionDirection with .conv_type → .direction
  • .value[0][index] → .matrix[index] for color conversion matrix access

Deprecation Fixes

  • Replace skimage.morphology.binary_dilation/binary_erosion with
    dilation/erosion
  • Simplify blur score logic (remove redundant > 0 casts, use in-place
    operators)

Bug Fixes

  • Fix fold detection return to handle non-H&E stained images (previously returned duplicate code paths)
  • Fix local tile handling when masks are None

Summary by CodeRabbit

  • New Features

    • Quality-control results now report examined and flagged pixel counts alongside per-pixel artifact, blur, and fold masks.
    • Improved handling of missing or empty image regions in fold detection.
    • OpenCV is now included in the package installation.
  • Documentation

    • Added hosted documentation links and updated setup instructions for uv.
    • Refreshed installation and quality-control examples, terminology, and result descriptions.
  • Developer Experience

    • Added automated documentation builds and Python lint checks.
    • Updated formatting and validation tooling.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 33473a89-1958-411d-827b-90ba6c1c562e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
Walkthrough

The project now uses shared GitHub workflows and updated development tooling. Quality-control APIs return per-pixel masks with examined and flagged pixel counts. Blur, residual-artifact, folding, staining, dependency, and documentation examples were updated for the new contracts.

Changes: Quality-control modernization

Layer / File(s) Summary
Project tooling and development setup
.github/workflows/*, .gitlab-ci.yml, pyproject.toml, .pre-commit-config.yaml, .ruff.toml, .mypy.ini, .markdownlint.yaml, README.md, docs/getting-started/installation.md, docs/index.md
Shared GitHub workflows replace the GitLab CI configuration. Development dependencies use dependency groups. Ruff, mypy, Markdownlint, pre-commit, package metadata, and installation instructions are updated.
Quality-control contracts and color conversions
rationai/qc/typing.py, rationai/qc/staining/*
Image and result types now expose floating-point image data, per-pixel masks, and examined or flagged pixel counts. Staining code uses the current conversion direction, matrix, and standard conversions.
Blur processing and pixel counts
rationai/qc/blur/*, docs/getting-started/quality-control.md
Blur implementations use updated morphology and conversion APIs, apply foreground masks, and return examined or flagged pixel counts. Blur documentation matches the updated outputs.
Residual-artifact result changes
rationai/qc/residual_artifacts/*, docs/getting-started/quality-control.md
Residual-artifact analysis returns artifacts_per_pixel, number_of_examined_pixels, and number_of_flagged_pixels instead of coverage data.
Fold detection and neighborhood thresholds
rationai/qc/folding/folding.py, docs/getting-started/quality-control.md
Fold detection renames neighborhood parameters, handles empty masked data, uses updated morphology and conversions, and returns folding_per_pixel with pixel counts.

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

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes to typing and API usage across the quality-control modules.
Finishing Touches
Fix failing CI checks
  • Fix failing CI checks
Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/typing-and-api
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request migrates the project's dependency management from PDM to uv, updates pre-commit and linter configurations, and standardizes the return structures of several quality control functions to consistently report the number of examined and flagged pixels. It also replaces deprecated scikit-image morphological operations with their modern equivalents and updates the documentation accordingly. The review identified a critical logic bug in the folding safety check where a condition is mathematically impossible to satisfy and creates a 3D array instead of a 2D array, a shape mismatch in the initialization of local_eosin_channel, and a potential shape mismatch in blur_score_piqe.py when image dimensions are not divisible by 16.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread rationai/qc/folding/folding.py Resolved
Comment thread rationai/qc/folding/folding.py Resolved
Comment thread rationai/qc/blur/blur_score_piqe.py Resolved
- Add FloatingPointImage type alias and update return type annotations
- Rename fold detection key from 'folding' to 'folding_per_pixel'
- Rename residual artifacts key from 'coverage_mask'/'coverage' to
  'artifacts_per_pixel'/'number_of_examined_pixels'/'number_of_flagged_pixels'
- Add number_of_examined_pixels and number_of_flagged_pixels to all
  blur score and fold artifact return dictionaries
- Replace deprecated binary_dilation/binary_erosion with dilation/erosion
- Replace deprecated ColorConversion with StandardConversions API
- Update color_difference.py for new staining library API
- Simplify blur score logic and fix shadowing issues
@TomasBalak
TomasBalak force-pushed the refactor/typing-and-api branch from 689becd to 7961a57 Compare June 9, 2026 18:51
@TomasBalak
TomasBalak marked this pull request as ready for review June 9, 2026 18:56
@TomasBalak
TomasBalak requested review from a team June 9, 2026 18:56
Comment thread rationai/qc/folding/folding.py Resolved
Comment thread rationai/qc/folding/folding.py Resolved
thresholded_value = inverted_value_channel > value_threshold
thresholded_eosin = eosin_channel > eosin_threshold

if (

@172454 172454 Jul 21, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

See gemini-code-assist[bot] comment on lines R151 to R154: https://github.com/RationAI/quality-control/pull/5/changes#r3383017764

If this does work as intended, please state the intended behavior/purpose explicitly in a comment in the code.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I am not that familiar with this folding code, so I've forwarded the issue to Erik (I couldn't find his username here), I believe he will be able to provide a better answer.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm still missing the intended behavior/purpose of this check. What state is the condition (with several or-ed np.sum(...) * 2 > np.prod(tile.shape[:2]) terms) describing?

@TomasBalak TomasBalak self-assigned this Jul 27, 2026

@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

🤖 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 @.github/workflows/mkdocs-build.yml:
- Line 11: Pin the reusable workflow references in
.github/workflows/mkdocs-build.yml:11 and .github/workflows/python-lint.yml:11
to approved full commit SHAs instead of the mutable `@main` ref, preserving the
existing RationAI/.github workflow targets.

In @.ruff.toml:
- Around line 5-6: Add the top-level Ruff setting force-exclude = true alongside
extend-exclude in .ruff.toml so pre-commit hooks honor the exclusion for
explicitly passed filenames.

In `@docs/getting-started/installation.md`:
- Line 1: Update the numbered H3 headings in the installation documentation,
including the pyvips section and the section at the corresponding later
occurrence, by moving each numeric prefix after the H3 marker (for example, “###
1. …”). Preserve the existing section titles and numbering.

In `@docs/getting-started/quality-control.md`:
- Around line 226-231: Update the documented folding() invocation to use the
current keyword arguments neighborhood_tiles and neighborhood_mask instead of
local_tiles and local_mask, while preserving the existing values
local_area_image and img_area_mask.
🪄 Autofix (Beta)

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 Plus

Run ID: 0134f611-dd5f-4eb0-8313-0610953fb747

📥 Commits

Reviewing files that changed from the base of the PR and between 9f3ec66 and 679d2c5.

⛔ Files ignored due to path filters (2)
  • pdm.lock is excluded by !**/*.lock
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • .github/workflows/mkdocs-build.yml
  • .github/workflows/python-lint.yml
  • .gitlab-ci.yml
  • .markdownlint.yaml
  • .mypy.ini
  • .pre-commit-config.yaml
  • .ruff.toml
  • README.md
  • docs/getting-started/installation.md
  • docs/getting-started/quality-control.md
  • docs/index.md
  • pyproject.toml
  • rationai/qc/blur/blur_score_laplacian.py
  • rationai/qc/blur/blur_score_piqe.py
  • rationai/qc/blur/blur_score_roberts.py
  • rationai/qc/blur/utils.py
  • rationai/qc/folding/folding.py
  • rationai/qc/residual_artifacts/residual_artifacts_and_coverage.py
  • rationai/qc/staining/color_difference.py
  • rationai/qc/staining/dominant_stains.py
  • rationai/qc/staining/staining_difference.py
  • rationai/qc/typing.py
💤 Files with no reviewable changes (1)
  • .gitlab-ci.yml

Comment thread .github/workflows/mkdocs-build.yml Resolved
Comment thread .ruff.toml Resolved
Comment thread docs/getting-started/installation.md Resolved
Comment thread docs/getting-started/quality-control.md Resolved
@TomasBalak
TomasBalak changed the base branch from master to refactor/gitlab-to-github-migration August 17, 2026 11:00
TomasBalak and others added 2 commits November 3, 2026 15:01
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@TomasBalak
TomasBalak requested a review from 172454 November 3, 2026 14:09
local_tiles: Optional n*n tiles in local neighbourhood of tile. Defaults to None.
local_mask: Optional n*n background mask of local_tiles. Defaults to None.
neighborhood_tiles: Optional n*n tiles in local neighbourhood of tile. Defaults to None.
neighborhood_mask: Optional n*n background mask of neighborhood_tiles. Defaults to None.

@172454 172454 Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is neighborhood_mask a background mask here? On line 65, neighborhood_mask: Tissue mask of neighborhood_tiles. It should be kept consistent (the same name should have the same semantic), and also match the expectation that usually, when we are using a mask, it's a mask of the thing in question, not of its inverse/surrounding. (Here, on line 34, it gets inverted anyway: local_values = MaskedArray(neighborhood_tiles, ~neighborhood_mask).compressed().)

(Be careful about all places that call this function, make sure the "(non)invertedness" of the arguments matches what the function works with.)

thresholded_value = inverted_value_channel > value_threshold
thresholded_eosin = eosin_channel > eosin_threshold

if (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm still missing the intended behavior/purpose of this check. What state is the condition (with several or-ed np.sum(...) * 2 > np.prod(tile.shape[:2]) terms) describing?

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.

2 participants