Repository: PlasmoGenEpi/pmotools-app
Pull request #11: Simkin modular merge
Author: login: alfredsimkin
Created: 2025-02-18T21:20:39Z | Merged: 2025-03-18T12:37:21Z

made small modifications to schema.json to facilitate MIP files
wrapped sections of merge into functions
added an 'init' block
changed output folder from 'PMO' to 'finished_PMO_files'

I didn't wrap the functions into classes - I can do this if it would be helpful for consistency with the other pages (left it this way because I think readability is better, but maybe there are advantages to implementing as classes that I'm unfamiliar with - I'd like to learn more about it)



Diff:
diff --git a/PMO_Builder.py b/PMO_Builder.py
index 008a5c8..a84129b 100644
--- a/PMO_Builder.py
+++ b/PMO_Builder.py
@@ -1,7 +1,6 @@
 import streamlit as st
 from src.format_page import render_header
 
-
 def main():
     render_header()
     # Introduction Section
diff --git a/conf/schema.json b/conf/schema.json
index 0911c60..5ee601f 100644
--- a/conf/schema.json
+++ b/conf/schema.json
@@ -8,13 +8,16 @@
         "alternatives": {
             "target_id": [
                 "locus",
-                "amplicon"
+                "amplicon",
+                "mip_id"
             ],
             "forward_primers": [
-                "fwd_primers"
+                "fwd_primers",
+                "extension_arm"
             ],
             "reverse_primers": [
-                "rev_primers"
+                "rev_primers",
+                "ligation_arm"
             ]
         }
     },
@@ -130,7 +133,8 @@
                 "locus",
                 "marker_id",
                 "amplicon",
-                "locus_id"
+                "locus_id",
+                "p_targetName"
             ],
             "asv": [
                 "amplicon_sequence_variant",
@@ -144,7 +148,9 @@
             "reads": [
                 "read_count",
                 "sequence_reads",
-                "read_depth"
+                "read_depth",
+                "c_barcodeCnt",
+                "c_readCnt"
             ]
         }
     },
diff --git a/pages/1_Panel_Information.py b/pages/1_Panel_Information.py
index a61f9ef..c53d030 100644
--- a/pages/1_Panel_Information.py
+++ b/pages/1_Panel_Information.py
@@ -7,7 +7,6 @@
 from src.format_page import render_header
 from src.utils import load_schema
 
-
 class PanelManager:
     def __init__(self, save_dir):
         self.save_dir = save_dir
diff --git a/pages/8_Create_Final_PMO.py b/pages/8_Create_Final_PMO.py
index e94da93..b9ab43d 100644
--- a/pages/8_Create_Final_PMO.py
+++ b/pages/8_Create_Final_PMO.py
@@ -3,94 +3,125 @@
 import os
 from src.format_page import render_header
 
-current_directory = os.getcwd()  # Get the current working directory
-SAVE_DIR = os.path.join(current_directory, "PMO")
-os.makedirs(SAVE_DIR, exist_ok=True)
+def check_panel_info():
+    # PANEL INFO
+    if "panel_info" in st.session_state:
+        panel_info = st.session_state["panel_info"]
+        panel_id = ', '.join(panel_info["panel_info"].keys())
+        st.write("**Current Panel Information:**", panel_id)
+    else:
+        panel_info, panel_id=None, None
+        st.error(
+            "No panel information found. Please go to the Panel Information tab before proceeding.")
+    return panel_info, panel_id
 
-render_header()
-st.subheader("Create Final PMO", divider="gray")
+def check_specimen_info():
+    # SPECIMEN INFO
+    if "specimen_info" in st.session_state:
+        spec_samples = ', '.join(
+            list(st.session_state["specimen_info"].keys())[:10])
+        st.write("**Current Specimen Information for samples (showing first 10):** ",
+                 spec_samples, '...')
+    else:
+        st.error(
+            "No specimen information found. Please go to the Specimen Information tab before proceeding.")
 
