Repository: saketkc/pysradb

Issue:
[BUG] SRX to SRR produces incorrect results when multiple SRRs are present
**Describe the bug**
When an SRX has multiple SRRs only one is returned.

**To Reproduce**
Steps to reproduce the behavior:
`pysradb srx-to-srr SRX8998846`


**Desktop (please complete the following information):**
 - OS: Ubuntu 20.04
 - Python version 3.8



Discussion:
codecov[bot]: ## [Codecov](https://codecov.io/gh/saketkc/pysradb/pull/183?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
Patch coverage: **`100.00`**% and project coverage change: **`-0.19`** :warning:
> Comparison is base [(`301193b`)](https://codecov.io/gh/saketkc/pysradb/commit/301193b8ef2a31f40541ba68c06a7eb628478aac?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) 59.04% compared to head [(`29de3b3`)](https://codecov.io/gh/saketkc/pysradb/pull/183?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) 58.85%.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop     #183      +/-   ##
===========================================
- Coverage    59.04%   58.85%   -0.19%     
===========================================
  Files            8        8              
  Lines         1836     1857      +21     
===========================================
+ Hits          1084     1093       +9     
- Misses         752      764      +12     
```


| [Impacted Files](https://codecov.io/gh/saketkc/pysradb/pull/183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [pysradb/sraweb.py](https://codecov.io/gh/saketkc/pysradb/pull/183?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cHlzcmFkYi9zcmF3ZWIucHk=) | `81.42% <100.00%> (-1.46%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

</details>

[:umbrella: View full report in Codecov by Sentry](https://codecov.io/gh/saketkc/pysradb/pull/183?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).

saketkc: Thank you @tfehlmann! This was a good opportunity to fix a bunch of things.

Patch:
diff --git a/pysradb/sraweb.py b/pysradb/sraweb.py
index 334e917..5232663 100644
--- a/pysradb/sraweb.py
+++ b/pysradb/sraweb.py
@@ -32,6 +32,8 @@ def _order_first(df, column_order_list):
     # check if all columns do exist in the dataframe
     if len(set(columns).intersection(df.columns)) == len(columns):
         df = df.loc[:, columns]
+    df = df.mask(df.applymap(str).eq("[]"))
+    df = df.fillna(pd.NA)
     return df
 
 
@@ -531,7 +533,7 @@ class SRAweb(SRAdb):
                 experiment_record["run_total_spots"] = run_total_spots
                 experiment_record["run_total_bases"] = run_total_bases
 
-                sra_record.append(experiment_record)
+                sra_record.append(experiment_record.copy())
 
         # TODO: the detailed call below does redundant operations
         # the code above this can be completeley done away with
@@ -841,6 +843,8 @@ class SRAweb(SRAdb):
 
     def srr_to_gsm(self, srr, **kwargs):
         """Get GSM for a SRR"""
+        if isinstance(srr, str):
+            srr = [srr]
         srr_df = self.srr_to_srp(srr, detailed=True)
         # remove NAs
         srp = [x for x in srr_df.study_accession.tolist() if not x is pd.NA]
@@ -853,39 +857,56 @@ class SRAweb(SRAdb):
             set(srr_df.columns.tolist()).difference(gsm_df.columns.tolist())
         ) + ["experiment_accession"]
         joined_df = gsm_df.merge(srr_df[srr_cols], on="experiment_accession")
-        return _order_first(joined_df, ["run_accession", "experiment_alias"])
+        df = _order_first(joined_df, ["run_accession", "experiment_alias"])
+        df = df.loc[df["run_accession"].isin(srr)]
+        return df
 
     def srr_to_srp(self, srr, **kwargs):
         """Get SRP for a SRR"""
+        if isinstance(srr, str):
+            srr = [srr]
         srr_df = self.sra_metadata(srr, **kwargs)
         if kwargs and kwargs["detailed"] == True:
             return srr_df
+        srr_df = srr_df.loc[srr_df["run_accession"].isin(srr)]
         return _order_first(srr_df, ["run_accession", "study_accession"])
 
     def srr_to_srs(self, srr, **kwargs):
         """Get SRS for a SRR"""
+        if isinstance(srr, str):
+            srr = [srr]
         srr_df = self.sra_metadata(srr, **kwargs)
+        srr_df = srr_df.loc[srr_df["run_accession"].isin(srr)]
         return _order_first(srr_df, ["run_accession", "sample_accession"])
 
     def srr_to_srx(self, srr, **kwargs):
         """Get SRX for a SRR"""
+        if isinstance(srr, str):
+            srr = [srr]
         srr_df = self.sra_metadata(srr)
+        srr_df = srr_df.loc[srr_df["run_accession"].isin(srr)]
         return _order_first(srr_df, ["run_accession", "experiment_accession"])
 
     def srs_to_gsm(self, srs, **kwargs):
         """Get GSM for a SRS"""
+        if isinstance(srs, str):
+            srs = [srs]
         srx_df = self.srs_to_srx(srs)
         time.sleep(self.sleep_time)
         gsm_df = self.srx_to_gsm(srx_df.experiment_accession.tolist(), **kwargs)
         srs_df = srx_df.merge(gsm_df, on="experiment_accession")
+        srs_df = srs_df.loc[srs_df["sample_accession"].isin(srs)]
         return _order_first(srs_df, ["sample_accession", "experiment_alias"])
 
     def srx_to_gsm(self, srx, **kwargs):
+        if isinstance(srx, str):
+            srx = [srx]
         gsm_df = self.fetch_gds_results(srx, **kwargs)
         gsm_df = gsm_df[gsm_df.entrytype == "GSM"].rename(
             columns={"SRA": "experiment_accession", "accession": "experiment_alias"}
         )
-        return gsm_df[["experiment_accession", "experiment_alias"]]
+        gsm_df = gsm_df.loc[gsm_df["experiment_accession"].isin(srx)]
+        return gsm_df[["experiment_accession", "experiment_alias"]].drop_duplicates()
 
     def srs_to_srx(self, srs, **kwargs):
         """Get SRX for a SRS"""


Test patch:
diff --git a/tests/test_sraweb.py b/tests/test_sraweb.py
index 884b32b..16d3e53 100644
--- a/tests/test_sraweb.py
+++ b/tests/test_sraweb.py
@@ -189,7 +189,7 @@ def test_srr_to_srx(sraweb_connection):
 def test_srs_to_gsm(sraweb_connection):
     """Test if srs is converted to gsm correctly"""
     df = sraweb_connection.srs_to_gsm("SRS079386")
-    assert list(df["experiment_alias"]) == ["GSM546921"]
+    assert list(df["experiment_alias"]) == ["GSM546921"] * 3
 
 
 def test_srs_to_srx(sraweb_connection):
@@ -216,6 +216,12 @@ def test_srx_to_srr(sraweb_connection):
     assert list(df["run_accession"]) == ["SRR5413172"]
 
 
+def test_srx_to_srr1(sraweb_connection):
+    """Test if srx is converted to srr correctly, including multiple srrs"""
+    df = sraweb_connection.srx_to_srr("SRX8998846")
+    assert list(df["run_accession"]) == ["SRR12508064", "SRR12508065"]
+
+
 def test_srx_to_srs(sraweb_connection):
     """Test if srx is converted to srs correctly"""
     df = sraweb_connection.srx_to_srs("SRX663253")