From 0655d32ef2a6aca64d0cea526c2e92d2863102d2 Mon Sep 17 00:00:00 2001 From: Glenn Hickey Date: Mon, 31 Aug 2026 07:19:03 -0400 Subject: [PATCH] fix_vcf_ploidies: bgzip must stay a filter, not take a filename 14d05895 ("log input vcf path") added raw_out_path as a positional argument to the bgzip call while leaving cactus_call's infile=/outfile= redirects in place. The intent was to get the path into the logged command line, but a filename argument switches bgzip from a stdin/stdout filter to compressing in place, and the two cannot be combined. cactus_call stages stdout under outfile + '.part' and only renames it into place once the command exits cleanly, so out_vcf_path does not exist when bgzip runs and bgzip takes the in-place path: 1. bgzip writes the real compressed VCF to raw_out_path + '.gz', which IS out_vcf_path, and deletes raw_out_path. It exits 0. 2. cactus_call sees success and os.replace()s its empty .part file over out_vcf_path, discarding what bgzip just wrote. 3. os.remove(raw_out_path) raises FileNotFoundError, because bgzip took it. Step 3 is the only reason this is loud. By then the output is already gone, so anything that swallowed that exception would ship an empty VCF with exit 0. Only reachable when the VCF actually needs ploidy padding: the scan above returns early via shutil.copyfile when every sample has one ploidy throughout, so a run whose samples are uniformly diploid never gets here. Mixed ploidy -- chrY alongside the autosomes -- is the common case that does. Reverts to the form d5218801 introduced and that minigraph_gfa_to_pansn uses: no filename, infile/outfile only. Verified against the bgzip in bin/: with a filename and no pre-existing .gz it deletes the input and exits 0 (the failure above); as a filter it leaves the input alone, writes 183 bytes for a 3-line test VCF, and round-trips byte-identically through bgzip -dc. Co-Authored-By: Claude Opus 5 (1M context) --- src/cactus/refmap/cactus_graphmap_join.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cactus/refmap/cactus_graphmap_join.py b/src/cactus/refmap/cactus_graphmap_join.py index 6dd3aef31..25d2c7125 100644 --- a/src/cactus/refmap/cactus_graphmap_join.py +++ b/src/cactus/refmap/cactus_graphmap_join.py @@ -2072,7 +2072,10 @@ def signature_ploidies(sig): out_file.write(b'\t'.join(toks) + b'\n') if raw_out_path != out_vcf_path: - cactus_call(parameters=['bgzip', raw_out_path, '--threads', str(threads)], infile=raw_out_path, + # no filename argument: bgzip given one compresses in place, writing raw_out_path.gz and + # deleting the original, so out_vcf_path would get an empty stdout and the remove below + # would fail. it has to stay a stdin/stdout filter, as in minigraph_gfa_to_pansn + cactus_call(parameters=['bgzip', '--threads', str(threads)], infile=raw_out_path, outfile=out_vcf_path) os.remove(raw_out_path)