-st.subheader("Components")
-# PANEL INFO
-if "panel_info" in st.session_state:
-    panel_info = st.session_state["panel_info"]
-    panel_id = ', '.join(panel_info["panel_info"].keys())
-    st.write("**Current Panel Information:**", panel_id)
-else:
-    st.error(
-        "No panel information found. Please go to the Panel Information tab before proceeding.")
+def check_experiment_info():
+    # EXPERIMENT INFO
+    if "experiment_info" in st.session_state:
+        experiment_samples = ', '.join(
+            list(st.session_state["experiment_info"].keys())[:10])
+        st.write("**Current Experiment Information for samples (showing first 10):** ",
+                 experiment_samples, '...')
+    else:
+        st.error(
+            "No experiment information found. Please go to the Experiment Information tab before proceeding.")
 
-# SPECIMEN INFO
-if "specimen_info" in st.session_state:
-    spec_samples = ', '.join(
-        list(st.session_state["specimen_info"].keys())[:10])
-    st.write("**Current Specimen Information for samples (showing first 10):** ",
-             spec_samples, '...')
-else:
-    st.error(
-        "No specimen information found. Please go to the Specimen Information tab before proceeding.")
+def check_microhaplotype_info():
+    # MICROHAPLOTYPE INFO
+    if "mhap_data" in st.session_state:
+        bioinfo_id = ', '.join(st.session_state["mhap_data"]["microhaplotypes_detected"].keys()
+                               )
+        st.write(
+            "**Current Microhaplotype Information from bioinformatics run:**", bioinfo_id)
+    else:
+        bioinfo_id=None
+        st.error(
+            "No microhaplotype information found. Please go to the Microhaplotype Information tab before proceeding.")
+    return bioinfo_id
 
-# EXPERIMENT INFO
-if "experiment_info" in st.session_state:
-    experiment_samples = ', '.join(
-        list(st.session_state["experiment_info"].keys())[:10])
-    st.write("**Current Experiment Information for samples (showing first 10):** ",
-             experiment_samples, '...')
-else:
-    st.error(
-        "No experiment information found. Please go to the Experiment Information tab before proceeding.")
+def check_demultiplexed_info():
+    # DEMULTIPLEXED INFO
+    if "demultiplexed_data" in st.session_state:
+        # demultiplexed_data = st.session_state["demultiplexed_data"]
+        demultiplexed_bioinfo_id = st.session_state["demultiplexed_data"].keys()
+        st.write("**Current Demultiplexed Information from bioinformatics run:**",
+                 ', '.join(demultiplexed_bioinfo_id))
+    else:
+        st.error(
+            "No demultiplexed information found. Please go to the Demultiplexed Samples tab before proceeding.")
 
-# MICROHAPLOTYPE INFO
-if "mhap_data" in st.session_state:
-    bioinfo_id = ', '.join(st.session_state["mhap_data"]["microhaplotypes_detected"].keys()
-                           )
-    st.write(
-        "**Current Microhaplotype Information from bioinformatics run:**", bioinfo_id)
-else:
-    st.error(
-        "No microhaplotype information found. Please go to the Microhaplotype Information tab before proceeding.")
+def check_sequencing_info():
+    # SEQUENCING INFO
+    if "seq_info" in st.session_state:
+        seq_info_id = st.session_state["seq_info"].keys(
+        )
+        st.write("**Current Sequencing Information had ID:**",
+                 ', '.join(seq_info_id))
+    else:
+        st.error(
+            "No sequencing information found. Please go to the Sequencing Information tab before proceeding.")
 
-# DEMULTIPLEXED INFO
-if "demultiplexed_data" in st.session_state:
-    # demultiplexed_data = st.session_state["demultiplexed_data"]
-    demultiplexed_bioinfo_id = st.session_state["demultiplexed_data"].keys()
-    st.write("**Current Demultiplexed Information from bioinformatics run:**",
-             ', '.join(demultiplexed_bioinfo_id))
-else:
-    st.error(
-        "No demultiplexed information found. Please go to the Demultiplexed Samples tab before proceeding.")
+def check_bioinformatics_info():
+    # BIOINFORMATICS INFO
+    if "bioinfo_infos" in st.session_state:
+        bioinfo_info_id = st.session_state["bioinfo_infos"]["tar_amp_bioinformatics_info_id"]
+        st.write("**Current Bioinformatics Information had ID:**", bioinfo_info_id)
+    else:
+        st.error(
+            "No bioinformatics information found. Please go to the Bioinformatics Information tab before proceeding.")
 
