Skip to content

chore: Add Python 3.13 to supported versions#1327

Merged
Czaki merged 15 commits intodevelopfrom
add_python_3_13
Dec 15, 2025
Merged

chore: Add Python 3.13 to supported versions#1327
Czaki merged 15 commits intodevelopfrom
add_python_3_13

Conversation

@Czaki
Copy link
Collaborator

@Czaki Czaki commented Oct 22, 2025

Summary by Sourcery

Add Python 3.13 support by updating CI workflows and project metadata and bump the development version.

Enhancements:

  • Enable compatibility with Python 3.13 across the project.

CI:

  • Include Python 3.13 in the GitHub Actions test matrix for both job configurations.

Documentation:

  • Add Python 3.13 to the project’s Python classifiers in pyproject.toml.

Chores:

  • Bump the fallback development version to 0.16.4dev0.

Summary by CodeRabbit

  • New Features

    • Added official Python 3.13 support across CI, tox, and packaging.
  • Chores

    • Added Python 3.13 constraints file and classifier; bumped internal tooling fallback version and adjusted napari PySide6 dependency.
  • Bug Fixes

    • Improved timeout handling to flush writer data and provide clearer failure diagnostics; standardized error serialization for queued exceptions.
  • Tests

    • Added/updated tests for error serialization and batch-processing robustness.

✏️ Tip: You can customize this high-level summary in your review settings.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Oct 22, 2025

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR adds support for Python 3.13 by updating the CI test matrices in GitHub Actions and updating project metadata to reflect the new version and classifier.

File-Level Changes

Change Details Files
Include Python 3.13 in CI test matrix
  • Add “3.13” to python_version lists in both test job matrices
.github/workflows/tests.yml
Bump development version and add Python 3.13 classifier
  • Update fallback_version to 0.16.4dev0
  • Add “Programming Language :: Python :: 3.13” to project classifiers
pyproject.toml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

Walkthrough

Adds Python 3.13 across CI, tox, dependency compilation, and packaging; introduces ErrorInfo and error-preparation helpers in PartSegCore.utils, updates batch-processing to use the shared error representation, and adjusts tests to exercise the new error serialization and timeout behavior.

Changes

