Skip to content

feat: Collection of Minor Changes after review#101

Merged
ameynert merged 26 commits into
mainfrom
zn_fixes
Jul 14, 2026
Merged

feat: Collection of Minor Changes after review#101
ameynert merged 26 commits into
mainfrom
zn_fixes

Conversation

@znorgaard

@znorgaard znorgaard commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

A collection of small correctness, quality, and consistency changes across the divref toolkit and the Snakemake workflows. The bulk is non-behavioral (docstrings, typing, refactors, added tests), with two behavioral changes called out below. All checks pass (uv run poe check-all: format, lint, mypy, tests; snakefmt clean).

Behavioral changes (worth a closer look)

  • fix(haplotype): break sort ties for co-located SNP + insertionget_haplo_sequence / haplo_coordinates sorted component variants by (position, len(ref)), which ties a SNP and an insertion at the same position. The tie was resolved by input order, and when the insertion applied first the SNP was silently dropped from the emitted sequence (a PASS row in the FASTA/DuckDB deliverable). Added a tertiary tiebreak on alt length so a substitution always composes before a pure insertion, plus a reversed-order regression test.
  • feat(fasta): order FASTA output by genomic positioncreate_divref_fasta now emits rows ORDER BY start, sequence_id, making per-chromosome FASTA output deterministic/checksummable across runs. Same content, stable byte-ordering.

Toolkit refactors & hardening

  • refactor(duckdb) — extract a shared sequences_table_exists helper; reuse it in finalize, append_contig, and create_divref_fasta (dedups the repeated information_schema check).
  • refactor(append-contig) — reuse the helper; switch the per-chunk insert to INSERT ... BY NAME (guards against column-order drift); eq=False on _RemapArrays; document the 0-based half-open coordinate convention at the DuckDB boundary.
  • refactor(extract) — single-source the HGDP+1KG table URIs from defaults; fix stale "sample metadata" docstrings; validate the .ht output path before starting Hail; type freq_threshold as 0.0.
  • refactor(hail) — use pathlib for connector-JAR path handling; validate the credentials path with is_file().
  • fix(haplotype-compat)parse_variants_string raises an informative ValueError naming the offending token; corrected the classify_pair / REASONS documentation.
  • refactor — replace to_hashable_items with frozenset(d.items()); drop the unused n_groups from _compute_locus_groups's return.

Observability

  • chore(compute-haplotypes) — log the count of samples dropped for an undefined population; document all five output tables; add comments for the biallelic call_stats and row_idx int32-downcast invariants.

Tests

  • test(hail): parametrized sub-1GB Spark memory guards.
  • FASTA genomic-ordering regression test (fixtures updated to the real schema); removed an unused test helper.
  • Reversed-order SNP+insertion regression test (guards the fix above).

Style & consistency

  • style — modern typing (PEP 695 type alias, collections.abc imports), lazy %s logging, Final constants with a provenance comment for the population set.

Workflows, CI & docs

  • refactor(workflows)curl --fail over wget (macOS-safe, fails loudly); chromosomes config-schema pattern; comment on the forced .fai name; fix an implicit string concat; correct the credentials comment.
  • CI/pixi — lock the pixi env in the Snakemake-linting action (--locked); pixi lock-file fixes.
  • README — note the gcloud CLI prerequisite for GCS runs.

Not in this PR (tracked follow-ups)

Larger items surfaced in review, deliberately left for separate PRs:

  • remap_divref pass: extract helpers to drop the C901 complexity, and a pandas→polars streaming rewrite.
  • extract_gnomad_single_afs: an in_sites_table override + happy-path test for the default v4.1 JOINT path (currently untested), and a shared pop_freq_indices helper.
  • Schema single-sourcing (index-path/table/column-name constants; shared output-partition constant).
  • Decisions pending: %.5f gnomAD-AF truncation, .fai naming convention, no_apply_filtersapply_filters, and softening the append_contig memory-bound docstrings.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added validation for required sequence data before FASTA generation and index finalization.
    • FASTA output now follows deterministic genomic ordering.
    • Added clearer validation for chromosome names and malformed variant input.
    • Haplotype ordering now consistently handles substitutions and insertions.
  • Bug Fixes

    • Improved cloud credential and Spark connector file validation.
    • DuckDB sequence imports now align columns by name.
    • Workflow downloads now report failures more clearly.
  • Documentation

    • Clarified authentication prerequisites, configuration-file usage, checkpoints, and workflow behavior.