-# SEQUENCING INFO
-if "seq_info" in st.session_state:
-    seq_info_id = st.session_state["seq_info"].keys(
-    )
-    st.write("**Current Sequencing Information had ID:**",
-             ', '.join(seq_info_id))
-else:
-    st.error(
-        "No sequencing information found. Please go to the Sequencing Information tab before proceeding.")
+def merge_data(panel_info, panel_id, bioinfo_id):
+    # MERGE DATA
+    if ('panel_info' in st.session_state
+        and 'specimen_info' in st.session_state
+        and 'experiment_info' in st.session_state
+        and 'mhap_data' in st.session_state
+        and 'demultiplexed_data' in st.session_state
+        and 'seq_info' in st.session_state
+        and 'bioinfo_infos' in st.session_state):
+        st.subheader("Merge Components to Final PMO")
+        if st.button("Merge Data"):
+            formatted_pmo = {
+                "experiment_infos": st.session_state["experiment_info"],
+                "sequencing_infos": st.session_state["seq_info"],
+                "specimen_infos": st.session_state["specimen_info"],
+                "taramp_bioinformatics_infos": st.session_state["bioinfo_infos"],
+                **st.session_state["mhap_data"],
+                **panel_info,
+                **st.session_state["demultiplexed_data"],
+            }
+            output_path = os.path.join(SAVE_DIR, f"{panel_id}_{bioinfo_id}.json")
+            with open(output_path, "w") as f:
+                json.dump(formatted_pmo, f, indent=4)
+            st.success(f"Your PMO has been saved! It can be found here: {output_path}")
 
-# BIOINFORMATICS INFO
-if "bioinfo_infos" in st.session_state:
-    bioinfo_info_id = st.session_state["bioinfo_infos"]["tar_amp_bioinformatics_info_id"]
-    st.write("**Current Bioinformatics Information had ID:**", bioinfo_info_id)
-else:
-    st.error(
-        "No bioinformatics information found. Please go to the Bioinformatics Information tab before proceeding.")
+def run_components():
+    panel_info, panel_id=check_panel_info()
+    check_specimen_info()
+    check_experiment_info()
+    bioinfo_id=check_microhaplotype_info()
+    check_demultiplexed_info()
+    check_sequencing_info()
+    check_bioinformatics_info()
+    merge_data(panel_info, panel_id, bioinfo_id)
 
-# MERGE DATA
-st.subheader("Merge Components to Final PMO")
-if st.button("Merge Data"):
-    formatted_pmo = {
-        "experiment_infos": st.session_state["experiment_info"],
-        "sequencing_infos": st.session_state["seq_info"],
-        "specimen_infos": st.session_state["specimen_info"],
-        "taramp_bioinformatics_infos": st.session_state["bioinfo_infos"],
-        **st.session_state["mhap_data"],
-        **panel_info,
-        **st.session_state["demultiplexed_data"],
-    }
-    output_path = os.path.join(SAVE_DIR, f"{panel_id}_{bioinfo_id}.json")
-    with open(output_path, "w") as f:
-        json.dump(formatted_pmo, f, indent=4)
-    st.success(f"Your PMO has been saved! It can be found here: {output_path}")
+# Initialize and run the app
+if __name__ == "__main__":
+    current_directory = os.getcwd()  # Get the current working directory
+    SAVE_DIR = os.path.join(current_directory, "finished_PMO_files")
+    os.makedirs(SAVE_DIR, exist_ok=True)
+    render_header()
+    st.subheader("Create Final PMO", divider="gray")
+    st.subheader("Components")
+    run_components()
\ No newline at end of file


Reviews:
user: login: alfredsimkin
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-01T04:42:18Z
user: login: alfredsimkin
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-01T04:43:07Z
user: login: alfredsimkin
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-01T04:44:43Z
user: login: kathrynmurie
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T22:23:36Z

Review comments:
diff_hunk: @@ -3,94 +3,125 @@
 import os
 from src.format_page import render_header
 
