Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refactor image utility functions and enhance documentation #154

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

jjjermiah
Copy link
Contributor

@jjjermiah jjjermiah commented Dec 25, 2024

Improve type annotations, error messages, and documentation across various modules, while updating mypy and ruff configurations for better type checking and linting. Add tests for the StructureSet class to ensure reliability.

Summary by CodeRabbit

  • New Features

    • Enhanced documentation for the segmentation.py and structureset.py modules, detailing class functionalities and methods.
    • New methods added to the StructureSet class for DICOM RTSTRUCT file handling.
    • New utility functions for image processing in imageutils.py.
  • Bug Fixes

    • Improved error handling in various methods across modules.
  • Tests

    • Added comprehensive unit tests for the StructureSet class, covering various scenarios and edge cases.

Copy link
Contributor

coderabbitai bot commented Dec 25, 2024

Walkthrough

This pull request introduces comprehensive documentation and type improvements across several modules in the imgtools project. The changes focus on enhancing type annotations, adding detailed docstrings, and expanding type checking configurations. Key modifications include updates to configuration files like mypy.ini and ruff.toml, significant documentation improvements in segmentation.py and structureset.py, and new utility functions in imageutils.py. A corresponding test suite for structureset.py has also been added to validate the new functionality.

Changes

File Change Summary
config/mypy.ini Added type checking for src/imgtools/modules/**/*.py
config/ruff.toml Added src/imgtools/modules/segmentation.py to include, removed src/imgtools/modules/**/*.py from exclude, added EM101 linting rule
src/imgtools/modules/segmentation.py Enhanced documentation, added type hints to accepts_segmentations and map_over_labels functions
src/imgtools/modules/structureset.py Added comprehensive docstrings, new constructor, from_dicom_rtstruct method, improved error handling
src/imgtools/utils/imageutils.py Added new functions image_to_array, idxs_to_physical_points, enhanced physical_points_to_idxs
tests/modules/test_structureset.py Added comprehensive test suite for StructureSet class with multiple fixtures and test scenarios

Sequence Diagram

sequenceDiagram
    participant User
    participant StructureSet
    participant DICOM
    User->>StructureSet: from_dicom_rtstruct(path)
    StructureSet->>DICOM: Read RTSTRUCT file
    DICOM-->>StructureSet: Return ROI data
    StructureSet->>StructureSet: Extract ROI points
    StructureSet-->>User: Return StructureSet instance
Loading

Possibly related PRs

Suggested reviewers

  • skim2257
  • strixy16

Poem

🐰 Hop, hop, through code so bright,
Type hints dancing with delight!
Docstrings bloom like spring's first flower,
Modules shine with newfound power.
Rabbit's code review takes flight! 🚀

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (6)
src/imgtools/utils/imageutils.py (2)

1-2: Use direct imports for clarity.

Currently, you're importing List and Tuple from the typing module. Consider directly using list and tuple in modern Python (3.9+), which supports these as type hints without needing from typing import List, Tuple.


36-92: Vectorized transformation may cause high memory usage for large point sets.

Using np.vectorize on lists of 3D points can simplify code, but be cautious about performance and memory usage if points becomes large. For extremely large sets, consider a streaming/batched approach to avoid potential memory overhead.

src/imgtools/modules/segmentation.py (1)

66-112: Decorator logic is clear; consider surfacing transformation details in docstring.

accepts_segmentations preserves Segmentation ROI indices and raw ROI names, which is excellent. You might consider clarifying in the docstring that the function automatically casts output to VectorUInt8.

src/imgtools/modules/structureset.py (2)

266-267: Refactor the pattern iteration logic
There's a TODO comment about refactoring this logic to use a generator for better readability. Refactoring _assign_labels into smaller, dedicated functions or generators could reduce complexity and improve testability.


329-329: Improve exception re-raising style
When re-raising exceptions inside an except block, it’s considered best practice to use raise ... from None or raise ... from err to clarify the exception chain. This helps differentiate between the original error and subsequent handling errors.

Possible minimal changes:

-            raise IndexError(f'{z} index is out of bounds for image sized {mask.shape}.')
+            raise IndexError(f'{z} index is out of bounds for image sized {mask.shape}.') from None

-            raise ValueError('This contour is corrupted and spans across 2 or more slices.')
+            raise ValueError('This contour is corrupted and spans across 2 or more slices.') from None

Also applies to: 337-337

🧰 Tools
🪛 Ruff (0.8.2)

329-329: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

tests/modules/test_structureset.py (1)

137-139: Duplicate docstring
Lines 137 and 139 both appear to declare the same docstring, creating redundancy. Removing the duplicate improves clarity.

 def test_from_dicom_rtstruct(mock_dcmread):
-    """Test from_dicom_rtstruct method with mocked DICOM file."""
     """Test from_dicom_rtstruct method with mocked DICOM file."""
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41a7c88 and faf16e3.

📒 Files selected for processing (6)
  • config/mypy.ini (1 hunks)
  • config/ruff.toml (3 hunks)
  • src/imgtools/modules/segmentation.py (1 hunks)
  • src/imgtools/modules/structureset.py (1 hunks)
  • src/imgtools/utils/imageutils.py (1 hunks)
  • tests/modules/test_structureset.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
