Skip to content

Conversation

@TullyMonster
Copy link

@TullyMonster TullyMonster commented Sep 9, 2025

Problem

The current type annotations in kWaveMedium use np.array which is a function, not a type. This causes IDE warnings like "Expected type 'None', got 'float'" when using scalar values for alpha_coeff and alpha_power.

Solution

  • Replace np.array type hints with proper Union[float, int, np.ndarray]
  • Use Optional[] for parameters that accept None
  • Add comprehensive docstring with parameter descriptions
  • Improve IDE support and type checking

Example Usage

# All these now work without IDE warnings:
medium1 = kWaveMedium(sound_speed=1500, alpha_coeff=0.75, alpha_power=1.5)
medium2 = kWaveMedium(sound_speed=np.array([1500, 1600]))
medium3 = kWaveMedium(sound_speed=1500)  # Optional params as None

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- Refactor
  - Medium properties now accept scalars, ints, or arrays; many fields are optional with sensible defaults and broader input types.
  - Validation updated to accept sequence-shaped inputs, conditional checks for optional fields, and refined axisymmetric/Stokes handling (alpha_power may be coerced to 2 with a logged warning).

- Bug Fixes
  - Corrected error message grammar and tightened validations for alpha-related fields and sign handling.

- Tests
  - Added comprehensive tests covering accessors, validation paths, mode switching, post-init normalization, and absorbing/Stokes behaviors.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

- Replace incorrect np.array type hints with proper Union types
- Add support for scalar (float/int) and array (np.ndarray) inputs
- Use Optional[] for parameters with None defaults
- Improve IDE type checking and autocompletion support

Addresses issue where IDE shows 'Expected type None, got float' warnings
for alpha_coeff and alpha_power parameters.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

Walkthrough

Broadened kWaveMedium type annotations to accept scalars, arrays, or None for several fields; added a kWaveMedium docstring; changed check_fields to accept Sequence[int]; updated alpha-related validations and axisymmetric/stokes handling; and added a comprehensive test suite for kWaveMedium.

Changes

Cohort / File(s) Summary
kWaveMedium core
kwave/kmedium.py
Broadened public field types to Union/Optional (e.g., sound_speed, sound_speed_ref, density, alpha_coeff, alpha_power, alpha_mode, alpha_filter, alpha_sign, BonA); added class docstring describing heterogeneous vs homogeneous inputs; changed check_fields(self, kgrid_shape: Sequence[int]); revised validations: alpha_filter shape check uses tuple(kgrid_shape), alpha_sign requires a 2-element numeric array (numpy-based check), alpha_coeff validation is conditional on non-None, alpha_power handling in axisymmetric/stokes coerces & uses np.isclose with logging.warning when adjusted to 2; corrected ensure_defined message grammar; expanded typing imports (Union, Optional, Sequence).
Tests added
tests/test_kmedium.py
New comprehensive test suite exercising property accessors, validation paths, mode switching, post-init normalization, absorbing/stokes interactions, alpha edge cases, and warning emission. Covers is_defined, ensure_defined, is_nonlinear, stokes/absorbing flag behavior, alpha array/value validations, and __post_init__ normalization.

Sequence Diagram(s)

sequenceDiagram
  participant Test as Test / Caller
  participant kMedium as kWaveMedium.__post_init__
  participant Validator as check_fields / validators
  participant Logger as logging

  Note over kMedium,Validator: Initialization → normalization → validation
  Test->>kMedium: instantiate with fields (scalar/array/None)
  kMedium->>kMedium: normalize scalars to 1-element np.array
  kMedium->>Validator: check_fields(kgrid_shape)
  Validator->>Validator: validate alpha_filter shape == tuple(kgrid_shape)
  Validator->>Validator: validate alpha_sign is numeric array of length 2
  alt alpha_coeff provided
    Validator->>Validator: validate alpha_coeff (non-negative, real)
  end
  alt axisymmetric & is_stokes
    Validator->>Validator: coerce alpha_power, if not np.isclose(..., 2.0)
    Validator->>Logger: logging.warning("alpha_power != 2, setting to 2")
    Validator->>kMedium: set alpha_power = 2
  else absorbing (non-stokes)
    Validator->>Validator: assert alpha_power is scalar and within [0,3]
  end
  Validator-->>kMedium: validations complete
  kMedium-->>Test: ready or raise AssertionError / ValueError
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