Cohort / File(s) Summary
CI Workflows
.github/workflows/tests.yml, .github/workflows/upgrade-dependencies.yml
Added Python 3.13 to test and upgrade matrices; upgrade loop includes 3.13.
Packaging / Metadata
pyproject.toml
Added Programming Language :: Python :: 3.13 classifier, bumped [tool.setuptools_scm] fallback_version 0.16.3dev00.16.5dev0, and changed napari[pyside6_experimental]>=0.5.0napari[pyside6]>=0.5.0.
Dependency Constraints
requirements/constraints_py3.13.txt
Added autogenerated pinned constraints file for Python 3.13 with provenance comments.
Test harness (tox)
tox.ini
Added py313/313 to envlists and gh-actions mappings; expanded testenv selectors to include 313.
Core utils / types
package/PartSegCore/utils.py
Modernized typing to PEP 604 (`A
Batch processing (backends)
package/PartSegCore/analysis/batch_processing/batch_backend.py, package/PartSegCore/analysis/batch_processing/parallel_backend.py
Replaced local error serialization with shared ErrorInfo and prepare_error_data imports; adjusted result/type aliases and exception handling to push prepared error payloads.
Tests
package/tests/test_PartSeg/test_sentry.py, package/tests/test_PartSegCore/test_analysis_batch.py, package/tests/test_PartSegCore/test_utils.py
Updated imports to use prepare_error_data from PartSegCore.utils; modified test signatures and timeout handling to dump writer data before kill; added test asserting prepare_error_data serializability via multiprocessing.Queue.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Focus review on:
    • package/PartSegCore/utils.py (new functions, type-hint changes, public API surface).
    • batch_backend.py and parallel_backend.py (error payload format and any assumptions about traceback structure).
    • requirements/constraints_py3.13.txt (verify autogenerated pins as intended).

Possibly related PRs

Poem

🐇 I hopped through CI and found a door,
3.13 now colors the testing floor.
Errors packed neatly for queue and play,
Constraints pinned tight to guide the way.
Nibble on carrots — code hops evermore! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main objective of the changeset: adding Python 3.13 support across workflows, dependencies, and project metadata.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add_python_3_13

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bda3eb and c337660.

📒 Files selected for processing (1)
  • package/tests/test_PartSeg/test_sentry.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
package/tests/test_PartSeg/test_sentry.py (1)
package/PartSegCore/utils.py (2)
  • prepare_error_data (509-518)
  • safe_repr (485-492)
🪛 GitHub Check: Codacy Static Code Analysis
package/tests/test_PartSeg/test_sentry.py

[notice] 51-51: package/tests/test_PartSeg/test_sentry.py#L51
Unused variable 'a'

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: repo py3.12
  • GitHub Check: repo py3.10
  • GitHub Check: repo py3.11
  • GitHub Check: Base py3.11 / windows-latest py 3.11 latest PyQt5
  • GitHub Check: Base py3.11 / macos-15-intel py 3.11 latest PyQt5
  • GitHub Check: test_coverage / ubuntu-24.04 py 3.12 latest PyQt5
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test windows)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test macos)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller_linux)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller windows)
  • GitHub Check: 4DNucleome.PartSeg (Builds sdist)
  • GitHub Check: 4DNucleome.PartSeg (Tests_linux test_linux)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos)
  • GitHub Check: 4DNucleome.PartSeg (GetTestData linux)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check help)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check Notebook_check)
  • GitHub Check: 4DNucleome.PartSeg (formatting_check check_formating)
  • GitHub Check: 4DNucleome.PartSeg (manifest_check manifest_check)
  • GitHub Check: Sourcery review
  • GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (2)
package/tests/test_PartSeg/test_sentry.py (2)

13-13: LGTM! Import consolidation improves code organization.

The move of prepare_error_data and safe_repr to PartSegCore.utils centralizes utility functions and improves maintainability.


51-51: LGTM! Multi-assignment pattern is clear and correct.

The multi-assignment approach explicitly creates the local variables needed to test Sentry's variable capture limits, which is more maintainable than the previous implementation.

Note: The static analysis warning about unused variable 'a' on line 51 is a false positive. These variables are intentionally created to populate the local scope for testing Sentry's MAX_DATABAG_BREADTH behavior when capturing exception context.

Also applies to: 65-66


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.

@codecov
Copy link

codecov bot commented Oct 22, 2025

Codecov Report

❌ Patch coverage is 96.15385% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.15%. Comparing base (f4e594e) to head (c337660).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
package/PartSegCore/utils.py 96.55% 1 Missing ⚠️
package/tests/test_PartSegCore/test_utils.py 93.33% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1327      +/-   ##
===========================================
- Coverage    93.17%   93.15%   -0.02%     
===========================================
  Files          210      210              
  Lines        33232    33251      +19     
===========================================
+ Hits         30964    30976      +12     
- Misses        2268     2275       +7     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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: 0

🧹 Nitpick comments (1)
tox.ini (1)

105-105: Minor: Fix inconsistent spacing in testenv key.

Line 105 has inconsistent spacing between key components: PyQt5, PySide2 (space after PyQt5 comma) vs. PySide2,PyQt6 (no space).

Apply this formatting fix:

-[testenv:py{39,310,311,312,313}-{PyQt5, PySide2,PyQt6,PySide6}-azure]
+[testenv:py{39,310,311,312,313}-{PyQt5,PySide2,PyQt6,PySide6}-azure]
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ad9f861 and 1386217.

📒 Files selected for processing (5)
  • .github/workflows/tests.yml (2 hunks)
  • .github/workflows/upgrade-dependencies.yml (1 hunks)
  • pyproject.toml (3 hunks)
  • requirements/constraints_py3.13.txt (1 hunks)
  • tox.ini (5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-10-08T20:57:48.839Z
Learnt from: Czaki
PR: 4DNucleome/PartSeg#1117
File: .github/workflows/make_release.yml:46-47
Timestamp: 2024-10-08T20:57:48.839Z
Learning: The `requirements/constraints_py3.10.txt` file is used to pin the versions of dependencies in the `pip install` command for the PartSeg project.

Applied to files:

  • requirements/constraints_py3.13.txt
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: Base py3.11 / windows-latest py 3.11 latest PyQt5
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test windows)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test macos)
  • GitHub Check: 4DNucleome.PartSeg (Tests_linux test_linux)
  • GitHub Check: repo py3.12
  • GitHub Check: repo py3.10
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller windows)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos_arm)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos)
  • GitHub Check: 4DNucleome.PartSeg (Builds sdist)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller_linux)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check help)
  • GitHub Check: 4DNucleome.PartSeg (GetTestData linux)
  • GitHub Check: 4DNucleome.PartSeg (manifest_check manifest_check)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check Notebook_check)
  • GitHub Check: 4DNucleome.PartSeg (formatting_check check_formating)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Sourcery review
🔇 Additional comments (7)
.github/workflows/upgrade-dependencies.yml (1)

38-41: Python 3.13 addition looks good.

The loop correctly iterates over Python 3.13 alongside existing versions, and the uv pip compile commands will generate the corresponding constraints file.

.github/workflows/tests.yml (1)

57-57: Python 3.13 test matrix expansion is consistent.

Both test job matrices (base-test and base-test-main) correctly include Python 3.13, aligned with the PR objective.

Also applies to: 100-100

tox.ini (1)

7-7: Python 3.13 tox environment setup is consistent and complete.

The envlist, gh-actions mapping, and testenv definitions properly extend support to Python 3.13 across all variations (PyQt5, PySide2, PyQt6, PySide6, napari versions, and coverage/azure/minimal configurations).

Also applies to: 16-16, 74-74, 84-84

requirements/constraints_py3.13.txt (1)

1-5: Autogenerated constraints file is properly formatted.

The constraints file follows the standard format with proper dependency tracking via comments. Generated command and metadata are clearly documented at the top.

pyproject.toml (3)

8-8: Version bump discrepancy between PR objective and code.

The PR objective states the fallback_version should be bumped to 0.16.4dev0, but the code shows 0.16.5dev0. Please confirm which value is correct.


26-26: Python 3.13 classifier is correctly added.

The classifier follows the established pattern for other Python versions.


139-139: Verify napari dependency change rationale.

Line 139 changes napari[pyside6_experimental]>=0.5.0 to napari[pyside6]>=0.5.0. This change is not mentioned in the PR objective for Python 3.13 support. Please confirm whether this is:

  1. Required for Python 3.13 compatibility, or
  2. A separate dependency update that should be documented

@Czaki Czaki added this to the 0.16.5 milestone Oct 22, 2025
@sonarqubecloud
Copy link

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

🧹 Nitpick comments (5)
package/tests/test_PartSegCore/test_utils.py (1)

374-384: Consider adding assertions on the error data structure.

The test verifies that prepare_error_data output can be queued, but only asserts item[0] == 1. Consider adding assertions to verify the structure of prepped_exc matches the expected ErrorInfo format (a tuple containing the exception and serialized data).

The broad except Exception (BLE001) is appropriate here since the test intentionally catches any exception type to validate prepare_error_data handling.

     item = q.get(timeout=1)
     assert item[0] == 1
+    prepped = item[1][0]
+    assert isinstance(prepped, tuple)
+    assert len(prepped) == 2
+    assert isinstance(prepped[0], ValueError)
package/PartSegCore/analysis/batch_processing/parallel_backend.py (1)

280-281: Inconsistent error handling in spawn_worker.

The exception handler in spawn_worker (line 281) still uses the old traceback.extract_tb approach, while BatchWorker.calculate_task (line 235) now uses prepare_error_data. For consistency, consider updating this handler as well.

     except Exception as e:  # pragma: no cover # pylint: disable=broad-except
-        result_queue.put(("-1", (-1, [(e, traceback.extract_tb(e.__traceback__))])))
+        result_queue.put(("-1", (-1, [prepare_error_data(e)])))

This would also allow removing the import traceback at line 22 if it's no longer needed elsewhere.

package/PartSegCore/utils.py (3)

63-132: Callback helpers: behavior unchanged; consider minor type-hint polish

The updated int | None logic in _inspect_signature and the use of MethodType in get_callback look consistent with how callbacks are sliced and dispatched. For extra clarity and type-checker friendliness, you could also:

  • Annotate max_args in get_callback as int | None.
  • Annotate method in CallbackMethod.__init__ as MethodType.

This is purely cosmetic and doesn’t affect runtime behavior.

-class CallbackMethod(CallbackBase):
-    def __init__(self, method, max_args: int | None = None):
+class CallbackMethod(CallbackBase):
+    def __init__(self, method: MethodType, max_args: int | None = None):
@@
-def get_callback(callback: typing.Callable | MethodType, max_args=None) -> CallbackBase:
+def get_callback(callback: typing.Callable | MethodType, max_args: int | None = None) -> CallbackBase:

293-405: ProfileDict: new union annotations align with usage; unify key_path types for consistency

The updated annotations for my_dict, update, connect, set, and _call_callback all match the existing runtime behavior and are more expressive. get still uses key_path: list | str while set/connect accept typing.Sequence[str] | str; functionally this already works with any iterable, but for symmetry and cleaner typing you might want to declare get’s key_path as Sequence[str] | str as well.

-    def get(self, key_path: list | str, default=None):
+    def get(self, key_path: typing.Sequence[str] | str, default=None):

466-482: napari_image_repr implementation is fine but now duplicated across modules

The new napari_image_repr(image: Image) -> str matches the implementation shown in package/PartSegImage/image.py (per provided snippet), which introduces duplication and a risk of future divergence. If import topology allows, consider centralizing this helper in a single place (e.g., keep it here in PartSegCore.utils and have PartSegImage.image import and re-export it, or move both to a small shared napari-utility module).

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0ef52e and 6bda3eb.

📒 Files selected for processing (9)
  • .github/workflows/tests.yml (2 hunks)
  • .github/workflows/upgrade-dependencies.yml (1 hunks)
  • package/PartSegCore/analysis/batch_processing/batch_backend.py (2 hunks)
  • package/PartSegCore/analysis/batch_processing/parallel_backend.py (2 hunks)
  • package/PartSegCore/utils.py (14 hunks)
  • package/tests/test_PartSeg/test_sentry.py (1 hunks)
  • package/tests/test_PartSegCore/test_analysis_batch.py (2 hunks)
  • package/tests/test_PartSegCore/test_utils.py (3 hunks)
  • tox.ini (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • .github/workflows/upgrade-dependencies.yml
  • .github/workflows/tests.yml
  • tox.ini
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Czaki
Repo: 4DNucleome/PartSeg PR: 1307
File: examples/dilate_segmentation_mask.py:0-0
Timestamp: 2025-10-15T11:26:16.151Z
Learning: In the PartSeg project, the minimum supported numpy version is 1.22.2, with a restriction to numpy<2 for Python versions below 3.10. Features from newer numpy versions (e.g., numpy 2.3) should be avoided to maintain backward compatibility.
🧬 Code graph analysis (5)
package/tests/test_PartSegCore/test_utils.py (1)
package/PartSegCore/utils.py (1)
  • prepare_error_data (509-518)
package/PartSegCore/analysis/batch_processing/batch_backend.py (1)
package/PartSegCore/utils.py (1)
  • prepare_error_data (509-518)
package/tests/test_PartSeg/test_sentry.py (1)
package/PartSegCore/utils.py (2)
  • prepare_error_data (509-518)
  • safe_repr (485-492)
package/PartSegCore/utils.py (1)
package/PartSegImage/image.py (1)
  • Image (198-1034)
package/tests/test_PartSegCore/test_analysis_batch.py (1)
package/PartSegCore/analysis/batch_processing/batch_backend.py (5)
  • CalculationManager (444-544)
  • dump_data (764-773)
  • kill_jobs (501-502)
  • has_work (495-499)
  • writing_finished (942-944)
🪛 Ruff (0.14.8)
package/tests/test_PartSegCore/test_utils.py

370-370: Avoid specifying long messages outside the exception class

(TRY003)


379-379: Do not catch blind exception: Exception

(BLE001)

package/PartSegCore/utils.py

511-511: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


512-512: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test windows)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test macos)
  • GitHub Check: 4DNucleome.PartSeg (Tests_linux test_linux)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller windows)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos_arm)
  • GitHub Check: 4DNucleome.PartSeg (Builds sdist)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller_linux)
  • GitHub Check: Base py3.12 / ubuntu-24.04 py 3.12 latest PyQt5
  • GitHub Check: Base py3.10 / ubuntu-24.04 py 3.10 latest PyQt5
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check Notebook_check)
  • GitHub Check: 4DNucleome.PartSeg (manifest_check manifest_check)
  • GitHub Check: 4DNucleome.PartSeg (GetTestData linux)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check help)
  • GitHub Check: 4DNucleome.PartSeg (formatting_check check_formating)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Sourcery review
🔇 Additional comments (9)
package/tests/test_PartSeg/test_sentry.py (1)

13-13: LGTM!

The import relocation aligns with the refactor that moves prepare_error_data and safe_repr to the central PartSegCore.utils module.

package/tests/test_PartSegCore/test_utils.py (2)

3-3: LGTM!

The new imports are correctly added to support the prepare_error_data test functionality.

Also applies to: 17-17


368-371: LGTM!

The helper function correctly creates a deep exception stack for testing prepare_error_data. The static analysis hint about the long exception message (TRY003) is acceptable for test code.

package/PartSegCore/analysis/batch_processing/parallel_backend.py (2)

33-33: LGTM!

The import of prepare_error_data from PartSegCore.utils aligns with the centralization of error handling utilities.


235-235: LGTM!

The error handling now uses the centralized prepare_error_data function for consistent error serialization.

package/tests/test_PartSegCore/test_analysis_batch.py (2)

456-456: LGTM!

Adding type hints to wait_for_calculation improves code clarity and IDE support.


466-474: LGTM! Improved hang detection and debugging.

The enhanced error handling provides valuable diagnostic information when calculations hang:

  • Dumping file writer data preserves partial results for analysis
  • kill_jobs() ensures proper cleanup
  • The detailed failure message includes work status, task count, queue state, and writing status

This will significantly aid debugging CI hang issues.

package/PartSegCore/analysis/batch_processing/batch_backend.py (2)

72-72: LGTM!

The import correctly sources ErrorInfo and prepare_error_data from the centralized PartSegCore.utils module, eliminating code duplication.


94-95: LGTM!

The type aliases correctly use the imported ErrorInfo type, maintaining type safety while leveraging the centralized definition.

Comment on lines +495 to +517
def pre_prepare_traceback_for_queue(exc: BaseException) -> StackSummary:
"""
Prepare exception for sending it through the multiprocessing queue.

:param exc: exception to prepare
:return: prepared exception
"""
traceback_list = traceback.extract_tb(exc.__traceback__)
for el in traceback_list:
if hasattr(el, "_code"):
del el._code
return traceback_list


def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize # noqa: PLC0415
from sentry_sdk.utils import event_from_exception # noqa: PLC0415

event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
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 | 🟡 Minor

Error serialization helpers look solid; drop or adjust unused noqa directives

The ErrorInfo alias plus pre_prepare_traceback_for_queue and prepare_error_data give a clear, queue‑friendly error payload, and the StackSummary usage looks correct. One small issue: Ruff flags the # noqa: PLC0415 comments on the inner imports as unused (RUF100, non-enabled code PLC0415).

To keep linters happy, either remove these noqa markers or convert them to tool-specific directives (e.g. # pylint: disable=import-outside-toplevel) if you still need to silence Pylint.

-        from sentry_sdk.serializer import serialize  # noqa: PLC0415
-        from sentry_sdk.utils import event_from_exception  # noqa: PLC0415
+        from sentry_sdk.serializer import serialize
+        from sentry_sdk.utils import event_from_exception

As per static analysis hints (Ruff RUF100).

📝 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
def pre_prepare_traceback_for_queue(exc: BaseException) -> StackSummary:
"""
Prepare exception for sending it through the multiprocessing queue.
:param exc: exception to prepare
:return: prepared exception
"""
traceback_list = traceback.extract_tb(exc.__traceback__)
for el in traceback_list:
if hasattr(el, "_code"):
del el._code
return traceback_list
def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize # noqa: PLC0415
from sentry_sdk.utils import event_from_exception # noqa: PLC0415
event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
def pre_prepare_traceback_for_queue(exc: BaseException) -> StackSummary:
"""
Prepare exception for sending it through the multiprocessing queue.
:param exc: exception to prepare
:return: prepared exception
"""
traceback_list = traceback.extract_tb(exc.__traceback__)
for el in traceback_list:
if hasattr(el, "_code"):
del el._code
return traceback_list
def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize
from sentry_sdk.utils import event_from_exception
event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
🧰 Tools
🪛 Ruff (0.14.8)

511-511: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


512-512: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In package/PartSegCore/utils.py around lines 495 to 517, the inner imports use
unused `# noqa: PLC0415` markers which Ruff flags (RUF100); either remove those
`noqa` markers entirely (preferred) or replace them with the explicit pylint
directive `# pylint: disable=import-outside-toplevel` if you must silence an
import-outside-toplevel warning, ensuring no unused lint codes remain.

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

🧹 Nitpick comments (1)
package/PartSegCore/analysis/batch_processing/parallel_backend.py (1)

235-235: Good standardization of error payload format.

Using prepare_error_data(e) standardizes the error payload format in the worker's exception handling, ensuring consistent error serialization with sentry support.

Consider updating the spawn_worker exception handler for consistency.

Line 281 in the spawn_worker function still uses the old format (e, traceback.extract_tb(e.__traceback__)) instead of prepare_error_data(e). For consistency, consider updating this as well.

     except Exception as e:  # pragma: no cover # pylint: disable=broad-except
-        result_queue.put(("-1", (-1, [(e, traceback.extract_tb(e.__traceback__))])))
+        result_queue.put(("-1", (-1, [prepare_error_data(e)])))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0ef52e and 6bda3eb.

📒 Files selected for processing (9)
  • .github/workflows/tests.yml (2 hunks)
  • .github/workflows/upgrade-dependencies.yml (1 hunks)
  • package/PartSegCore/analysis/batch_processing/batch_backend.py (2 hunks)
  • package/PartSegCore/analysis/batch_processing/parallel_backend.py (2 hunks)
  • package/PartSegCore/utils.py (14 hunks)
  • package/tests/test_PartSeg/test_sentry.py (1 hunks)
  • package/tests/test_PartSegCore/test_analysis_batch.py (2 hunks)
  • package/tests/test_PartSegCore/test_utils.py (3 hunks)
  • tox.ini (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/tests.yml
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Czaki
Repo: 4DNucleome/PartSeg PR: 1307
File: examples/dilate_segmentation_mask.py:0-0
Timestamp: 2025-10-15T11:26:16.151Z
Learning: In the PartSeg project, the minimum supported numpy version is 1.22.2, with a restriction to numpy<2 for Python versions below 3.10. Features from newer numpy versions (e.g., numpy 2.3) should be avoided to maintain backward compatibility.
Learnt from: Czaki
Repo: 4DNucleome/PartSeg PR: 1206
File: package/PartSegCore/image_transforming/transform_base.py:2-2
Timestamp: 2024-10-09T13:08:00.401Z
Learning: The project supports Python 3.9+ but not 3.10+, so features introduced in Python 3.10 like the `|` operator for type annotations cannot be used.
📚 Learning: 2024-10-08T20:57:48.839Z
Learnt from: Czaki
Repo: 4DNucleome/PartSeg PR: 1117
File: .github/workflows/make_release.yml:46-47
Timestamp: 2024-10-08T20:57:48.839Z
Learning: The `requirements/constraints_py3.10.txt` file is used to pin the versions of dependencies in the `pip install` command for the PartSeg project.

Applied to files:

  • .github/workflows/upgrade-dependencies.yml
🧬 Code graph analysis (5)
package/PartSegCore/analysis/batch_processing/parallel_backend.py (1)
package/PartSegCore/utils.py (1)
  • prepare_error_data (509-518)
package/tests/test_PartSeg/test_sentry.py (1)
package/PartSegCore/utils.py (2)
  • prepare_error_data (509-518)
  • safe_repr (485-492)
package/PartSegCore/analysis/batch_processing/batch_backend.py (1)
package/PartSegCore/utils.py (2)
  • iterate_names (466-475)
  • prepare_error_data (509-518)
package/tests/test_PartSegCore/test_analysis_batch.py (1)
package/PartSegCore/analysis/batch_processing/batch_backend.py (4)
  • dump_data (764-773)
  • kill_jobs (501-502)
  • has_work (495-499)
  • writing_finished (942-944)
package/tests/test_PartSegCore/test_utils.py (1)
package/PartSegCore/utils.py (1)
  • prepare_error_data (509-518)
🪛 GitHub Actions: Tests
package/tests/test_PartSeg/test_sentry.py

[error] 49-59: Sentry data bag clipping test failed: expected MAX_DATABAG_BREADTH of 10 but got 4 in first clipped vars result.


[error] 64-76: Sentry data bag clipping breadth test failed: after increasing MAX_DATABAG_BREADTH to 100, expected all letters to be present in vars, but some were missing.

🪛 Ruff (0.14.8)
package/tests/test_PartSegCore/test_utils.py

370-370: Avoid specifying long messages outside the exception class

(TRY003)


379-379: Do not catch blind exception: Exception

(BLE001)

package/PartSegCore/utils.py

511-511: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


512-512: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test windows)
  • GitHub Check: 4DNucleome.PartSeg (Tests_other test macos)
  • GitHub Check: 4DNucleome.PartSeg (Tests_linux test_linux)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller windows)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos_arm)
  • GitHub Check: 4DNucleome.PartSeg (Builds sdist)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller macos)
  • GitHub Check: 4DNucleome.PartSeg (Builds pyinstaller_linux)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check Notebook_check)
  • GitHub Check: 4DNucleome.PartSeg (manifest_check manifest_check)
  • GitHub Check: 4DNucleome.PartSeg (GetTestData linux)
  • GitHub Check: 4DNucleome.PartSeg (Documentation_check help)
  • GitHub Check: 4DNucleome.PartSeg (formatting_check check_formating)
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Sourcery review
🔇 Additional comments (14)
.github/workflows/upgrade-dependencies.yml (1)

