Skip to content

refactor: residual coverage, uv, and migration #2

Closed
TomasBalak wants to merge 36 commits into
masterfrom
refactor/residual-coverage-and-uv
Closed

refactor: residual coverage, uv, and migration #2
TomasBalak wants to merge 36 commits into
masterfrom
refactor/residual-coverage-and-uv

Conversation

@TomasBalak

@TomasBalak TomasBalak commented Mar 9, 2026

Copy link
Copy Markdown
Collaborator

This pull request includes the following changes:

  • Changes necessary to accommodate breaking changes in the Staining library.
  • Migration of the repository from GitLab to GitHub and switch from GitLab CI to GitHub actions.
  • Replacement of pdm with the uv dependency manager.
  • Small improvements to the documentation.
  • Typing fixes in various places.
  • Updating various tools used within the repository.

Unfortunately, I couldn't think of a clean way to merge only the changes required for the repo migration (the code in the master branch would not be runnable, and linting checks would not pass due to typing and linting errors, and the breaking update to the Staining library in the meantime).
Any suggestions for improvement are appreciated. 😄

Summary by CodeRabbit

  • New Features

    • Added per-image metrics (number_of_examined_pixels, number_of_flagged_pixels) and renamed per-pixel outputs (e.g., folding_per_pixel, artifacts_per_pixel) across QC results.
  • Bug Fixes / Improvements

    • Standardized color conversions, refined morphological and pooling behavior, and improved type hints for more consistent QC outputs.
  • Documentation

    • Expanded README and getting-started docs with installation and development setup; updated QC examples and schemas.
  • Chores

    • Migrated CI to GitHub Actions, added lint/markdown configs, updated pre-commit tooling, and bumped project version to 1.0.1.

TomasBalak and others added 30 commits January 27, 2026 11:16
See merge request rationai/digital-pathology/quality-control/quality-control!7
@TomasBalak TomasBalak self-assigned this Mar 9, 2026
@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds GitHub Actions workflows and lint/config files, removes GitLab CI, updates project metadata and docs, and refactors QC modules to use StandardConversions, change several return shapes to per-pixel masks plus number_of_examined_pixels/number_of_flagged_pixels, and update typing and utils signatures.

Changes

Cohort / File(s) Summary
CI / Workflows
.github/workflows/mkdocs-build.yml, .github/workflows/python-lint.yml, .gitlab-ci.yml
Adds two GitHub Actions workflows that reuse external RationAI workflows; removes GitLab CI include directives and stages.
Pre-commit / Lint / Mypy / Markdownlint
.pre-commit-config.yaml, .ruff.toml, .mypy.ini, .markdownlint.yaml
Bumps pre-commit hook revisions and adjusts ruff hook args; adds ruff exclude for rationai/qc/blur/piqe.py; updates type-check codes; adds mypy ignore for the piqe module; disables several markdownlint rules.
Project Metadata & Tooling
pyproject.toml
Bumps version 1.0.0→1.0.1, updates authors, migrates pdm dev-dependencies into dependency-groups, and removes legacy script/post_install entries.
Documentation
README.md, docs/getting-started/installation.md, docs/getting-started/quality-control.md, docs/index.md
Adds Documentation and dev setup sections; changes installation examples to GitHub/uv/pip usage; updates QC docs and examples to new API field names and color-conversion usage.
Typing / Public Contracts
rationai/qc/typing.py
Adds FloatingPointImage alias; renames and expands TypedDict fields across ResidualArtifacts, BlurScore, and FoldArtifacts to use *_per_pixel masks and include number_of_examined_pixels/number_of_flagged_pixels.
Blur Module
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
Switches to StandardConversions/convert_color, replaces binary_* morphology calls with dilation/erosion/opening, introduces type hints in utils, and adds per-image counts and adjusted per-pixel mask handling in returns.
Folding Module
rationai/qc/folding/folding.py
Migrates color conversion to StandardConversions, replaces binary_opening with opening, tightens threshold/local-tile logic, renames output to folding_per_pixel, and adds examined/flagged pixel counts.
Residual Artifacts
rationai/qc/residual_artifacts/residual_artifacts_and_coverage.py
Refactors helper to return examined/flagged pixel counts plus mask; renames outputs to artifacts_per_pixel, number_of_examined_pixels, and number_of_flagged_pixels; updates examples and imports.
Staining Utilities
rationai/qc/staining/color_difference.py, rationai/qc/staining/dominant_stains.py, rationai/qc/staining/staining_difference.py
Adjusts imports and enum/attribute usage to the updated staining API (e.g., ConversionDirection, StandardConversions) and reorders minor imports.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through workflows, swapped an old CI stream,