I twitch my whiskers at widened types,
Scalars, arrays, and None share bites.
Docstrings hum and checks align,
Alpha rules adjust — a tidy sign.
Hop, test, repeat — the medium is fine. 🐇✨

Pre-merge checks and finishing touches

✅ 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 "fix: correct type annotations in kWaveMedium class" succinctly and accurately summarizes the primary change in the changeset — updating type hints on the kWaveMedium class. It is a single clear sentence, directly related to the modifications in kwave/kmedium.py, and avoids noise or irrelevant details. A reviewer scanning history can quickly understand the main intent from this title.
Docstring Coverage ✅ Passed Docstring coverage is 88.24% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d0db5fc and f868179.

📒 Files selected for processing (1)
  • tests/test_kmedium.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_kmedium.py

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 11, 2025

🧩 Analysis chain

I'll examine the changes in this PR to provide a comprehensive review of the type annotation fixes in the kWaveMedium class.


🏁 Script executed:

#!/bin/bash
# First, let's see what files were changed in this PR
git diff --name-only HEAD~1 HEAD

# Look at the specific changes made to understand the type annotation fixes
git diff HEAD~1 HEAD

# Find the kWaveMedium class file
fd -t f -e py | xargs grep -l "class kWaveMedium"

Length of output: 390


🏁 Script executed:

#!/bin/bash
# Let's examine the kWaveMedium class in the current state
cat kwave/kmedium.py

# Also check if there are any recent commits to understand what changed
git log --oneline -10

# Check the git status to see what's in the working directory
git status

Length of output: 9407


@waltsims I've reviewed the type annotation fixes in the kWaveMedium class. Here's my analysis:

✅ Excellent Improvements Made

The type annotation fixes are well implemented:

  1. Proper Union Types: Correctly replaced np.array (function) with Union[float, int, np.ndarray] for all numeric parameters
  2. Optional Handling: Proper use of Optional[] wrapper for parameters that accept None
  3. Required vs Optional: sound_speed is correctly marked as required while other parameters are optional with None defaults
  4. Import Structure: Clean imports with necessary typing components

⚠️ Issues Found

Critical Bug in Validation Logic:

# Line 80 - This will crash when alpha_coeff is None
if not np.all(np.isreal(self.alpha_coeff)) or np.any(self.alpha_coeff < 0):
    raise ValueError("medium.alpha_coeff must be non-negative and real.")

This check should only run when alpha_coeff is not None:

if self.alpha_coeff is not None and (not np.all(np.isreal(self.alpha_coeff)) or np.any(self.alpha_coeff < 0)):
    raise ValueError("medium.alpha_coeff must be non-negative and real.")

📝 Missing Documentation

The PR objectives mentioned adding a comprehensive docstring, but the current docstring is still commented out (lines 25-30). Consider uncommmenting and properly formatting it as a proper class docstring.

🔧 Minor Enhancements

  1. Method Return Types: Some methods could benefit from explicit return type hints:
def __post_init__(self) -> None:
def is_nonlinear(self) -> bool:
  1. Type Consistency: The alpha_sign field could be more specific:
alpha_sign: Optional[np.ndarray[float]] = None

✅ Testing Verification

The type annotations now properly support the usage examples from the PR:

  • kWaveMedium(sound_speed=1500, alpha_coeff=0.75, alpha_power=1.5)
  • kWaveMedium(sound_speed=np.array([1500, 1600]))
  • kWaveMedium(sound_speed=1500)

Overall, this is a solid improvement that will significantly enhance IDE support and type checking capabilities!

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Caution

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

⚠️ Outside diff range comments (1)
kwave/kmedium.py (1)

77-78: Potential null pointer exception with new Optional types.

The validation logic directly accesses self.alpha_coeff without checking if it's None, which could cause runtime errors since alpha_coeff is now Optional[Union[float, int, np.ndarray]].

Apply this diff to add null checking:

