diff --git a/src/pmotools/pmo_builder/metatable_to_pmo.py b/src/pmotools/pmo_builder/metatable_to_pmo.py index 4162c22..6169646 100644 --- a/src/pmotools/pmo_builder/metatable_to_pmo.py +++ b/src/pmotools/pmo_builder/metatable_to_pmo.py @@ -157,7 +157,7 @@ def library_sample_info_table_to_pmo( library_prep_plate_position_col, meta_json, copy_contents, - "specimen_name", + "library_sample_name", "library_prep_plate_info", ) meta_json = add_parasite_density_info( @@ -166,7 +166,7 @@ def library_sample_info_table_to_pmo( meta_json, copy_contents, "library_sample_name", - entry_name="parasite_density_info", + entry_name="qpcr_parasite_density_info", ) # listify columns that contain values that could be list, are delimited by the argument list_values_library_values_delimiter primitives = (int, float, str, bool, complex) @@ -494,7 +494,7 @@ def add_plate_info( plate_position_col, meta_json, df, - specimen_name_col, + match_col, entry_name="plate_info", ): if all( @@ -531,7 +531,7 @@ def add_plate_info( ) from e for row in meta_json: - content_row = df[df[specimen_name_col] == row[specimen_name_col]] + content_row = df[df[match_col] == row[match_col]] plate_name_val = content_row[plate_name_col].iloc[0] if plate_name_col else None plate_row_val = ( content_row[plate_row_col].iloc[0].upper() if plate_row_col else None @@ -560,7 +560,7 @@ def add_parasite_density_info( parasite_density_method_col, meta_json, df, - specimen_name_col, + match_col, entry_name, ): density_method_pairs = [] @@ -608,7 +608,7 @@ def add_parasite_density_info( # Add parasite density info to meta_json for row in meta_json: - content_row = df[df[specimen_name_col] == row[specimen_name_col]] + content_row = df[df[match_col] == row[match_col]] density_infos = [] for density_col, method_col in density_method_pairs: density_val = content_row[density_col].iloc[0] if density_col else None diff --git a/src/pmotools/pmo_builder/panel_information_to_pmo.py b/src/pmotools/pmo_builder/panel_information_to_pmo.py index 949fd8c..563307f 100644 --- a/src/pmotools/pmo_builder/panel_information_to_pmo.py +++ b/src/pmotools/pmo_builder/panel_information_to_pmo.py @@ -332,8 +332,8 @@ def build_target_info_dict( fwd_primer_dict["location"] = { "genome_id": genome_id, "chrom": row[chrom_col], - "end": int(row[forward_primers_start_col]), - "start": int(row[forward_primers_end_col]), + "start": int(row[forward_primers_start_col]), + "end": int(row[forward_primers_end_col]), } if strand_col and pd.notna(row[strand_col]): fwd_primer_dict["location"]["strand"] = row[strand_col] diff --git a/src/pmotools/pmo_engine/pmo_exporter.py b/src/pmotools/pmo_engine/pmo_exporter.py index 361ebd7..646436a 100644 --- a/src/pmotools/pmo_engine/pmo_exporter.py +++ b/src/pmotools/pmo_engine/pmo_exporter.py @@ -451,6 +451,7 @@ def write_bed_locs(bed_locs: list[BedLoc], fnp, add_header: bool = False): ] ) ) + f.write("\n") for bed_loc in bed_locs: f.write( "\t".join( @@ -540,11 +541,10 @@ def extract_panels_insert_bed_loc( :param sort_output: whether to sort output by genomic location :return: a list of target inserts, with named tuples with fields: chrom, start, end, name, score, strand, ref_seq, extra_info """ - bed_loc_out = {} + bed_loc_out = [] if select_panel_ids is None: select_panel_ids = list(range(len(pmodata["panel_info"]))) for panel_id in select_panel_ids: - bed_loc_out_per_panel = [] for reaction_id in range(len(pmodata["panel_info"][panel_id]["reactions"])): for target_id in pmodata["panel_info"][panel_id]["reactions"][ reaction_id @@ -589,7 +589,7 @@ def extract_panels_insert_bed_loc( if "ref_seq" not in tar["insert_location"] else tar["insert_location"]["ref_seq"] ) - bed_loc_out_per_panel.append( + bed_loc_out.append( BedLoc( tar["insert_location"]["chrom"], tar["insert_location"]["start"], @@ -602,12 +602,8 @@ def extract_panels_insert_bed_loc( extra_info, ) ) - if sort_output: - return sorted( - bed_loc_out_per_panel, - key=lambda bed: (bed.chrom, bed.start, bed.end), - ) - bed_loc_out[panel_id] = bed_loc_out_per_panel + if sort_output: + return sorted(bed_loc_out, key=lambda bed: (bed.chrom, bed.start, bed.end)) return bed_loc_out @staticmethod diff --git a/tests/test_pmo_builder/test_metatable_to_pmo.py b/tests/test_pmo_builder/test_metatable_to_pmo.py index 38d59bc..7223cca 100644 --- a/tests/test_pmo_builder/test_metatable_to_pmo.py +++ b/tests/test_pmo_builder/test_metatable_to_pmo.py @@ -1603,13 +1603,18 @@ def test_library_sample_info_table_to_pmo_with_parasite_density(self): parasite_density_method_col="parasite_density_method", ) - self.assertEqual(result[0]["parasite_density_info"][0]["parasite_density"], 10) self.assertEqual( - result[0]["parasite_density_info"][0]["parasite_density_method"], "qPCR" + result[0]["qpcr_parasite_density_info"][0]["parasite_density"], 10 ) - self.assertEqual(result[1]["parasite_density_info"][0]["parasite_density"], 100) self.assertEqual( - result[1]["parasite_density_info"][0]["parasite_density_method"], + result[0]["qpcr_parasite_density_info"][0]["parasite_density_method"], + "qPCR", + ) + self.assertEqual( + result[1]["qpcr_parasite_density_info"][0]["parasite_density"], 100 + ) + self.assertEqual( + result[1]["qpcr_parasite_density_info"][0]["parasite_density_method"], "microscopy", ) @@ -1638,10 +1643,18 @@ def test_library_sample_info_table_to_pmo_with_parasite_density_multiple(self): parasite_density_method_col=["method1", "method2"], ) - self.assertEqual(result[0]["parasite_density_info"][0]["parasite_density"], 15) - self.assertEqual(result[0]["parasite_density_info"][1]["parasite_density"], 10) - self.assertEqual(result[1]["parasite_density_info"][0]["parasite_density"], 107) - self.assertEqual(result[1]["parasite_density_info"][1]["parasite_density"], 100) + self.assertEqual( + result[0]["qpcr_parasite_density_info"][0]["parasite_density"], 15 + ) + self.assertEqual( + result[0]["qpcr_parasite_density_info"][1]["parasite_density"], 10 + ) + self.assertEqual( + result[1]["qpcr_parasite_density_info"][0]["parasite_density"], 107 + ) + self.assertEqual( + result[1]["qpcr_parasite_density_info"][1]["parasite_density"], 100 + ) def test_library_sample_info_table_to_pmo_with_all_new_fields(self): """Test all new optional fields together""" @@ -1685,7 +1698,9 @@ def test_library_sample_info_table_to_pmo_with_all_new_fields(self): self.assertEqual(result[0]["experiment_accession"], "EXP001") self.assertEqual(result[0]["fastqs_loc"], "/path/to/fastqs1") self.assertEqual(result[0]["run_accession"], "RUN001") - self.assertEqual(result[0]["parasite_density_info"][0]["parasite_density"], 10) + self.assertEqual( + result[0]["qpcr_parasite_density_info"][0]["parasite_density"], 10 + ) self.assertIn("library_prep_plate_info", result[0]) self.assertEqual(result[0]["library_prep_plate_info"]["plate_col"], 1) @@ -1693,7 +1708,9 @@ def test_library_sample_info_table_to_pmo_with_all_new_fields(self): self.assertEqual(result[1]["experiment_accession"], "EXP002") self.assertEqual(result[1]["fastqs_loc"], "/path/to/fastqs2") self.assertEqual(result[1]["run_accession"], "RUN002") - self.assertEqual(result[1]["parasite_density_info"][0]["parasite_density"], 100) + self.assertEqual( + result[1]["qpcr_parasite_density_info"][0]["parasite_density"], 100 + ) self.assertIn("library_prep_plate_info", result[1]) self.assertEqual(result[1]["library_prep_plate_info"]["plate_col"], 2) diff --git a/tests/test_pmo_builder/test_panel_information_to_pmo.py b/tests/test_pmo_builder/test_panel_information_to_pmo.py index 29158a3..bf74cf3 100644 --- a/tests/test_pmo_builder/test_panel_information_to_pmo.py +++ b/tests/test_pmo_builder/test_panel_information_to_pmo.py @@ -416,8 +416,8 @@ def test_build_target_info_dict_full_info( "location": { "genome_id": 0, "chrom": "chrom1", - "end": 1, - "start": 2, + "start": 1, + "end": 2, }, }, "reverse_primer": { @@ -443,8 +443,8 @@ def test_build_target_info_dict_full_info( "location": { "genome_id": 0, "chrom": "chrom1", - "end": 1, - "start": 2, + "start": 1, + "end": 2, }, }, "reverse_primer": { @@ -470,8 +470,8 @@ def test_build_target_info_dict_full_info( "location": { "genome_id": 0, "chrom": "chrom1", - "end": 1, - "start": 2, + "start": 1, + "end": 2, }, }, "reverse_primer": { @@ -526,8 +526,8 @@ def test_build_target_info_dict_missing_info( "location": { "genome_id": 0, "chrom": "chrom1", - "end": 1, - "start": 2, + "start": 1, + "end": 2, }, }, "reverse_primer": {"seq": "GTT"}, diff --git a/tests/test_pmo_engine/test_pmo_exporter.py b/tests/test_pmo_engine/test_pmo_exporter.py index 1984bfa..99c7045 100755 --- a/tests/test_pmo_engine/test_pmo_exporter.py +++ b/tests/test_pmo_engine/test_pmo_exporter.py @@ -105,6 +105,54 @@ def test_extract_panels_insert_bed_loc(self): PMOExporter.write_bed_locs(all_target_inserts, output_fnp) self.assertEqual("52b1f79a3a89f8265573fa54b5a7ce57", md5sum_of_fnp(output_fnp)) + def test_extract_panels_insert_bed_loc_covers_all_reactions(self): + # regression: previously the function returned early inside the reaction + # loop, so only the first reaction of the first panel was returned. + import copy + + pmo = copy.deepcopy(self.combined_pmo_data) + panel = pmo["panel_info"][0] + targets = panel["reactions"][0]["panel_targets"] + half = len(targets) // 2 + panel["reactions"] = [ + {"reaction_name": "pool1", "panel_targets": targets[:half]}, + {"reaction_name": "pool2", "panel_targets": targets[half:]}, + ] + bed_locs = PMOExporter.extract_panels_insert_bed_loc(pmo, sort_output=False) + # every target across BOTH reactions is present + self.assertEqual(len(bed_locs), len(targets)) + self.assertEqual( + {b.name for b in bed_locs}, + {pmo["target_info"][t]["target_name"] for t in targets}, + ) + + def test_write_bed_locs_header_on_own_line(self): + # regression: header was written without a trailing newline, gluing the + # first data row onto it. + bed_locs = PMOExporter.extract_targets_insert_bed_loc( + self.combined_pmo_data, sort_output=True + ) + out_fnp = os.path.join(self.test_dir.name, "with_header.bed") + PMOExporter.write_bed_locs(bed_locs, out_fnp, add_header=True) + with open(out_fnp) as f: + lines = f.read().splitlines() + self.assertEqual( + lines[0], + "\t".join( + [ + "#chrom", + "start", + "end", + "name", + "score", + "strand", + "ref_seq", + "extra_info", + ] + ), + ) + self.assertEqual(len(lines), len(bed_locs) + 1) + def test_extract_alleles_per_sample_table(self): allele_data = PMOExporter.extract_alleles_per_sample_table( self.combined_pmo_data,