znorgaard and others added 16 commits July 2, 2026 14:15
Extract the repeated information_schema existence check into a single
sequences_table_exists helper in duckdb_index.py and use it in
finalize_duckdb_index. Also drop the redundant str() inside the
index-path f-strings in init/finalize.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reuse sequences_table_exists at the three existence checks; switch the
per-chunk INSERT to INSERT ... BY NAME so a future column-order change
surfaces as a bind error rather than silently misaligning columns; set
eq=False on _RemapArrays so the frozen dataclass keeps a usable __hash__
despite its list fields; document the 0-based half-open start/end
convention at the DuckDB boundary; drop a redundant str().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ORDER BY start, sequence_id so per-contig FASTA output is deterministic
across runs (checksummable), with sequence_id as a unique tiebreak. Also
add a missing-sequences-table ValueError for parity with finalize, and
replace the deprecated fetch_record_batch with to_arrow_reader. Update
test fixtures to the real schema (a start column) and add a
genomic-ordering regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Log the count of samples dropped for an undefined population assignment
(parity with the other count log lines). Document all five output tables
in the docstring, and add comments for the biallelic call_stats
assumption, the row_idx int32-downcast invariant, and the fixed output
partition count.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reference the defaults constants for the HGDP+1KG table URIs in
extract_gnomad_single_afs instead of duplicating them. Correct the stale
'sample metadata' docstrings (neither tool writes sample data), type
freq_threshold as 0.0, and validate the .ht output path before starting
Hail for parity with the TSV path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
parse_variants_string now raises a ValueError naming the offending token
(and documents it) instead of an opaque unpack/int() error. Correct the
classify_pair 'adjacent' docstring (it classifies any pair) and the
REASONS comment (it is documentation only; classify_pair uses its own
if/elif order and compatibility_flag emits alphabetically).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the missing Raises: block for the ValueError raised when loci is empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace os.path.join/os.path.exists with pathlib for the connector JAR
paths, keeping os only for environ. Validate the credentials path with
is_file().

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parametrized test that driver/executor memory below 1GB raises before
any credentials or JAR resolution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PEP 695 'type' alias for HailPath; Hashable/Callable imported from
collections.abc; lazy %s logging in main; Final on POPULATIONS and
REFERENCE_GENOME with a provenance comment for the population set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use 'curl --fail' instead of wget in the analysis download rule (ships on
macOS; fails loudly on HTTP errors); constrain the chromosomes config
schema with a pattern so typos fail at validation; add a comment
explaining the forced .fai name; fix an accidental implicit string concat;
and correct the create_test_data credentials comment.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The helper only produced hashable dict keys for equality lookup, which
frozenset of items does directly. Drops the function, its _V TypeVar, and
its tests in favor of the inline stdlib call.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ameynert, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fbdcb41d-43da-4aae-80a0-c4ba8c4e389a

📥 Commits

Reviewing files that changed from the base of the PR and between d7444a6 and c21561b.

⛔ Files ignored due to path filters (1)
  • pixi.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • .github/workflows/python_package.yml
  • .github/workflows/workflow_linting.yml
📝 Walkthrough

Walkthrough

This PR updates DuckDB index and FASTA handling, haplotype ordering and frequency extraction, Hail path validation, type declarations, workflow validation, dependency constraints, logging, and related documentation and tests.

Changes

DivRef consistency and workflow updates