-        # check alpha_coeff is non-negative and real
-        if not np.all(np.isreal(self.alpha_coeff)) or np.any(self.alpha_coeff < 0):
-            raise ValueError("medium.alpha_coeff must be non-negative and real.")
+        # check alpha_coeff is non-negative and real
+        if self.alpha_coeff is not None and (not np.all(np.isreal(self.alpha_coeff)) or np.any(self.alpha_coeff < 0)):
+            raise ValueError("medium.alpha_coeff must be non-negative and real.")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51b2041 and 5ffa109.

📒 Files selected for processing (1)
  • kwave/kmedium.py (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Ruff
kwave/kmedium.py

[error] 1-1: I001 Import block is un-sorted or un-formatted.

🔇 Additional comments (6)
kwave/kmedium.py (6)

14-14: LGTM! Improved type annotation for sound_speed.

The change from np.array (which is a function) to Union[float, int, np.ndarray] correctly reflects that this field can accept scalar values or arrays, resolving IDE warnings.


16-16: LGTM! Consistent type improvements for numeric parameters.

The updates to sound_speed_ref, density, alpha_coeff, alpha_power, and BonA properly use Optional[Union[float, int, np.ndarray]] with None defaults, allowing both scalar and array inputs while maintaining optional behavior.

Also applies to: 18-18, 20-20, 22-22, 31-31


25-25: LGTM! Correct string type for alpha_mode.

The change from np.array = None to Optional[str] = None is correct since alpha_mode accepts string values like 'no_absorption' or 'no_dispersion' as seen in the validation logic.


27-27: LGTM! Appropriate array-only types for filter parameters.

Using Optional[np.ndarray] for alpha_filter and alpha_sign is correct since these parameters specifically require array structures based on the validation logic (shape checking and size requirements).

Also applies to: 29-29


35-35: Document and confirm new stokes boolean (Stokes absorption / axisymmetric)

Verified: medium.stokes is set in kwave/kmedium.py (set_absorbing) and referenced in kwave/kWaveSimulation.py (selects "stokes" vs "absorbing") and kwave/kWaveSimulation_helper/save_to_disk_func.py (sets absorbing_flag=2). Update the PR description to explain this field, why the default is False, when it should be enabled (axisymmetric or alpha_mode == "stokes"), and any backward-compat/serialization implications.


46-46: Verify sound_speed handling in post_init

np.atleast_1d accepts scalar int/float and returns a 1D ndarray; sandbox verification failed because numpy is not installed. Run locally to confirm:

python3 - <<'PY'
import numpy as np
for v in (1500.0, 1500, [1500,1600], np.array([1500,1600])):
print(repr(v), '->', np.atleast_1d(v))
PY

- Consolidate typing imports to fix Ruff linter errors
- Add None check for alpha_coeff validation to prevent runtime errors
- Resolves CodeRabbit review comments
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

Caution

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

⚠️ Outside diff range comments (3)
kwave/kmedium.py (3)

65-67: Bug: alpha_filter shape check can raise AttributeError and mis-compare.

Comparing tuple (alpha_filter.shape) to kgrid_shape (often a tuple) and then calling .all() on a bool will fail; also tuple==ndarray semantics are wrong.

-        if self.alpha_filter is not None and not (self.alpha_filter.shape == kgrid_shape).all():
-            raise ValueError("medium.alpha_filter must be the same size as the computational grid.")
+        if self.alpha_filter is not None and self.alpha_filter.shape != tuple(kgrid_shape):
+            raise ValueError("medium.alpha_filter must be the same size as the computational grid.")

70-73: Bug: wrong module name and fragile numeric check for alpha_sign.

kwave.utils.checkutils doesn’t exist here (import is checks). Also, validating arrays via is_number isn’t appropriate.

-        if self.alpha_sign is not None and (not kwave.utils.checkutils.is_number(self.alpha_sign) or (self.alpha_sign.size != 2)):
-            raise ValueError(
-                "medium.alpha_sign must be given as a " "2 element numerical array controlling absorption and dispersion, respectively."
-            )
+        if self.alpha_sign is not None:
+            alpha_sign_arr = np.atleast_1d(self.alpha_sign)
+            if alpha_sign_arr.size != 2 or not np.issubdtype(alpha_sign_arr.dtype, np.number):
+                raise ValueError(
+                    "medium.alpha_sign must be a 2 element numeric array controlling absorption and dispersion, respectively."
+                )

170-175: Bug: attribute access on scalar and deprecated logging level.

self.alpha_power.size breaks for Python scalars; use np.size. Also prefer logging.warning and tolerant equality for floats.

-        if self.alpha_power is not None and (self.alpha_power.size != 1 or self.alpha_power != 2):
-            logging.log(logging.WARN, "the axisymmetric code and stokes absorption assume alpha_power = 2, user value ignored.")
+        if self.alpha_power is not None:
+            ap = np.asarray(self.alpha_power)
+            if ap.size != 1 or not np.isclose(float(ap), 2.0):
+                logging.warning("the axisymmetric code and stokes absorption assume alpha_power = 2, user value ignored.")
♻️ Duplicate comments (1)
kwave/kmedium.py (1)

3-3: Import consolidation fixed; prior pipeline issue resolved.

Single, sorted typing import looks good.

🧹 Nitpick comments (3)
kwave/kmedium.py (3)

3-3: Prefer Sequence[int] for kgrid_shape to reflect actual usage (tuple).

This matches callers passing kgrid_k.shape and avoids confusion.

-from typing import List, Optional, Union
+from typing import List, Optional, Sequence, Union
@@
-    def check_fields(self, kgrid_shape: np.ndarray) -> None:
+    def check_fields(self, kgrid_shape: Sequence[int]) -> None:

Also applies to: 47-47


11-12: Promote the commented guidance to a real class docstring (and remove the commented block).

Improves IDE/help introspection and keeps the class self-documented.

 class kWaveMedium(object):
+    """
+    Note: For heterogeneous medium parameters, medium.sound_speed and medium.density
+    must be given in matrix form with the same dimensions as kgrid. For homogeneous
+    medium parameters, these can be given as single numeric values. If the medium is
+    homogeneous and velocity inputs or outputs are not required, it is not necessary
+    to specify medium.density.
+    """
@@
-    #  """
-    #     Note: For heterogeneous medium parameters, medium.sound_speed and
-    #     medium.density must be given in matrix form with the same dimensions as
-    #     kgrid. For homogeneous medium parameters, these can be given as single
-    #     numeric values. If the medium is homogeneous and velocity inputs or
-    #     outputs are not required, it is not necessary to specify medium.density.
-    # """

Also applies to: 36-42


105-105: Nit: fix grammar in assertion message.

-            assert getattr(self, f) is not None, f"The field {f} must be not be None"
+            assert getattr(self, f) is not None, f"The field {f} must not be None"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ffa109 and 4042be7.

📒 Files selected for processing (1)
  • kwave/kmedium.py (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
kwave/kmedium.py (4)
kwave/kWaveSimulation.py (2)
  • check_medium (576-605)
  • kWaveSimulation (34-1552)
kwave/kWaveSimulation_helper/expand_grid_matrices.py (1)
  • expand_medium (106-127)
kwave/kWaveSimulation_helper/create_absorption_variables.py (1)
  • create_stokes_medium_variables (33-39)
kwave/kWaveSimulation_helper/save_to_disk_func.py (1)
  • grab_medium_props (214-241)
🔇 Additional comments (2)
kwave/kmedium.py (2)

13-31: Broadened type hints are correct and align with runtime conversions.

Accepting float|int|ndarray for these fields matches downstream usage.


76-77: Nice guard added for optional alpha_coeff.

The None-check avoids exceptions when alpha_coeff is unspecified.

- Fix alpha_filter shape comparison bug
- Fix alpha_sign validation with proper numpy checks
- Fix alpha_power scalar access using np.asarray()
- Fix grammar error in assertion message
- Improve type hints and add class docstring
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 (8)
kwave/kmedium.py (8)

12-20: Docstring OK; consider expanding later for parameters.

High-level class docstring is fine. A future pass could add per-field notes (e.g., units, homogeneous vs heterogeneous expectations) for IDE tooltips.


31-33: Fix alpha_mode docs: 'stokes' is also a valid value.

The comment says valid inputs are 'no_absorption' or 'no_dispersion', but check_fields also accepts 'stokes'. Update to avoid misleading users.

Apply this diff:

-    # valid inputs are 'no_absorption' or 'no_dispersion'
+    # valid inputs are 'no_absorption', 'no_dispersion', or 'stokes'

45-47: Add explicit return type to dunder for clarity.

Minor typing polish: annotate post_init return as None.

-    def __post_init__(self):
+    def __post_init__(self) -> None:

71-76: Tighten alpha_sign validation to enforce 1-D, exactly two elements.

Current check allows any shape with size 2 (e.g., (2,1)). If you truly require a flat 2-vector, enforce 1-D shape.

-        if self.alpha_sign is not None:
-            alpha_sign_arr = np.atleast_1d(self.alpha_sign)
-            if alpha_sign_arr.size != 2 or not np.issubdtype(alpha_sign_arr.dtype, np.number):
+        if self.alpha_sign is not None:
+            alpha_sign_arr = np.asarray(self.alpha_sign)
+            if alpha_sign_arr.ndim != 1 or alpha_sign_arr.shape != (2,) or not np.issubdtype(alpha_sign_arr.dtype, np.number):
                 raise ValueError(
                     "medium.alpha_sign must be a 2 element numeric array controlling absorption and dispersion, respectively."
                 )

97-109: Prefer explicit exceptions over assert for user input validation.

Asserts can be stripped with Python -O, disabling critical validation. Consider raising ValueError/TypeError for public API checks like ensure_defined.

-        for f in fields:
-            assert getattr(self, f) is not None, f"The field {f} must not be None"
+        for f in fields:
+            if getattr(self, f) is None:
+                raise ValueError(f"The field {f} must not be None")

147-154: Separate validations and fix misleading error message.

This assert mixes alpha_coeff “real” with alpha_power range but the message mentions only alpha_power. Split checks and raise explicit exceptions.

-        # check y is scalar
-        assert np.isscalar(self.alpha_power), "medium.alpha_power must be scalar."
-
-        # check y is real and within 0 to 3
-        assert (
-            np.all(np.isreal(self.alpha_coeff)) and 0 <= self.alpha_power < 3
-        ), "medium.alpha_power must be a real number between 0 and 3."
+        # alpha_power must be a real scalar in [0, 3)
+        if not np.isscalar(self.alpha_power):
+            raise ValueError("medium.alpha_power must be a real scalar.")
+        if not (0 <= float(self.alpha_power) < 3):
+            raise ValueError("medium.alpha_power must be in the range [0, 3).")
+        # alpha_coeff should be real (non-negativity is checked elsewhere)
+        if not np.all(np.isreal(self.alpha_coeff)):
+            raise ValueError("medium.alpha_coeff must be real.")

182-185: Clean up message string concatenation.

Join the error message as a single literal for readability.

-            raise NotImplementedError(
-                "Input option medium.alpha_mode is not supported with the axisymmetric code " "or medium.alpha_mode = " "stokes" "."
-            )
+            raise NotImplementedError(
+                "Input option medium.alpha_mode is not supported with the axisymmetric code or with medium.alpha_mode = 'stokes'."
+            )

188-190: Same here: simplify concatenated assert message.

-        assert self.alpha_filter is None, (
-            "Input option medium.alpha_filter is not supported with the axisymmetric code " "or medium.alpha_mode = 'stokes'. "
-        )
+        assert self.alpha_filter is None, (
+            "Input option medium.alpha_filter is not supported with the axisymmetric code or with medium.alpha_mode = 'stokes'."
+        )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4042be7 and c0f4732.

📒 Files selected for processing (1)
  • kwave/kmedium.py (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
kwave/kmedium.py (3)
kwave/kgrid.py (2)
  • size (297-301)
  • kWaveGrid (14-701)
kwave/kWaveSimulation_helper/expand_grid_matrices.py (1)
  • expand_medium (106-127)
kwave/kWaveSimulation.py (2)
  • check_medium (576-605)
  • kWaveSimulation (34-1552)
🔇 Additional comments (4)
kwave/kmedium.py (4)

22-40: Type-hint broadening looks correct and consistent.

Allowing scalars, arrays, and None via Union/Optional for the public fields aligns with usage in the rest of the codebase and resolves prior type-checker friction for scalar inputs.


48-57: check_fields now accepts Sequence[int]: LGTM.

Accepting Sequence[int] makes call sites with tuple shapes natural and keeps the function flexible.


67-68: alpha_filter shape validation: LGTM.

Comparing to tuple(kgrid_shape) is robust and clear.


79-81: Good: alpha_coeff guard handles None before numeric checks.

Prevents exceptions when alpha_coeff is omitted.

@codecov
Copy link

codecov bot commented Sep 14, 2025

Codecov Report

❌ Patch coverage is 86.36364% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.15%. Comparing base (64699ce) to head (f868179).

Files with missing lines Patch % Lines
kwave/kmedium.py 86.36% 0 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #636      +/-   ##
==========================================
+ Coverage   73.95%   74.15%   +0.20%     
==========================================
  Files          50       50              
  Lines        7000     7004       +4     
  Branches     1338     1340       +2     
==========================================
+ Hits         5177     5194      +17     
+ Misses       1280     1269      -11     
+ Partials      543      541       -2     
Flag Coverage Δ
3.10 74.15% <86.36%> (+0.20%) ⬆️
3.11 74.15% <86.36%> (+0.20%) ⬆️
3.12 74.15% <86.36%> (+0.20%) ⬆️
3.13 74.15% <86.36%> (+0.20%) ⬆️
macos-latest 74.12% <86.36%> (+0.20%) ⬆️
ubuntu-latest 74.12% <86.36%> (+0.20%) ⬆️
windows-latest 74.14% <86.36%> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ 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.

tully (work) and others added 2 commits September 15, 2025 10:02
- Fix NumPy deprecation warning in _check_absorbing_with_stokes by using ap.item() instead of float(ap)
- Add comprehensive test suite for kWaveMedium class to improve code coverage
- Test all edge cases including elastic properties, validation methods, and Stokes mode restrictions
- All tests pass without warnings or errors
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)
tests/test_kmedium.py (6)

16-37: Parametrize elastic-property access checks to reduce repetition.

Same assertion pattern across six properties; a small parametrize cleans it up.

Apply this refactor:

-def test_elastic_properties_access():
-    """Test access to elastic code related properties (should raise NotImplementedError)"""
-    medium = kWaveMedium(sound_speed=1500)
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.sound_speed_shear
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.sound_speed_ref_shear
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.sound_speed_compression
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.sound_speed_ref_compression
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.alpha_coeff_compression
-    
-    with pytest.raises(NotImplementedError, match="Elastic simulation"):
-        _ = medium.alpha_coeff_shear
+@pytest.mark.parametrize(
+    "attr",
+    [
+        "sound_speed_shear",
+        "sound_speed_ref_shear",
+        "sound_speed_compression",
+        "sound_speed_ref_compression",
+        "alpha_coeff_compression",
+        "alpha_coeff_shear",
+    ],
+)
+def test_elastic_properties_access(attr):
+    """Elastic properties should raise NotImplementedError."""
+    medium = kWaveMedium(sound_speed=1500)
+    with pytest.raises(NotImplementedError, match="Elastic simulation"):
+        getattr(medium, attr)

59-72: Tighten error-message matching (optional).

Matching the full message guards against regressions.

-with pytest.raises(AssertionError, match="alpha_coeff must not be None"):
+with pytest.raises(AssertionError, match=r"^The field alpha_coeff must not be None$")
     medium.ensure_defined('alpha_coeff')
 
-with pytest.raises(AssertionError, match="alpha_power must not be None"):
+with pytest.raises(AssertionError, match=r"^The field alpha_power must not be None$")
     medium.ensure_defined('alpha_power')

127-139: Also assert valid alpha_mode values pass.

Covers the allowed enum surface.

 def test_alpha_mode_validation_edge_cases():
@@
     with pytest.raises(AssertionError):
         medium2.check_fields(kgrid.N)
+
+@pytest.mark.parametrize("mode", ["no_absorption", "no_dispersion", "stokes"])
+def test_alpha_mode_valid_values(mode):
+    kgrid = kWaveGrid(Vector([64, 64]), Vector([0.1e-3, 0.1e-3]))
+    medium = kWaveMedium(sound_speed=1500, alpha_mode=mode)
+    # Should not raise
+    medium.check_fields(kgrid.N)

210-236: Avoid direct mutation of flags; use the API.

Keeps tests aligned with public surface and avoids redundant state changes.

-    # Reset
-    medium.absorbing = False
-    medium.stokes = False
-    
-    # Set to Stokes absorbing
+    # Set to Stokes absorbing (no need to reset via direct assignment)
     medium.set_absorbing(is_absorbing=True, is_stokes=True)
@@
-    # Set to non-absorbing
-    medium.set_absorbing(is_absorbing=False, is_stokes=False)
+    # Set to non-absorbing
+    medium.set_absorbing(is_absorbing=False, is_stokes=False)

197-208: Consider testing that alpha_filter is forbidden in Stokes mode.

Covers the assertion path in _check_absorbing_with_stokes.

 def test_stokes_mode_alpha_mode_restrictions():
@@
     with pytest.raises(NotImplementedError, match="not supported with the axisymmetric code"):
         medium2.set_absorbing(is_absorbing=True, is_stokes=True)
+
+def test_stokes_mode_rejects_alpha_filter():
+    kgrid = kWaveGrid(Vector([64, 64]), Vector([0.1e-3, 0.1e-3]))
+    filt = np.zeros(tuple(kgrid.N))
+    medium = kWaveMedium(sound_speed=1500, alpha_coeff=0.75, alpha_filter=filt)
+    with pytest.raises(AssertionError, match=r"alpha_filter.*not supported"):
+        medium.set_absorbing(is_absorbing=True, is_stokes=True)

238-240: Drop the pytest entry point.

Tests are discovered by runners; this block isn’t needed.

-if __name__ == '__main__':
-    pytest.main([__file__, '-v'])
+# No module entry point needed; use `pytest -q`.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0f4732 and 35c45a2.

📒 Files selected for processing (2)
  • kwave/kmedium.py (5 hunks)
  • tests/test_kmedium.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • kwave/kmedium.py
🧰 Additional context used
🧬 Code graph analysis (1)
tests/test_kmedium.py (2)
kwave/data.py (1)
  • Vector (7-49)
kwave/kmedium.py (12)
  • kWaveMedium (11-237)
  • sound_speed_shear (198-202)
  • sound_speed_ref_shear (205-209)
  • sound_speed_compression (212-216)
  • sound_speed_ref_compression (219-223)
  • alpha_coeff_compression (226-230)
  • alpha_coeff_shear (233-237)
  • is_defined (82-95)
  • ensure_defined (97-108)
  • is_nonlinear (110-117)
  • set_absorbing (119-135)
  • check_fields (48-80)
🔇 Additional comments (10)
tests/test_kmedium.py (10)

1-5: Nice, clear module docstring.

Good context-setting for the suite.


7-14: Imports look tidy and minimal.

No unnecessary deps; explicit module paths are good.


39-57: is_defined scenarios are thorough.

Covers single and multi-field cases; matches the current API returning a list.


74-83: is_nonlinear coverage is crisp.

Linear vs nonlinear paths validated.


85-92: Stokes + alpha_power=None path validated.

Confirms coercion to 2; good.


157-163: LGTM.

None passes as intended.


165-182: Alpha-coeff array validation tests are solid.

Covers happy path, negatives, and complex values.


184-195: Post-init normalization assertions are good.

Catches scalar-to-array promotion and shape preservation.


197-208: Restrictions in Stokes mode covered.

Correctly targets NotImplementedError path.


94-105: Verified — patch('logging.warning') is correct.
kwave/kmedium.py imports logging and calls logging.warning(...) (line 176), so patch('logging.warning') will capture the call.

TullyMonster and others added 3 commits September 15, 2025 10:19
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
- Reorder imports according to PEP 8 standards (stdlib, third-party, local)
- Remove unnecessary __main__ block from test file
- Fix I001 import block formatting issue
…r/k-wave-python into fix/type-annotations-kmedium
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