src/imgtools/modules/segmentation.py

56-56: typing.Dict imported but unused

Remove unused import: typing.Dict

(F401)

tests/modules/test_structureset.py

4-4: typing.Dict imported but unused

Remove unused import

(F401)


4-4: typing.List imported but unused

Remove unused import

(F401)


5-5: pydicom.dataset.Dataset imported but unused

Remove unused import: pydicom.dataset.Dataset

(F401)

src/imgtools/modules/structureset.py

323-323: Do not use bare except

(E722)


329-329: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


337-337: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🔇 Additional comments (9)
src/imgtools/utils/imageutils.py (2)

11-33: Comprehensive docstring and accurate return types.

The image_to_array function provides a clear docstring and robust type hints, ensuring a strong contract for users. This is a best practice for maintainability and clarity.


94-117: Good docstring; consider adding edge-case handling.

The idxs_to_physical_points function provides thorough documentation. If idxs is empty or has an unexpected shape, consider adding input validation or error handling to improve robustness.

src/imgtools/modules/segmentation.py (2)

1-50: Excellent top-level documentation.

The module-level docstring thoroughly describes the purpose, classes, and functions. This is a great practice to help new contributors understand the functionality quickly.


114-172: Well-organized function with thorough parameter documentation.

map_over_labels sets a high documentation standard by detailing behavior, usage, and examples. The step of optionally returning a new Segmentation object is especially clear.

config/mypy.ini (1)

6-7: Good expansion of type-checking coverage.

Including src/imgtools/modules/**/*.py broadens the type coverage of your project. This ensures new modules, such as those in segmentation.py, are validated by mypy.

config/ruff.toml (3)

7-8: Strategic inclusion for segmentation lint checks.

Adding src/imgtools/modules/segmentation.py to the include list ensures coverage under linting rules. This complements the mypy inclusion for thorough code quality control.


24-24: Extend-include reformatting looks consistent.

No issues detected. The single line for extend-include is structurally coherent and maintains readability.


105-106: Newly ignored rule EM101.

Adding EM101 to the ignore list can be helpful if your team has a specific style or pattern for error messages. Confirm that this rule’s suppression aligns with your project’s best practices.

src/imgtools/modules/structureset.py (1)

1-29: Comprehensive module docstring
The high-level overview and usage examples provide clear context for the StructureSet class. This thorough documentation enhances maintainability and helps new contributors quickly understand the module's purpose.

Comment on lines +52 to +56
from __future__ import annotations

import warnings
from functools import wraps
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove unused Dict import.

Static analysis indicates that typing.Dict is never referenced. Removing unused imports helps keep the code clean and reduces confusion.

- from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+ from typing import Any, Callable, List, Optional, Tuple, Union
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from __future__ import annotations
import warnings
from functools import wraps
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
from __future__ import annotations
import warnings
from functools import wraps
from typing import Any, Callable, List, Optional, Tuple, Union
🧰 Tools
🪛 Ruff (0.8.2)

56-56: typing.Dict imported but unused

Remove unused import: typing.Dict

(F401)

Comment on lines +323 to +324
except: # rounding errors for points on the boundary
if z == mask.shape[0]:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Avoid bare except
Catching all exceptions masks the root cause and can make debugging harder. To address this, catch specific exception types or use except Exception as e:. Additionally, consider chaining the exception properly to preserve its traceback.

Below is a suggested fix:

-        except:  # rounding errors for points on the boundary
+        except Exception as exc:
+            logger.debug("Caught an unexpected exception for boundary rounding", error=exc)
             if z == mask.shape[0]:
                 ...

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff (0.8.2)

323-323: Do not use bare except

(E722)

Comment on lines +4 to +5
from typing import Dict, List
from pydicom.dataset import Dataset
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused imports
Dict, List, and Dataset imports are unused, per static analysis hints. Removing them helps keep the file clean and avoids confusion.

-from typing import Dict, List
-from pydicom.dataset import Dataset
+from typing import Any

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff (0.8.2)

4-4: typing.Dict imported but unused

Remove unused import

(F401)


4-4: typing.List imported but unused

Remove unused import

(F401)


5-5: pydicom.dataset.Dataset imported but unused

Remove unused import: pydicom.dataset.Dataset

(F401)

Copy link

codecov bot commented Dec 25, 2024

Codecov Report

Attention: Patch coverage is 69.23077% with 60 lines in your changes missing coverage. Please review.

Project coverage is 44.82%. Comparing base (41a7c88) to head (faf16e3).

Files with missing lines Patch % Lines
src/imgtools/modules/structureset.py 73.85% 40 Missing ⚠️
src/imgtools/modules/segmentation.py 27.27% 16 Missing ⚠️
src/imgtools/utils/imageutils.py 80.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #154      +/-   ##
==========================================
+ Coverage   44.03%   44.82%   +0.78%     
==========================================
  Files          48       48              
  Lines        3540     3558      +18     
==========================================
+ Hits         1559     1595      +36     
+ Misses       1981     1963      -18     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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