-current_directory = os.getcwd()  # Get the current working directory
-SAVE_DIR = os.path.join(current_directory, "PMO")
-os.makedirs(SAVE_DIR, exist_ok=True)
+def check_panel_info():
+    # PANEL INFO
+    if "panel_info" in st.session_state:
+        panel_info = st.session_state["panel_info"]
+        panel_id = ', '.join(panel_info["panel_info"].keys())
+        st.write("**Current Panel Information:**", panel_id)
+    else:
+        panel_info, panel_id=None, None
+        st.error(
+            "No panel information found. Please go to the Panel Information tab before proceeding.")
+    return panel_info, panel_id
 
-render_header()
-st.subheader("Create Final PMO", divider="gray")
+def check_specimen_info():
+    # SPECIMEN INFO
+    if "specimen_info" in st.session_state:
+        spec_samples = ', '.join(
+            list(st.session_state["specimen_info"].keys())[:10])
+        st.write("**Current Specimen Information for samples (showing first 10):** ",
+                 spec_samples, '...')
+    else:
+        st.error(
+            "No specimen information found. Please go to the Specimen Information tab before proceeding.")
 
-st.subheader("Components")
-# PANEL INFO
-if "panel_info" in st.session_state:
-    panel_info = st.session_state["panel_info"]
-    panel_id = ', '.join(panel_info["panel_info"].keys())
-    st.write("**Current Panel Information:**", panel_id)
-else:
-    st.error(
-        "No panel information found. Please go to the Panel Information tab before proceeding.")
+def check_experiment_info():
+    # EXPERIMENT INFO
+    if "experiment_info" in st.session_state:
+        experiment_samples = ', '.join(
+            list(st.session_state["experiment_info"].keys())[:10])
+        st.write("**Current Experiment Information for samples (showing first 10):** ",
+                 experiment_samples, '...')
+    else:
+        st.error(
+            "No experiment information found. Please go to the Experiment Information tab before proceeding.")
 
-# SPECIMEN INFO
-if "specimen_info" in st.session_state:
-    spec_samples = ', '.join(
-        list(st.session_state["specimen_info"].keys())[:10])
-    st.write("**Current Specimen Information for samples (showing first 10):** ",
-             spec_samples, '...')
-else:
-    st.error(
-        "No specimen information found. Please go to the Specimen Information tab before proceeding.")
+def check_microhaplotype_info():
+    # MICROHAPLOTYPE INFO
+    if "mhap_data" in st.session_state:
+        bioinfo_id = ', '.join(st.session_state["mhap_data"]["microhaplotypes_detected"].keys()
+                               )
+        st.write(
+            "**Current Microhaplotype Information from bioinformatics run:**", bioinfo_id)
+    else:
+        bioinfo_id=None
path: pages/8_Create_Final_PMO.py
user: login: alfredsimkin
body: fixes missing return value errors
created_at: 2025-03-01T04:42:18Z
author_association: COLLABORATOR
diff_hunk: @@ -3,94 +3,125 @@
 import os
 from src.format_page import render_header
 
-current_directory = os.getcwd()  # Get the current working directory
-SAVE_DIR = os.path.join(current_directory, "PMO")
-os.makedirs(SAVE_DIR, exist_ok=True)
+def check_panel_info():
+    # PANEL INFO
+    if "panel_info" in st.session_state:
+        panel_info = st.session_state["panel_info"]
+        panel_id = ', '.join(panel_info["panel_info"].keys())
+        st.write("**Current Panel Information:**", panel_id)
+    else:
+        panel_info, panel_id=None, None
path: pages/8_Create_Final_PMO.py
user: login: alfredsimkin
body: fixes empty return value errors when streamlit sees that this data is missing
created_at: 2025-03-01T04:43:07Z
author_association: COLLABORATOR
diff_hunk: @@ -3,94 +3,125 @@
 import os
 from src.format_page import render_header
 