Masks turned per-pixel, counts added to the team.
Conversions tidied, types now crisp and bright,
Docs and hooks refreshed — I nibble code with delight. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main changes: refactoring related to residual coverage API updates, migrating to the uv dependency manager, and broader infrastructure migration from GitLab to GitHub.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/residual-coverage-and-uv
📝 Coding Plan
  • Generate coding plan for human review comments

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

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

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request encompasses a significant overhaul of the project's development and deployment infrastructure, alongside critical updates to its core image quality control functionalities. The migration from GitLab to GitHub, coupled with the adoption of uv for dependency management, modernizes the project's workflow. Simultaneously, the integration of breaking changes from the Staining library and the enhancement of QC function outputs with more granular metrics improve the robustness and analytical capabilities of the artifact detection algorithms. These changes are thoroughly documented to ensure a smooth transition for developers and users.

Highlights

  • Infrastructure Migration: The repository has been migrated from GitLab to GitHub, including a complete switch from GitLab CI to GitHub Actions for continuous integration.
  • Dependency Management Update: The project's dependency manager has been changed from pdm to uv, streamlining package management and environment setup.
  • Staining Library Integration: Breaking changes from an updated Staining library have been integrated, affecting color conversion methods and related functionalities.
  • Tooling and Linting Updates: Development tools like commitizen and ruff have been updated to their latest versions, with corresponding adjustments to pre-commit hooks and configurations.
  • Enhanced QC Function Outputs: Blur, folding, and residual artifact detection functions now return additional metrics, including number_of_examined_pixels and number_of_flagged_pixels, providing more detailed insights into artifact detection.
  • Documentation Refresh: The README.md and docs have been updated to reflect the new uv commands, GitHub repository links, and improved code examples for clarity and accuracy.
Changelog
  • .gitlab-ci.yml
    • Removed GitLab CI configuration.
  • .markdownlint.yaml
    • Added markdown linting exclusions.
  • .mypy.ini
    • Added type error ignore for a specific file.
  • .pre-commit-config.yaml
    • Updated pre-commit hook versions and configurations.
  • .ruff.toml
    • Updated Ruff configuration to exclude a file and adjust rule codes.
  • README.md
    • Updated documentation links and development setup instructions.
  • docs/getting-started/installation.md
    • Updated installation guide for uv and GitHub.
  • docs/getting-started/quality-control.md
    • Updated code examples and documentation for QC functions.
  • docs/index.md
    • Adjusted minor formatting.
  • pyproject.toml
    • Updated project metadata, dependencies, and removed PDM scripts.
  • rationai/qc/blur/blur_score_laplacian.py
    • Updated imports, added pixel count metrics, and refined blur score calculation.
  • rationai/qc/blur/blur_score_piqe.py
    • Added pixel count metrics and refined activity mask logic.
  • rationai/qc/blur/blur_score_roberts.py
    • Added pixel count metrics and refined blur score calculation.
  • rationai/qc/blur/utils.py
    • Updated imports, type hints, and morphological operation names.
  • rationai/qc/folding/folding.py
    • Updated imports, type hints, thresholding logic, and added pixel count metrics.
  • rationai/qc/residual_artifacts/residual_artifacts_and_coverage.py
    • Updated imports, modified return values for debris coverage, and added pixel count metrics.
  • rationai/qc/staining/color_difference.py
    • Updated imports and adjusted reference stain retrieval.
  • rationai/qc/staining/dominant_stains.py
    • Reordered import statements.
  • rationai/qc/staining/staining_difference.py
    • Reordered imports and updated example usage.
  • rationai/qc/typing.py
    • Added FloatingPointImage type and expanded TypedDicts with pixel count metrics.
