@@ -60,9 +60,7 @@ def _check_df(df: pd.DataFrame, req_cols: Iterable, name: str) -> None:
6060 Raises:
6161 AssertionError: if a column is missing
6262 """
63- cols_set = df .columns .values
64- missing_cols = set (req_cols ) - set (cols_set )
65- if missing_cols :
63+ if missing_cols := set (req_cols ) - set (df .columns .values ):
6664 raise AssertionError (
6765 f"DataFrame { name } requires the columns { missing_cols } ." )
6866
@@ -85,12 +83,16 @@ def assert_no_leading_trailing_whitespace(
8583
8684
8785def check_condition_df (
88- df : pd .DataFrame , model : Optional [Model ] = None ) -> None :
86+ df : pd .DataFrame ,
87+ model : Optional [Model ] = None ,
88+ observable_df : Optional [pd .DataFrame ] = None
89+ ) -> None :
8990 """Run sanity checks on PEtab condition table
9091
9192 Arguments:
9293 df: PEtab condition DataFrame
9394 model: Model for additional checking of parameter IDs
95+ observable_df: PEtab observables DataFrame
9496
9597 Raises:
9698 AssertionError: in case of problems
@@ -101,7 +103,7 @@ def check_condition_df(
101103 _check_df (df , req_cols , "condition" )
102104
103105 # Check for correct index
104- if not df .index .name = = CONDITION_ID :
106+ if df .index .name ! = CONDITION_ID :
105107 raise AssertionError (
106108 f"Condition table has wrong index { df .index .name } ."
107109 f"expected { CONDITION_ID } ." )
@@ -119,6 +121,9 @@ def check_condition_df(
119121
120122 if model is not None :
121123 allowed_cols = set (model .get_valid_ids_for_condition_table ())
124+ if observable_df is not None :
125+ allowed_cols |= set (petab .get_output_parameters (
126+ model = model , observable_df = observable_df ))
122127 for column_name in df .columns :
123128 if column_name != CONDITION_NAME \
124129 and column_name not in allowed_cols :
@@ -154,14 +159,9 @@ def check_measurement_df(df: pd.DataFrame,
154159 df [column_name ].values , column_name )
155160
156161 if observable_df is not None :
157- # Check all observables are defined
158- observables_defined = set (observable_df .index .values )
159- observables_used = set (df [OBSERVABLE_ID ])
160- observables_undefined = observables_used - observables_defined
161- if observables_undefined :
162- raise ValueError (f"Observables { observables_undefined } used in "
163- "measurement table but not defined in "
164- "observables table." )
162+ assert_measured_observables_defined (df , observable_df )
163+ measurements .assert_overrides_match_parameter_count (
164+ df , observable_df )
165165
166166 if OBSERVABLE_TRANSFORMATION in observable_df :
167167 # Check for positivity of measurements in case of
@@ -176,11 +176,6 @@ def check_measurement_df(df: pd.DataFrame,
176176 f'transformation { trafo } must be '
177177 f'positive, but { measurement } <= 0.' )
178178
179- if observable_df is not None :
180- assert_measured_observables_defined (df , observable_df )
181- measurements .assert_overrides_match_parameter_count (
182- df , observable_df )
183-
184179 assert_measurements_not_null (df )
185180 assert_measurements_numeric (df )
186181
@@ -206,7 +201,7 @@ def check_parameter_df(
206201
207202 _check_df (df , PARAMETER_DF_REQUIRED_COLS [1 :], "parameter" )
208203
209- if not df .index .name = = PARAMETER_ID :
204+ if df .index .name ! = PARAMETER_ID :
210205 raise AssertionError (
211206 f"Parameter table has wrong index { df .index .name } ."
212207 f"expected { PARAMETER_ID } ." )
@@ -232,10 +227,11 @@ def check_parameter_df(
232227 f"but column { NOMINAL_VALUE } is missing." )
233228 try :
234229 df .loc [non_estimated_par_ids , NOMINAL_VALUE ].apply (float )
235- except ValueError :
236- raise AssertionError ("Expected numeric values for "
237- f"`{ NOMINAL_VALUE } ` in parameter table for "
238- "all non-estimated parameters." )
230+ except ValueError as e :
231+ raise AssertionError (
232+ f"Expected numeric values for `{ NOMINAL_VALUE } ` in parameter "
233+ "table for all non-estimated parameters."
234+ ) from e
239235
240236 assert_parameter_id_is_string (df )
241237 assert_parameter_scale_is_valid (df )
@@ -285,8 +281,9 @@ def check_observable_df(observable_df: pd.DataFrame) -> None:
285281 try :
286282 sp .sympify (obs )
287283 except sp .SympifyError as e :
288- raise AssertionError (f"Cannot parse expression '{ obs } ' "
289- f"for observable { row .Index } : { e } " )
284+ raise AssertionError (
285+ f"Cannot parse expression '{ obs } ' "
286+ f"for observable { row .Index } : { e } " ) from e
290287
291288 noise = getattr (row , NOISE_FORMULA )
292289 try :
@@ -297,9 +294,10 @@ def check_observable_df(observable_df: pd.DataFrame) -> None:
297294 raise AssertionError (f"No or non-finite { NOISE_FORMULA } "
298295 f"given for observable { row .Index } ." )
299296 except sp .SympifyError as e :
300- raise AssertionError (f"Cannot parse expression '{ noise } ' "
301- f"for noise model for observable "
302- f"{ row .Index } : { e } " )
297+ raise AssertionError (
298+ f"Cannot parse expression '{ noise } ' "
299+ f"for noise model for observable " f"{ row .Index } : { e } "
300+ ) from e
303301
304302
305303def assert_all_parameters_present_in_parameter_df (
@@ -346,7 +344,8 @@ def assert_all_parameters_present_in_parameter_df(
346344
347345def assert_measured_observables_defined (
348346 measurement_df : pd .DataFrame ,
349- observable_df : pd .DataFrame ) -> None :
347+ observable_df : pd .DataFrame
348+ ) -> None :
350349 """Check if all observables in the measurement table have been defined in
351350 the observable table
352351
@@ -360,12 +359,11 @@ def assert_measured_observables_defined(
360359
361360 used_observables = set (measurement_df [OBSERVABLE_ID ].values )
362361 defined_observables = set (observable_df .index .values )
363- undefined_observables = used_observables - defined_observables
364-
365- if undefined_observables :
362+ if undefined_observables := (used_observables - defined_observables ):
366363 raise AssertionError (
367- "Undefined observables in measurement file: "
368- f"{ undefined_observables } ." )
364+ f"Observables { undefined_observables } used in "
365+ "measurement table but not defined in observables table."
366+ )
369367
370368
371369def condition_table_is_parameter_free (condition_df : pd .DataFrame ) -> bool :
@@ -540,9 +538,10 @@ def assert_parameter_prior_parameters_are_valid(
540538 pars = tuple (
541539 float (val ) for val in pars_str .split (PARAMETER_SEPARATOR )
542540 )
543- except ValueError :
541+ except ValueError as e :
544542 raise AssertionError (
545- f"Could not parse prior parameters '{ pars_str } '." )
543+ f"Could not parse prior parameters '{ pars_str } '." ) from e
544+
546545 # all distributions take 2 parameters
547546 if len (pars ) != 2 :
548547 raise AssertionError (
@@ -795,7 +794,8 @@ def lint_problem(problem: 'petab.Problem') -> bool:
795794 if problem .condition_df is not None :
796795 logger .info ("Checking condition table..." )
797796 try :
798- check_condition_df (problem .condition_df , problem .model )
797+ check_condition_df (problem .condition_df , problem .model ,
798+ problem .observable_df )
799799 except AssertionError as e :
800800 logger .error (e )
801801 errors_occurred = True
@@ -925,9 +925,7 @@ def assert_measurement_conditions_present_in_condition_table(
925925 used_conditions |= \
926926 set (measurement_df [PREEQUILIBRATION_CONDITION_ID ].dropna ().values )
927927 available_conditions = set (condition_df .index .values )
928- missing_conditions = used_conditions - available_conditions
929-
930- if missing_conditions :
928+ if missing_conditions := (used_conditions - available_conditions ):
931929 raise AssertionError ("Measurement table references conditions that "
932930 "are not specified in the condition table: "
933931 + str (missing_conditions ))
0 commit comments