Repository: pastas/pastas
Pull request #946: Update tests after leftover comments in PR #941
Author: login: raoulcollenteur
Labels: name: code quality
description: Related to code quality, testing, CI, project setup etc.
Created: 2025-04-29T06:45:13Z | Merged: 2025-04-29T09:41:43Z

# Short description
Add a short description describing the pull request here.

# Checklist before PR can be merged:
- [ ] closes issue #xxxx
- [x] is documented
- [x] code formatted and linted with [ruff](https://docs.astral.sh/ruff/)
- [x] type hints
- [x] tests added or expanded


Diff:
diff --git a/tests/test_dutch.py b/tests/test_dutch.py
index ee127a4f9..95d9b3f95 100644
--- a/tests/test_dutch.py
+++ b/tests/test_dutch.py
@@ -94,24 +94,19 @@ def test_in_spring() -> None:
     assert_series_equal(result, expected)
 
 
-def test_q_gxg() -> None:
+def test_q_gxg(sample_timeseries: pd.Series) -> None:
     """Test the _q_gxg helper function."""
-    # Create test series with a seasonal pattern
-    index = pd.date_range(start="2018-01-01", end="2020-12-31", freq="D")
-    time = np.arange(len(index))
-    seasonal = 10 * np.sin(2 * np.pi * time / 365.25) + 100
-    series = pd.Series(seasonal, index=index)
 
     # Test q_gxg with different quantiles
-    result_high = _q_gxg(series, q=0.94, by_year=True)
-    result_low = _q_gxg(series, q=0.06, by_year=True)
+    result_high = _q_gxg(sample_timeseries, q=0.94, by_year=True)
+    result_low = _q_gxg(sample_timeseries, q=0.06, by_year=True)
 
     # High quantile should be higher than low quantile
     assert result_high > result_low
 
     # Test by_year parameter
-    result_by_year = _q_gxg(series, q=0.5, by_year=True)
-    result_all = _q_gxg(series, q=0.5, by_year=False)
+    result_by_year = _q_gxg(sample_timeseries, q=0.5, by_year=True)
+    result_all = _q_gxg(sample_timeseries, q=0.5, by_year=False)
 
     # Results should be roughly similar but not identical
     assert abs(result_by_year - result_all) < 1.0
@@ -170,7 +165,7 @@ def test_gvg(biweekly_timeseries: pd.Series) -> None:
 
     # Test with None limit (no filling)
     result_none = gvg(biweekly_timeseries, limit=None)
-    assert isinstance(result_none, float) or np.isnan(result_none)
+    assert isinstance(result_none, float)
 
 
 def test_get_spring(sample_timeseries: pd.Series) -> None:
@@ -220,7 +215,7 @@ def test_gg(biweekly_timeseries: pd.Series) -> None:
     # Verify average calculation
     mean_value = biweekly_timeseries.mean()
     # GG should be somewhat close to the mean of all values
-    assert abs(result - mean_value) < 10.0
+    assert abs(result - mean_value) < 1.0
 
 
 def test_ghg_outputs(biweekly_timeseries: pd.Series) -> None:
@@ -286,7 +281,7 @@ def test_gxg_min_requirements() -> None:
 
     # Test with relaxed requirements
     result = ps.stats.ghg(short_series, min_n_years=1, min_n_meas=4)
-    assert isinstance(result, float)
+    assert isinstance(result, float) and not np.isnan(result)
 
     # Create a sparse series that doesn't meet min_n_meas requirement
     sparse_index = pd.date_range("2018-01-01", "2021-12-31", freq="90D")
@@ -297,7 +292,7 @@ def test_gxg_min_requirements() -> None:
 
     # Test with relaxed requirements
     result = ps.stats.glg(sparse_series, min_n_meas=1, min_n_years=3)
-    assert isinstance(result, float)
+    assert isinstance(result, float) and not np.isnan(result)
 
 
 def test_fill_methods(sample_timeseries: pd.Series) -> None:
@@ -457,6 +452,7 @@ def test_q_gvg_tmin_tmax(self) -> None:
         assert v == 5
 
     def test_q_gxg_series(self) -> None:
+        """Test q_gxg functions against reference values from Menyanthes."""
         s = pd.read_csv(
             "tests/data/hseries_gxg.csv",
             index_col=0,
@@ -464,19 +460,19 @@ def test_q_gxg_series(self) -> None:
             parse_dates=True,
             dayfirst=True,
         ).squeeze("columns")
+
+        # Calculate GXG values
         ghg = ps.stats.q_ghg(s)
         glg = ps.stats.q_glg(s)
         gvg = ps.stats.q_gvg(s)
-        print("\n")
-        print("calculated GXG's percentile method: \n")
-        print(
-            (
-                "GHG: {ghg:.2f} m+NAP\nGLG: {glg:.2f} m+NAP\nGVG: {gvg:.2f} m+NAP\n"
-            ).format(ghg=ghg, glg=glg, gvg=gvg)
-        )
-        print("Menyanthes GXG's: \n")
-        print(
-            (
-                "GHG: {ghg:.2f} m+NAP\nGLG: {glg:.2f} m+NAP\nGVG: {gvg:.2f} m+NAP\n"
-            ).format(ghg=-3.23, glg=-3.82, gvg=-3.43)
-        )
+
+        # Reference values from Menyanthes
+        ref_ghg = -3.23
+        ref_glg = -3.82
+        ref_gvg = -3.43
+
+        # Assert that calculated values are close to reference values
+        # Using tolerance of 0.1m which is reasonable for groundwater levels
+        assert abs(ghg - ref_ghg) < 0.1, f"GHG expected {ref_ghg}, got {ghg:.2f}"
+        assert abs(glg - ref_glg) < 0.1, f"GLG expected {ref_glg}, got {glg:.2f}"
+        assert abs(gvg - ref_gvg) < 0.1, f"GVG expected {ref_gvg}, got {gvg:.2f}"
diff --git a/tests/test_model.py b/tests/test_model.py
index 6666337d8..5dacbda9a 100644
--- a/tests/test_model.py
+++ b/tests/test_model.py
@@ -583,9 +583,7 @@ def test_to_file_and_load(self, ml_noisemodel: ps.Model, tmp_path: Any) -> None:
         assert loaded_model.stressmodels.keys() == ml_noisemodel.stressmodels.keys()
 
         # Check parameters
-        assert_frame_equal(
-            loaded_model.parameters.sort_index(), ml_noisemodel.parameters.sort_index()
-        )
+        assert_frame_equal(loaded_model.parameters, ml_noisemodel.parameters)
 
     def test_copy(self, ml_noisemodel: ps.Model) -> None:
         """Test copying a model."""
diff --git a/tests/test_modelstats.py b/tests/test_modelstats.py
index 3dd9f5870..f13b76c78 100644
--- a/tests/test_modelstats.py
+++ b/tests/test_modelstats.py
@@ -6,11 +6,6 @@
 
 import pastas as ps
 
-# Use model fixtures from conftest.py instead of defining custom fixtures
-# We can use:
-# - ml_rm: Basic model with response model
-# - ml_solved: Model with noise model
-
 
 class TestStatistics:
     """Test Statistics class methods."""
diff --git a/tests/test_noisemodels.py b/tests/test_noisemodels.py
index dec19e3a5..e35bb2d26 100644
--- a/tests/test_noisemodels.py
+++ b/tests/test_noisemodels.py
@@ -228,19 +228,15 @@ def test_set_parameter_methods(self) -> None:
 def test_irregular_time_steps(irregular_residual_series: Series) -> None:
     """Test noise models with irregular time steps."""
     ar_model = ArNoiseModel()
-    arma_model = ArmaNoiseModel()
 
     # Set parameters
     ar_params = [10.0]  # alpha
-    arma_params = [10.0, 5.0]  # alpha, beta
 
     # Simulate noise
     ar_noise = ar_model.simulate(irregular_residual_series, ar_params)
-    arma_noise = arma_model.simulate(irregular_residual_series, arma_params)
 
     # Check properties
     assert len(ar_noise) == len(irregular_residual_series)
-    assert len(arma_noise) == len(irregular_residual_series)
 
     # Calculate weights for AR model
     weights = ar_model.weights(irregular_residual_series, ar_params)
diff --git a/tests/test_recharge.py b/tests/test_recharge.py
index 2600ffc4d..6641773b1 100644
--- a/tests/test_recharge.py
+++ b/tests/test_recharge.py
@@ -81,3 +81,128 @@ def test_flexmodel_water_balance_interception(prec: Series, evap: Series) -> Non
     si, ei, pi = rch.get_interception_balance.py_func(p, e)
     error = si[0] - si[-1] + (pi + ei)[:-1].sum()
     assert isclose(error, 0)
+
+
+def test_check_snow_balance(prec: Series, temp: Series) -> None:
+    """Test the check_snow_balance method of FlexModel."""
+    rch = ps.rch.FlexModel(snow=True)
+    error = rch.check_snow_balance(prec=prec.to_numpy(), temp=temp.to_numpy())
+    assert isclose(error, 0)
+
+
+def test_check_interception_balance(prec: Series, evap: Series) -> None:
+    """Test the check_interception_balance method of FlexModel."""
+    rch = ps.rch.FlexModel(interception=True)
+    error = rch.check_interception_balance(prec=prec.to_numpy(), evap=evap.to_numpy())
+    assert isclose(error, 0, atol=5e-3)
+
+
+def test_check_root_zone_balance(prec: Series, evap: Series) -> None:
+    """Test the check_root_zone_balance method of FlexModel."""
+    rch = ps.rch.FlexModel()
+    error = rch.check_root_zone_balance(prec=prec.to_numpy(), evap=evap.to_numpy())
+    assert isclose(error, 0, atol=5e-3)
+
+
+def test_check_balance_with_parameters(
+    prec: Series, evap: Series, temp: Series
+) -> None:
+    """Test that water balance checks work with custom parameters."""
+    rch = ps.rch.FlexModel(snow=True, interception=True)
+
+    # Test snow balance with custom parameters
+    snow_error = rch.check_snow_balance(
+        prec=prec.to_numpy(),
+        temp=temp.to_numpy(),
+        tt=-2.0,  # threshold temperature
+        k=3.5,  # degree-day factor
+    )
+    assert isclose(snow_error, 0)
+
+    # Test interception balance with custom parameters
+    int_error = rch.check_interception_balance(
+        prec=prec.to_numpy(),
+        evap=evap.to_numpy(),
+        simax=5.0,  # maximum interception storage
+    )
+    assert isclose(int_error, 0, atol=5e-3)
+
+    # Test root zone balance with custom parameters
+    rz_error = rch.check_root_zone_balance(
+        prec=prec.to_numpy(),
+        evap=evap.to_numpy(),
+        srmax=300.0,  # maximum root zone storage
+        lp=0.3,  # threshold parameter
+        ks=150.0,  # saturated hydraulic conductivity
+        gamma=3.0,  # nonlinearity parameter
+    )
+    assert isclose(rz_error, 0, atol=5e-3)
+
+
+# Tests for the raw njit functions
+def test_njit_root_zone_balance(prec: Series, evap: Series) -> None:
+    """Test the raw njit function for root zone water balance."""
+    p = prec.to_numpy()
+    e = evap.to_numpy()
+
+    # Test with default parameters
+    sr, r, ea, q, pe = ps.rch.FlexModel.get_root_zone_balance.py_func(pe=p, ep=e)
+    error = sr[0] - sr[-1] + (r + ea + q + pe)[:-1].sum()
+    assert isclose(error, 0)
+
+    # Test with custom parameters
+    sr, r, ea, q, pe = ps.rch.FlexModel.get_root_zone_balance(
+        pe=p, ep=e, srmax=300.0, lp=0.25, ks=150.0, gamma=3.0
+    )
+    error = sr[0] - sr[-1] + (r + ea + q + pe)[:-1].sum()
+    assert isclose(error, 0)
+
+
+def test_njit_interception_balance(prec: Series, evap: Series) -> None:
+    """Test the raw njit function for interception water balance."""
+    p = prec.to_numpy()
+    e = evap.to_numpy()
+
+    # Test with default parameters
+    si, ei, pi = ps.rch.FlexModel.get_interception_balance.py_func(pr=p, ep=e)
+    error = si[0] - si[-1] + (pi + ei)[:-1].sum()
+    assert isclose(error, 0)
+
+    # Test with custom parameters
+    si, ei, pi = ps.rch.FlexModel.get_interception_balance(pr=p, ep=e, simax=5.0)
+    error = si[0] - si[-1] + (pi + ei)[:-1].sum()
+    assert isclose(error, 0)
+
+
+def test_njit_snow_balance(prec: Series, temp: Series) -> None:
+    """Test the raw njit function for snow water balance."""
+    p = prec.to_numpy()
+    t = temp.to_numpy()
+
+    # Test with default parameters
+    ss, snow, m = ps.rch.FlexModel.get_snow_balance.py_func(prec=p, temp=t)
+    error = ss[0] - ss[-1] + (snow + m)[:-1].sum()
+    assert isclose(error, 0)
+
+    # Test with custom parameters
+    ss, snow, m = ps.rch.FlexModel.get_snow_balance(prec=p, temp=t, tt=-2.0, k=3.5)
+    error = ss[0] - ss[-1] + (snow + m)[:-1].sum()
+    assert isclose(error, 0)
+
+
+def test_njit_peterson_recharge(prec: Series, evap: Series) -> None:
+    """Test the raw njit function for Peterson recharge calculation."""
+    p = prec.to_numpy()
+    e = evap.to_numpy()
+
+    # Test with default parameters
+    r, s, ea, pe = ps.rch.Peterson.get_recharge.py_func(prec=p, evap=e)
+    # Check that the final state is reasonable (not NaN or inf)
+    assert isclose(s[-1], s[-1])  # Quick way to check for NaN
+
+    # Test with custom parameters
+    r, s, ea, pe = ps.rch.Peterson.get_recharge(
+        prec=p, evap=e, scap=1.0, alpha=1.0, ksat=1.0, beta=0.5, gamma=1.0
+    )
+    # Check that the final state is reasonable (not NaN or inf)
+    assert isclose(s[-1], s[-1])  # Quick way to check for NaN
diff --git a/tests/test_rfuncs.py b/tests/test_rfuncs.py
index 7571e7b65..ce0bfe9c1 100644
--- a/tests/test_rfuncs.py
+++ b/tests/test_rfuncs.py
@@ -1,12 +1,15 @@
+import numpy as np
 import pytest
 
 import pastas as ps
 
 
 @pytest.mark.parametrize("rfunc_name", ps.rfunc.__all__)
-def test_rfunc(rfunc_name: str) -> None:
+@pytest.mark.parametrize("up", [True, False])
+def test_rfunc(rfunc_name: str, up: bool) -> None:
     if rfunc_name not in []:
         rfunc = getattr(ps.rfunc, rfunc_name)()
+        rfunc.update_rfunc_settings(up=up)
         if rfunc_name == "HantushWellModel":
             rfunc.set_distances(100.0)
         p = rfunc.get_init_parameters("test").initial.to_numpy()
@@ -15,8 +18,10 @@ def test_rfunc(rfunc_name: str) -> None:
 
 
 @pytest.mark.parametrize("rfunc_name", ps.rfunc.__all__)
-def test_to_dict_rfuncs(rfunc_name: str) -> None:
+@pytest.mark.parametrize("up", [True, False])
+def test_to_dict_rfuncs(rfunc_name: str, up: bool) -> None:
     rfunc1 = getattr(ps.rfunc, rfunc_name)(cutoff=0.5)
+    rfunc1.update_rfunc_settings(up=up)
 
     # Create the exact same instance using to_dict
     data = rfunc1.to_dict()
@@ -25,6 +30,7 @@ def test_to_dict_rfuncs(rfunc_name: str) -> None:
     rfunc_gsf = data.pop("gain_scale_factor", None)
     rfunc2 = getattr(ps.rfunc, rfunc_class)(**data)
     rfunc2.update_rfunc_settings(up=rfunc_up, gain_scale_factor=rfunc_gsf)
+    rfunc2.update_rfunc_settings(up=rfunc_up, gain_scale_factor=rfunc_gsf)
 
     if rfunc_name == "HantushWellModel":
         rfunc1.set_distances(100.0)
@@ -34,3 +40,54 @@ def test_to_dict_rfuncs(rfunc_name: str) -> None:
     p2 = rfunc2.get_init_parameters("test").initial.to_numpy()
 
     assert (rfunc1.step(p1) - rfunc2.step(p2)).sum() == 0.0
+
+
+@pytest.mark.parametrize("rfunc_name", ps.rfunc.__all__)
+@pytest.mark.parametrize("up", [True, False, None])
+def test_gain_methods(rfunc_name: str, up: bool) -> None:
+    rfunc = getattr(ps.rfunc, rfunc_name)()
+    rfunc.update_rfunc_settings(up=up)
+
+    # Set distances for HantushWellModel
+    if rfunc_name == "HantushWellModel":
+        rfunc.set_distances(100.0)
+
+    # Get parameters
+    p = rfunc.get_init_parameters("test").initial.to_numpy()
+
+    # Test gain method exists and returns expected type
+    gain_value = rfunc.gain(p)
+    assert isinstance(gain_value, (float, np.float64, np.ndarray))
+
+    # Compare gain with final step value for steady-state response functions
+    if rfunc_name not in ["FourParam"]:  # Some functions need special handling
+        tmax = rfunc.get_tmax(p)
+        if np.isfinite(tmax) and tmax > 0:
+            step_response = rfunc.step(p)
+            # Check if they're approximately equal at steady state
+            if len(step_response) > 0:
+                assert abs(gain_value - step_response[-1]) < 0.02
+
+
+@pytest.mark.parametrize("rfunc_name", ["HantushWellModel"])
+def test_gain_methods_with_distance(rfunc_name: str) -> None:
+    """Test gain methods that require distance parameter."""
+    rfunc = getattr(ps.rfunc, rfunc_name)()
+
+    # Set distances
+    distances = [50.0, 100.0, 200.0]
+    rfunc.set_distances(distances[0])
+
+    # Get parameters
+    p = rfunc.get_init_parameters("test").initial.to_numpy()
+
+    # Test gain method with distance parameter
+    for distance in distances:
+        gain_value = rfunc.gain(p, r=distance)
+        assert isinstance(gain_value, (float, np.float64))
+
+        # Test gain method with different distances
+        rfunc.set_distances(distance)
+        p2 = rfunc.get_init_parameters("test").initial.to_numpy()
+        gain_value2 = rfunc.gain(p2)
+        assert isinstance(gain_value2, (float, np.float64))


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request cleans up test files by removing leftover comments and outdated test code, aligning tests with current expectations. Key changes include:
- Removal of obsolete ARMA noise model test cases in tests/test_noisemodels.py.
- Cleanup of unnecessary fixture comments in tests/test_modelstats.py.
- Refinement of parameter comparison and tighter tolerance checks in tests/test_model.py and tests/test_dutch.py.

### Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

| File                    | Description                                                           |
| ----------------------- | --------------------------------------------------------------------- |
| tests/test_noisemodels.py | Removed ARMA noise model simulation tests to clean up leftover code.  |
| tests/test_modelstats.py  | Removed unused fixture comments.                                      |
| tests/test_model.py       | Changed parameter assertion to compare unsorted data directly.        |
| tests/test_dutch.py       | Updated tests with stricter tolerances and use of provided fixtures.  |


<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**tests/test_noisemodels.py:230**
* The removal of the ARMA noise model tests might leave a gap in test coverage. If ARMA behavior is still required, consider adding or retaining a dedicated test case to verify its functionality.
```
arma_model = ArmaNoiseModel()
```
**tests/test_dutch.py:218**
* The stricter tolerance of 1.0 compared to the previous 10.0 may cause failures if minor numeric variations occur. Please verify that this new threshold is robust under all expected conditions.
```
assert abs(result - mean_value) < 1.0
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-29T06:46:04Z
user: login: raoulcollenteur
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T08:30:10Z
user: login: dbrakenhoff
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T09:12:04Z
user: login: dbrakenhoff
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-29T09:14:08Z
user: login: raoulcollenteur
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-29T09:18:36Z

Review comments:
diff_hunk: @@ -583,9 +583,7 @@ def test_to_file_and_load(self, ml_noisemodel: ps.Model, tmp_path: Any) -> None:
         assert loaded_model.stressmodels.keys() == ml_noisemodel.stressmodels.keys()
 
         # Check parameters
-        assert_frame_equal(
-            loaded_model.parameters.sort_index(), ml_noisemodel.parameters.sort_index()
-        )
+        assert_frame_equal(loaded_model.parameters, ml_noisemodel.parameters)
path: tests/test_model.py
user: login: Copilot
body: Directly comparing 'loaded_model.parameters' with 'ml_noisemodel.parameters' without sorting may lead to flaky tests if the column order is not deterministic. Consider applying sort_index() to both dataframes or ensuring that the ordering is consistent.
```suggestion
        assert_frame_equal(
            loaded_model.parameters.sort_index(axis=0).sort_index(axis=1),
            ml_noisemodel.parameters.sort_index(axis=0).sort_index(axis=1),
        )
```
created_at: 2025-04-29T06:46:04Z
author_association: NONE
diff_hunk: @@ -583,9 +583,7 @@ def test_to_file_and_load(self, ml_noisemodel: ps.Model, tmp_path: Any) -> None:
         assert loaded_model.stressmodels.keys() == ml_noisemodel.stressmodels.keys()
 
         # Check parameters
-        assert_frame_equal(
-            loaded_model.parameters.sort_index(), ml_noisemodel.parameters.sort_index()
-        )
+        assert_frame_equal(loaded_model.parameters, ml_noisemodel.parameters)
path: tests/test_model.py
user: login: raoulcollenteur
body: The loaded param dataframes are sorted
created_at: 2025-04-29T08:30:10Z
author_association: MEMBER
diff_hunk: @@ -34,3 +40,56 @@ def test_to_dict_rfuncs(rfunc_name: str) -> None:
     p2 = rfunc2.get_init_parameters("test").initial.to_numpy()
 
     assert (rfunc1.step(p1) - rfunc2.step(p2)).sum() == 0.0
+
+
+@pytest.mark.parametrize("rfunc_name", ps.rfunc.__all__)
+@pytest.mark.parametrize("up", [True, False, None])
+def test_gain_methods(rfunc_name: str, up: bool) -> None:
+    rfunc = getattr(ps.rfunc, rfunc_name)()
+    rfunc.update_rfunc_settings(up=up)
+
+    # Set distances for HantushWellModel
+    if rfunc_name == "HantushWellModel":
+        rfunc.set_distances(100.0)
+    if rfunc_name == "HantushWellModel":
path: tests/test_rfuncs.py
user: login: dbrakenhoff
body: double code?
created_at: 2025-04-29T09:12:04Z
author_association: MEMBER
diff_hunk: @@ -34,3 +40,56 @@ def test_to_dict_rfuncs(rfunc_name: str) -> None:
     p2 = rfunc2.get_init_parameters("test").initial.to_numpy()
 
     assert (rfunc1.step(p1) - rfunc2.step(p2)).sum() == 0.0
+
+
+@pytest.mark.parametrize("rfunc_name", ps.rfunc.__all__)
+@pytest.mark.parametrize("up", [True, False, None])
+def test_gain_methods(rfunc_name: str, up: bool) -> None:
+    rfunc = getattr(ps.rfunc, rfunc_name)()
+    rfunc.update_rfunc_settings(up=up)
+
+    # Set distances for HantushWellModel
+    if rfunc_name == "HantushWellModel":
+        rfunc.set_distances(100.0)
+    if rfunc_name == "HantushWellModel":
path: tests/test_rfuncs.py
user: login: raoulcollenteur
body: Yes, removed! :)
created_at: 2025-04-29T09:18:36Z
author_association: MEMBER

PR comments:
user: login: codacy-production[bot]
created_at: 2025-04-29T06:54:38Z
body: ## Coverage summary from Codacy
### [See diff coverage on Codacy](https://app.codacy.com/gh/pastas/pastas/pull-requests/946/coverage?utm_source=github.com&utm_medium=coverageSummary&utm_campaign=coverageSummaryPullRequest)

 | Coverage variation | Diff coverage | 
 | ------------- | ------------- |
 | :white_check_mark: **+0.70%** (target: -1.00%) | :white_check_mark: **100.00%** |

<details>
<summary>Coverage variation details</summary>

| | Coverable lines | Covered lines | Coverage |
| ------------- | ------------- | ------------- | ------------- |
| Common ancestor commit (e00fc1a1d2076dee627b686cd2e6b76bdbf44aaa) | 9022 | 7935 | 87.95% | |
| Head commit (b9a869d7867c1fa32723c578476118ed148eb9f5) | 9104 (+82) | 8071 (+136) | 88.65% (**+0.70%**) |

**Coverage variation** is the difference between the coverage for the head and common ancestor commits of the pull request branch: `<coverage of head commit> - <coverage of common ancestor commit>`
</details>

<details>
<summary>Diff coverage details</summary>

| | Coverable lines | Covered lines | Diff coverage |
| ------------- | ------------- | ------------- | ------------- |
| Pull request (#946) | 107 | 107 | **100.00%** |

**Diff coverage** is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: `<covered lines added or modified>/<coverable lines added or modified> * 100%`
</details>

#### [See your quality gate settings](https://app.codacy.com/gh/pastas/pastas/settings/quality?utm_source=github.com&utm_medium=coverageSummary&utm_campaign=coverageSummaryGates)&nbsp;&nbsp;&nbsp;&nbsp;[Change summary preferences](https://app.codacy.com/gh/pastas/pastas/settings/integrations?utm_source=github.com&utm_medium=coverageSummary&utm_campaign=coverageSummarySettings)

<!-- 108f945d-e553-4918-8ccf-027c6d4acc2c -->
author_association: NONE
user: login: raoulcollenteur
created_at: 2025-04-29T09:31:30Z
body: Thanks, I'll merge after the tests are run.
author_association: MEMBER