38-38: LGTM! Python 3.13 added to dependency upgrade workflow.

The addition of Python 3.13 to the upgrade loop correctly extends dependency compilation coverage and aligns with the broader Python 3.13 support added across CI workflows and test configurations.

tox.ini (2)

7-7: LGTM! Python 3.13 test coverage added consistently.

Python 3.13 (py313) has been correctly added to all relevant test environment patterns and GitHub Actions mappings, ensuring comprehensive test coverage for the new Python version.

Also applies to: 16-16, 74-74, 84-84, 105-105


65-65: Good refactor: pytest invocation simplified.

Replacing the specific pytest subpath invocation with a more generic form improves maintainability. This change appears independent of Python 3.13 support but is a positive improvement.

package/tests/test_PartSegCore/test_analysis_batch.py (2)

456-456: Good addition: type hints improve clarity.

Adding explicit type annotations (manager: CalculationManager) and return type (-> None) improves code documentation and enables better static analysis.


466-474: Excellent improvement: enhanced timeout diagnostics.

The timeout handling now:

  1. Dumps writer data for all files (preserving partial results for debugging)
  2. Provides detailed state information in the failure message (work flag, current task, queue status, writer status)

This significantly improves debuggability when tests timeout.

package/PartSegCore/utils.py (3)

1-2: LGTM! Future annotations enable modern type syntax.

