From ef14ee4c841338e153c5e8a1857cce8dec495ec9 Mon Sep 17 00:00:00 2001 From: Stas Khirman Date: Tue, 17 Jun 2025 01:28:20 +0300 Subject: [PATCH 1/4] ruff reformating --- iglu_python/adrr.py | 4 +- iglu_python/ea1c.py | 4 +- iglu_python/grade_eugly.py | 6 +-- iglu_python/grade_hyper.py | 4 +- iglu_python/grade_hypo.py | 6 +-- iglu_python/gvp.py | 4 +- iglu_python/hbgi.py | 2 +- iglu_python/hyper_index.py | 2 +- iglu_python/hypo_index.py | 2 +- iglu_python/igc.py | 14 +++--- iglu_python/iqr_glu.py | 4 +- iglu_python/j_index.py | 2 +- iglu_python/mad_glu.py | 2 +- iglu_python/median_glu.py | 2 +- iglu_python/sd_measures.py | 2 +- iglu_python/sd_roc.py | 4 +- iglu_r_discrepancies.ipynb | 4 +- notebooks/auc_evaluation.ipynb | 2 + tests/test_above_percent.py | 4 +- tests/test_active_percent.py | 16 +++---- tests/test_adrr.py | 14 +++--- tests/test_conga.py | 2 +- tests/test_cv_glu.py | 57 +++++++++++----------- tests/test_cv_measures.py | 56 +++++++++++----------- tests/test_ea1c.py | 26 +++++----- tests/test_gmi.py | 2 +- tests/test_grade_eugly.py | 32 ++++++------- tests/test_hyper_index.py | 6 +-- tests/test_in_range_percent.py | 2 +- tests/test_iqr_glu.py | 2 +- tests/test_m_value.py | 2 +- tests/test_modd.py | 4 +- tests/test_process_data.py | 86 +++++++++++++++++----------------- tests/test_sd_measures.py | 72 ++++++++++++++-------------- tests/test_summary_glu.py | 58 +++++++++++------------ 35 files changed, 258 insertions(+), 253 deletions(-) diff --git a/iglu_python/adrr.py b/iglu_python/adrr.py index 5e7a419..1ae3da9 100644 --- a/iglu_python/adrr.py +++ b/iglu_python/adrr.py @@ -1,10 +1,10 @@ -import warnings import numpy as np import pandas as pd from .utils import check_data_columns + def adrr(data: pd.DataFrame|pd.Series) -> pd.DataFrame|float: """ Calculate average daily risk range (ADRR) @@ -83,7 +83,7 @@ def adrr_single(data: pd.DataFrame|pd.Series) -> float: data_filtered = data.dropna() if len(data_filtered) == 0: return np.nan - + # Group by date and calculate daily risk for each day daily_risks = data_filtered.groupby(data_filtered.index.date).apply( lambda x: _calculate_daily_risk(x) diff --git a/iglu_python/ea1c.py b/iglu_python/ea1c.py index 730ea69..b9bca91 100644 --- a/iglu_python/ea1c.py +++ b/iglu_python/ea1c.py @@ -72,9 +72,9 @@ def ea1c_single(data: pd.Series) -> float: """Calculate eA1C for a single subject""" if not isinstance(data, pd.Series): raise ValueError("Data must be a pandas Series") - + data = data.dropna() if len(data) == 0: return np.nan - return (46.7 + data.mean()) / 28.7 \ No newline at end of file + return (46.7 + data.mean()) / 28.7 diff --git a/iglu_python/grade_eugly.py b/iglu_python/grade_eugly.py index 6577caa..9023ecc 100644 --- a/iglu_python/grade_eugly.py +++ b/iglu_python/grade_eugly.py @@ -9,7 +9,7 @@ def grade_eugly( data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: int = 70, upper: int = 140 -) -> pd.DataFrame|float: +) -> pd.DataFrame|float: """ Calculate percentage of GRADE score attributable to target range. @@ -63,7 +63,7 @@ def grade_eugly( if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return grade_eugly_single(data, lower, upper) - + # Handle DataFrame input data = check_data_columns(data) @@ -91,4 +91,4 @@ def grade_eugly_single(data: pd.Series, lower: int = 70, upper: int = 140) -> fl return np.nan eugly_percent = (np.sum(grade_scores[in_range]) / total_grade) * 100 - return eugly_percent \ No newline at end of file + return eugly_percent diff --git a/iglu_python/grade_hyper.py b/iglu_python/grade_hyper.py index 4255396..d7afde2 100644 --- a/iglu_python/grade_hyper.py +++ b/iglu_python/grade_hyper.py @@ -75,7 +75,7 @@ def grade_hyper_single(data: pd.Series, upper: int = 140) -> float: # Calculate GRADE scores grade_scores = _grade_formula(data) - + # Calculate percentage above upper bound above_upper = data > upper total_grade = np.sum(grade_scores) @@ -83,4 +83,4 @@ def grade_hyper_single(data: pd.Series, upper: int = 140) -> float: return np.nan hyper_percent = (np.sum(grade_scores[above_upper]) / total_grade) * 100 - return hyper_percent \ No newline at end of file + return hyper_percent diff --git a/iglu_python/grade_hypo.py b/iglu_python/grade_hypo.py index 2a18697..b2563dd 100644 --- a/iglu_python/grade_hypo.py +++ b/iglu_python/grade_hypo.py @@ -58,7 +58,7 @@ def grade_hypo(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: in if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return grade_hypo_single(data, lower) - + # Handle DataFrame input data = check_data_columns(data) @@ -77,7 +77,7 @@ def grade_hypo_single(data: pd.Series, lower: int = 80) -> float: # Calculate GRADE scores grade_scores = _grade_formula(data) - + # Calculate percentage below lower bound below_lower = data < lower total_grade = np.sum(grade_scores) @@ -85,4 +85,4 @@ def grade_hypo_single(data: pd.Series, lower: int = 80) -> float: return np.nan hypo_percent = (np.sum(grade_scores[below_lower]) / total_grade) * 100 - return hypo_percent \ No newline at end of file + return hypo_percent diff --git a/iglu_python/gvp.py b/iglu_python/gvp.py index b53fbce..ce08e31 100644 --- a/iglu_python/gvp.py +++ b/iglu_python/gvp.py @@ -63,7 +63,7 @@ def gvp(data: Union[pd.DataFrame, pd.Series]) -> pd.DataFrame|float: return gvp_single(data) # Handle DataFrame input - data = check_data_columns(data) + data = check_data_columns(data) data.set_index("time", inplace=True, drop=True) out = data.groupby('id').agg( @@ -138,4 +138,4 @@ def gvp_single(subj_data): if base_length == 0: return np.nan - return (np.sum(added_length) / base_length - 1) * 100 \ No newline at end of file + return (np.sum(added_length) / base_length - 1) * 100 diff --git a/iglu_python/hbgi.py b/iglu_python/hbgi.py index 3eef969..6697c60 100644 --- a/iglu_python/hbgi.py +++ b/iglu_python/hbgi.py @@ -88,4 +88,4 @@ def calculate_hbgi_single(glucose_values: pd.Series) -> float: n = len(glucose_values) hbgi_value = 10 * np.sum(fbg[glucose_values >= 112.5] ** 2) / n - return hbgi_value \ No newline at end of file + return hbgi_value diff --git a/iglu_python/hyper_index.py b/iglu_python/hyper_index.py index c184555..a687846 100644 --- a/iglu_python/hyper_index.py +++ b/iglu_python/hyper_index.py @@ -90,4 +90,4 @@ def hyper_index_single( hyper_values = gl[gl > ULTR] - ULTR hyper_index = np.sum(hyper_values**a) / (len(gl) * c) - return hyper_index \ No newline at end of file + return hyper_index diff --git a/iglu_python/hypo_index.py b/iglu_python/hypo_index.py index c92ac37..0bc3a22 100644 --- a/iglu_python/hypo_index.py +++ b/iglu_python/hypo_index.py @@ -67,7 +67,7 @@ def hypo_index( if isinstance(data, (np.ndarray, list)): data = pd.Series(data) return hypo_index_single(data, LLTR, b, d) - + data = check_data_columns(data) out = data.groupby('id').agg( hypo_index = ("gl", lambda x: hypo_index_single(x, LLTR, b, d)) diff --git a/iglu_python/igc.py b/iglu_python/igc.py index 0d058e1..b1707b8 100644 --- a/iglu_python/igc.py +++ b/iglu_python/igc.py @@ -86,12 +86,12 @@ def igc( return out def igc_single( - gl: pd.Series, - LLTR: int = 80, - ULTR: int = 140, - a: float = 1.1, - b: float = 2, - c: int = 30, + gl: pd.Series, + LLTR: int = 80, + ULTR: int = 140, + a: float = 1.1, + b: float = 2, + c: int = 30, d: int = 30 ) -> float: """ @@ -102,4 +102,4 @@ def igc_single( out_hypo = hypo_index(gl, LLTR=LLTR, b=b, d=d) out = out_hyper + out_hypo - return out \ No newline at end of file + return out diff --git a/iglu_python/iqr_glu.py b/iglu_python/iqr_glu.py index 93dc40b..18e5859 100644 --- a/iglu_python/iqr_glu.py +++ b/iglu_python/iqr_glu.py @@ -51,7 +51,7 @@ def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr return np.nan # Calculate IQR for Series iqr_val = iqr_glu_single(data) - return iqr_val + return iqr_val # Handle DataFrame input data = check_data_columns(data) @@ -85,4 +85,4 @@ def iqr_glu_single( return np.nan # Calculate IQR for Series iqr_val = np.percentile(gl, 75) - np.percentile(gl, 25) - return iqr_val \ No newline at end of file + return iqr_val diff --git a/iglu_python/j_index.py b/iglu_python/j_index.py index c3b477d..74b68cd 100644 --- a/iglu_python/j_index.py +++ b/iglu_python/j_index.py @@ -78,4 +78,4 @@ def j_index_single(gl: pd.Series) -> float: # Calculate J-index j_index = 0.001 * (mean_gl + sd_gl) ** 2 - return j_index \ No newline at end of file + return j_index diff --git a/iglu_python/mad_glu.py b/iglu_python/mad_glu.py index d46edc1..2f3b92f 100644 --- a/iglu_python/mad_glu.py +++ b/iglu_python/mad_glu.py @@ -74,4 +74,4 @@ def mad_glu_single(gl: pd.Series, constant: float = 1.4826) -> float: if len(gl) == 0: return np.nan mad_val = np.median(np.abs(gl - np.median(gl))) * constant - return mad_val \ No newline at end of file + return mad_val diff --git a/iglu_python/median_glu.py b/iglu_python/median_glu.py index b23c735..3ff0be7 100644 --- a/iglu_python/median_glu.py +++ b/iglu_python/median_glu.py @@ -1,7 +1,7 @@ from typing import Union -import pandas as pd import numpy as np +import pandas as pd from .utils import check_data_columns diff --git a/iglu_python/sd_measures.py b/iglu_python/sd_measures.py index 18242fa..653856b 100644 --- a/iglu_python/sd_measures.py +++ b/iglu_python/sd_measures.py @@ -102,7 +102,7 @@ def sd_measures_single(data: pd.DataFrame, dt0: Optional[int] = None, inter_gap: int = 45, tz: str = "") -> dict[str, float]: - + gd2d, actual_dates, gd2d_dt0 = CGMS2DayByDay(data, tz=tz, dt0=dt0, inter_gap=inter_gap) return _calculate_sd_subtypes(gd2d, gd2d_dt0) diff --git a/iglu_python/sd_roc.py b/iglu_python/sd_roc.py index 71ea28d..36bafbd 100644 --- a/iglu_python/sd_roc.py +++ b/iglu_python/sd_roc.py @@ -108,7 +108,7 @@ def sd_roc_single(data: pd.Series, dt0: int = 5, inter_gap: int = 45, tz: str = "") -> float: - + roc_data = roc(data, timelag=timelag, dt0=dt0, inter_gap=inter_gap, tz=tz) sd_roc = np.nanstd(roc_data.dropna()['roc'], ddof=1) - return sd_roc \ No newline at end of file + return sd_roc diff --git a/iglu_r_discrepancies.ipynb b/iglu_r_discrepancies.ipynb index a873ca2..98ee64c 100644 --- a/iglu_r_discrepancies.ipynb +++ b/iglu_r_discrepancies.ipynb @@ -17,9 +17,9 @@ "import sys\n", "from importlib.metadata import version\n", "\n", + "import iglu_py\n", "import pandas as pd\n", "import rpy2.robjects as ro\n", - "import iglu_py\n", "from iglu_py import bridge" ] }, @@ -818,7 +818,7 @@ "print(actual_dates) # expected [datetime.date(2020, 1, 1)]\n", "print(dt0) # expected 5\n", "\n", - "print(gd2d[:,280:]) \n", + "print(gd2d[:,280:])\n", "print(gd2d[:,:8]) # expected [[150. 155. 160. 165. nan]]" ] }, diff --git a/notebooks/auc_evaluation.ipynb b/notebooks/auc_evaluation.ipynb index 3c2f8b3..280c5eb 100644 --- a/notebooks/auc_evaluation.ipynb +++ b/notebooks/auc_evaluation.ipynb @@ -417,7 +417,9 @@ "# Add project directory to PYTHONPATH\n", "import os\n", "import sys\n", + "\n", "import pandas as pd\n", + "\n", "sys.path.append(os.path.abspath('..'))\n", "import iglu_python\n" ] diff --git a/tests/test_above_percent.py b/tests/test_above_percent.py index 3f0b60f..cc8725a 100644 --- a/tests/test_above_percent.py +++ b/tests/test_above_percent.py @@ -1,7 +1,7 @@ import json -import pandas as pd import numpy as np +import pandas as pd import pytest import iglu_python as iglu @@ -123,4 +123,4 @@ def test_above_percent_output_format(): # Test with numpy array input result_array = iglu.above_percent(data["gl"].values, targets_above=custom_targets) assert isinstance(result_array, dict) - assert all(f"above_{t}" in result_array for t in custom_targets) \ No newline at end of file + assert all(f"above_{t}" in result_array for t in custom_targets) diff --git a/tests/test_active_percent.py b/tests/test_active_percent.py index cb61899..748b2bf 100644 --- a/tests/test_active_percent.py +++ b/tests/test_active_percent.py @@ -188,7 +188,7 @@ def test_active_percent_single_subject_no_gaps(): "gl": [150, 155, 160], } ) - + result = iglu.active_percent(single_subject, dt0=5) assert len(result) == 1 assert result["active_percent"].iloc[0] == 100.0 # Should be 100% active with no gaps @@ -203,7 +203,7 @@ def test_active_percent_series_with_datetime_index(): 90, 130, 95], # Day 2: 3 measurements index=time ) - + # Calculate active_percent result = iglu.active_percent(data) @@ -212,13 +212,13 @@ def test_active_percent_series_with_datetime_index(): assert "ndays" in result assert "start_date" in result assert "end_date" in result - + # Expected results: # Total possible measurements: 2 days * 24 hours * 12 measurements per hour = 576 # Actual measurements: 6 # active_percent = (6 / 576) * 100 = 1.042 expected = 2.061856 - + # Compare results np.testing.assert_allclose(result["active_percent"], expected, rtol=0.001) @@ -229,7 +229,7 @@ def test_active_percent_series_without_datetime_index(): [100, 120, 110, 90, 130, 95], index=range(6) # Regular integer index instead of DatetimeIndex ) - + # Attempt to calculate active_percent - should raise ValueError with pytest.raises(ValueError, match="Series must have a DatetimeIndex"): iglu.active_percent(data) @@ -244,7 +244,7 @@ def test_active_percent_series_with_missing_values(): 90, 130, np.nan], # Day 2: 2 measurements index=time ) - + # Calculate active_percent result = iglu.active_percent(data) assert isinstance(result, dict) @@ -252,13 +252,13 @@ def test_active_percent_series_with_missing_values(): assert "ndays" in result assert "start_date" in result assert "end_date" in result - + # Expected results: # Total possible measurements: 2 days * 24 hours * 12 measurements per hour = 576 # Actual measurements (excluding NaN): 4 # active_percent = (4 / 576) * 100 = 0.694 expected = 2.068966 - + # Compare results np.testing.assert_allclose(result["active_percent"], expected, rtol=0.001) diff --git a/tests/test_adrr.py b/tests/test_adrr.py index 0f26da2..2fd62bc 100644 --- a/tests/test_adrr.py +++ b/tests/test_adrr.py @@ -1,7 +1,7 @@ import json -import pandas as pd import numpy as np +import pandas as pd import pytest import iglu_python as iglu @@ -72,10 +72,10 @@ def test_adrr_series_with_datetime_index(): 90, 130, 95], # Day 2: LBGI=0.7, HBGI=1.2 index=time ) - + # Calculate ADRR result = iglu.adrr(data) - + # Expected results: # Day 1: LBGI=0.5, HBGI=0.8, Risk=1.3 # Day 2: LBGI=0.7, HBGI=1.2, Risk=1.9 @@ -92,7 +92,7 @@ def test_adrr_series_without_datetime_index(): [100, 120, 110, 90, 130, 95], index=range(6) # Regular integer index instead of DatetimeIndex ) - + # Attempt to calculate ADRR - should raise ValueError with pytest.raises(ValueError, match="Series must have a DatetimeIndex"): iglu.adrr(data) @@ -107,16 +107,16 @@ def test_adrr_series_with_missing_values(): 90, 130, np.nan], # Day 2: LBGI=0.7, HBGI=1.2 (after interpolation) index=time ) - + # Calculate ADRR with interpolation result = iglu.adrr(data) - + # Expected results: # Day 1: LBGI=0.5, HBGI=0.8, Risk=0.48 # Day 2: LBGI=0.7, HBGI=1.2, Risk=2.45 # ADRR = mean([0.48, 2.45]) = 1.466489 expected = 1.466489 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) diff --git a/tests/test_conga.py b/tests/test_conga.py index e487bd6..64a36a7 100644 --- a/tests/test_conga.py +++ b/tests/test_conga.py @@ -124,7 +124,7 @@ def test_conga_series_without_datetime_index(): [100, 120, 110, 90, 130, 95], index=range(6) # Regular integer index instead of DatetimeIndex ) - + # Attempt to calculate CONGA - should raise ValueError with pytest.raises(ValueError, match="Series must have a DatetimeIndex"): iglu.conga(data) diff --git a/tests/test_cv_glu.py b/tests/test_cv_glu.py index 88cf302..1a9a85d 100644 --- a/tests/test_cv_glu.py +++ b/tests/test_cv_glu.py @@ -1,6 +1,7 @@ """Unit tests for CV (Coefficient of Variation) calculation.""" import json + import numpy as np import pandas as pd import pytest @@ -44,7 +45,7 @@ def test_cv_glu_iglu_r_compatible(scenario): # Calculate CV result_df = iglu.cv_glu(df,**kwargs) - + assert result_df is not None # Compare DataFrames with precision to 0.001 for numeric columns @@ -73,10 +74,10 @@ def test_cv_glu_basic(): 'time': pd.date_range('2020-01-01', periods=6, freq='5min'), 'gl': [100, 120, 110, 90, 130, 95] }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected results: # Subject 1: CV = 100 * np.std([100, 120, 110],ddof=1) / np.mean([100, 120, 110]) ≈ 9.09 # Subject 2: CV = 100 * np.std([90, 130, 95],ddof=1) / np.mean([90, 130, 95]) ≈ 20.75.75 @@ -84,7 +85,7 @@ def test_cv_glu_basic(): 'id': ['1', '2'], 'CV': [9.09, 20.75] }) - + pd.testing.assert_frame_equal( result, expected, @@ -96,13 +97,13 @@ def test_cv_glu_series(): """Test CV calculation with pandas Series input.""" # Create test data data = pd.Series([100, 120, 110, 90, 130, 95]) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected result: CV = 100 * std([100, 120, 110, 90, 130, 95],ddof=1) / mean([100, 120, 110, 90, 130, 95]) ≈ 14.14 expected = 14.33 - + np.testing.assert_allclose(result, expected, rtol=0.001) def test_cv_glu_empty(): @@ -110,7 +111,7 @@ def test_cv_glu_empty(): # Test with empty DataFrame with pytest.raises(ValueError): iglu.cv_glu(pd.DataFrame(columns=['id', 'time', 'gl'])) - + # Test with empty Series with pytest.raises(ValueError): iglu.cv_glu(pd.Series([])) @@ -123,16 +124,16 @@ def test_cv_glu_constant_glucose(): 'time': pd.date_range('2020-01-01', periods=3, freq='5min'), 'gl': [100, 100, 100] }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected result: CV = 0 (since std = 0) expected = pd.DataFrame({ 'id': ['1'], 'CV': [0.0] }) - + pd.testing.assert_frame_equal( result, expected, @@ -148,16 +149,16 @@ def test_cv_glu_missing_values(): 'time': pd.date_range('2020-01-01', periods=4, freq='5min'), 'gl': [100, np.nan, 120, 110] }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected result: CV = 100 * np.std([100, 120, 110],ddof=1) / np.mean([100, 120, 110]) ≈ 9.0909 expected = pd.DataFrame({ 'id': ['1'], - 'CV': [9.0909] + 'CV': [9.0909] }) - + pd.testing.assert_frame_equal( result, expected, @@ -173,16 +174,16 @@ def test_cv_glu_extreme_values(): 'time': pd.date_range('2020-01-01', periods=3, freq='5min'), 'gl': [40, 400, 40] # Very low and very high values }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected result: CV = 100 * std([40, 400, 40],ddof=1) / mean([40, 400, 40]) ≈ 129.90 expected = pd.DataFrame({ 'id': ['1'], 'CV': [129.90] }) - + pd.testing.assert_frame_equal( result, expected, @@ -198,16 +199,16 @@ def test_cv_glu_single_subject(): 'time': pd.date_range('2020-01-01', periods=5, freq='5min'), 'gl': [120, 118, 122, 119, 121] # Small variations around 120 }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected result: CV = 100 * std([120, 118, 122, 119, 121],ddof=1) / mean([120, 118, 122, 119, 121]) ≈ 1.317 expected = pd.DataFrame({ 'id': ['1'], 'CV': [1.317] }) - + pd.testing.assert_frame_equal( result, expected, @@ -224,10 +225,10 @@ def test_cv_glu_uneven_measurements(): 'gl': [100, 120, 110, # Subject 1 90, 130, 95, 125, 105] # Subject 2 }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected results: # Subject 1: CV = 100 * std([100, 120, 110],ddof=1) / mean([100, 120, 110]) ≈ 9.0909 # Subject 2: CV = 100 * std([90, 130, 95, 125, 105],ddof=1) / mean([90, 130, 95, 125, 105]) ≈ 16.3472 @@ -235,7 +236,7 @@ def test_cv_glu_uneven_measurements(): 'id': ['1', '2'], 'CV': [9.0909, 16.3472] }) - + pd.testing.assert_frame_equal( result, expected, @@ -253,10 +254,10 @@ def test_cv_glu_mixed_missing(): 90, 130, np.nan, # Subject 2: one missing np.nan, np.nan, 95] # Subject 3: two missing }) - + # Calculate CV result = iglu.cv_glu(data) - + # Expected results: # Subject 1: CV = 100 * std([100, 110]) / mean([100, 110]) ≈ 4.76 # Subject 2: CV = 100 * std([90, 130]) / mean([90, 130]) ≈ 18.18 @@ -265,10 +266,10 @@ def test_cv_glu_mixed_missing(): 'id': ['1', '2', '3'], 'CV': [6.73435, 25.712, np.nan] }) - + pd.testing.assert_frame_equal( result, expected, check_dtype=False, rtol=1e-2 - ) \ No newline at end of file + ) diff --git a/tests/test_cv_measures.py b/tests/test_cv_measures.py index ec9edbf..f74232c 100644 --- a/tests/test_cv_measures.py +++ b/tests/test_cv_measures.py @@ -1,9 +1,11 @@ """Unit tests for CV measures (CVmean and CVsd) calculation.""" import json + import numpy as np import pandas as pd import pytest + import iglu_python as iglu method_name = "cv_measures" @@ -40,10 +42,10 @@ def test_cv_measures_iglu_r_compatible(scenario): df = pd.read_csv(input_file_name, index_col=0) if "time" in df.columns: df["time"] = pd.to_datetime(df["time"]) - + # Calculate CV measures result_df = iglu.cv_measures(df,**kwargs) - + # Compare with expected results pd.testing.assert_frame_equal( result_df.round(3), @@ -73,10 +75,10 @@ def test_cv_measures_basic(): 'gl': [100, 120, 110, # Day 1: mean=110, std=10, CV=9.09 90, 130, 95] # Day 2: mean=105, std=21.21, CV=20.75 }) - + # Calculate CV measures result = iglu.cv_measures(data) - + # Expected results: # CVmean = np.mean([9.09, 20.75]) = 14.92 # CVsd = np.std([9.09, 20.75],ddof=1) = 8.244 @@ -85,7 +87,7 @@ def test_cv_measures_basic(): 'CVmean': [14.92], 'CVsd': [8.244] }) - + pd.testing.assert_frame_equal( result, expected, @@ -109,10 +111,10 @@ def test_cv_measures_multiple_subjects(): 80, 100, 90, # Subject 2, Day 1: CV=11.11 70, 110, 80] # Subject 2, Day 2: CV=25.00 }) - + # Calculate CV measures result = iglu.cv_measures(data) - + # Expected results: # Subject 1: CVmean=14.92, CVsd=8.244 # Subject 2: CVmean=17.565, CVsd=9.127 @@ -121,7 +123,7 @@ def test_cv_measures_multiple_subjects(): 'CVmean': [14.92, 17.565], 'CVsd': [8.244, 9.127] }) - + pd.testing.assert_frame_equal( result, expected, @@ -141,10 +143,10 @@ def test_cv_measures_missing_values(): 'gl': [100, np.nan, 110, # Day 1: CV=7.07 (after interpolation) 90, 130, np.nan] # Day 2: CV=28.28 (after interpolation) }) - + # Calculate CV measures result = iglu.cv_measures(data, inter_gap=45) # Allow interpolation - + # Expected results: # CVmean = mean([7.07, 28.28]) = 17.68 # CVsd = np.std([7.07, 28.28],ddof=1) = 13.419 @@ -153,7 +155,7 @@ def test_cv_measures_missing_values(): 'CVmean': [16.223], 'CVsd': [13.419] }) - + pd.testing.assert_frame_equal( result, expected, @@ -173,10 +175,10 @@ def test_cv_measures_constant_glucose(): 'gl': [100, 100, 100, # Day 1: CV=0 100, 100, 100] # Day 2: CV=0 }) - + # Calculate CV measures result = iglu.cv_measures(data) - + # Expected results: # CVmean = mean([0, 0]) = 0 # CVsd = std([0, 0]) = 0 @@ -185,7 +187,7 @@ def test_cv_measures_constant_glucose(): 'CVmean': [0.0], 'CVsd': [0.0] }) - + pd.testing.assert_frame_equal( result, expected, @@ -201,10 +203,10 @@ def test_cv_measures_single_day(): 'time': pd.date_range('2020-01-01 10:00:00', periods=3, freq='5min'), 'gl': [100, 120, 110] # CV=9.09 }) - + # Calculate CV measures result = iglu.cv_measures(data) - + # Expected results: # CVmean = 9.09 (only one day) # CVsd = NaN (can't calculate std with one value) @@ -213,7 +215,7 @@ def test_cv_measures_single_day(): 'CVmean': [9.09], 'CVsd': [np.nan] }) - + pd.testing.assert_frame_equal( result, expected, @@ -239,17 +241,17 @@ def test_cv_measures_custom_dt0(): 'gl': [100, 120, 110, # Day 1 90, 130, 95] # Day 2 }) - + # Calculate CV measures with custom dt0 result = iglu.cv_measures(data, dt0=5) # 5-minute intervals - + # The results should be the same as without dt0 since our data is already in 5-minute intervals expected = pd.DataFrame({ 'id': ['1'], 'CVmean': [14.92], 'CVsd': [8.244] }) - + pd.testing.assert_frame_equal( result, expected, @@ -267,10 +269,10 @@ def test_cv_measures_series_with_datetime_index(): 90, 130, 95], # Day 2: mean=105, std=21.21, CV=20.75 index=time ) - + # Calculate CV measures result = iglu.cv_measures(data) - + # Expected results: # CVmean = np.mean([9.09, 20.75]) = 14.92 # CVsd = np.std([9.09, 20.75], ddof=1) = 8.244 @@ -278,7 +280,7 @@ def test_cv_measures_series_with_datetime_index(): 'CVmean': 14.92, 'CVsd': 8.244 } - + # Compare results assert isinstance(result, dict) np.testing.assert_allclose(result['CVmean'], expected['CVmean'], rtol=0.001) @@ -291,7 +293,7 @@ def test_cv_measures_series_without_datetime_index(): [100, 120, 110, 90, 130, 95], index=range(6) # Regular integer index instead of DatetimeIndex ) - + # Attempt to calculate CV measures - should raise ValueError with pytest.raises(ValueError, match="Series must have a DatetimeIndex"): iglu.cv_measures(data) @@ -306,10 +308,10 @@ def test_cv_measures_series_with_missing_values(): 90, 130, np.nan], # Day 2: CV=28.28 (after interpolation) index=time ) - + # Calculate CV measures with interpolation result = iglu.cv_measures(data, inter_gap=45) - + # Expected results: # CVmean = 16.223 # CVsd = 13.419 @@ -317,7 +319,7 @@ def test_cv_measures_series_with_missing_values(): 'CVmean': 16.223, 'CVsd': 13.419 } - + # Compare results assert isinstance(result, dict) np.testing.assert_allclose(result['CVmean'], expected['CVmean'], rtol=0.001) diff --git a/tests/test_ea1c.py b/tests/test_ea1c.py index 0ff6538..0a00bf0 100644 --- a/tests/test_ea1c.py +++ b/tests/test_ea1c.py @@ -200,15 +200,15 @@ def test_ea1c_list_input(): """Test EA1c calculation with list input.""" # Create test data as a list data = [100, 120, 110, 90, 130, 95] # mean = 107.5 - + # Calculate EA1c result = iglu.ea1c(data) - + # Expected results: # EA1c = (mean_glucose + 46.7) / 28.7 # EA1c = (107.5 + 46.7) / 28.7 = 5.376 expected = 5.376 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -218,15 +218,15 @@ def test_ea1c_numpy_array_input(): """Test EA1c calculation with numpy array input.""" # Create test data as a numpy array data = np.array([100, 120, 110, 90, 130, 95]) # mean = 107.5 - + # Calculate EA1c result = iglu.ea1c(data) - + # Expected results: # EA1c = (mean_glucose + 46.7) / 28.7 # EA1c = (107.5 + 46.7) / 28.7 = 5.376 expected = 5.376 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -236,15 +236,15 @@ def test_ea1c_list_with_missing_values(): """Test EA1c calculation with list input containing missing values.""" # Create test data as a list with None values data = [100, None, 110, 90, 130, None] # mean = 107.5 (excluding None) - + # Calculate EA1c result = iglu.ea1c(data) - + # Expected results: # EA1c = (mean_glucose + 46.7) / 28.7 # EA1c = (107.5 + 46.7) / 28.7 = 5.376 expected = 5.376 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -254,15 +254,15 @@ def test_ea1c_numpy_array_with_nan(): """Test EA1c calculation with numpy array input containing NaN values.""" # Create test data as a numpy array with NaN values data = np.array([100, np.nan, 110, 90, 130, np.nan]) # mean = 107.5 (excluding NaN) - + # Calculate EA1c result = iglu.ea1c(data) - + # Expected results: # EA1c = (mean_glucose + 46.7) / 28.7 # EA1c = (107.5 + 46.7) / 28.7 = 5.376 expected = 5.376 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -274,7 +274,7 @@ def test_ea1c_empty_input(): result = iglu.ea1c([]) assert isinstance(result, float) assert np.isnan(result) - + # Test with empty numpy array result = iglu.ea1c(np.array([])) assert isinstance(result, float) diff --git a/tests/test_gmi.py b/tests/test_gmi.py index 3e6047a..9157788 100644 --- a/tests/test_gmi.py +++ b/tests/test_gmi.py @@ -194,4 +194,4 @@ def test_gmi_extreme_values(): # Mean glucose = (40 + 400 + 600 + 800) / 4 = 460 # GMI = 3.31 + (0.02392 * 460) = 14.3132 expected_gmi = 3.31 + (0.02392 * 460) - assert abs(result["GMI"].iloc[0] - expected_gmi) < 0.001 \ No newline at end of file + assert abs(result["GMI"].iloc[0] - expected_gmi) < 0.001 diff --git a/tests/test_grade_eugly.py b/tests/test_grade_eugly.py index 1acde3f..c24237e 100644 --- a/tests/test_grade_eugly.py +++ b/tests/test_grade_eugly.py @@ -247,16 +247,16 @@ def test_grade_eugly_list_input(): """Test GRADE euglycemia calculation with list input.""" # Create test data as a list data = [70, 80, 90, 100, 110, 120, 130, 140, 150, 160] # 4 values in euglycemic range (70-140) - + # Calculate GRADE euglycemia result = iglu.grade_eugly(data) - + # Expected results: # Euglycemic values: 80, 90, 100, 110, 120, 130, 140 (7 values) # Total values: 10 # GRADE euglycemia = (7 / 10) * 100 = 70.0 expected = 51.496907 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -266,16 +266,16 @@ def test_grade_eugly_numpy_array_input(): """Test GRADE euglycemia calculation with numpy array input.""" # Create test data as a numpy array data = np.array([70, 80, 90, 100, 110, 120, 130, 140, 150, 160]) # 4 values in euglycemic range (70-140) - + # Calculate GRADE euglycemia result = iglu.grade_eugly(data) - + # Expected results: # Euglycemic values: 80, 90, 100, 110, 120, 130, 140 (7 values) # Total values: 10 # GRADE euglycemia = (7 / 10) * 100 = 70.0 expected = 51.496907 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -285,16 +285,16 @@ def test_grade_eugly_list_with_missing_values(): """Test GRADE euglycemia calculation with list input containing missing values.""" # Create test data as a list with None values data = [70, None, 90, 100, None, 120, 130, 140, None, 160] # 5 values in euglycemic range (70-140) - + # Calculate GRADE euglycemia result = iglu.grade_eugly(data) - + # Expected results: # Euglycemic values: 90, 100, 120, 130, 140 (5 values) # Total non-None values: 7 # GRADE euglycemia = (5 / 7) * 100 = 71.429 expected = 63.297202 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -304,16 +304,16 @@ def test_grade_eugly_numpy_array_with_nan(): """Test GRADE euglycemia calculation with numpy array input containing NaN values.""" # Create test data as a numpy array with NaN values data = np.array([70, np.nan, 90, 100, np.nan, 120, 130, 140, np.nan, 160]) # 5 values in euglycemic range (70-140) - + # Calculate GRADE euglycemia result = iglu.grade_eugly(data) - + # Expected results: # Euglycemic values: 90, 100, 120, 130, 140 (5 values) # Total non-NaN values: 7 # GRADE euglycemia = (5 / 7) * 100 = 71.429 expected = 63.297202 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) @@ -325,7 +325,7 @@ def test_grade_eugly_empty_input(): result = iglu.grade_eugly([]) assert isinstance(result, float) assert np.isnan(result) - + # Test with empty numpy array result = iglu.grade_eugly(np.array([])) assert isinstance(result, float) @@ -336,16 +336,16 @@ def test_grade_eugly_boundary_values(): """Test GRADE euglycemia calculation with boundary values.""" # Create test data with boundary values (70 and 140) data = [60, 70, 80, 140, 150] # 70 and 140 are included in euglycemic range - + # Calculate GRADE euglycemia result = iglu.grade_eugly(data) - + # Expected results: # Euglycemic values: 70, 80, 140 (3 values) # Total values: 5 # GRADE euglycemia = (3 / 5) * 100 = 60.0 expected = 36.910589 - + # Compare results assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=0.001) diff --git a/tests/test_hyper_index.py b/tests/test_hyper_index.py index d7c2bfc..dc8bdbb 100644 --- a/tests/test_hyper_index.py +++ b/tests/test_hyper_index.py @@ -108,7 +108,7 @@ def test_hyper_index_list_input(): # Calculate hyper_index result = iglu.hyper_index(data) - expected = 1.453976 + expected = 1.453976 # Check output format assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=1e-3) @@ -120,7 +120,7 @@ def test_hyper_index_numpy_array_input(): # Calculate hyper_index result = iglu.hyper_index(data) - expected = 1.453976 + expected = 1.453976 # Check output format assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=1e-3) @@ -132,7 +132,7 @@ def test_hyper_index_series_input(): # Calculate hyper_index result = iglu.hyper_index(data) - expected = 1.453976 + expected = 1.453976 # Check output format assert isinstance(result, float) np.testing.assert_allclose(result, expected, rtol=1e-3) diff --git a/tests/test_in_range_percent.py b/tests/test_in_range_percent.py index a39876e..45828b6 100644 --- a/tests/test_in_range_percent.py +++ b/tests/test_in_range_percent.py @@ -147,7 +147,7 @@ def test_in_range_percent_numpy_array_input(): # Check that percentages are between 0 and 100 np.testing.assert_allclose(result["in_range_70_180"], 83.33, rtol=1e-3) np.testing.assert_allclose(result["in_range_63_140"], 66.66, rtol=1e-3) - + def test_in_range_percent_custom_targets(): """Test in_range_percent calculation with custom targets.""" data = pd.DataFrame( diff --git a/tests/test_iqr_glu.py b/tests/test_iqr_glu.py index 0e8faec..adbd7ca 100644 --- a/tests/test_iqr_glu.py +++ b/tests/test_iqr_glu.py @@ -123,7 +123,7 @@ def test_iqr_glu_output_format(): result_array = iglu.iqr_glu(array_data) assert isinstance(result_array, float) np.testing.assert_allclose(result_array, 12.5, rtol=1e-3) - + # Test with empty data empty_data = pd.DataFrame(columns=["id", "time", "gl"]) with pytest.raises(ValueError): diff --git a/tests/test_m_value.py b/tests/test_m_value.py index aef13d1..705b4b5 100644 --- a/tests/test_m_value.py +++ b/tests/test_m_value.py @@ -106,7 +106,7 @@ def test_m_value_series_input(): """Test M-value calculation with Series input.""" data = pd.Series([90, 180, 90, 90]) result = iglu.m_value(data) - expected = 6.819764 + expected = 6.819764 # Check output format assert isinstance(result, float) diff --git a/tests/test_modd.py b/tests/test_modd.py index b17d04c..ba559bd 100644 --- a/tests/test_modd.py +++ b/tests/test_modd.py @@ -106,7 +106,7 @@ def test_modd_default_output(): def test_modd_custom_lag(): """Test modd calculation with custom lag value""" - samples_per_day = int(24*60/5) # sample each 5 min + samples_per_day = int(24*60/5) # sample each 5 min data = pd.DataFrame( { "id": ["subject1"] * 3 * samples_per_day, @@ -123,7 +123,7 @@ def test_modd_custom_lag(): def test_modd_series_input(): """Test modd calculation with Series input""" - samples_per_day = int(24*60/5) # sample each 5 min + samples_per_day = int(24*60/5) # sample each 5 min series_data = pd.Series( [150]*samples_per_day + [200]*samples_per_day + [250]*samples_per_day, index=pd.date_range(start="2020-01-01 00:00:00", periods=3*samples_per_day, freq="5min") diff --git a/tests/test_process_data.py b/tests/test_process_data.py index 5520dcc..2332c70 100644 --- a/tests/test_process_data.py +++ b/tests/test_process_data.py @@ -73,23 +73,23 @@ def test_process_data_basic(): """Test basic process_data functionality.""" data = pd.DataFrame({ 'subject_id': ['A', 'A', 'B', 'B'], - 'datetime': ['2020-01-01 10:00:00', '2020-01-01 10:05:00', + 'datetime': ['2020-01-01 10:00:00', '2020-01-01 10:05:00', '2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'glucose': [120, 130, 110, 125] }) - + result = iglu.process_data(data, id='subject_id', timestamp='datetime', glu='glucose') - + # Check output structure assert isinstance(result, pd.DataFrame) assert list(result.columns) == ['id', 'time', 'gl'] assert len(result) == 4 - + # Check data types assert pd.api.types.is_string_dtype(result['id']) for col in ['gl']: assert np.issubdtype(result[col].dtype, np.number) - + # Check values assert set(result['id'].unique()) == {'A', 'B'} assert all(result['gl'] >= 0) @@ -101,21 +101,21 @@ def test_process_data_default_id(): 'datetime': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'glucose': [120, 130] }) - + # Capture the print output import io import sys captured_output = io.StringIO() sys.stdout = captured_output - + result = iglu.process_data(data, timestamp='datetime', glu='glucose') - + # Restore stdout sys.stdout = sys.__stdout__ - + # Check that the default id message was printed assert "No 'id' parameter passed, defaulting id to 1" in captured_output.getvalue() - + # Check result assert list(result.columns) == ['id', 'time', 'gl'] assert all(result['id'] == '1') @@ -128,9 +128,9 @@ def test_process_data_case_insensitive(): 'DateTime': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'Glucose': [120, 130] }) - + result = iglu.process_data(data, id='subject_id', timestamp='datetime', glu='glucose') - + assert list(result.columns) == ['id', 'time', 'gl'] assert len(result) == 2 @@ -142,9 +142,9 @@ def test_process_data_mmol_conversion(): 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'glucose_mmol/l': [6.7, 7.2] # mmol/L values }) - + result = iglu.process_data(data, id='id', timestamp='time', glu='glucose_mmol/l') - + # Check conversion (6.7 mmol/L * 18 = 120.6 mg/dL) assert abs(result['gl'].iloc[0] - 120.6) < 0.1 assert abs(result['gl'].iloc[1] - 129.6) < 0.1 @@ -154,9 +154,9 @@ def test_process_data_series_with_datetime_index(): """Test process_data with Series input having datetime index.""" dates = pd.date_range('2020-01-01 10:00:00', periods=3, freq='5min') series_data = pd.Series([120, 130, 125], index=dates) - + result = iglu.process_data(series_data) - + assert list(result.columns) == ['id', 'time', 'gl'] assert len(result) == 3 assert all(result['id'] == '1') @@ -173,7 +173,7 @@ def test_process_data_series_without_datetime_index(): def test_process_data_list_input(): """Test process_data with list input.""" glucose_list = [120, 130, 125, 140] - + with pytest.raises(ValueError): iglu.process_data(glucose_list) @@ -181,23 +181,23 @@ def test_process_data_list_input(): def test_process_data_numpy_array(): """Test process_data with numpy array input.""" glucose_array = np.array([120, 130, 125, 140]) - + with pytest.raises(ValueError): iglu.process_data(glucose_array) - + def test_process_data_missing_values(): """Test handling of missing values.""" data = pd.DataFrame({ 'id': ['A', 'A', 'A', 'A'], - 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00', + 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00', '2020-01-01 10:10:00', '2020-01-01 10:15:00'], 'gl': [120, np.nan, 125, 140] }) - + result = iglu.process_data(data, id='id', timestamp='time', glu='gl') - + # Should remove rows with NaN glucose values assert len(result) == 3 assert not result['gl'].isna().any() @@ -210,11 +210,11 @@ def test_process_data_glucose_warnings(): 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00', '2020-01-01 10:10:00'], 'gl': [10, 120, 600] # Very low and very high values }) - + with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") result = iglu.process_data(data, id='id', timestamp='time', glu='gl') - + # Should generate warnings for extreme values warning_messages = [str(warning.message) for warning in w] assert any("below 20" in msg for msg in warning_messages) @@ -233,12 +233,12 @@ def test_process_data_column_rename(): # Check column names and order assert list(result.columns) == ['id', 'time', 'gl'] - + # Check data types assert pd.api.types.is_string_dtype(result['id']) assert pd.api.types.is_datetime64_any_dtype(result['time']) assert pd.api.types.is_numeric_dtype(result['gl']) - + # Check values were preserved assert all(result['id'] == 'A') assert result['gl'].tolist() == [120, 130] @@ -251,15 +251,15 @@ def test_process_data_column_not_found_errors(): 'datetime': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'glucose': [120, 130] }) - + # Test missing id column with pytest.raises(ValueError, match="Column 'wrong_id' not found"): iglu.process_data(data, id='wrong_id', timestamp='datetime', glu='glucose') - + # Test missing timestamp column with pytest.raises(ValueError, match="Column 'wrong_time' not found"): iglu.process_data(data, id='subject', timestamp='wrong_time', glu='glucose') - + # Test missing glucose column with pytest.raises(ValueError, match="Column 'wrong_glucose' not found"): iglu.process_data(data, id='subject', timestamp='datetime', glu='wrong_glucose') @@ -272,7 +272,7 @@ def test_process_data_alternative_column_suggestion(): 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'gl': [120, 130] }) - + # Test suggestion for id column with pytest.raises(ValueError, match="Fix user-defined argument name for id"): iglu.process_data(data, id='wrong_id', timestamp='time', glu='gl') @@ -283,14 +283,14 @@ def test_process_data_invalid_data_types(): # Test invalid data type with pytest.raises(TypeError, match="Invalid data type"): iglu.process_data("invalid_data") - + # Test invalid parameter types data = pd.DataFrame({ 'id': ['A', 'A'], 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'gl': [120, 130] }) - + with pytest.raises(ValueError, match="User-defined id name must be string"): iglu.process_data(data, id=123, timestamp='time', glu='gl') @@ -302,13 +302,13 @@ def test_process_data_custom_time_parser(): 'time': ['01/01/2020 10:00:00', '01/01/2020 10:05:00'], 'gl': [120, 130] }) - + # Custom parser for MM/DD/YYYY format custom_parser = lambda x: pd.to_datetime(x, format='%m/%d/%Y %H:%M:%S') - - result = iglu.process_data(data, id='id', timestamp='time', glu='gl', + + result = iglu.process_data(data, id='id', timestamp='time', glu='gl', time_parser=custom_parser) - + assert len(result) == 2 assert pd.api.types.is_datetime64_any_dtype(result['time']) @@ -320,7 +320,7 @@ def test_process_data_empty_after_processing(): 'time': ['2020-01-01 10:00:00', '2020-01-01 10:05:00'], 'gl': [np.nan, np.nan] # All NaN glucose values }) - + with pytest.raises(ValueError): iglu.process_data(data, id='id', timestamp='time', glu='gl') @@ -328,7 +328,7 @@ def test_process_data_empty_after_processing(): def test_process_data_empty_input(): """Test error handling for empty input.""" empty_data = pd.DataFrame() - + with pytest.raises(ValueError, match="No data remaining after removing NAs"): iglu.process_data(empty_data) @@ -336,9 +336,9 @@ def test_process_data_empty_input(): def test_process_data_list_with_column_specs_error(): """Test error when providing column specs with list input.""" glucose_list = [120, 130, 125] - + with pytest.raises(ValueError, match="Cannot process list/array data with column specifications"): - iglu.process_data(glucose_list, id='id', timestamp='time', glu='gl') + iglu.process_data(glucose_list, id='id', timestamp='time', glu='gl') def test_process_data_output_dtypes(): @@ -349,10 +349,10 @@ def test_process_data_output_dtypes(): 'time': dates, 'gl': np.random.normal(120, 20, 48) }) - + result = iglu.process_data(data, id='id', timestamp='time', glu='gl') - + # Check data types assert pd.api.types.is_string_dtype(result['id']) assert pd.api.types.is_datetime64_any_dtype(result['time']) - assert pd.api.types.is_numeric_dtype(result['gl']) \ No newline at end of file + assert pd.api.types.is_numeric_dtype(result['gl']) diff --git a/tests/test_sd_measures.py b/tests/test_sd_measures.py index bd5177b..29fec4d 100644 --- a/tests/test_sd_measures.py +++ b/tests/test_sd_measures.py @@ -77,18 +77,18 @@ def test_sd_measures_basic(): 'time': dates, 'gl': np.random.normal(120, 20, samples) }) - + result = iglu.sd_measures(data) - + # Check output structure assert isinstance(result, pd.DataFrame) assert len(result) == 1 assert result.iloc[0]['id'] == 'subject1' - + # Check that all SD measures are present expected_columns = ['id', 'SDw', 'SDhhmm', 'SDwsh', 'SDdm', 'SDb', 'SDbdm'] assert list(result.columns) == expected_columns - + # Check that all values are numeric and non-negative for col in ['SDw', 'SDhhmm', 'SDwsh', 'SDdm', 'SDb', 'SDbdm']: assert pd.notna(result.iloc[0][col]) @@ -104,21 +104,21 @@ def test_sd_measures_multiple_days(): dates = pd.date_range('2020-01-01', periods=samples, freq=f"{dt0}min") glucose_values = np.concatenate([ np.random.normal(100, 15, int(samples/3)), # Day 1 - np.random.normal(130, 25, int(samples/3)), # Day 2 + np.random.normal(130, 25, int(samples/3)), # Day 2 np.random.normal(110, 20, int(samples/3)), # Day 3 ]) - + data = pd.DataFrame({ 'id': ['subject1'] * samples, 'time': dates, 'gl': glucose_values }) - + result = iglu.sd_measures(data) - + # All measures should be calculated assert not result.isnull().any().any() - + # SDdm should capture between-day variation assert result.iloc[0]['SDdm'] > 0 @@ -131,9 +131,9 @@ def test_sd_measures_constant_values(): 'time': dates, 'gl': [120] * 48 }) - + result = iglu.sd_measures(data) - + # Most SD measures should be 0 or very small for constant values assert result.iloc[0]['SDw'] < 1e-10 # Should be essentially 0 assert result.iloc[0]['SDhhmm'] < 1e-10 @@ -150,9 +150,9 @@ def test_sd_measures_single_day(): 'time': dates, 'gl': np.random.normal(120, 20, 24) }) - + result = iglu.sd_measures(data) - + # SDdm and SDb should be NaN or 0 with only one day assert pd.isna(result.iloc[0]['SDdm']) or result.iloc[0]['SDdm'] == 0 assert pd.isna(result.iloc[0]['SDb']) or result.iloc[0]['SDb'] == 0 @@ -170,27 +170,27 @@ def test_sd_measures_multiple_subjects_error(): 'time': dates, 'gl': np.random.normal(120, 20, samples) }) - + result = iglu.sd_measures(data) # Test that multiple subjects are handled correctly assert len(result) == 2 # Should have results for both subjects assert set(result['id']) == {'subject1', 'subject2'} # Should have both subject IDs - + # Test that results are calculated for each subject independently subject1_data = data[data['id'] == 'subject1'] subject2_data = data[data['id'] == 'subject2'] - + result1 = iglu.sd_measures(subject1_data) result2 = iglu.sd_measures(subject2_data) - + # Results from individual calculations should match combined results for col in ['SDw', 'SDhhmm', 'SDwsh']: assert abs(result.iloc[0][col] - result1.iloc[0][col]) < 1e-10 # subject1 assert abs(result.iloc[1][col] - result2.iloc[0][col]) < 1e-10 # subject2 for col in ['SDdm', 'SDb', 'SDbdm']: - assert np.isnan(result.iloc[0][col]) - assert np.isnan(result.iloc[1][col]) + assert np.isnan(result.iloc[0][col]) + assert np.isnan(result.iloc[1][col]) def test_sd_measures_dt0_parameter(): @@ -204,11 +204,11 @@ def test_sd_measures_dt0_parameter(): 'time': dates, 'gl': np.random.normal(120, 20, samples) }) - + # Test with explicit dt0 result_30min = iglu.sd_measures(data, dt0=30) result_auto = iglu.sd_measures(data) # Should auto-detect 30min - + # Results should be similar (allowing for small numerical differences) for col in ['SDw', 'SDhhmm', 'SDwsh', 'SDdm', 'SDb', 'SDbdm']: assert abs(result_30min.iloc[0][col] - result_auto.iloc[0][col]) < 1e-10 @@ -225,16 +225,16 @@ def test_sd_measures_inter_gap_parameter(): 'time': dates, 'gl': np.random.normal(120, 20, samples) }) - + #make 5h gap from 12:00 - gap_start = 12*(60/dt0) + gap_start = 12*(60/dt0) gap_hour = int(60/dt0) data.loc[gap_start:gap_start + 5*gap_hour - 1, 'gl'] = np.nan # Test with different inter_gap values result_small_gap = iglu.sd_measures(data, inter_gap=gap_hour) # Small gap - won't interpolate result_large_gap = iglu.sd_measures(data, inter_gap=6*gap_hour) # Large gap - will interpolate - + # Both should work but may give different results assert not result_small_gap.isnull().any().any() assert not result_large_gap.isnull().any().any() @@ -251,11 +251,11 @@ def test_sd_measures_timezone_parameter(): 'time': dates, 'gl': np.random.normal(120, 20, samples) }) - + # Test with different timezone result_utc = iglu.sd_measures(data, tz="UTC") result_no_tz = iglu.sd_measures(data) - + # Results should be the same regardless of timezone for this data for col in [ 'SDhhmm']: assert abs(result_utc.iloc[0][col] - result_no_tz.iloc[0][col]) < 1 @@ -264,7 +264,7 @@ def test_sd_measures_timezone_parameter(): def test_sd_measures_empty_dataframe(): """Test that empty DataFrame raises appropriate error.""" data = pd.DataFrame(columns=['id', 'time', 'gl']) - + with pytest.raises(ValueError): iglu.sd_measures(data) @@ -277,9 +277,9 @@ def test_sd_measures_output_dtypes(): 'time': dates, 'gl': np.random.normal(120, 20, 48) }) - + result = iglu.sd_measures(data) - + # Check data types assert result['id'].dtype == object # string for col in ['SDw', 'SDhhmm', 'SDwsh', 'SDdm', 'SDb', 'SDbdm']: @@ -295,10 +295,10 @@ def test_sd_measures_reproducibility(): 'time': dates, 'gl': np.random.normal(120, 20, 48) }) - + result1 = iglu.sd_measures(data) result2 = iglu.sd_measures(data) - + # Results should be identical pd.testing.assert_frame_equal(result1, result2) @@ -313,10 +313,10 @@ def test_sd_measures_series_with_datetime_index(): 90, 130, 95], # Day 2: mean=105, std=21.21 index=time ) - + # Calculate SD measures result = iglu.sd_measures(data) - + # Expected results: # SDmean = mean([10, 21.21]) = 15.605 # SDsd = std([10, 21.21], ddof=1) = 7.931 @@ -325,10 +325,10 @@ def test_sd_measures_series_with_datetime_index(): 'SDhhmm':15.612495, 'SDwsh': 16.341298, 'SDdm': 3.535534, - 'SDb': 8.249579, + 'SDb': 8.249579, 'SDbdm': 7.071068 } - + # Compare results assert isinstance(result, dict) assert len(result) == 6 @@ -347,7 +347,7 @@ def test_sd_measures_series_without_datetime_index(): [100, 120, 110, 90, 130, 95], index=range(6) # Regular integer index instead of DatetimeIndex ) - + # Attempt to calculate SD measures - should raise ValueError with pytest.raises(ValueError, match="Series must have a DatetimeIndex"): iglu.sd_measures(data) diff --git a/tests/test_summary_glu.py b/tests/test_summary_glu.py index fc8def7..13d20cd 100644 --- a/tests/test_summary_glu.py +++ b/tests/test_summary_glu.py @@ -79,19 +79,19 @@ def test_summary_glu_basic_dataframe(): # Check output structure assert isinstance(result, pd.DataFrame) assert len(result) == 2 # Two subjects - + # Check columns expected_columns = ['id', 'Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] assert list(result.columns) == expected_columns - + # Check data types assert pd.api.types.is_string_dtype(result['id']) for col in ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']: assert pd.api.types.is_numeric_dtype(result[col]) - + # Check that we have the correct subjects assert set(result['id']) == {'subject1', 'subject2'} - + # Check that summary values are reasonable subject1_data = result[result['id'] == 'subject1'].iloc[0] assert subject1_data['Min.'] <= subject1_data['Max.'] @@ -110,7 +110,7 @@ def test_summary_glu_single_subject(): assert len(result) == 1 assert result.iloc[0]['id'] == 'subject1' - + # Check specific values for known data row = result.iloc[0] assert row['Min.'] == 100 @@ -124,16 +124,16 @@ def test_summary_glu_single_subject(): def test_summary_glu_vector_input_series(): """Test summary_glu with Series input.""" glucose_series = pd.Series([100, 120, 140, 160, 180]) - + result = iglu.summary_glu(glucose_series) - + assert isinstance(result, dict) assert len(result) == 6 - + # Should not have id column for vector input expected_columns = ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] assert list(result.keys()) == expected_columns - + # Check values assert result['Min.'] == 100 @@ -145,12 +145,12 @@ def test_summary_glu_vector_input_series(): def test_summary_glu_vector_input_list(): """Test summary_glu with list input.""" glucose_list = [100, 120, 140, 160, 180] - + result = iglu.summary_glu(glucose_list) - + assert isinstance(result, dict) assert len(result) == 6 - + # Should not have id column for vector input expected_columns = ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] assert list(result.keys()) == expected_columns @@ -159,12 +159,12 @@ def test_summary_glu_vector_input_list(): def test_summary_glu_vector_input_numpy(): """Test summary_glu with numpy array input.""" glucose_array = np.array([100, 120, 140, 160, 180]) - + result = iglu.summary_glu(glucose_array) - + assert isinstance(result, dict) assert len(result) == 6 - + # Should not have id column for vector input expected_columns = ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] assert list(result.keys()) == expected_columns @@ -191,9 +191,9 @@ def test_summary_glu_missing_values(): def test_summary_glu_missing_values_vector(): """Test handling of missing values in vector input.""" glucose_series = pd.Series([100, np.nan, 140, 160, np.nan, 180]) - + result = iglu.summary_glu(glucose_series) - + assert len(result) == 6 # Should calculate stats only on non-NaN values: [100, 140, 160, 180] assert result['Min.'] == 100 @@ -213,12 +213,12 @@ def test_summary_glu_all_missing_values(): result = iglu.summary_glu(data) assert len(result) == 2 - + # subject1 should have all NaN values subject1_row = result[result['id'] == 'subject1'].iloc[0] for col in ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']: assert pd.isna(subject1_row[col]) - + # subject2 should have valid values subject2_row = result[result['id'] == 'subject2'].iloc[0] assert not pd.isna(subject2_row['Mean']) @@ -227,7 +227,7 @@ def test_summary_glu_all_missing_values(): def test_summary_glu_all_missing_vector(): """Test error with all missing values in vector input.""" glucose_series = pd.Series([np.nan, np.nan, np.nan]) - + with pytest.raises(ValueError, match="No valid glucose values found"): iglu.summary_glu(glucose_series) @@ -244,7 +244,7 @@ def test_summary_glu_single_value(): assert len(result) == 1 row = result.iloc[0] - + # All summary stats should be the same for single value for col in ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']: assert row[col] == 150 @@ -256,7 +256,7 @@ def test_summary_glu_multiple_subjects(): 'id': ['A'] * 3 + ['B'] * 4 + ['C'] * 2, 'time': pd.date_range(start='2020-01-01', periods=9, freq='5min'), 'gl': [100, 110, 120, # Subject A: low glucose - 200, 210, 220, 230, # Subject B: high glucose + 200, 210, 220, 230, # Subject B: high glucose 150, 160] # Subject C: medium glucose }) @@ -264,12 +264,12 @@ def test_summary_glu_multiple_subjects(): assert len(result) == 3 assert set(result['id']) == {'A', 'B', 'C'} - + # Check that B has higher values than A a_mean = result[result['id'] == 'A']['Mean'].iloc[0] b_mean = result[result['id'] == 'B']['Mean'].iloc[0] c_mean = result[result['id'] == 'C']['Mean'].iloc[0] - + assert a_mean < c_mean < b_mean @@ -285,7 +285,7 @@ def test_summary_glu_identical_values(): assert len(result) == 1 row = result.iloc[0] - + # All summary stats should be the same for identical values for col in ['Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.']: assert row[col] == 120 @@ -294,7 +294,7 @@ def test_summary_glu_identical_values(): def test_summary_glu_empty_dataframe(): """Test error handling for empty DataFrame.""" data = pd.DataFrame(columns=['id', 'time', 'gl']) - + with pytest.raises(ValueError): iglu.summary_glu(data) @@ -308,7 +308,7 @@ def test_summary_glu_column_order(): }) result = iglu.summary_glu(data) - + expected_columns = ['id', 'Min.', '1st Qu.', 'Median', 'Mean', '3rd Qu.', 'Max.'] assert list(result.columns) == expected_columns @@ -325,11 +325,11 @@ def test_summary_glu_percentile_accuracy(): result = iglu.summary_glu(data) row = result.iloc[0] - + # Verify against numpy percentile calculations assert row['Min.'] == np.min(glucose_values) assert row['1st Qu.'] == np.percentile(glucose_values, 25) assert row['Median'] == np.median(glucose_values) assert row['Mean'] == np.mean(glucose_values) assert row['3rd Qu.'] == np.percentile(glucose_values, 75) - assert row['Max.'] == np.max(glucose_values) \ No newline at end of file + assert row['Max.'] == np.max(glucose_values) From 533f387cba56ade75e9322746df2f508d57db6df Mon Sep 17 00:00:00 2001 From: Stas Khirman Date: Tue, 17 Jun 2025 01:28:49 +0300 Subject: [PATCH 2/4] ruff reformating --- iglu_python/adrr.py | 2 +- iglu_python/hbgi.py | 2 +- iglu_python/hypo_index.py | 2 +- iglu_python/j_index.py | 2 +- iglu_python/mad_glu.py | 4 ++-- iglu_python/median_glu.py | 2 +- iglu_python/modd.py | 4 ++-- iglu_python/pgs.py | 2 +- iglu_python/quantile_glu.py | 2 +- iglu_python/range_glu.py | 2 +- iglu_python/sd_measures.py | 2 +- iglu_python/sd_roc.py | 2 +- tests/test_process_data.py | 5 +++-- 13 files changed, 17 insertions(+), 16 deletions(-) diff --git a/iglu_python/adrr.py b/iglu_python/adrr.py index 1ae3da9..cf26023 100644 --- a/iglu_python/adrr.py +++ b/iglu_python/adrr.py @@ -13,7 +13,7 @@ def adrr(data: pd.DataFrame|pd.Series) -> pd.DataFrame|float: Parameters ---------- - data : pd.DataFrame|pd.Series + data : pd.DataFrame|pd.Series DataFrame object with column names "id", "time", and "gl". or a Timeseries of glucose values. diff --git a/iglu_python/hbgi.py b/iglu_python/hbgi.py index 6697c60..49bc67e 100644 --- a/iglu_python/hbgi.py +++ b/iglu_python/hbgi.py @@ -25,7 +25,7 @@ def hbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values Returns diff --git a/iglu_python/hypo_index.py b/iglu_python/hypo_index.py index 0bc3a22..bce1dbb 100644 --- a/iglu_python/hypo_index.py +++ b/iglu_python/hypo_index.py @@ -20,7 +20,7 @@ def hypo_index( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values LLTR : int, default=80 Lower Limit of Target Range, in mg/dL diff --git a/iglu_python/j_index.py b/iglu_python/j_index.py index 74b68cd..417c029 100644 --- a/iglu_python/j_index.py +++ b/iglu_python/j_index.py @@ -17,7 +17,7 @@ def j_index(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values Returns diff --git a/iglu_python/mad_glu.py b/iglu_python/mad_glu.py index 2f3b92f..5d13881 100644 --- a/iglu_python/mad_glu.py +++ b/iglu_python/mad_glu.py @@ -19,7 +19,7 @@ def mad_glu( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values constant : float, default=1.4826 Scaling factor to multiply the MAD value. The default value of 1.4826 @@ -31,7 +31,7 @@ def mad_glu( pd.DataFrame|float DataFrame with columns: - id: subject identifier (if DataFrame input) - - MAD: MAD value (median absolute deviation of glucose values). + - MAD: MAD value (median absolute deviation of glucose values). If a Series of glucose values is passed, then a float is returned. Examples diff --git a/iglu_python/median_glu.py b/iglu_python/median_glu.py index 3ff0be7..b2ca9da 100644 --- a/iglu_python/median_glu.py +++ b/iglu_python/median_glu.py @@ -17,7 +17,7 @@ def median_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.Dat Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values Returns diff --git a/iglu_python/modd.py b/iglu_python/modd.py index af26259..a8bba91 100644 --- a/iglu_python/modd.py +++ b/iglu_python/modd.py @@ -19,7 +19,7 @@ def modd( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values lag : int, default=1 Integer indicating which lag (# days) to use. Default is 1. @@ -31,7 +31,7 @@ def modd( pd.DataFrame|float DataFrame with columns: - id: subject identifier (if DataFrame input) - - MODD: Mean of Daily Differences value. + - MODD: Mean of Daily Differences value. If a Series of glucose values is passed, then a float is returned. References diff --git a/iglu_python/pgs.py b/iglu_python/pgs.py index a930133..763203f 100644 --- a/iglu_python/pgs.py +++ b/iglu_python/pgs.py @@ -23,7 +23,7 @@ def pgs( Parameters ---------- data : Union[pd.DataFrame, pd.Series] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values Should only be data for 1 subject. In case multiple subject ids are detected, a warning is produced and only 1st subject is used. diff --git a/iglu_python/quantile_glu.py b/iglu_python/quantile_glu.py index f493bb6..20e9d16 100644 --- a/iglu_python/quantile_glu.py +++ b/iglu_python/quantile_glu.py @@ -19,7 +19,7 @@ def quantile_glu( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values quantiles : List[float], default=[0, 25, 50, 75, 100] List of quantile values between 0 and 100 diff --git a/iglu_python/range_glu.py b/iglu_python/range_glu.py index 1f39ef4..c94ca37 100644 --- a/iglu_python/range_glu.py +++ b/iglu_python/range_glu.py @@ -16,7 +16,7 @@ def range_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.Data Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values Returns diff --git a/iglu_python/sd_measures.py b/iglu_python/sd_measures.py index 653856b..8d0db02 100644 --- a/iglu_python/sd_measures.py +++ b/iglu_python/sd_measures.py @@ -32,7 +32,7 @@ def sd_measures(data: pd.DataFrame|pd.Series, Returns ------- pd.DataFrame - A DataFrame with columns for id and each of the six SD subtypes. + A DataFrame with columns for id and each of the six SD subtypes. If a Series of glucose values is passed, then a dictionary is returned. - SDw: vertical within days - SDhhmm: between time points diff --git a/iglu_python/sd_roc.py b/iglu_python/sd_roc.py index 36bafbd..e60fd4e 100644 --- a/iglu_python/sd_roc.py +++ b/iglu_python/sd_roc.py @@ -41,7 +41,7 @@ def sd_roc( ------- pd.DataFrame|float DataFrame with two columns: subject id and standard deviation of the rate of change - values for each subject. + values for each subject. If a Series of glucose values is passed, then a float is returned. Notes diff --git a/tests/test_process_data.py b/tests/test_process_data.py index 2332c70..9455bf9 100644 --- a/tests/test_process_data.py +++ b/tests/test_process_data.py @@ -213,7 +213,7 @@ def test_process_data_glucose_warnings(): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") - result = iglu.process_data(data, id='id', timestamp='time', glu='gl') + iglu.process_data(data, id='id', timestamp='time', glu='gl') # Should generate warnings for extreme values warning_messages = [str(warning.message) for warning in w] @@ -304,7 +304,8 @@ def test_process_data_custom_time_parser(): }) # Custom parser for MM/DD/YYYY format - custom_parser = lambda x: pd.to_datetime(x, format='%m/%d/%Y %H:%M:%S') + def custom_parser(x): + return pd.to_datetime(x, format='%m/%d/%Y %H:%M:%S') result = iglu.process_data(data, id='id', timestamp='time', glu='gl', time_parser=custom_parser) From 4015ac5631dbd0f8c2341e9a3a0ed6443460d3b2 Mon Sep 17 00:00:00 2001 From: Stas Khirman Date: Tue, 17 Jun 2025 01:32:00 +0300 Subject: [PATCH 3/4] ruff reformating --- iglu_python/grade_eugly.py | 3 ++- iglu_python/grade_hyper.py | 3 ++- iglu_python/grade_hypo.py | 3 ++- iglu_python/hyper_index.py | 3 ++- iglu_python/igc.py | 3 ++- iglu_python/iqr_glu.py | 3 ++- iglu_python/lbgi.py | 3 ++- iglu_python/m_value.py | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/iglu_python/grade_eugly.py b/iglu_python/grade_eugly.py index 9023ecc..8320198 100644 --- a/iglu_python/grade_eugly.py +++ b/iglu_python/grade_eugly.py @@ -20,7 +20,8 @@ def grade_eugly( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values lower : int, default=70 Lower bound used for hypoglycemia cutoff, in mg/dL upper : int, default=140 diff --git a/iglu_python/grade_hyper.py b/iglu_python/grade_hyper.py index d7afde2..3c60e44 100644 --- a/iglu_python/grade_hyper.py +++ b/iglu_python/grade_hyper.py @@ -17,7 +17,8 @@ def grade_hyper(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], upper: i Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values upper : int, default=140 Upper bound used for hyperglycemia cutoff, in mg/dL diff --git a/iglu_python/grade_hypo.py b/iglu_python/grade_hypo.py index b2563dd..591a2a8 100644 --- a/iglu_python/grade_hypo.py +++ b/iglu_python/grade_hypo.py @@ -17,7 +17,8 @@ def grade_hypo(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], lower: in Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values lower : int, default=80 Lower bound used for hypoglycemia cutoff, in mg/dL diff --git a/iglu_python/hyper_index.py b/iglu_python/hyper_index.py index a687846..8ca2302 100644 --- a/iglu_python/hyper_index.py +++ b/iglu_python/hyper_index.py @@ -20,7 +20,8 @@ def hyper_index( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values ULTR : int, default=140 Upper Limit of Target Range, in mg/dL a : float, default=1.1 diff --git a/iglu_python/igc.py b/iglu_python/igc.py index b1707b8..b4200e8 100644 --- a/iglu_python/igc.py +++ b/iglu_python/igc.py @@ -26,7 +26,8 @@ def igc( Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values LLTR : int, default=80 Lower Limit of Target Range, in mg/dL ULTR : int, default=140 diff --git a/iglu_python/iqr_glu.py b/iglu_python/iqr_glu.py index 18e5859..4ab936b 100644 --- a/iglu_python/iqr_glu.py +++ b/iglu_python/iqr_glu.py @@ -16,7 +16,8 @@ def iqr_glu(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFr Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values Returns ------- diff --git a/iglu_python/lbgi.py b/iglu_python/lbgi.py index ea0a90c..54807ab 100644 --- a/iglu_python/lbgi.py +++ b/iglu_python/lbgi.py @@ -22,7 +22,8 @@ def lbgi(data: Union[pd.DataFrame, pd.Series, np.ndarray, list]) -> pd.DataFrame Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns ['id', 'time', 'gl'] or Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns ['id', 'time', 'gl'] or Series of glucose values, + or a numpy array or list of glucose values in mg/dL Returns diff --git a/iglu_python/m_value.py b/iglu_python/m_value.py index 0859a11..9048acf 100644 --- a/iglu_python/m_value.py +++ b/iglu_python/m_value.py @@ -23,7 +23,8 @@ def m_value(data: Union[pd.DataFrame, pd.Series, np.ndarray, list], r: float = 9 Parameters ---------- data : Union[pd.DataFrame, pd.Series, np.ndarray, list] - DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, or a numpy array or list of glucose values + DataFrame with columns 'id', 'time', and 'gl', or a Series of glucose values, + or a numpy array or list of glucose values r : float, default=90 A reference value corresponding to basal glycemia in normal subjects From 097ca212614d609c2afccea232501db0ceb92609 Mon Sep 17 00:00:00 2001 From: Stas Khirman Date: Tue, 17 Jun 2025 01:32:44 +0300 Subject: [PATCH 4/4] version 0.2.0 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a7d5fd4..f040f24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "iglu_python" -version = "0.1.7" +version = "0.2.0" description = "Python implementation of the iglu package for continuous glucose monitoring data analysis" readme = "README.md" requires-python = ">=3.11"