Layer / File(s) Summary
Runtime contracts and validation
divref/divref/alias.py, divref/divref/defaults.py, divref/divref/hail.py, divref/pyproject.toml, divref/tests/test_hail.py
Type aliases and constants use updated declarations; Hail credentials and connector paths require files; output validation and dependency constraints are updated.
Haplotype and frequency processing
divref/divref/haplotype.py, divref/divref/haplotype_compat.py, divref/divref/tools/extract_gnomad_*.py, divref/tests/test_haplotype.py
Variant ordering gains an alternate-allele-length tie-breaker, malformed variant tokens receive clearer errors, and population metadata lookup uses frozenset keys.
Haplotype computation contracts and reporting
divref/divref/tools/compute_haplotypes.py, divref/divref/tools/gnomad_hail_table_test_data.py
Locus-group returns, checkpoint documentation, missing-population reporting, and computation comments are updated.
Sequence-table detection and index writes
divref/divref/duckdb_index.py, divref/divref/tools/append_contig_to_duckdb_index.py, divref/divref/tools/finalize_duckdb_index.py, divref/divref/tools/init_duckdb_index.py
Sequence-table detection is centralized, DuckDB inserts use name-based alignment, and index path construction is adjusted.
Validated and ordered FASTA streaming
divref/divref/tools/create_divref_fasta.py, divref/tests/tools/test_create_divref_fasta.py
FASTA generation validates the required table, streams Arrow batches, orders by genomic start and sequence ID, and updates test fixtures.
Workflow checks and input handling
.github/workflows/workflow_linting.yml, pixi.toml, workflows/*, README.md, divref/divref/main.py
Linting uses locked Pixi execution, chromosome inputs are schema-validated, downloads use curl with failure handling, command logging is parameterized, and workflow instructions are clarified.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: ameynert

Poem

I hopped through indexes, tidy and bright,
Sorted each sequence in genomic light.
The haplotypes twirled, the workflows locked,
Bad paths and chromosomes now get checked.
Thump, thump—clean data down the lane!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the PR, but it is too generic to clearly summarize the main changes or distinguish this patch from other review follow-ups. Use a more specific title that names the primary changes, such as deterministic haplotype/FASTA ordering and DuckDB/Hail/workflow updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 97.44% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The group count was never used by any caller; return just the
row_idx → locus_group mapping.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@znorgaard
znorgaard temporarily deployed to github-actions-snakemake-linting July 6, 2026 20:12 — with GitHub Actions Inactive
get_haplo_sequence and haplo_coordinates sorted variants by
(position, len(ref)), which ties a co-located SNP and insertion; the tie
was resolved by input order and, when the insertion applied first, the
SNP was silently dropped from the emitted sequence (a PASS row in the
FASTA/DuckDB deliverable). Add a tertiary tiebreak on alt length so a
substitution always composes before a pure insertion at the same
position. Includes a reversed-order regression test, and removes an
unused test helper (_make_haplotype_table).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@znorgaard
znorgaard temporarily deployed to github-actions-snakemake-linting July 10, 2026 21:14 — with GitHub Actions Inactive
Comment thread pixi.toml
Comment thread divref/divref/tools/create_divref_fasta.py
Comment thread divref/divref/tools/compute_haplotypes.py
Comment thread divref/divref/hail.py Outdated
Comment thread divref/divref/tools/compute_haplotypes.py Outdated
Comment thread divref/divref/haplotype.py Outdated
@ameynert
ameynert marked this pull request as ready for review July 14, 2026 18:39
@ameynert ameynert changed the title [WIP] Collection of Minor Changes feat: Collection of Minor Changes after review Jul 14, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
divref/divref/defaults.py (1)

28-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a tuple to fully enforce immutability.

While Final prevents reassignment of POPULATIONS, the underlying list remains mutable. As per coding guidelines, prefer immutable data. Consider defining this as a tuple (e.g., tuple[str, ...]) and updating downstream function signatures that currently expect a list[str].

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@divref/divref/defaults.py` at line 28, Change the POPULATIONS constant from a
mutable list to an immutable tuple, using an appropriate tuple type annotation.
Update downstream functions that consume POPULATIONS, including their parameter
annotations, to accept the tuple type without changing behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@README.md`:
- Line 33: Update the sentence introducing Hail-dependent tools to replace the
comma splice with clear wording, preserving the requirement that users log in
and install the gcloud CLI first.

---

Nitpick comments:
In `@divref/divref/defaults.py`:
- Line 28: Change the POPULATIONS constant from a mutable list to an immutable
tuple, using an appropriate tuple type annotation. Update downstream functions
that consume POPULATIONS, including their parameter annotations, to accept the
tuple type without changing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 38a3c1ca-0de0-4a63-bce5-3c7f768146bf

📥 Commits

Reviewing files that changed from the base of the PR and between e1a4fc2 and e712a72.

📒 Files selected for processing (27)
  • .github/workflows/workflow_linting.yml
  • CONTRIBUTING.md
  • README.md
  • divref/divref/alias.py
  • divref/divref/defaults.py
  • divref/divref/duckdb_index.py
  • divref/divref/hail.py
  • divref/divref/haplotype.py
  • divref/divref/haplotype_compat.py
  • divref/divref/main.py
  • divref/divref/tools/append_contig_to_duckdb_index.py
  • divref/divref/tools/compute_haplotypes.py
  • divref/divref/tools/create_divref_fasta.py
  • divref/divref/tools/extract_gnomad_afs.py
  • divref/divref/tools/extract_gnomad_single_afs.py
  • divref/divref/tools/finalize_duckdb_index.py
  • divref/divref/tools/gnomad_hail_table_test_data.py
  • divref/divref/tools/init_duckdb_index.py
  • divref/tests/test_hail.py
  • divref/tests/test_haplotype.py
  • divref/tests/test_main.py
  • divref/tests/tools/test_create_divref_fasta.py
  • pixi.toml
  • workflows/compare_divref_gnomad.smk
  • workflows/config/config_schema.yml
  • workflows/create_test_data.smk
  • workflows/generate_divref.smk
💤 Files with no reviewable changes (1)
  • pixi.toml

Comment thread README.md
```

Log in before running any Hail-dependent tools:
Log in before running any Hail-dependent tools, requires [the gcloud cli be installed](https://docs.cloud.google.com/sdk/docs/install-sdk):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the sentence structure.

Replace the comma splice with clearer wording, for example: “Log in before running any Hail-dependent tools; the gcloud CLI must be installed first:”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` at line 33, Update the sentence introducing Hail-dependent tools
to replace the comma splice with clear wording, preserving the requirement that
users log in and install the gcloud CLI first.

ameynert and others added 5 commits July 14, 2026 12:37
Commit c87b97f removed the `check-lock` pixi task but left `check-all` and
`fix-and-check-all` referencing it, breaking both. Restore the task definition
and revert the CONTRIBUTING.md command back to `pixi run check-lock`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
create_divref_fasta streams results via DuckDBPyRelation.to_arrow_reader,
which is only available on duckdb>=1.4.0; the prior >=1.0 bound could resolve
an older version lacking the method.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Match the GCS-side check: a directory at the JAR path would pass `.exists()`
but is not a usable connector JAR. `.is_file()` rejects it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Explain that a full tie (same position, ref length, and alt length) can only
arise from two alleles at one site, which cannot occur on a single phased
haplotype, so the input-order fallback is never exercised in practice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The tool itself never deletes the intermediate `.variants/.blocks/.parents/
.hap_ac` checkpoints; the Snakemake rule removes them post-run. State that
explicitly rather than "kept, not cleaned up".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Spell out why a sample is dropped: its population is outside the DivRef legend
(a gnomAD ancestry not in the pop set, or an unassigned population marking an
aneuploid karyotype). Include the legend in the message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ameynert
ameynert had a problem deploying to github-actions-snakemake-linting July 14, 2026 20:33 — with GitHub Actions Failure
@ameynert
ameynert had a problem deploying to github-actions-snakemake-linting July 14, 2026 20:36 — with GitHub Actions Failure
@ameynert
ameynert temporarily deployed to github-actions-snakemake-linting July 14, 2026 20:39 — with GitHub Actions Inactive
@ameynert

Copy link
Copy Markdown
Collaborator

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ameynert
ameynert merged commit dbea3d6 into main Jul 14, 2026
4 checks passed
@ameynert
ameynert deleted the zn_fixes branch July 14, 2026 22:25
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