Adding from __future__ import annotations allows the use of | union syntax throughout this file while maintaining compatibility with Python 3.9+. This is the correct approach for type modernization given the project's Python 3.9+ support requirement.

Based on learnings, the project supports Python 3.9+ (not 3.10+), and the | operator for type annotations was introduced in Python 3.10. However, with from __future__ import annotations, these annotations are treated as strings and not evaluated at runtime, making them compatible with Python 3.9+.


22-22: Good addition: centralized error type definition.

The ErrorInfo type alias standardizes error representation across batch processing components, improving type safety and maintainability. The union of StackSummary or tuple[dict, StackSummary] accommodates both sentry-enabled and sentry-free environments.


64-64: LGTM! Type modernization with union syntax.

All function signatures have been correctly updated to use the | union syntax (e.g., int | None, dict | EventedDict, str | None). This modernizes the codebase while maintaining Python 3.9+ compatibility through the from __future__ import annotations import.

Also applies to: 76-76, 105-105, 127-127, 293-293, 303-303, 324-324, 340-340, 365-365, 383-383, 466-466, 478-478

package/PartSegCore/analysis/batch_processing/parallel_backend.py (1)

33-33: LGTM! Centralized error handling utility imported.

The import of prepare_error_data from PartSegCore.utils aligns with the broader refactor to centralize error handling utilities across batch processing components.