Ignored Files
  • Ignored by pattern: .github/workflows/** (2)
    • .github/workflows/mkdocs-build.yml
    • .github/workflows/python-lint.yml
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@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

The pull request updates CI/CD and linting configurations, including upgrading commitizen and ruff, and adding specific linting exclusions for markdown and Python type checking. Documentation for installation and usage examples has been significantly revised, introducing uv for dependency management and clarifying code snippets for residual artifact, blur, and fold detection. Core QC functions (blur_score_laplacian, blur_score_piqe, blur_score_roberts, folding, residual_artifacts_and_coverage) have been refactored to standardize return values, improve type hinting, and update morphological operations. Review comments highlight a potential UnboundLocalError in the folding function, semantic and usage issues with the tissue_img parameter in blur utility functions, typos and inconsistencies in documentation code examples for fold detection, and a type mismatch in the blur_score_piqe function's return value.

Comment thread rationai/qc/folding/folding.py
Comment thread rationai/qc/blur/utils.py
Comment thread docs/getting-started/quality-control.md Outdated
Comment thread docs/getting-started/quality-control.md Outdated
Comment thread rationai/qc/blur/blur_score_piqe.py

@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: 8

Caution

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

⚠️ Outside diff range comments (2)
docs/getting-started/quality-control.md (2)

193-233: ⚠️ Potential issue | 🟠 Major

The folding walkthrough is out of sync with the shown API.

As written, this section is not runnable: folding is never imported, pixel_size is undefined, local_area_image / img_area / local_area_img are mixed, and the prose below still explains level_downsample / nuclues_diameter_at_base_level even though the example calls folding(..., mpp=1.76, ...).

💡 Proposed fix
+from rationai.qc.folding import folding
 ...
-img = np.asarray(Image.open("fold.png").convert("RGB")) # Investigated image
-local_area_image =img_area = np.asarray(Image.open("fold_area.png").convert("RGB")) # Local area of investigated image
+img = np.asarray(Image.open("fold.png").convert("RGB"))  # Investigated image
+local_area_img = np.asarray(Image.open("fold_area.png").convert("RGB"))  # Local area of investigated image
+mpp = 1.76
 ...
 img_mask = tissue_mask(
-        pyvips.Image.new_from_array(img), mpp=pixel_size).numpy() > 0
+        pyvips.Image.new_from_array(img), mpp=mpp).numpy() > 0
 
 img_area_mask = tissue_mask(
-        pyvips.Image.new_from_array(local_area_img), mpp=pixel_size).numpy() > 0
+        pyvips.Image.new_from_array(local_area_img), mpp=mpp).numpy() > 0
 ...
-The `level_downsample argument` is the downsample rate between the highest resolution level and the level from which the image was taken.
-`nuclues_diameter_at_base_level` specifies the nucleus diameter at the highest resolution level (it can be easily measured when browsing the WSI).
+The `mpp` argument is the pixel size of the analyzed image in micrometers.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/getting-started/quality-control.md` around lines 193 - 233, The
walkthrough is broken: update the sample to import the actual folding API (e.g.,
add from rationai.artifacts import folding), define pixel_size (or consistently
use mpp) and pass it into tissue_mask, and consistently name the local area
variables (use local_area_image everywhere, not img_area/local_area_img); also
align the prose with the call by removing or updating the outdated mentions of
level_downsample/nuclues_diameter_at_base_level (or describe mpp and
nucleus_diameter_at_base_level if those args are used) so the example and
documentation refer to the same parameters and names.

83-117: ⚠️ Potential issue | 🟡 Minor

Import blur_score_piqe before calling it in the sample.

This example invokes blur_score_piqe(...) three times, but the import block never brings that symbol into scope, so the snippet raises NameError.

💡 Proposed fix
 import pyvips
 from rationai.masks import tissue_mask
+from rationai.qc.blur import blur_score_piqe
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/getting-started/quality-control.md` around lines 83 - 117, Add the
missing import for blur_score_piqe (e.g., add "from rationai.blur import
blur_score_piqe" to the top import block) so blur_score_piqe is in scope before
it's called; also avoid shadowing the tissue_mask function by renaming the mask
variable (e.g., mask = tissue_mask(...).numpy()) and use that renamed variable
when calling blur_score_piqe(img_c, pixel_size, mask).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/mkdocs-build.yml:
- Line 11: Replace the branch reference in the reusable workflow call so it is
pinned to an exact commit SHA instead of using `@main`; locate the `uses:
RationAI/.github/.github/workflows/mkdocs-build.yml@main` entry and update the
suffix to the full commit SHA from the RationAI/.github repository (obtain the
SHA for the desired commit and substitute it, e.g., `@<full-commit-sha>`),
commit the change so the workflow now references an immutable revision.

In @.pre-commit-config.yaml:
- Around line 19-22: Pre-commit currently calls the Ruff hooks (id: ruff and id:
ruff-format) without enabling Ruff's --force-exclude, so pre-commit-staged files
will bypass extend-exclude entries; update the hooks in .pre-commit-config.yaml
so the ruff hook (id: ruff) includes --force-exclude alongside existing args
(e.g., add --force-exclude to the args array where --fix is set) and ensure the
ruff-format hook (id: ruff-format) also runs with --force-exclude so configured
exclusions in .ruff.toml are respected during pre-commit runs.

In `@docs/getting-started/installation.md`:
- Around line 23-29: Update the "uv" tab example in
docs/getting-started/installation.md to use the pip workflow or clarify its
preconditions: either change the shown command from `uv add
git+https://github.com/RationAI/quality-control.git` to the pip-equivalent `uv
pip install git+https://github.com/RationAI/quality-control.git`, or add a brief
note that `uv add` updates pyproject.toml and requires an existing uv project
structure. Ensure you modify the code block inside the "uv" tab (the
triple-backtick bash block) and/or add one short sentence explaining the
difference so users know when to use `uv add` vs `uv pip install`.

In `@docs/getting-started/quality-control.md`:
- Around line 57-63: The example prints use nested double quotes which make the
f-strings invalid; update the two print statements to use either single quotes
for the dict keys or escape the inner quotes so that the f-strings are valid
(e.g., change artifacts["number_of_flagged_pixels"] and
artifacts["number_of_examined_pixels"] to artifacts['number_of_flagged_pixels']
and artifacts['number_of_examined_pixels'] in the print calls). Ensure you only
modify the quote characters in the two print(...) lines and leave the rest (mask
creation and save) unchanged.

In `@pyproject.toml`:
- Line 20: The pyproject dependency entries for rationai-masks and
rationai-staining are unpinned and still reference the GitLab HEAD; update the
dependency strings for both rationai-masks and rationai-staining to pin them to
explicit git revisions using the uv-supported syntax (e.g., append @<rev-or-tag>
after the .git URL or use `@tag`=<tag>) so installs are deterministic and match
the docs; modify the entries that reference "rationai-masks" and
"rationai-staining" accordingly to include a specific commit hash or tag.

In `@rationai/qc/folding/folding.py`:
- Around line 147-164: The non-H&E return path references folding_test but it is
only created inside the hematoxylin_eosin_stained branch; initialize or assign
folding_test before the if so both paths return a defined value—e.g., compute
folding_test using reconstruction(folding_test_markers, thresholded_eosin) or
set folding_test = np.zeros_like(thresholded_eosin, dtype=...) when
hematoxylin_eosin_stained is False so np.count_nonzero(folding_test) and the
returned "folding_per_pixel" are valid (refer to variables folding_test,
reconstruction, thresholded_eosin, hematoxylin_eosin_stained).
- Around line 29-31: The local-threshold branch can call threshold_yen on an
empty array when local_mask or mask have no tissue; update the conditional
around the MaskedArray usage (the branch that uses local_tiles/local_mask and
the fallback using img/mask) to check that MaskedArray(...).compressed() yields
a non-empty array before calling threshold_yen, and if empty fall back to the
other available non-empty compressed array (or a default behavior) so
threshold_yen is never invoked on a zero-length array; reference the existing
symbols local_tiles, local_mask, MaskedArray, threshold_yen, img, and mask to
locate and modify the logic.

In `@rationai/qc/typing.py`:
- Around line 58-62: The docstring for the TypedDict class ResidualArtifacts is
stale — it still says the type exposes a "coverage mask" while the actual field
name artifacts_per_pixel (and type BinaryMask) indicates it's a mask of detected
residual artifacts; update the class docstring to accurately describe that
ResidualArtifacts contains a binary mask of detected residual artifacts and
counts for examined/flagged pixels, ensuring the wording aligns with the
artifacts_per_pixel field and any other fields in ResidualArtifacts.

---

Outside diff comments:
In `@docs/getting-started/quality-control.md`:
- Around line 193-233: The walkthrough is broken: update the sample to import
the actual folding API (e.g., add from rationai.artifacts import folding),
define pixel_size (or consistently use mpp) and pass it into tissue_mask, and
consistently name the local area variables (use local_area_image everywhere, not
img_area/local_area_img); also align the prose with the call by removing or
updating the outdated mentions of
level_downsample/nuclues_diameter_at_base_level (or describe mpp and
nucleus_diameter_at_base_level if those args are used) so the example and
documentation refer to the same parameters and names.
- Around line 83-117: Add the missing import for blur_score_piqe (e.g., add
"from rationai.blur import blur_score_piqe" to the top import block) so
blur_score_piqe is in scope before it's called; also avoid shadowing the
tissue_mask function by renaming the mask variable (e.g., mask =
tissue_mask(...).numpy()) and use that renamed variable when calling
blur_score_piqe(img_c, pixel_size, mask).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97b86365-670a-4c89-bfd9-d1b7a5ae1016

📥 Commits

Reviewing files that changed from the base of the PR and between 9f3ec66 and 82675bf.

⛔ 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
Comment thread .pre-commit-config.yaml Outdated
Comment thread docs/getting-started/installation.md
Comment thread docs/getting-started/quality-control.md Outdated
Comment thread pyproject.toml
Comment thread rationai/qc/folding/folding.py Outdated
Comment thread rationai/qc/folding/folding.py
Comment thread rationai/qc/typing.py
@TomasBalak TomasBalak marked this pull request as draft March 9, 2026 21:02
@TomasBalak TomasBalak marked this pull request as ready for review March 17, 2026 18:09
@TomasBalak TomasBalak requested review from a team March 17, 2026 18:09

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
rationai/qc/folding/folding.py (1)

144-153: ⚠️ Potential issue | 🔴 Critical

Use a 2D boolean zero mask for thresholded_value reset.

Line 149 currently resets thresholded_value with np.zeros(tile.shape), which creates a 3D float array. This causes a runtime TypeError at line 152 when performing bitwise AND operations with 2D boolean masks:

TypeError: ufunc 'bitwise_and' not supported for the input types, and the inputs could not be safely coerced to any supported types

The fix should maintain the 2D boolean shape consistent with thresholded_saturation and thresholded_eosin:

Suggested patch
-        thresholded_value = np.zeros(tile.shape)
+        thresholded_value = np.zeros_like(thresholded_value, dtype=bool)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rationai/qc/folding/folding.py` around lines 144 - 153, The reset of
thresholded_value currently uses np.zeros(tile.shape) producing a 3D float array
and breaking bitwise ops with 2D boolean masks; change the reset to create a 2D
boolean mask instead (e.g. use np.zeros(thresholded_value.shape, dtype=bool) or
np.zeros(tile.shape[:2], dtype=bool)) so thresholded_value remains a 2D boolean
array compatible with the subsequent opening(...) and bitwise AND operations
(see thresholded_value, thresholded_saturation, thresholded_eosin and the
opening(...) call).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/getting-started/quality-control.md`:
- Line 15: Replace the misspellings in the user-facing docs: change "neccessary"
to "necessary" (found in the sentence "The following examples should provide you
with the neccessary information..." near Line 15) and change "computated" to
"computed" (found near Line 121); update both occurrences in
docs/getting-started/quality-control.md so the documentation reads correctly.

---

Outside diff comments:
In `@rationai/qc/folding/folding.py`:
- Around line 144-153: The reset of thresholded_value currently uses
np.zeros(tile.shape) producing a 3D float array and breaking bitwise ops with 2D
boolean masks; change the reset to create a 2D boolean mask instead (e.g. use
np.zeros(thresholded_value.shape, dtype=bool) or np.zeros(tile.shape[:2],
dtype=bool)) so thresholded_value remains a 2D boolean array compatible with the
subsequent opening(...) and bitwise AND operations (see thresholded_value,
thresholded_saturation, thresholded_eosin and the opening(...) call).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 799b67ee-252e-41ab-be2b-5f931fd50319

📥 Commits

Reviewing files that changed from the base of the PR and between 82675bf and f01109b.

📒 Files selected for processing (5)
  • .pre-commit-config.yaml
  • docs/getting-started/installation.md
  • docs/getting-started/quality-control.md
  • rationai/qc/folding/folding.py
  • rationai/qc/typing.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • .pre-commit-config.yaml

Comment thread docs/getting-started/quality-control.md Outdated

@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: 1

🧹 Nitpick comments (1)
docs/getting-started/quality-control.md (1)

106-113: Avoid shadowing tissue_mask in the example snippet.

At Line 106 and Line 110-113, tissue_mask is used as both function and variable name. This is a common Python pitfall for readers who extend the snippet.

💡 Suggested patch
-tissue_mask = tissue_mask(
+tissue_mask_arr = tissue_mask(
         pyvips.Image.new_from_array(img_c), mpp=pixel_size
 ).numpy()

-tissue_mask = (tissue_mask > 0).astype(int) # binarize mask
+tissue_mask_arr = (tissue_mask_arr > 0).astype(int) # binarize mask

 # blur score with tissue mask
-blur_score_c = blur_score_piqe(img_c, pixel_size, tissue_mask)
+blur_score_c = blur_score_piqe(img_c, pixel_size, tissue_mask_arr)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/getting-started/quality-control.md` around lines 106 - 113, The example
shadows the tissue_mask function by reassigning it to a variable; change the
variable name (e.g., tissue_mask_arr or tissue_mask_img) so you do not override
the tissue_mask function, update the binarize line to assign to that new name,
and pass the new variable into blur_score_piqe(img_c, pixel_size,
<new_variable>) to avoid function/variable name collision while keeping
tissue_mask() as the callable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/getting-started/quality-control.md`:
- Around line 3-4: Replace the three phrasing issues in the document: change
"good overview" to "a good overview" where the intro sentence uses that phrase,
change "Function gives" to "The function gives" where the sentence begins with
"Function gives…", and ensure the sentence ending with "of the investigated
image" has a trailing period (replace any variant without a period). Locate
these exact phrases in the text and perform the replacements to improve clarity.

---

Nitpick comments:
In `@docs/getting-started/quality-control.md`:
- Around line 106-113: The example shadows the tissue_mask function by
reassigning it to a variable; change the variable name (e.g., tissue_mask_arr or
tissue_mask_img) so you do not override the tissue_mask function, update the
binarize line to assign to that new name, and pass the new variable into
blur_score_piqe(img_c, pixel_size, <new_variable>) to avoid function/variable
name collision while keeping tissue_mask() as the callable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76d2ff9c-ad2c-4702-b8bd-a572a4deb091

📥 Commits

Reviewing files that changed from the base of the PR and between f01109b and 8bd6373.

📒 Files selected for processing (1)
  • docs/getting-started/quality-control.md

Comment thread docs/getting-started/quality-control.md Outdated

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/getting-started/quality-control.md`:
- Line 57: The mask construction uses Image.fromarray with
artifacts["artifacts_per_pixel"].astype(np.uint8) before scaling, which can
truncate values; change the expression to perform the scaling first and then
cast to uint8 (i.e., multiply the float array by 255, then call
.astype(np.uint8)) so that the mask assignment (the line building mask via
Image.fromarray) uses the scaled-then-cast array; apply the same change for the
other occurrence around line 239 to match the blur examples' safer pattern.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 366120b4-2c7e-4d2e-9ff4-7ba1bc45e170

📥 Commits

Reviewing files that changed from the base of the PR and between 8bd6373 and 69f6b54.

📒 Files selected for processing (1)
  • docs/getting-started/quality-control.md

```python linenums="19"
mask = Image.fromarray(255 * artifacts["coverage_mask"].astype(np.uint8))
```python linenums="18"
mask = Image.fromarray(255 * artifacts["artifacts_per_pixel"].astype(np.uint8))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n docs/getting-started/quality-control.md | sed -n '50,65p;235,245p'

Repository: RationAI/quality-control

Length of output: 1351


🏁 Script executed:

# Also check if the other lines mentioned (132, 135, 138, 144, 147, 150) exist and what patterns they use
cat -n docs/getting-started/quality-control.md | sed -n '130,155p'

Repository: RationAI/quality-control

Length of output: 1042


Cast after scaling when building masks for Image.fromarray.

Lines 57 and 239 apply astype(np.uint8) before the multiplication, which is inconsistent with the safer pattern used in the blur examples (lines 132, 135, 138, 144, 147, 150). Move the cast after the scaling operation to ensure proper type handling.

Suggested patch
-mask = Image.fromarray(255 * artifacts["artifacts_per_pixel"].astype(np.uint8))
+mask = Image.fromarray((255 * artifacts["artifacts_per_pixel"]).astype(np.uint8))
-mask = Image.fromarray(255 * artifacts["folding_per_pixel"].astype(np.uint8))
+mask = Image.fromarray((255 * artifacts["folding_per_pixel"]).astype(np.uint8))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/getting-started/quality-control.md` at line 57, The mask construction
uses Image.fromarray with artifacts["artifacts_per_pixel"].astype(np.uint8)
before scaling, which can truncate values; change the expression to perform the
scaling first and then cast to uint8 (i.e., multiply the float array by 255,
then call .astype(np.uint8)) so that the mask assignment (the line building mask
via Image.fromarray) uses the scaled-then-cast array; apply the same change for
the other occurrence around line 239 to match the blur examples' safer pattern.

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