Skip to content

Commit 6c76cd3

Browse files
committed
fix: keep plasmid copy-number column float-typed (fixes --no_chromosome)
The earlier collate_depths hardening set the copy-number column to the string "NA" when chromosome depth was missing or zero. In --no_chromosome mode a fake chromosome of A's (zero depth) is created, so the column became "NA" and combine_depth_mash_tsvs's `.astype(float)` raised `ValueError: could not convert string to float: 'NA'` -- the two CI failures (test_plassembler_run_no_chromosome / _long_no_chromosome). Keep the column float-typed: dividing by a zero chromosome depth yields inf (which the depth filter treats as "keep", matching prior behaviour), and NaN is emitted only when the chromosome depth is genuinely unusable. Regression tests updated, including one that reproduces the .astype(float) failure. Validated: both --no_chromosome end-to-end tests pass with the real toolchain.
1 parent eab7ea9 commit 6c76cd3

2 files changed

Lines changed: 28 additions & 15 deletions

File tree

src/plassembler/utils/depth.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,20 @@ def collate_depths(depths, shortFlag, contig_lengths):
148148
)
149149
mean_col, copy_col = "mean_depth_long", "plasmid_copy_number_long"
150150

151-
# plasmid copy number = mean depth / chromosome mean depth. Guard against a
152-
# missing (no "chromosome" contig), non-numeric or zero chromosome depth,
153-
# which previously raised NameError/TypeError or produced inf copy numbers.
154-
if not isinstance(chromosome_depth, (int, float)) or chromosome_depth == 0:
155-
summary_df[copy_col] = "NA"
151+
# plasmid copy number = mean depth / chromosome mean depth.
152+
if not isinstance(chromosome_depth, (int, float)):
153+
# no usable chromosome depth: either no "chromosome" contig at all
154+
# (chromosome_depth is None) or its stats could not be computed
155+
# ("NA"). Copy number is undefined; keep the column float-typed.
156+
summary_df[copy_col] = float("nan")
156157
else:
157-
summary_df[copy_col] = (
158-
pd.to_numeric(summary_df[mean_col], errors="coerce") / chromosome_depth
159-
).round(2)
158+
# chromosome_depth may be 0 (e.g. the fake --no_chromosome chromosome of
159+
# A's, which no reads map to); dividing then yields inf, which the
160+
# downstream depth filter treats as "keep" - preserving prior behaviour.
161+
# A non-numeric ("NA") mean is coerced to NaN so the column stays float
162+
# (a string here broke .astype(float) in combine_depth_mash_tsvs).
163+
mean_numeric = pd.to_numeric(summary_df[mean_col], errors="coerce")
164+
summary_df[copy_col] = (mean_numeric / chromosome_depth).round(2)
160165
# return df
161166
return summary_df
162167

tests/test_deterministic.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from pathlib import Path
99

10+
import numpy as np
11+
1012
from src.plassembler.utils.depth import (
1113
collate_depths,
1214
get_contig_circularity,
@@ -54,17 +56,23 @@ def test_collate_depths_copy_number_math():
5456
assert df.loc["plasmid00001", "plasmid_copy_number_short"] == 2.0
5557

5658

57-
def test_collate_depths_no_chromosome_returns_na():
58-
"""No contig named 'chromosome' -> copy number is 'NA' (previously NameError)."""
59+
def test_collate_depths_no_chromosome_is_nan_not_crash():
60+
"""No contig named 'chromosome' -> copy number NaN, not a NameError/crash."""
5961
depths = {"plasmid00001": [20] * 60}
6062
contig_lengths = {"plasmid00001": 60}
6163
df = collate_depths(depths, "short", contig_lengths)
62-
assert df["plasmid_copy_number_short"].tolist() == ["NA"]
64+
assert df["plasmid_copy_number_short"].isna().all()
65+
# must stay float-convertible (downstream does .astype(float))
66+
df["plasmid_copy_number_short"].astype(float)
6367

6468

65-
def test_collate_depths_zero_chromosome_depth_returns_na():
66-
"""Zero chromosome depth -> copy number is 'NA' (previously inf)."""
69+
def test_collate_depths_zero_chromosome_depth_stays_float():
70+
"""Zero chromosome depth (e.g. the fake --no_chromosome chromosome) -> inf,
71+
which the depth filter treats as 'keep'. Regression: a string 'NA' here broke
72+
the downstream .astype(float) in combine_depth_mash_tsvs (CI --no_chromosome)."""
6773
depths = {"chromosome": [0] * 100, "plasmid00001": [5] * 60}
6874
contig_lengths = {"chromosome": 100, "plasmid00001": 60}
69-
df = collate_depths(depths, "short", contig_lengths)
70-
assert (df["plasmid_copy_number_short"] == "NA").all()
75+
df = collate_depths(depths, "short", contig_lengths).set_index("contig")
76+
assert np.isinf(df.loc["plasmid00001", "plasmid_copy_number_short"])
77+
# the actual CI failure: this must not raise
78+
df["plasmid_copy_number_short"].astype(float)

0 commit comments

Comments
 (0)