package/tests/test_PartSegCore/test_utils.py (2)

3-3: LGTM! Test dependencies added.

The imports for multiprocessing and prepare_error_data support the new test coverage for error data serialization in multiprocessing contexts.

Also applies to: 17-17


368-384: Good test coverage for error serialization.

The new tests verify that prepare_error_data correctly:

  1. Handles deep exception stacks (via raise_in_depth)
  2. Produces serializable output that can be queued and retrieved

This validates the core functionality needed for error handling in multiprocessing batch operations.

Note: Minor style hints from static analysis.

  • Line 370: Ruff suggests avoiding long messages outside exception class (TRY003)
  • Line 379: Ruff suggests avoiding blind exception catching (BLE001)

These are stylistic suggestions and don't affect functionality. Given this is test code with clear intent (testing error handling), these can be safely ignored.

package/PartSegCore/analysis/batch_processing/batch_backend.py (2)

72-72: LGTM! Centralized error handling utilities imported.

The imports of ErrorInfo, iterate_names, and prepare_error_data from PartSegCore.utils complete the refactor to centralize error handling utilities. This eliminates local definitions and ensures consistent error handling across batch processing components.


94-95: Good type alias updates using shared ErrorInfo.

The type aliases CalculationResultList and WrappedResult now correctly reference the shared ErrorInfo type from PartSegCore.utils, ensuring type consistency across the codebase.