-current_directory = os.getcwd()  # Get the current working directory
-SAVE_DIR = os.path.join(current_directory, "PMO")
-os.makedirs(SAVE_DIR, exist_ok=True)
+def check_panel_info():
+    # PANEL INFO
+    if "panel_info" in st.session_state:
+        panel_info = st.session_state["panel_info"]
+        panel_id = ', '.join(panel_info["panel_info"].keys())
+        st.write("**Current Panel Information:**", panel_id)
+    else:
+        panel_info, panel_id=None, None
+        st.error(
+            "No panel information found. Please go to the Panel Information tab before proceeding.")
+    return panel_info, panel_id
 
-render_header()
-st.subheader("Create Final PMO", divider="gray")
+def check_specimen_info():
+    # SPECIMEN INFO
+    if "specimen_info" in st.session_state:
+        spec_samples = ', '.join(
+            list(st.session_state["specimen_info"].keys())[:10])
+        st.write("**Current Specimen Information for samples (showing first 10):** ",
+                 spec_samples, '...')
+    else:
+        st.error(
+            "No specimen information found. Please go to the Specimen Information tab before proceeding.")
 
-st.subheader("Components")
-# PANEL INFO
-if "panel_info" in st.session_state:
-    panel_info = st.session_state["panel_info"]
-    panel_id = ', '.join(panel_info["panel_info"].keys())
-    st.write("**Current Panel Information:**", panel_id)
-else:
-    st.error(
-        "No panel information found. Please go to the Panel Information tab before proceeding.")
+def check_experiment_info():
+    # EXPERIMENT INFO
+    if "experiment_info" in st.session_state:
+        experiment_samples = ', '.join(
+            list(st.session_state["experiment_info"].keys())[:10])
+        st.write("**Current Experiment Information for samples (showing first 10):** ",
+                 experiment_samples, '...')
+    else:
+        st.error(
+            "No experiment information found. Please go to the Experiment Information tab before proceeding.")
 
-# SPECIMEN INFO
-if "specimen_info" in st.session_state:
-    spec_samples = ', '.join(
-        list(st.session_state["specimen_info"].keys())[:10])
-    st.write("**Current Specimen Information for samples (showing first 10):** ",
-             spec_samples, '...')
-else:
-    st.error(
-        "No specimen information found. Please go to the Specimen Information tab before proceeding.")
+def check_microhaplotype_info():
+    # MICROHAPLOTYPE INFO
+    if "mhap_data" in st.session_state:
+        bioinfo_id = ', '.join(st.session_state["mhap_data"]["microhaplotypes_detected"].keys()
+                               )
+        st.write(
+            "**Current Microhaplotype Information from bioinformatics run:**", bioinfo_id)
+    else:
+        bioinfo_id=None
+        st.error(
+            "No microhaplotype information found. Please go to the Microhaplotype Information tab before proceeding.")
+    return bioinfo_id
 
-# EXPERIMENT INFO
-if "experiment_info" in st.session_state:
-    experiment_samples = ', '.join(
-        list(st.session_state["experiment_info"].keys())[:10])
-    st.write("**Current Experiment Information for samples (showing first 10):** ",
-             experiment_samples, '...')
-else:
-    st.error(
-        "No experiment information found. Please go to the Experiment Information tab before proceeding.")
+def check_demultiplexed_info():
+    # DEMULTIPLEXED INFO
+    if "demultiplexed_data" in st.session_state:
+        # demultiplexed_data = st.session_state["demultiplexed_data"]
+        demultiplexed_bioinfo_id = st.session_state["demultiplexed_data"].keys()
+        st.write("**Current Demultiplexed Information from bioinformatics run:**",
+                 ', '.join(demultiplexed_bioinfo_id))
+    else:
+        st.error(
+            "No demultiplexed information found. Please go to the Demultiplexed Samples tab before proceeding.")
 
-# MICROHAPLOTYPE INFO
-if "mhap_data" in st.session_state:
-    bioinfo_id = ', '.join(st.session_state["mhap_data"]["microhaplotypes_detected"].keys()
-                           )
-    st.write(
-        "**Current Microhaplotype Information from bioinformatics run:**", bioinfo_id)
-else:
-    st.error(
-        "No microhaplotype information found. Please go to the Microhaplotype Information tab before proceeding.")
+def check_sequencing_info():
+    # SEQUENCING INFO
+    if "seq_info" in st.session_state:
+        seq_info_id = st.session_state["seq_info"].keys(
+        )
+        st.write("**Current Sequencing Information had ID:**",
+                 ', '.join(seq_info_id))
+    else:
+        st.error(
+            "No sequencing information found. Please go to the Sequencing Information tab before proceeding.")
 
