Skip to content

#88 plus review fixes - #89

Open
gbouras13 wants to merge 8 commits into
mainfrom
pr88-review-fixes
Open

#88 plus review fixes#89
gbouras13 wants to merge 8 commits into
mainfrom
pr88-review-fixes

Conversation

@gbouras13

Copy link
Copy Markdown
Owner

sanjaynagi-eit and others added 7 commits August 13, 2026 21:53
The chopper QC chain is gunzip -c | chopper --threads N | gzip. Only the
compressor is parallel-unaware, and it dominated: on a 300 MB ONT fastq the
whole chain took 47.7s, of which gunzip+chopper was 5.4s and gzip was 42s.

Use bgzip -@ threads instead. bgzip ships with htslib/samtools, already a hard
plassembler dependency, so this adds nothing to the environment; BGZF is a
valid gzip stream, so flye, minimap2 and chopper read the result unchanged.
It is also slightly smaller here (277 vs 293 MiB). Falls back to gzip if bgzip
is somehow missing.

  gunzip | chopper (no compression)   5.4s
  ... | gzip     (before)            47.7s   293.4 MiB
  ... | bgzip -@ 8 (after)            5.9s   276.7 MiB

Verified content-identical: with chopper --threads 1 (chopper is not
order-deterministic above 1 thread) the decompressed output of the two chains
is byte-for-byte equal.

Also fixes the process handling. Only gzip_proc was waited on, so a failing
gunzip or chopper was silently swallowed - the bare 'except: logger.error'
never saw it - and left zombies behind. Every stage is now waited on and a
non-zero exit is reported with the stage name and log path. The parent also
closes its copy of each upstream pipe read end, and plain (uncompressed) input
is handed to chopper directly instead of through a pointless 'cat' process.

gzip_file, used by --skip_qc, went through python's gzip module, which is
slower still; it now uses the same compressor with a python fallback.
tests/test_data/end_to_end/input_half.fastq.gz is 778 lines - 194.5 FASTQ
records. It ends mid-record, with a header and a sequence line but no + or
quality line, so chopper rejects it (IncompleteRecord) and exits 101 after
emitting 193 complete reads.

That has been true since the fixture was committed;
test_plassembler_case_depth_filter_some passed only because the chopper
failure was swallowed. With this PR's process handling it is detected, and
the test fails.

Drop the two orphan lines. chopper then exits 0 and emits the same 193
records, so nothing the test exercises changes - and the test asserts only
that the command exits 0, so no expectation depends on the fixture's exact
contents.

The full suite (including slow) is 169 passed / 1 failed before this commit
and 170 passed after.
chopper v0.11.0 introduced --trim-approach and made --headcrop/--tailcrop
apply only under `fixed-crop`. They were silently ignored otherwise, with no
warning until v0.13.0 added one, so plassembler's intended 75bp head and tail
crop has been a no-op for anyone on chopper >=0.11.0 since September 2025.

Pass --trim-approach fixed-crop and raise the minimum chopper version to
v0.11.0 in pyproject.toml, build/environment.yaml, README.md and docs/install.md.
Older chopper rejects the flag outright, and plassembler does not check
chopper's exit code, so allowing <0.11.0 would yield an empty read file.

Note chopper >=0.11.0 also re-checks --minlength against the post-crop
segment, which older versions did not, so reads within 150bp of --min_length
are now dropped rather than kept and cropped.

Verified end to end: plasmid sequences are byte-identical, with small shifts
in long read depths and one copy number moving by 0.01.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tests/test_data/validation/concat.fastq was truncated to 0 bytes in the bgzip
commit, unrelated to everything else in that change.

It is not a fixture clobbered by a suite run. test_concat_single_fastq_bad
(tests/test_plassembler.py:218) does name it as an output path, but
concatenate_single_fastq consumes both inputs via
records.extend(SeqIO.parse(handle, "fastq")) before it opens the output, so
parsing test.fasta as fastq raises ValueError first and the file is never
opened for writing. Restoring it and running the full non-slow suite leaves it
at 104636 bytes.

Nothing reads it as an input, so the deletion broke nothing, but it drops 100 KB
of real ONT reads for no reason. Restored from main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The OSError handler kills each already-started stage but never waits on it,
leaving exactly the zombies the rest of this change exists to avoid.

Also records why the `return` below it is load-bearing rather than dead code:
logger.error terminates the process under the ERROR sink that begin_plassembler
installs, but plassembler.utils.qc is importable without that sink, and falling
through would wait on the processes just killed above and report them a second
time as failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only the last process in the gunzip -> chopper -> compressor chain was
checked, so a chopper that exited non-zero went unnoticed: the compressor
still wrote a valid but empty chopper_long_reads.fastq.gz, "Finished
running chopper" was still logged, and Flye/Raven ran on zero reads. The
real diagnosis reached only <logdir>/chopper.err, which users rarely open.

Every stage is now checked, and any failure - a dead stage, a chopper that
could not be spawned at all, or output with no reads in it - reports
chopper's own stderr alongside the path to the logfile and exits, matching
how external_tools.py handles a CalledProcessError.

check_dependencies() also warns when the installed chopper predates v0.11.0.
The pin was raised to >=0.11.0 for --trim-approach, but a pin only binds when
an environment is first created, so an existing environment can still hold a
chopper that rejects the flag.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The 1.8.4 entry covered the cropping fix and the fatal-failure handling but
said nothing about the change they were built on top of.

Adds the bgzip compression speedup, including the caveat that bgzip only
reaches us transitively via samtools -> htslib and does not resolve on
osx-arm64, so Apple Silicon users get the gzip fallback and no speedup.

Also credits the per-stage process handling on the existing fatal-failure
bullet, and notes that it is what exposed the long-standing mid-record
truncation in the input_half.fastq.gz fixture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants