gapit 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gapit-0.2.2/.gitattributes +2 -0
- gapit-0.2.2/.github/workflows/ci.yml +43 -0
- gapit-0.2.2/.github/workflows/docs.yml +44 -0
- gapit-0.2.2/.github/workflows/release.yml +28 -0
- gapit-0.2.2/.github/workflows/snapshot-refresh.yml +129 -0
- gapit-0.2.2/.gitignore +21 -0
- gapit-0.2.2/AGENTS.md +197 -0
- gapit-0.2.2/CHANGELOG.md +133 -0
- gapit-0.2.2/LICENSE +21 -0
- gapit-0.2.2/PKG-INFO +183 -0
- gapit-0.2.2/PLAN.md +166 -0
- gapit-0.2.2/README.md +153 -0
- gapit-0.2.2/SPEC.md +470 -0
- gapit-0.2.2/docs/agents.md +198 -0
- gapit-0.2.2/docs/custom-db.md +399 -0
- gapit-0.2.2/docs/databases.md +527 -0
- gapit-0.2.2/docs/faq.md +111 -0
- gapit-0.2.2/docs/index.md +46 -0
- gapit-0.2.2/docs/installation.md +91 -0
- gapit-0.2.2/docs/mcp.md +311 -0
- gapit-0.2.2/docs/outputs.md +440 -0
- gapit-0.2.2/docs/quickstart.md +142 -0
- gapit-0.2.2/docs/reads.md +588 -0
- gapit-0.2.2/docs/screen.md +205 -0
- gapit-0.2.2/docs/summary.md +183 -0
- gapit-0.2.2/mkdocs.yml +36 -0
- gapit-0.2.2/pixi.lock +4428 -0
- gapit-0.2.2/pixi.toml +59 -0
- gapit-0.2.2/pyproject.toml +73 -0
- gapit-0.2.2/recipe/meta.yaml +74 -0
- gapit-0.2.2/src/gapit/__init__.py +3 -0
- gapit-0.2.2/src/gapit/blast.py +239 -0
- gapit-0.2.2/src/gapit/cli.py +128 -0
- gapit-0.2.2/src/gapit/cmd_db.py +113 -0
- gapit-0.2.2/src/gapit/cmd_db_build.py +72 -0
- gapit-0.2.2/src/gapit/cmd_db_install.py +126 -0
- gapit-0.2.2/src/gapit/cmd_db_outdated.py +51 -0
- gapit-0.2.2/src/gapit/cmd_db_search.py +66 -0
- gapit-0.2.2/src/gapit/cmd_screen.py +214 -0
- gapit-0.2.2/src/gapit/cmd_summary.py +65 -0
- gapit-0.2.2/src/gapit/config.py +51 -0
- gapit-0.2.2/src/gapit/data/snapshots/card.tar.gz +0 -0
- gapit-0.2.2/src/gapit/data/snapshots/vfdb.tar.gz +0 -0
- gapit-0.2.2/src/gapit/db.py +226 -0
- gapit-0.2.2/src/gapit/db_build_ops.py +210 -0
- gapit-0.2.2/src/gapit/db_ops.py +128 -0
- gapit-0.2.2/src/gapit/db_query_ops.py +252 -0
- gapit-0.2.2/src/gapit/dbbuild.py +207 -0
- gapit-0.2.2/src/gapit/dbcodec.py +117 -0
- gapit-0.2.2/src/gapit/dispatch.py +31 -0
- gapit-0.2.2/src/gapit/errors.py +87 -0
- gapit-0.2.2/src/gapit/fasta.py +123 -0
- gapit-0.2.2/src/gapit/formats/__init__.py +1 -0
- gapit-0.2.2/src/gapit/formats/json.py +309 -0
- gapit-0.2.2/src/gapit/formats/md.py +190 -0
- gapit-0.2.2/src/gapit/formats/schemas.py +30 -0
- gapit-0.2.2/src/gapit/formats/summary.py +103 -0
- gapit-0.2.2/src/gapit/formats/tsv.py +45 -0
- gapit-0.2.2/src/gapit/hits.py +107 -0
- gapit-0.2.2/src/gapit/mcp.py +158 -0
- gapit-0.2.2/src/gapit/mcp_schemas.py +123 -0
- gapit-0.2.2/src/gapit/mcp_tools.py +289 -0
- gapit-0.2.2/src/gapit/minimap.py +20 -0
- gapit-0.2.2/src/gapit/minimap2_run.py +114 -0
- gapit-0.2.2/src/gapit/paf.py +115 -0
- gapit-0.2.2/src/gapit/proctools.py +24 -0
- gapit-0.2.2/src/gapit/providers/__init__.py +39 -0
- gapit-0.2.2/src/gapit/providers/argannot.py +94 -0
- gapit-0.2.2/src/gapit/providers/bacmet2.py +59 -0
- gapit-0.2.2/src/gapit/providers/card.py +150 -0
- gapit-0.2.2/src/gapit/providers/common.py +245 -0
- gapit-0.2.2/src/gapit/providers/ecoh.py +63 -0
- gapit-0.2.2/src/gapit/providers/ecoli_vf.py +74 -0
- gapit-0.2.2/src/gapit/providers/megares.py +71 -0
- gapit-0.2.2/src/gapit/providers/ncbi.py +103 -0
- gapit-0.2.2/src/gapit/providers/plasmidfinder.py +69 -0
- gapit-0.2.2/src/gapit/providers/resfinder.py +123 -0
- gapit-0.2.2/src/gapit/providers/snapshots.py +119 -0
- gapit-0.2.2/src/gapit/providers/upec_expec_vf.py +85 -0
- gapit-0.2.2/src/gapit/providers/vfdb.py +92 -0
- gapit-0.2.2/src/gapit/providers/victors.py +109 -0
- gapit-0.2.2/src/gapit/py.typed +0 -0
- gapit-0.2.2/src/gapit/reads.py +221 -0
- gapit-0.2.2/src/gapit/records.py +152 -0
- gapit-0.2.2/src/gapit/report.py +25 -0
- gapit-0.2.2/src/gapit/screening.py +145 -0
- gapit-0.2.2/src/gapit/screening_reads.py +255 -0
- gapit-0.2.2/src/gapit/seqconvert.py +203 -0
- gapit-0.2.2/src/gapit/summary.py +151 -0
- gapit-0.2.2/tests/data/contigs/full.fa +3 -0
- gapit-0.2.2/tests/data/contigs/gap.fa +3 -0
- gapit-0.2.2/tests/data/contigs/none.fa +3 -0
- gapit-0.2.2/tests/data/contigs/partial.fa +2 -0
- gapit-0.2.2/tests/data/contigs/sort.fa +11 -0
- gapit-0.2.2/tests/data/convert/sample.embl +20 -0
- gapit-0.2.2/tests/data/convert/sample.embl.bz2 +0 -0
- gapit-0.2.2/tests/data/convert/sample.fa +6 -0
- gapit-0.2.2/tests/data/convert/sample.fa.gz +0 -0
- gapit-0.2.2/tests/data/convert/sample.fq +8 -0
- gapit-0.2.2/tests/data/convert/sample.gbk +19 -0
- gapit-0.2.2/tests/data/convert/sample.gbk.gz +0 -0
- gapit-0.2.2/tests/data/db/tinyamr/sequences +9 -0
- gapit-0.2.2/tests/data/providers/argannot/ARG-ANNOT_NT_V6_July2019.txt +7 -0
- gapit-0.2.2/tests/data/providers/bacmet2/BacMet2_EXP_database.fasta +6 -0
- gapit-0.2.2/tests/data/providers/card/card.json +132 -0
- gapit-0.2.2/tests/data/providers/ecoh/EcOH.fasta +8 -0
- gapit-0.2.2/tests/data/providers/ecoli_vf/repaired_ecoli_vfs_shortnames.ffn +6 -0
- gapit-0.2.2/tests/data/providers/megares/megares_drugs_demo.fasta +6 -0
- gapit-0.2.2/tests/data/providers/ncbi/AMR_CDS.fa +14 -0
- gapit-0.2.2/tests/data/providers/ncbi/ReferenceGeneCatalog.txt +7 -0
- gapit-0.2.2/tests/data/providers/plasmidfinder/plasmids_a.fsa +4 -0
- gapit-0.2.2/tests/data/providers/plasmidfinder/plasmids_b.fsa +2 -0
- gapit-0.2.2/tests/data/providers/resfinder/aminoglycoside.fsa +6 -0
- gapit-0.2.2/tests/data/providers/resfinder/beta-lactam.fsa +4 -0
- gapit-0.2.2/tests/data/providers/resfinder/phenotypes.txt +5 -0
- gapit-0.2.2/tests/data/providers/upec_expec_vf/UPEC_ExPEC_VF.tsv +5 -0
- gapit-0.2.2/tests/data/providers/vfdb/VFDB_setA_nt.fas +6 -0
- gapit-0.2.2/tests/data/providers/victors/gen_downloads.php +6 -0
- gapit-0.2.2/tests/data/providers/victors/gen_downloads_protein.php +6 -0
- gapit-0.2.2/tests/data/reads/bla_partial.fq +4 -0
- gapit-0.2.2/tests/data/reads/junk.fq +8 -0
- gapit-0.2.2/tests/data/reads/suly_partial.fq +12 -0
- gapit-0.2.2/tests/data/reads/tetx_R1.fq +24 -0
- gapit-0.2.2/tests/data/reads/tetx_R2.fq +24 -0
- gapit-0.2.2/tests/data/reads/tetx_full.fq +48 -0
- gapit-0.2.2/tests/data/reads/tetx_full.fq.gz +0 -0
- gapit-0.2.2/tests/data/reads/tetx_lane1.fq +24 -0
- gapit-0.2.2/tests/data/reads/tetx_lane2.fq +24 -0
- gapit-0.2.2/tests/data/reads/tetx_pe1_R1.fq +12 -0
- gapit-0.2.2/tests/data/reads/tetx_pe1_R2.fq +12 -0
- gapit-0.2.2/tests/data/reads/tetx_pe2_R1.fq +12 -0
- gapit-0.2.2/tests/data/reads/tetx_pe2_R2.fq +12 -0
- gapit-0.2.2/tests/data/reads2/ont_homologs.fq +120 -0
- gapit-0.2.2/tests/data/reads2/sr_homologs.fq +400 -0
- gapit-0.2.2/tests/data/reads2_db/homologs/sequences +4 -0
- gapit-0.2.2/tests/data/reads_db/tinyreads/sequences +4 -0
- gapit-0.2.2/tests/data/summary/empty.tsv +1 -0
- gapit-0.2.2/tests/data/summary/multi_sample.tsv +4 -0
- gapit-0.2.2/tests/data/summary/sample_a.csv +4 -0
- gapit-0.2.2/tests/data/summary/sample_a.tsv +4 -0
- gapit-0.2.2/tests/data/summary/sample_b.csv +3 -0
- gapit-0.2.2/tests/data/summary/sample_b.tsv +3 -0
- gapit-0.2.2/tests/golden/reads_tinyamr.json +35 -0
- gapit-0.2.2/tests/golden/reads_tinyamr.md +20 -0
- gapit-0.2.2/tests/golden/screen_multi.json +131 -0
- gapit-0.2.2/tests/golden/screen_multi.md +39 -0
- gapit-0.2.2/tests/golden/summary_dutch.tsv +4 -0
- gapit-0.2.2/tests/golden/summary_multi.csv +3 -0
- gapit-0.2.2/tests/golden/summary_multi.json +48 -0
- gapit-0.2.2/tests/golden/summary_multi.md +17 -0
- gapit-0.2.2/tests/golden/summary_multi.tsv +4 -0
- gapit-0.2.2/tests/golden/tinyamr_multi_nopath.csv +7 -0
- gapit-0.2.2/tests/golden/tinyamr_multi_nopath.tsv +7 -0
- gapit-0.2.2/tests/parity/corpus/01_exact_and_junk.fa +34 -0
- gapit-0.2.2/tests/parity/corpus/02_mutated.fa +28 -0
- gapit-0.2.2/tests/parity/corpus/03_truncated.fa +17 -0
- gapit-0.2.2/tests/parity/make_corpus.py +114 -0
- gapit-0.2.2/tests/parity/run_parity.py +119 -0
- gapit-0.2.2/tests/parity/run_summary_parity.py +141 -0
- gapit-0.2.2/tests/test_blast_parse.py +78 -0
- gapit-0.2.2/tests/test_blast_pipeline.py +100 -0
- gapit-0.2.2/tests/test_cli_aligner.py +404 -0
- gapit-0.2.2/tests/test_cli_completion.py +61 -0
- gapit-0.2.2/tests/test_cli_db_build.py +450 -0
- gapit-0.2.2/tests/test_cli_db_fetch.py +353 -0
- gapit-0.2.2/tests/test_cli_db_query.py +506 -0
- gapit-0.2.2/tests/test_cli_list.py +153 -0
- gapit-0.2.2/tests/test_cli_reads.py +503 -0
- gapit-0.2.2/tests/test_cli_reads2.py +367 -0
- gapit-0.2.2/tests/test_cli_schema.py +48 -0
- gapit-0.2.2/tests/test_cli_screen.py +280 -0
- gapit-0.2.2/tests/test_cli_screen_jobs.py +108 -0
- gapit-0.2.2/tests/test_cli_summary.py +201 -0
- gapit-0.2.2/tests/test_config.py +47 -0
- gapit-0.2.2/tests/test_db.py +89 -0
- gapit-0.2.2/tests/test_db_fetch.py +128 -0
- gapit-0.2.2/tests/test_db_headers.py +60 -0
- gapit-0.2.2/tests/test_dbbuild.py +275 -0
- gapit-0.2.2/tests/test_dbcodec.py +205 -0
- gapit-0.2.2/tests/test_error_envelope.py +122 -0
- gapit-0.2.2/tests/test_fasta.py +172 -0
- gapit-0.2.2/tests/test_gapit_db_e2e.py +140 -0
- gapit-0.2.2/tests/test_hits.py +278 -0
- gapit-0.2.2/tests/test_json_format.py +146 -0
- gapit-0.2.2/tests/test_mcp.py +265 -0
- gapit-0.2.2/tests/test_mcp_db_tools.py +422 -0
- gapit-0.2.2/tests/test_mcp_protocol.py +60 -0
- gapit-0.2.2/tests/test_mcp_reads.py +279 -0
- gapit-0.2.2/tests/test_md_format.py +204 -0
- gapit-0.2.2/tests/test_minimap.py +59 -0
- gapit-0.2.2/tests/test_mol_type.py +38 -0
- gapit-0.2.2/tests/test_oversubscription.py +110 -0
- gapit-0.2.2/tests/test_paf.py +75 -0
- gapit-0.2.2/tests/test_paf_identity.py +133 -0
- gapit-0.2.2/tests/test_provider_argannot.py +85 -0
- gapit-0.2.2/tests/test_provider_bacmet2.py +104 -0
- gapit-0.2.2/tests/test_provider_card.py +169 -0
- gapit-0.2.2/tests/test_provider_ecoh.py +97 -0
- gapit-0.2.2/tests/test_provider_ecoli_vf.py +124 -0
- gapit-0.2.2/tests/test_provider_megares.py +79 -0
- gapit-0.2.2/tests/test_provider_ncbi.py +102 -0
- gapit-0.2.2/tests/test_provider_plasmidfinder.py +111 -0
- gapit-0.2.2/tests/test_provider_resfinder.py +161 -0
- gapit-0.2.2/tests/test_provider_upec_expec_vf.py +150 -0
- gapit-0.2.2/tests/test_provider_vfdb.py +101 -0
- gapit-0.2.2/tests/test_provider_victors.py +116 -0
- gapit-0.2.2/tests/test_providers_common.py +314 -0
- gapit-0.2.2/tests/test_reads2_homologs.py +135 -0
- gapit-0.2.2/tests/test_reads2_model.py +158 -0
- gapit-0.2.2/tests/test_reads_aggregate.py +129 -0
- gapit-0.2.2/tests/test_reads_integration.py +240 -0
- gapit-0.2.2/tests/test_reads_interval_union.py +269 -0
- gapit-0.2.2/tests/test_reads_streaming.py +174 -0
- gapit-0.2.2/tests/test_records.py +218 -0
- gapit-0.2.2/tests/test_report.py +71 -0
- gapit-0.2.2/tests/test_screen_integration.py +128 -0
- gapit-0.2.2/tests/test_screening_reads_unit.py +57 -0
- gapit-0.2.2/tests/test_seqconvert.py +252 -0
- gapit-0.2.2/tests/test_seqconvert_differential.py +79 -0
- gapit-0.2.2/tests/test_snapshots.py +204 -0
- gapit-0.2.2/tests/test_summary.py +291 -0
- gapit-0.2.2/tests/test_summary_formats.py +119 -0
- gapit-0.2.2/tests/test_tsv.py +144 -0
- gapit-0.2.2/tests/test_version.py +35 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
gates:
|
|
14
|
+
name: gates (${{ matrix.env }})
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
env: [default, py311, py313]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: prefix-dev/setup-pixi@v0.8.1
|
|
23
|
+
with:
|
|
24
|
+
cache: true
|
|
25
|
+
- run: pixi run -e ${{ matrix.env }} lint
|
|
26
|
+
- run: pixi run -e ${{ matrix.env }} fmt -- --check
|
|
27
|
+
- run: pixi run -e ${{ matrix.env }} typecheck
|
|
28
|
+
- run: pixi run -e ${{ matrix.env }} test
|
|
29
|
+
|
|
30
|
+
# Independent of gates: the bioconda solve is slow and orthogonal to the
|
|
31
|
+
# python matrix. Needs BOTH envs installed — the harness runs on the default
|
|
32
|
+
# env's python and invokes .pixi/envs/default/bin/gapit while parity env
|
|
33
|
+
# supplies abricate (see pixi.toml parity feature).
|
|
34
|
+
parity:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@v4
|
|
38
|
+
- uses: prefix-dev/setup-pixi@v0.8.1
|
|
39
|
+
with:
|
|
40
|
+
cache: true
|
|
41
|
+
- run: pixi install -e default -e parity
|
|
42
|
+
- run: pixi run -e parity parity
|
|
43
|
+
- run: pixi run -e parity summary-parity
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- docs/**
|
|
8
|
+
- mkdocs.yml
|
|
9
|
+
- pixi.toml
|
|
10
|
+
- pixi.lock
|
|
11
|
+
- .github/workflows/docs.yml
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
pages: write
|
|
17
|
+
id-token: write
|
|
18
|
+
|
|
19
|
+
concurrency:
|
|
20
|
+
group: pages
|
|
21
|
+
cancel-in-progress: true
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
build:
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: prefix-dev/setup-pixi@v0.8.1
|
|
29
|
+
with:
|
|
30
|
+
cache: true
|
|
31
|
+
- run: pixi run -e docs mkdocs build --strict
|
|
32
|
+
- uses: actions/upload-pages-artifact@v3
|
|
33
|
+
with:
|
|
34
|
+
path: site
|
|
35
|
+
|
|
36
|
+
deploy:
|
|
37
|
+
needs: build
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment:
|
|
40
|
+
name: github-pages
|
|
41
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
42
|
+
steps:
|
|
43
|
+
- id: deployment
|
|
44
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
tags: ["v*"]
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
# OIDC token for PyPI trusted publishing (pypa/gh-action-pypi-publish).
|
|
10
|
+
id-token: write
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.13"
|
|
21
|
+
|
|
22
|
+
- name: Build sdist and wheel
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install --upgrade pip build
|
|
25
|
+
python -m build
|
|
26
|
+
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
name: Snapshot refresh
|
|
2
|
+
|
|
3
|
+
# Monthly: re-fetch card + vfdb from upstream and regenerate the bundled
|
|
4
|
+
# snapshot tars, so the wheel's zero-network defaults do not rot. A PR is the
|
|
5
|
+
# review gate (license/provenance hygiene); `gapit db fetch <db> --from-source`
|
|
6
|
+
# remains the manual path outside Actions.
|
|
7
|
+
on:
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: "0 3 1 * *"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
pull-requests: write
|
|
15
|
+
issues: write
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: snapshot-refresh
|
|
19
|
+
cancel-in-progress: true
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
refresh:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: prefix-dev/setup-pixi@v0.8.1
|
|
27
|
+
with:
|
|
28
|
+
cache: true
|
|
29
|
+
- run: pixi install
|
|
30
|
+
- name: Refresh card and vfdb snapshots from upstream
|
|
31
|
+
id: refresh
|
|
32
|
+
run: |
|
|
33
|
+
pixi run python - <<'PY'
|
|
34
|
+
import hashlib
|
|
35
|
+
import os
|
|
36
|
+
from datetime import UTC, datetime
|
|
37
|
+
from pathlib import Path
|
|
38
|
+
from tempfile import TemporaryDirectory
|
|
39
|
+
|
|
40
|
+
from gapit.providers import REGISTRY
|
|
41
|
+
from gapit.providers.common import fetch_provider
|
|
42
|
+
from gapit.providers.snapshots import extract_snapshot, make_snapshot
|
|
43
|
+
|
|
44
|
+
# Local verification reruns this exact script against a scratch dir
|
|
45
|
+
# via GAPIT_SNAPSHOT_REFRESH_DIR; the committed tars stay untouched.
|
|
46
|
+
snapshot_dir = Path(os.environ.get("GAPIT_SNAPSHOT_REFRESH_DIR", "src/gapit/data/snapshots"))
|
|
47
|
+
now = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def sha256(path: Path) -> str:
|
|
51
|
+
digest = hashlib.sha256()
|
|
52
|
+
with path.open("rb") as handle:
|
|
53
|
+
for chunk in iter(lambda: handle.read(1 << 20), b""):
|
|
54
|
+
digest.update(chunk)
|
|
55
|
+
return digest.hexdigest()
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def emit(key: str, value: str) -> None:
|
|
59
|
+
target = os.environ.get("GITHUB_OUTPUT")
|
|
60
|
+
if target:
|
|
61
|
+
with open(target, "a", encoding="utf-8") as handle:
|
|
62
|
+
print(f"{key}<<EOF", value, "EOF", sep="\n", file=handle)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
rows = []
|
|
66
|
+
with TemporaryDirectory(prefix="gapit-snapshot-refresh.") as scratch:
|
|
67
|
+
for name in ("card", "vfdb"):
|
|
68
|
+
db_dir = Path(scratch) / name
|
|
69
|
+
manifest = fetch_provider(
|
|
70
|
+
REGISTRY[name], db_dir, fetched_at=now, from_source=True, quiet=False
|
|
71
|
+
)
|
|
72
|
+
dest = snapshot_dir / f"{name}.tar.gz"
|
|
73
|
+
before = sha256(dest) if dest.is_file() else "-"
|
|
74
|
+
# The tar turns over only when the records changed: the
|
|
75
|
+
# archived manifest carries fetched_at, so an unconditional
|
|
76
|
+
# rebuild would rewrite bytes (and open a PR) on every run
|
|
77
|
+
# even with identical upstream content.
|
|
78
|
+
changed = True
|
|
79
|
+
if dest.is_file():
|
|
80
|
+
bundled = Path(scratch) / f"{name}-bundled"
|
|
81
|
+
bundled.mkdir()
|
|
82
|
+
extract_snapshot(dest, bundled)
|
|
83
|
+
changed = (bundled / "records.jsonl").read_bytes() != (
|
|
84
|
+
db_dir / "records.jsonl"
|
|
85
|
+
).read_bytes()
|
|
86
|
+
if changed:
|
|
87
|
+
snapshot_dir.mkdir(parents=True, exist_ok=True)
|
|
88
|
+
make_snapshot(db_dir, dest)
|
|
89
|
+
after = sha256(dest)
|
|
90
|
+
rows.append((name, manifest.n_records, before, after, changed))
|
|
91
|
+
verdict = "changed" if changed else "unchanged"
|
|
92
|
+
print(f"{name}: {manifest.n_records} records, tar sha256 {before} -> {after} ({verdict})")
|
|
93
|
+
|
|
94
|
+
summary = "\n".join(
|
|
95
|
+
[
|
|
96
|
+
"Monthly upstream refresh of the bundled card and vfdb snapshots.",
|
|
97
|
+
"",
|
|
98
|
+
"The snapshot carries `records.jsonl` plus the manifest; the BLAST index",
|
|
99
|
+
"rebuilds locally on install (deterministic, matches the installed BLAST).",
|
|
100
|
+
"",
|
|
101
|
+
"| db | records | tar sha256 before | tar sha256 after | changed |",
|
|
102
|
+
"|---|---|---|---|---|",
|
|
103
|
+
*(
|
|
104
|
+
f"| {name} | {records} | `{before}` | `{after}` | {'yes' if changed else 'no'} |"
|
|
105
|
+
for name, records, before, after, changed in rows
|
|
106
|
+
),
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
print()
|
|
110
|
+
print(summary)
|
|
111
|
+
emit("month", f"{datetime.now(UTC):%Y-%m}")
|
|
112
|
+
emit("summary", summary)
|
|
113
|
+
PY
|
|
114
|
+
- name: Open snapshot refresh pull request
|
|
115
|
+
uses: peter-evans/create-pull-request@v7
|
|
116
|
+
with:
|
|
117
|
+
branch: chore/snapshot-refresh
|
|
118
|
+
title: "data: refresh card and vfdb snapshots (${{ steps.refresh.outputs.month }})"
|
|
119
|
+
body: ${{ steps.refresh.outputs.summary }}
|
|
120
|
+
commit-message: "data: refresh card and vfdb snapshots"
|
|
121
|
+
delete-branch: true
|
|
122
|
+
- name: Open failure issue
|
|
123
|
+
if: failure() && github.event_name == 'schedule'
|
|
124
|
+
env:
|
|
125
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
126
|
+
run: |
|
|
127
|
+
gh issue create --repo "$GITHUB_REPOSITORY" \
|
|
128
|
+
--title "snapshot-refresh failed (run ${{ github.run_id }})" \
|
|
129
|
+
--body "Scheduled snapshot refresh failed. Check the [run log](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}). Common cause: upstream source outage (card.mcmaster.ca / mgc.ac.cn)."
|
gapit-0.2.2/.gitignore
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# pixi environments
|
|
2
|
+
.pixi/*
|
|
3
|
+
!.pixi/config.toml
|
|
4
|
+
|
|
5
|
+
# agent session tooling
|
|
6
|
+
.omo/
|
|
7
|
+
|
|
8
|
+
# python
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.pytest_cache/
|
|
13
|
+
.ruff_cache/
|
|
14
|
+
dist/
|
|
15
|
+
build/
|
|
16
|
+
|
|
17
|
+
# opencode
|
|
18
|
+
.omo/
|
|
19
|
+
|
|
20
|
+
# mkdocs rendered site
|
|
21
|
+
site/
|
gapit-0.2.2/AGENTS.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# AGENTS.md — gapit
|
|
2
|
+
|
|
3
|
+
> Python reimplementation of [abricate](https://github.com/tseemann/abricate): mass screening of
|
|
4
|
+
> contigs for antimicrobial resistance and virulence genes. **Agent-first**: every output is
|
|
5
|
+
> machine-readable (JSON / Markdown) by design, not as an afterthought.
|
|
6
|
+
|
|
7
|
+
## 1. Mission
|
|
8
|
+
|
|
9
|
+
`gapit` answers one question: **which known genes are present in this assembly, and how confident
|
|
10
|
+
are we?** It replaces abricate (Perl) with a modern, typed, testable Python tool that:
|
|
11
|
+
|
|
12
|
+
1. Produces byte-compatible TSV with abricate (drop-in replacement for existing pipelines).
|
|
13
|
+
2. Adds first-class **JSON** and **Markdown** outputs so LLM agents and humans can consume
|
|
14
|
+
results without parsing tab-delimited text.
|
|
15
|
+
3. Exposes stable, versioned output contracts (schemas, exit codes, error envelopes) that
|
|
16
|
+
autonomous agents can rely on.
|
|
17
|
+
|
|
18
|
+
## 2. Environment & toolchain
|
|
19
|
+
|
|
20
|
+
- **Environment manager**: [pixi](https://pixi.sh) (conda-forge channel). Never use pip/conda
|
|
21
|
+
directly; add dependencies to `pixi.toml` (`pixi add <pkg>` for conda, `pixi add --pypi <pkg>`
|
|
22
|
+
for PyPI).
|
|
23
|
+
- **Python**: 3.14 in the pixi dev env (current stable); the package declares
|
|
24
|
+
`requires-python = ">=3.11"` and CI tests 3.11 / 3.13 / 3.14.
|
|
25
|
+
- **External binaries**: BLAST+ (`blastn`, `blastx`, `makeblastdb`, `blastdbcmd`) and `minimap2`
|
|
26
|
+
(FASTQ read screening, SPEC.md §10), all from conda-forge/bioconda. Invoked only via `subprocess`
|
|
27
|
+
with an argument list — never `shell=True`. Input normalization (fa/fq/gbk/embl, gz/bz2) is
|
|
28
|
+
native (`seqconvert.py`); `any2fasta` is no longer a gapit dependency anywhere — the
|
|
29
|
+
differential-validation oracle binary arrives transitively via abricate in the opt-in
|
|
30
|
+
`parity` pixi env (prepend `.pixi/envs/parity/bin` to PATH for the differential test).
|
|
31
|
+
- **Core libraries**: `typer` (CLI), `pydantic` v2 (data models / JSON schema), `rich` (terminal
|
|
32
|
+
output). No biopython — FASTA I/O is a small streaming parser we own.
|
|
33
|
+
- **Quality gates**: `ruff` (lint + format), `basedpyright` (strict mode), `pytest`.
|
|
34
|
+
|
|
35
|
+
### Commands (pixi tasks)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pixi run lint # ruff check
|
|
39
|
+
pixi run fmt # ruff format
|
|
40
|
+
pixi run typecheck # basedpyright --strict
|
|
41
|
+
pixi run test # pytest (unit, offline)
|
|
42
|
+
pixi run gapit # the CLI itself
|
|
43
|
+
pixi run -e parity parity # byte-diff screening vs real abricate (abricate-only env)
|
|
44
|
+
pixi run -e parity summary-parity # byte-diff summary vs real abricate
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Every change must leave `lint`, `typecheck`, and `test` green.
|
|
48
|
+
|
|
49
|
+
## 3. Repository layout
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
gapit/
|
|
53
|
+
├── AGENTS.md # this file
|
|
54
|
+
├── PLAN.md # development roadmap (phase-gated)
|
|
55
|
+
├── SPEC.md # distilled abricate behavior spec (source of truth for parity)
|
|
56
|
+
├── pixi.toml
|
|
57
|
+
├── recipe/
|
|
58
|
+
│ └── meta.yaml # conda recipe (submission deferred)
|
|
59
|
+
├── .github/workflows/
|
|
60
|
+
│ └── ci.yml # gates matrix 3.11/3.13/3.14 + parity job
|
|
61
|
+
├── src/gapit/
|
|
62
|
+
│ ├── __init__.py
|
|
63
|
+
│ ├── cli.py # typer entrypoint: screen / summary / db / list / setupdb / schema / mcp
|
|
64
|
+
│ ├── config.py # datadir resolution, defaults, env vars
|
|
65
|
+
│ ├── dispatch.py # shared CLI dispatch (error envelope → exit codes) + --datadir option
|
|
66
|
+
│ ├── proctools.py # external-tool plumbing: argv subprocess runner + stderr notes
|
|
67
|
+
│ ├── fasta.py # streaming FASTA reader + shared gz/bz2 text opener
|
|
68
|
+
│ ├── seqconvert.py # native input normalization: fa/fq/gbk/embl (±gz/bz2) → FASTA
|
|
69
|
+
│ ├── db.py # database discovery, header parsing, makeblastdb wrapper
|
|
70
|
+
│ ├── dbcodec.py # gapit/v1 tagged-header codec (percent-encoded ids)
|
|
71
|
+
│ ├── records.py # records.jsonl truth store + gapit.manifest/1 provenance
|
|
72
|
+
│ ├── dbbuild.py # deterministic native-db build pipeline with self-check
|
|
73
|
+
│ ├── db_ops.py # db use-cases: provider fetch + list (shared CLI + MCP; no typer)
|
|
74
|
+
│ ├── db_query_ops.py # db use-cases: search + outdated over installed DBs (shared CLI + MCP)
|
|
75
|
+
│ ├── db_build_ops.py # db use-case: custom FASTA+TSV → native db build (shared CLI + MCP)
|
|
76
|
+
│ ├── blast.py # blastn invocation + tabular output parsing
|
|
77
|
+
│ ├── hits.py # Hit model, identity/coverage computation, filtering, dedup
|
|
78
|
+
│ ├── minimap.py # COVERAGE_MAP construction (exact abricate arithmetic)
|
|
79
|
+
│ ├── minimap2_run.py # minimap2 invocation layer for reads mode (streaming PAF, --cs/NM tags)
|
|
80
|
+
│ ├── paf.py # PAF row parsing + interval arithmetic (minimap2 output boundary)
|
|
81
|
+
│ ├── report.py # Report model: the canonical in-memory result
|
|
82
|
+
│ ├── screening.py # blastn screen use-case + shared engine helpers (OutputFormat, AlignerEnum)
|
|
83
|
+
│ ├── screening_reads.py # minimap2 use-cases: --r1/--r2 reads + --aligner minimap2 assemblies
|
|
84
|
+
│ ├── reads.py # FASTQ mode: minimap2 PAF parsing, coverage breadth/depth, presence
|
|
85
|
+
│ ├── summary.py # summary core: parse report tables into a gene matrix
|
|
86
|
+
│ ├── cmd_screen.py # `gapit screen` CLI (registered from cli.py)
|
|
87
|
+
│ ├── cmd_summary.py # `gapit summary` CLI (registered from cli.py)
|
|
88
|
+
│ ├── cmd_db.py # `gapit db` command group (fetch | list; registers the subcommands)
|
|
89
|
+
│ ├── cmd_db_install.py # `gapit db install`: SHA256-verified local-file install
|
|
90
|
+
│ ├── cmd_db_build.py # `gapit db build` CLI (custom FASTA → native db)
|
|
91
|
+
│ ├── cmd_db_search.py # `gapit db search` CLI (records.jsonl lookup)
|
|
92
|
+
│ ├── cmd_db_outdated.py # `gapit db outdated` CLI (staleness report)
|
|
93
|
+
│ ├── mcp.py # MCP stdio server (hand-rolled JSON-RPC 2.0); backs gapit-mcp
|
|
94
|
+
│ ├── mcp_tools.py # MCP tool implementations (call the shared use-cases)
|
|
95
|
+
│ ├── mcp_schemas.py # MCP tools/list declarations (names, descriptions, inputSchemas)
|
|
96
|
+
│ ├── errors.py # typed errors + JSON error envelope
|
|
97
|
+
│ ├── formats/
|
|
98
|
+
│ │ ├── tsv.py # abricate-compatible TSV/CSV
|
|
99
|
+
│ │ ├── json.py # versioned JSON (gapit.report/1 et al.)
|
|
100
|
+
│ │ ├── md.py # Markdown (human + agent readable, YAML frontmatter)
|
|
101
|
+
│ │ ├── schemas.py # registered output models behind `gapit schema`
|
|
102
|
+
│ │ └── summary.py # summary matrix renderers (TSV/CSV/JSON/MD)
|
|
103
|
+
│ ├── providers/ # 12 DB providers + common.py helpers + snapshots.py loader
|
|
104
|
+
│ ├── data/snapshots/ # bundled card + vfdb snapshot archives (.tar.gz)
|
|
105
|
+
│ └── py.typed
|
|
106
|
+
└── tests/
|
|
107
|
+
├── data/ # tiny synthetic db + contigs + reads (fast, offline)
|
|
108
|
+
├── golden/ # expected outputs incl. abricate reference TSVs
|
|
109
|
+
├── parity/ # corpus + run_parity.py / run_summary_parity.py (opt-in env)
|
|
110
|
+
└── test_*.py # unit + CLI + provider + integration tests
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
One file, one responsibility. Target ≤ 250 LOC per module; split before it hurts.
|
|
114
|
+
|
|
115
|
+
## 4. Coding conventions
|
|
116
|
+
|
|
117
|
+
- **Strict typing everywhere.** basedpyright strict; no `Any` unless isolated and justified in a
|
|
118
|
+
comment. No `# type: ignore`, no `cast` to silence real errors.
|
|
119
|
+
- **Parse, don't validate.** BLAST rows, FASTA records, and db headers become typed models at the
|
|
120
|
+
boundary; the core logic never touches raw strings.
|
|
121
|
+
- **No silent failures.** Errors are typed (`errors.py`), carry context, and map to documented
|
|
122
|
+
exit codes. Empty `except` blocks are forbidden.
|
|
123
|
+
- **Deterministic output.** Stable sort orders, no wall-clock timestamps inside data payloads
|
|
124
|
+
(metadata block only), LF line endings, UTF-8.
|
|
125
|
+
- **TDD for core logic.** hit filtering, merging, and coverage-map math are written test-first.
|
|
126
|
+
- Match the style of the file you are editing; when in doubt, `ruff format` decides.
|
|
127
|
+
|
|
128
|
+
## 5. The agent-facing output contract (design center)
|
|
129
|
+
|
|
130
|
+
This is what distinguishes gapit from abricate. Treat it as a public API.
|
|
131
|
+
|
|
132
|
+
- **Formats**: `--format tsv|csv|json|md` (default `tsv` for abricate compatibility).
|
|
133
|
+
- **JSON**: top-level `"schema": "gapit.report/1"`; schema introspectable via
|
|
134
|
+
`gapit schema report | reads | reads2 | summary | list | error | version`. Keys are snake_case,
|
|
135
|
+
units explicit (`identity_pct`, `coverage_pct`). Semver the schema; never rename or
|
|
136
|
+
retype a field in a minor bump.
|
|
137
|
+
- **Markdown**: YAML frontmatter (tool version, db, params, ISO-8601 UTC timestamp) + tables a
|
|
138
|
+
human can read and an agent can regex reliably.
|
|
139
|
+
- **Errors**: failures print a JSON envelope to stderr
|
|
140
|
+
`{"schema": "gapit.error/1", "code": "...", "message": "...", "context": {...}}` and exit with a
|
|
141
|
+
documented non-zero code (2 = usage, 3 = missing dependency, 4 = db error, 5 = input error).
|
|
142
|
+
- **DB acquisition** `[gapit-extension]`: `gapit db fetch|list|search|outdated|build|install` —
|
|
143
|
+
provider fetch (bundled card/vfdb snapshots install offline; `--from-source` forces upstream),
|
|
144
|
+
provider listing, records.jsonl gene search, staleness report, custom FASTA→native-db build,
|
|
145
|
+
and SHA256-verified local-file install.
|
|
146
|
+
- **MCP** `[gapit-extension]`: `gapit mcp` / `gapit-mcp` stdio server exposing nine tools:
|
|
147
|
+
read-only `screen` (incl. `aligner minimap2` assembly survey), `screen_reads` (FASTQ via
|
|
148
|
+
minimap2), `summary`, `schema`, `db_list`, `db_search`, `db_outdated`, plus the datadir-mutating
|
|
149
|
+
`db_fetch` (installs provider databases; may download) and `db_build` (writes a custom db);
|
|
150
|
+
tool failures carry the `gapit.error/1` envelope.
|
|
151
|
+
- **stdout purity**: data on stdout, diagnostics on stderr, always. `--quiet` only affects stderr.
|
|
152
|
+
- **Self-description**: `gapit --version --json`, `gapit list --json`, `gapit schema` — an agent
|
|
153
|
+
must be able to discover everything without reading docs.
|
|
154
|
+
|
|
155
|
+
## 6. Testing strategy
|
|
156
|
+
|
|
157
|
+
- **Unit**: pure functions (coverage %, merge rules, header parsing) — no I/O beyond `tests/data`.
|
|
158
|
+
- **Golden files**: fixed tiny db + fixed contigs → expected TSV/JSON/MD committed; update the
|
|
159
|
+
committed files deliberately and review diffs like code.
|
|
160
|
+
- **Parity harness**: `pixi run -e parity parity` (and `summary-parity`) runs real abricate
|
|
161
|
+
(conda) and gapit over a small genome corpus and diffs the gene calls byte-for-byte (file,
|
|
162
|
+
gene, %identity, %coverage). Parity on the corpus is the release gate for v1.0.
|
|
163
|
+
- Full suite + CI matrix 3.11/3.13/3.14; parity byte-diff is opt-in via the `parity` pixi env.
|
|
164
|
+
Offline tests stay fast.
|
|
165
|
+
|
|
166
|
+
## 7. Domain knowledge (abridged; full detail in SPEC.md)
|
|
167
|
+
|
|
168
|
+
- A **database** is a directory `<datadir>/<dbname>/sequences`: a nucleotide FASTA whose headers
|
|
169
|
+
encode `>~~~GENE~~~PRODUCT` (and accession / resistance metadata depending on the source db).
|
|
170
|
+
`makeblastdb -dbtype nucl` builds the index. gapit also writes its own native `gapit/v1`
|
|
171
|
+
tagged-header format (SPEC §11), whose `func` key carries a locked per-provider function
|
|
172
|
+
vocabulary (antibiotic classes, `virulence`, `replicon`, ...); abricate cannot read
|
|
173
|
+
gapit-native databases.
|
|
174
|
+
- Screening = native normalize (`seqconvert.py`, any2fasta-equivalent semantics) → `blastn` of
|
|
175
|
+
query contigs against one db → 15-field
|
|
176
|
+
tabular hits → filter by identity / coverage thresholds → **dedup hits sharing identical
|
|
177
|
+
`(contig, qstart, qend)`** (first/best BLAST row wins) → one TSV row per surviving hit.
|
|
178
|
+
abricate does **not** merge overlapping intervals — do not "improve" this on the default path.
|
|
179
|
+
- Key computed fields: `%COVERAGE = 100*(length-gaps)/slen` (filtered unrounded, displayed
|
|
180
|
+
`%.2f`), `%IDENTITY` (BLAST pident, never post-filtered), `COVERAGE_MAP` (15-char minimap),
|
|
181
|
+
`GAPS`. Exact formulas, the dedup rule, and the minimap arithmetic live in `SPEC.md` — when
|
|
182
|
+
abricate and intuition disagree, **abricate wins** (parity is a feature).
|
|
183
|
+
|
|
184
|
+
## 8. Git & workflow
|
|
185
|
+
|
|
186
|
+
- Conventional Commits (`feat:`, `fix:`, `test:`, `docs:`, `refactor:`).
|
|
187
|
+
- Never commit unless the user explicitly asks. Never force-push.
|
|
188
|
+
- `PLAN.md` tracks phases; update it when scope changes, not retroactively.
|
|
189
|
+
|
|
190
|
+
## 9. For agents working in this repo
|
|
191
|
+
|
|
192
|
+
1. Read `SPEC.md` before touching `blast.py`, `hits.py`, or `minimap.py`.
|
|
193
|
+
2. Public contract changes (JSON schema, exit codes, CLI flags) require a schema version bump and
|
|
194
|
+
a note in `PLAN.md`.
|
|
195
|
+
3. Do not add dependencies without checking this file's §2 first — the list is intentionally short.
|
|
196
|
+
4. Verification is part of the task: `pixi run lint && pixi run typecheck && pixi run test` before
|
|
197
|
+
declaring done.
|
gapit-0.2.2/CHANGELOG.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to gapit are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
|
|
6
|
+
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.2] - 2026-09-24
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
|
|
12
|
+
- minimap2 input paths are passed as absolute paths, so a file named like an option
|
|
13
|
+
(e.g. `-d`) can no longer inject minimap2 flags; the child process no longer inherits
|
|
14
|
+
stdin (the MCP protocol stream).
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- `--minid`/`--mincov` with `--aligner minimap2` or `--r1/--r2` are now a usage error
|
|
19
|
+
(exit 2) instead of being silently ignored.
|
|
20
|
+
- MCP `screen` (blastn) reuses the CLI use-case; its validation messages now match the CLI.
|
|
21
|
+
- MCP `screen_reads` passes read arrays natively, so filenames containing commas work.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- MCP server replies `-32600`/`-32602` to malformed requests that carry an `id` instead of
|
|
26
|
+
silently dropping them.
|
|
27
|
+
- A truncated gzip reads file raises a typed `INVALID_READS_FORMAT` error (exit 5) instead
|
|
28
|
+
of `UNEXPECTED` (exit 1).
|
|
29
|
+
|
|
30
|
+
## [0.2.1] - 2026-09-22
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- License changed from GPL-2.0-only to MIT (rightsholder decision; behavioral
|
|
35
|
+
reimplementation status unchanged).
|
|
36
|
+
|
|
37
|
+
## [0.2.0] - 2026-09-22
|
|
38
|
+
|
|
39
|
+
Development window: 2026-09-15 to 2026-09-22 (PLAN.md Phases 1 through 8 and post-phase
|
|
40
|
+
hardening).
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- Screening core: `any2fasta` to `blastn` pipeline with SPEC-exact hit processing, and
|
|
45
|
+
byte-compatible TSV against abricate 1.4.0 (PLAN Phases 1-3, 2026-09-15). Parity is
|
|
46
|
+
checked on a genome corpus with `pixi run -e parity parity` (6/6 byte-identical).
|
|
47
|
+
- Agent-facing outputs: `--format json|md` with versioned schemas (`gapit.report/1`,
|
|
48
|
+
`gapit.reads/1`, `gapit.summary/1`, `gapit.list/1`, `gapit.version/1`), the
|
|
49
|
+
`gapit.error/1` stderr envelope with documented exit codes, and introspection via
|
|
50
|
+
`gapit schema report|reads|summary|list|error|version` (2026-09-16).
|
|
51
|
+
- FASTQ reads mode via minimap2: `gapit screen --r1/--r2 --read-type sr|map-ont|map-hifi`;
|
|
52
|
+
presence is called on alignment breadth (2026-09-16).
|
|
53
|
+
- Summary matrix mode: `gapit summary` emits TSV/CSV/JSON/MD; byte parity with
|
|
54
|
+
`abricate --summary` via `pixi run -e parity summary-parity` (2026-09-17).
|
|
55
|
+
- `gapit db install`: checksum-verified (SHA256), atomic local-file installation
|
|
56
|
+
(2026-09-17).
|
|
57
|
+
- Native `gapit/v1` database format: tagged-header codec, `records.jsonl` truth store
|
|
58
|
+
with `gapit.manifest/1` provenance, deterministic build pipeline with self-check, and
|
|
59
|
+
`.mmi` BLAST index build with version-gated reuse (2026-09-18).
|
|
60
|
+
- 12 database providers (ncbi, card, resfinder, argannot, plasmidfinder, megares, ecoh,
|
|
61
|
+
vfdb, ecoli_vf, bacmet2, victors, upec_expec_vf) with offline-tested transforms
|
|
62
|
+
(2026-09-18).
|
|
63
|
+
- Bundled card and vfdb snapshots: a bare `gapit db fetch` installs the default set with
|
|
64
|
+
zero network; `--from-source` forces upstream download (2026-09-18).
|
|
65
|
+
- CLI hardening: shell completions, `--debug` argv echo on stderr, and `--jobs` parallel
|
|
66
|
+
screening across inputs with input-order stdout (2026-09-18).
|
|
67
|
+
- CI: gates matrix (lint, fmt, typecheck, test on Python 3.11 / 3.13 / 3.14) plus a
|
|
68
|
+
parity job that byte-diffs against real abricate (2026-09-18).
|
|
69
|
+
- MCP stdio server: `gapit mcp` subcommand and `gapit-mcp` console script, hand-rolled
|
|
70
|
+
JSON-RPC 2.0 with zero new dependencies; read-only tools `screen`, `summary`,
|
|
71
|
+
`schema`, `db_list` (2026-09-18).
|
|
72
|
+
- Conda recipe (`recipe/meta.yaml`) for PyPI/bioconda packaging (2026-09-18).
|
|
73
|
+
- Custom database construction: `gapit db build NAME FASTA` builds a screening-ready native
|
|
74
|
+
database from plain, abricate `~~~`, or `gapit|` FASTA (auto-detected), with optional
|
|
75
|
+
`--tsv` metadata (accession, function classes) and `--dbtype` override; guide with worked
|
|
76
|
+
examples in `docs/custom-db.md` (2026-09-19).
|
|
77
|
+
- `--aligner blastn|minimap2` engine selector on `gapit screen`: defaults follow the input
|
|
78
|
+
(blastn for contig files, minimap2 for `--r1`/`--r2` reads); `--aligner minimap2` screens
|
|
79
|
+
positional assembly FASTA through the minimap2 engine, `--aligner blastn` with `--r1`/`--r2`
|
|
80
|
+
is a usage error (2026-09-19).
|
|
81
|
+
- `gapit db outdated`: staleness report over installed databases (age vs `--days`, newer
|
|
82
|
+
bundled snapshot) as a TSV table or `gapit.dboutdated/1` JSON document (2026-09-20).
|
|
83
|
+
- `gapit db search TERM`: case-insensitive gene/accession/function/product lookup across
|
|
84
|
+
installed databases' `records.jsonl`, with `--field`, `--exact`, `--db`, `--limit` and
|
|
85
|
+
JSONL output (2026-09-20).
|
|
86
|
+
- MCP database tools `db_fetch`, `db_build`, `db_search`, `db_outdated`: the MCP server now
|
|
87
|
+
exposes the `db` commands alongside the analysis tools, so agents can self-provision and
|
|
88
|
+
inspect databases mid-session; `mcp.py` split into protocol (`mcp.py`) and tool
|
|
89
|
+
implementations (`mcp_tools.py`) with zero wire change for the existing tools (2026-09-20).
|
|
90
|
+
- CI snapshot refresh: monthly scheduled workflow (`.github/workflows/snapshot-refresh.yml`)
|
|
91
|
+
re-fetching card and vfdb from upstream, regenerating the bundled tars only when the
|
|
92
|
+
records changed, and opening a review PR (2026-09-20).
|
|
93
|
+
- Reads-mode opt-in alignment filtering: `gapit screen --min-identity/--min-mapq` (reads
|
|
94
|
+
engine only) drops PAF alignments below the thresholds before aggregation and emits the new
|
|
95
|
+
`gapit.reads/2` document (params gain both thresholds; gene entries gain
|
|
96
|
+
`mean_identity_pct`, the alignment-length-weighted mean identity; introspectable via
|
|
97
|
+
`gapit schema reads2`). Both flags off keeps `gapit.reads/1` byte-identical, and the
|
|
98
|
+
identity floor fixes the documented family-splitting over-calls on homologous genes
|
|
99
|
+
(2026-09-20).
|
|
100
|
+
- MCP reads tools: new `screen_reads` tool (FASTQ lanes via minimap2 → `gapit.reads/1`,
|
|
101
|
+
`min_identity`/`min_mapq` > 0 → `gapit.reads/2`) and new `screen` arguments
|
|
102
|
+
`aligner`/`min_breadth`/`min_identity`/`min_mapq` (`aligner minimap2` = fast assembly
|
|
103
|
+
survey). Both delegate to the shared reads use-cases with `quiet` stderr; additive
|
|
104
|
+
`gapit.mcp` contract — nine tools, the other eight wire-identical, no output-schema
|
|
105
|
+
version bump (2026-09-22).
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- `any2fasta` is no longer a runtime dependency: input normalization (FASTA/FASTQ/GenBank/EMBL,
|
|
110
|
+
plain/gz/bz2 → FASTA) is native (`seqconvert.py`, perl-extracted semantics) and blastn reads the
|
|
111
|
+
converted FASTA on stdin. Parsed-record equivalence with the binary is differentially tested
|
|
112
|
+
with the parity env on PATH (abricate provides any2fasta transitively), and `.fa` parity
|
|
113
|
+
remains byte-identical (2026-09-21).
|
|
114
|
+
- Screening and reads paths route `gapit/v1` tagged headers to the native codec; legacy
|
|
115
|
+
abricate `~~~` headers keep the frozen parser, so abricate-built datadirs screen
|
|
116
|
+
identically. The reverse does not hold: gapit-built databases are unreadable by
|
|
117
|
+
abricate (accepted trade-off).
|
|
118
|
+
- A bare `gapit db fetch` installs the bundled default set (card, vfdb) instead of
|
|
119
|
+
downloading; `--from-source` restores the upstream fetch path.
|
|
120
|
+
- `gapit setupdb` honors the `gapit.manifest/1` dbtype on reindex (manifest-less abricate
|
|
121
|
+
dirs keep the mol_type heuristic), and reads/minimap2-assembly screening now rejects the
|
|
122
|
+
blastn-only flags `--fofn`, `--noheader`, `--nopath`, `--jobs N>1` with usage errors
|
|
123
|
+
(exit 2) instead of silently ignoring them (2026-09-22).
|
|
124
|
+
|
|
125
|
+
### Removed
|
|
126
|
+
|
|
127
|
+
- `--csv` flag on `gapit screen`; use `--format csv` instead (breaking: the flag is now
|
|
128
|
+
rejected as an unknown option, exit 2) (2026-09-19).
|
|
129
|
+
|
|
130
|
+
### Fixed
|
|
131
|
+
|
|
132
|
+
- Summary mode auto-detects TSV vs CSV per input file, avoiding the upstream quirk where
|
|
133
|
+
a global `--csv` flag mangles mixed-format input sets.
|
gapit-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 indexofire
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|