-# DEMULTIPLEXED INFO
-if "demultiplexed_data" in st.session_state:
-    # demultiplexed_data = st.session_state["demultiplexed_data"]
-    demultiplexed_bioinfo_id = st.session_state["demultiplexed_data"].keys()
-    st.write("**Current Demultiplexed Information from bioinformatics run:**",
-             ', '.join(demultiplexed_bioinfo_id))
-else:
-    st.error(
-        "No demultiplexed information found. Please go to the Demultiplexed Samples tab before proceeding.")
+def check_bioinformatics_info():
+    # BIOINFORMATICS INFO
+    if "bioinfo_infos" in st.session_state:
+        bioinfo_info_id = st.session_state["bioinfo_infos"]["tar_amp_bioinformatics_info_id"]
+        st.write("**Current Bioinformatics Information had ID:**", bioinfo_info_id)
+    else:
+        st.error(
+            "No bioinformatics information found. Please go to the Bioinformatics Information tab before proceeding.")
 
-# SEQUENCING INFO
-if "seq_info" in st.session_state:
-    seq_info_id = st.session_state["seq_info"].keys(
-    )
-    st.write("**Current Sequencing Information had ID:**",
-             ', '.join(seq_info_id))
-else:
-    st.error(
-        "No sequencing information found. Please go to the Sequencing Information tab before proceeding.")
+def merge_data(panel_info, panel_id, bioinfo_id):
+    # MERGE DATA
+    if ('panel_info' in st.session_state
path: pages/8_Create_Final_PMO.py
user: login: alfredsimkin
body: Now the 'merge data' subheader and button only appear if all the other checks work - should probably move this to the 'main' block since all these checks are performed earlier
created_at: 2025-03-01T04:44:43Z
author_association: COLLABORATOR

PR comments:
user: login: kathrynmurie
created_at: 2025-02-20T23:48:08Z
body: This looks so much neater, thanks Alfred! 

When I build the app I am seeing these errors when the panel info and bioinformatics info aren't entered yet:
<img width="1428" alt="Screenshot 2025-02-20 at 3 37 12 PM" src="https://github.com/user-attachments/assets/85442612-3d67-4a0c-9ae4-d1a6d3d8e05a" />
<img width="1435" alt="Screenshot 2025-02-20 at 3 38 06 PM" src="https://github.com/user-attachments/assets/123a7a6f-7056-41d5-b695-1b3b801f3994" />

I'm also wondering if the check functions could be made into one more general function as they have the same pattern? 
author_association: CONTRIBUTOR
user: login: kathrynmurie
created_at: 2025-02-20T23:48:58Z
body: Also, what formatter are you using for your code? We seem to have some conflicts between what we're using 
author_association: CONTRIBUTOR
user: login: alfredsimkin
created_at: 2025-03-01T04:46:49Z
body: > This looks so much neater, thanks Alfred!
> 
> When I build the app I am seeing these errors when the panel info and bioinformatics info aren't entered yet: <img alt="Screenshot 2025-02-20 at 3 37 12 PM" width="1428" src="https://private-user-images.githubusercontent.com/52662905/415415744-85442612-3d67-4a0c-9ae4-d1a6d3d8e05a.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDA4MDQ1OTIsIm5iZiI6MTc0MDgwNDI5MiwicGF0aCI6Ii81MjY2MjkwNS80MTU0MTU3NDQtODU0NDI2MTItM2Q2Ny00YTBjLTlhZTQtZDFhNmQzZDhlMDVhLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzAxVDA0NDQ1MlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTYzM2Q3YzY5ODk5OTEyZGQ3YjRhZTEyMGE5ZWRiZTlmNjNiMmQ3YmM3MmVmYzhkYWJiY2ZkN2I4NWVhNzBkY2YmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.B7zM1Ps3_JR48BdMLQKcTlnygomrgCpCiUKizFkwpZ0"> <img alt="Screenshot 2025-02-20 at 3 38 06 PM" width="1435" src="https://private-user-images.githubusercontent.com/52662905/415415908-123a7a6f-7056-41d5-b695-1b3b801f3994.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDA4MDQ1OTIsIm5iZiI6MTc0MDgwNDI5MiwicGF0aCI6Ii81MjY2MjkwNS80MTU0MTU5MDgtMTIzYTdhNmYtNzA1Ni00MWQ1LWI2OTUtMWIzYjgwMWYzOTk0LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMDElMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzAxVDA0NDQ1MlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTFiYWJjYTNmZDk4NThiMmFlZGZkOWVlZDM3NDI2MmVlZTdkZWNkZjA3MGVlYzdmYjVhOWFlNDRjM2I0ODM2ZWEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.L0zxMYE7uA79j6bvC50cEy165A81EZ0NvUgaC8Pgx7Q">
> 
> I'm also wondering if the check functions could be made into one more general function as they have the same pattern?

Fixed this issue in latest commit - I like the idea of merging check functions into one - I would just need to standardize the messages upon 'success' somewhat. I'll experiment with this soon.
author_association: COLLABORATOR
user: login: alfredsimkin
created_at: 2025-03-01T04:47:58Z
body: > Also, what formatter are you using for your code? We seem to have some conflicts between what we're using

I'm using sublime - I usually use tabs instead of spaces for indentation. I converted the tabs back to spaces (I think) in latest commit
author_association: COLLABORATOR
user: login: kathrynmurie
created_at: 2025-03-03T22:23:14Z
body: Hi Alfred, I prefer the output from this one. I think it's more useful for the user to get all the things they've missed in one go. I was wondering more if the duplicated code across functions could be generalised into one that is then called for each key that needs to be checked. e.g. could check_specimen_info be converted to something like this and used for multiple fields instead of having a separate function for each 

```

def check_field_info(field_name, field, max_display):
    if field in st.session_state:
        field_values = ', '.join(
            list(st.session_state[field].keys())[:max_display])
        st.write(f"**Current Specimen Information for samples (showing first {max_display}):** ",
                 field_values, '...')
    else:
        st.error(
            f"No {field} found. Please go to the f{field_name} tab before proceeding.")
        
```

This is still much neater and the errors I had before are gone. So happy if you want to merge this or do something like the above. 
author_association: CONTRIBUTOR
user: login: alfredsimkin
created_at: 2025-03-04T21:49:56Z
body: > Hi Alfred, I prefer the output from this one. I think it's more useful for the user to get all the things they've missed in one go. I was wondering more if the duplicated code across functions could be generalised into one that is then called for each key that needs to be checked. e.g. could check_specimen_info be converted to something like this and used for multiple fields instead of having a separate function for each
> 
> ```
> 
> def check_field_info(field_name, field, max_display):
>     if field in st.session_state:
>         field_values = ', '.join(
>             list(st.session_state[field].keys())[:max_display])
>         st.write(f"**Current Specimen Information for samples (showing first {max_display}):** ",
>                  field_values, '...')
>     else:
>         st.error(
>             f"No {field} found. Please go to the f{field_name} tab before proceeding.")
>         
> ```
> 
> This is still much neater and the errors I had before are gone. So happy if you want to merge this or do something like the above.

This function that you have above looks good, except it only works for functions for which 'field' is the top layer of streamlit.sessions() (i.e. specimen info and experiment info). By contrast, for panel_info, experiment_info, and microhaplotype_info there's an additional layer of nesting with hardcoded keys underneath the streamlit.sessions keys, and for the remaining functions there's an additional layer of nesting with user-defined keys under the streamlit.sessions keys. The 'specimen Information' content of the function would also need to be assigned to a variable. I went back to the other branch (modular_merge_unified_check_function) which uses a function that is very similar to the function you listed above. I removed the break statement in my function - this allows a user to see all the pages that 'passed' vs. all the ones that 'failed' in one go. I also modified streamlit.write to be streamlit.success and modified a duplicated subheader to accurately describe the demultiplexing page.
author_association: COLLABORATOR