Repository: PEtab-dev/libpetab-python

Issue:
no lint error for non-unique condition ids
`petab.lint.check_condition_df` does not check whether index entries are unique, but this is required according to documentation.

Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev) Report
> Merging [#92](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev) (17dae45) into [develop](https://codecov.io/gh/PEtab-dev/libpetab-python/commit/f6fd4896f557497a16afe3773467eb06a2614a79?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev) (f6fd489) will **increase** coverage by `0.11%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92/graphs/tree.svg?width=650&height=150&src=pr&token=Z0YPFA5GGM&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev)](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev)

```diff
@@             Coverage Diff             @@
##           develop      #92      +/-   ##
===========================================
+ Coverage    79.54%   79.65%   +0.11%     
===========================================
  Files           26       26              
  Lines         2933     2935       +2     
  Branches       708      709       +1     
===========================================
+ Hits          2333     2338       +5     
+ Misses         423      422       -1     
+ Partials       177      175       -2     
```


| [Impacted Files](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev) | Coverage Δ | |
|---|---|---|
| [petab/lint.py](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev#diff-cGV0YWIvbGludC5weQ==) | `78.14% <100.00%> (+1.03%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev). Last update [f6fd489...17dae45](https://codecov.io/gh/PEtab-dev/libpetab-python/pull/92?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PEtab-dev).


Patch:
diff --git a/petab/lint.py b/petab/lint.py
index fe353ac..ba9ad8f 100644
--- a/petab/lint.py
+++ b/petab/lint.py
@@ -108,6 +108,10 @@ def check_condition_df(
 
     check_ids(df.index.values, kind='condition')
 
+    if not df.index.is_unique:
+        raise AssertionError("Non-unique condition IDs: "
+                             f"{df.index.values[df.index.duplicated()]}")
+
     for column_name in req_cols:
         if not np.issubdtype(df[column_name].dtype, np.number):
             assert_no_leading_trailing_whitespace(


Test patch:
diff --git a/tests/test_lint.py b/tests/test_lint.py
index 2756226..eccbed2 100644
--- a/tests/test_lint.py
+++ b/tests/test_lint.py
@@ -494,3 +494,36 @@ def test_check_observable_df():
     bad_observable_df.index = ['obs1', 'obs1']
     with pytest.raises(AssertionError):
         lint.check_observable_df(bad_observable_df)
+
+
+def test_condition_ids_are_unique():
+    condition_df = pd.DataFrame(data={
+        CONDITION_ID: ['condition1', 'condition1'],
+        'parameter1': [1.0, 2.0]
+    })
+    condition_df.set_index(CONDITION_ID, inplace=True)
+
+    with pytest.raises(AssertionError):
+        lint.check_condition_df(condition_df)
+
+    condition_df.index = ['condition0', 'condition1']
+    condition_df.index.name = 'conditionId'
+    lint.check_condition_df(condition_df)
+
+
+def test_parameter_ids_are_unique():
+    parameter_df = pd.DataFrame({
+        PARAMETER_ID: ['par0', 'par0'],
+        PARAMETER_SCALE: [LIN, LIN],
+        ESTIMATE: [1, 1],
+        LOWER_BOUND: [1e-5, 1e-6],
+        UPPER_BOUND: [1e5, 1e6]
+
+    }).set_index(PARAMETER_ID)
+
+    with pytest.raises(AssertionError):
+        lint.check_parameter_df(parameter_df)
+
+    parameter_df.index = ['par0', 'par1']
+    parameter_df.index.name = 'parameterId'
+    lint.check_parameter_df(parameter_df)