Skip to content

Commit b613b97

Browse files
dilpathdweindl
andauthored
Ensure measurements are numeric and not null with linter (#76)
Co-authored-by: Daniel Weindl <[email protected]>
1 parent 4468248 commit b613b97

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

petab/lint.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
__all__ = ['assert_all_parameters_present_in_parameter_df',
2121
'assert_measured_observables_defined',
2222
'assert_measurement_conditions_present_in_condition_table',
23+
'assert_measurements_not_null',
24+
'assert_measurements_numeric',
2325
'assert_model_parameters_in_condition_or_parameter_table',
2426
'assert_no_leading_trailing_whitespace',
2527
'assert_noise_distributions_valid',
@@ -177,6 +179,9 @@ def check_measurement_df(df: pd.DataFrame,
177179
measurements.assert_overrides_match_parameter_count(
178180
df, observable_df)
179181

182+
assert_measurements_not_null(df)
183+
assert_measurements_numeric(df)
184+
180185

181186
def check_parameter_df(
182187
df: pd.DataFrame,
@@ -906,6 +911,51 @@ def assert_measurement_conditions_present_in_condition_table(
906911
+ str(missing_conditions))
907912

908913

914+
def assert_measurements_not_null(
915+
measurement_df: pd.DataFrame,
916+
) -> None:
917+
"""Check whether all measurements are not null.
918+
919+
Arguments:
920+
measurement_df:
921+
PEtab measurement table.
922+
923+
Raises:
924+
AssertionError:
925+
Some measurement value(s) are null (missing).
926+
"""
927+
if measurement_df[MEASUREMENT].isnull().any():
928+
raise AssertionError('Some measurement(s) are null (missing).')
929+
930+
931+
def assert_measurements_numeric(
932+
measurement_df: pd.DataFrame,
933+
) -> None:
934+
"""Check whether all measurements are numeric.
935+
936+
Note that null (missing) measurements are ignored.
937+
938+
Arguments:
939+
measurement_df:
940+
PEtab measurement table.
941+
942+
Raises:
943+
AssertionError:
944+
Some measurement value(s) are not numeric.
945+
"""
946+
not_null_measurement_values = measurement_df[MEASUREMENT].dropna()
947+
all_measurements_are_numeric = (
948+
pd.to_numeric(not_null_measurement_values, errors='coerce')
949+
.notnull()
950+
.all()
951+
)
952+
if not all_measurements_are_numeric:
953+
raise AssertionError(
954+
'Some values in the `petab.C.MEASUREMENT` column of the PEtab '
955+
'measurements table are not numeric.'
956+
)
957+
958+
909959
def is_valid_identifier(x: str) -> bool:
910960
"""Check whether `x` is a valid identifier
911961

tests/test_petab.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ def test_flatten_timepoint_specific_output_overrides():
340340
TIME:
341341
[1.0, 1.0, 2.0, 2.0],
342342
MEASUREMENT:
343-
[np.nan] * 4,
343+
[.1] * 4,
344344
OBSERVABLE_PARAMETERS:
345345
['obsParOverride1;1.0', 'obsParOverride2;1.0',
346346
'obsParOverride2;1.0', 'obsParOverride2;1.0'],
@@ -362,7 +362,7 @@ def test_flatten_timepoint_specific_output_overrides():
362362
TIME:
363363
[1.0, 1.0, 2.0, 2.0],
364364
MEASUREMENT:
365-
[np.nan] * 4,
365+
[.1] * 4,
366366
OBSERVABLE_PARAMETERS:
367367
['obsParOverride1;1.0', 'obsParOverride2;1.0',
368368
'obsParOverride2;1.0', 'obsParOverride2;1.0'],
@@ -425,7 +425,7 @@ def test_flatten_timepoint_specific_output_overrides_special_cases():
425425
TIME:
426426
[1.0, 1.0, 2.0, 2.0],
427427
MEASUREMENT:
428-
[np.nan] * 4,
428+
[.1] * 4,
429429
NOISE_PARAMETERS:
430430
['noiseParOverride1', 'noiseParOverride1',
431431
'noiseParOverride2', 'noiseParOverride2'],
@@ -442,7 +442,7 @@ def test_flatten_timepoint_specific_output_overrides_special_cases():
442442
TIME:
443443
[1.0, 1.0, 2.0, 2.0],
444444
MEASUREMENT:
445-
[np.nan] * 4,
445+
[.1] * 4,
446446
NOISE_PARAMETERS:
447447
['noiseParOverride1', 'noiseParOverride1',
448448
'noiseParOverride2', 'noiseParOverride2'],

0 commit comments

Comments
 (0)