package/tests/test_PartSeg/test_sentry.py (1)

13-13: Import refactoring verified: utilities correctly moved to centralized location.

The imports for prepare_error_data and safe_repr have been correctly moved from PartSegCore.analysis.batch_processing.batch_backend to PartSegCore.utils. Both functions are properly defined and actively used in the test file.

Comment on lines +495 to +517
def pre_prepare_traceback_for_queue(exc: BaseException) -> StackSummary:
"""
Prepare exception for sending it through the multiprocessing queue.

:param exc: exception to prepare
:return: prepared exception
"""
traceback_list = traceback.extract_tb(exc.__traceback__)
for el in traceback_list:
if hasattr(el, "_code"):
del el._code
return traceback_list


def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize # noqa: PLC0415
from sentry_sdk.utils import event_from_exception # noqa: PLC0415

event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
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 | 🟡 Minor

Well-designed error serialization utilities.

The new functions provide robust error data preparation for multiprocessing queues:

  • pre_prepare_traceback_for_queue: Sanitizes traceback by removing unpicklable _code attributes
  • prepare_error_data: Attempts sentry serialization with graceful fallback to basic traceback

The design correctly handles the ImportError case when sentry-sdk is not available.

However, there's a minor issue flagged by static analysis:

Remove unused noqa directives.

Lines 511-512 have # noqa: PLC0415 directives that are flagged as unused by Ruff. These should be removed for code cleanliness.

Apply this diff:

     try:
-        from sentry_sdk.serializer import serialize  # noqa: PLC0415
-        from sentry_sdk.utils import event_from_exception  # noqa: PLC0415
+        from sentry_sdk.serializer import serialize
+        from sentry_sdk.utils import event_from_exception

         event = event_from_exception(exception)[0]
📝 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
def pre_prepare_traceback_for_queue(exc: BaseException) -> StackSummary:
"""
Prepare exception for sending it through the multiprocessing queue.
:param exc: exception to prepare
:return: prepared exception
"""
traceback_list = traceback.extract_tb(exc.__traceback__)
for el in traceback_list:
if hasattr(el, "_code"):
del el._code
return traceback_list
def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize # noqa: PLC0415
from sentry_sdk.utils import event_from_exception # noqa: PLC0415
event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
def prepare_error_data(exception: Exception) -> ErrorInfo:
try:
from sentry_sdk.serializer import serialize
from sentry_sdk.utils import event_from_exception
event = event_from_exception(exception)[0]
event = serialize(event)
return exception, (event, pre_prepare_traceback_for_queue(exception))
except ImportError: # pragma: no cover
🧰 Tools
🪛 Ruff (0.14.8)

511-511: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)


512-512: Unused noqa directive (non-enabled: PLC0415)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In package/PartSegCore/utils.py around lines 495 to 517, the two imports from
sentry_sdk at lines ~511-512 include unnecessary "# noqa: PLC0415" directives
flagged by Ruff; simply remove those "# noqa: PLC0415" comments from the import
lines so the imports remain but the unused noqa directives are eliminated.

@sonarqubecloud
Copy link

@Czaki Czaki merged commit 5cde4c9 into develop Dec 15, 2025
66 of 67 checks passed
@Czaki Czaki deleted the add_python_3_13 branch December 15, 2025 16:35
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

Comments