ont-bed-generator 0.4.0__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.
Files changed (29) hide show
  1. ont_bed_generator-0.4.0/.github/workflows/ci.yml +38 -0
  2. ont_bed_generator-0.4.0/.github/workflows/release.yml +49 -0
  3. ont_bed_generator-0.4.0/.gitignore +13 -0
  4. ont_bed_generator-0.4.0/CHANGELOG.md +70 -0
  5. ont_bed_generator-0.4.0/CITATION.cff +16 -0
  6. ont_bed_generator-0.4.0/LICENSE +21 -0
  7. ont_bed_generator-0.4.0/PKG-INFO +143 -0
  8. ont_bed_generator-0.4.0/README.md +100 -0
  9. ont_bed_generator-0.4.0/annotation/README.md +96 -0
  10. ont_bed_generator-0.4.0/annotation/build_gene_gff.sh +31 -0
  11. ont_bed_generator-0.4.0/environment.yml +11 -0
  12. ont_bed_generator-0.4.0/pyproject.toml +63 -0
  13. ont_bed_generator-0.4.0/src/ont_bed_generator/__init__.py +25 -0
  14. ont_bed_generator-0.4.0/src/ont_bed_generator/__main__.py +7 -0
  15. ont_bed_generator-0.4.0/src/ont_bed_generator/_version.py +24 -0
  16. ont_bed_generator-0.4.0/src/ont_bed_generator/cli.py +76 -0
  17. ont_bed_generator-0.4.0/src/ont_bed_generator/intervals.py +70 -0
  18. ont_bed_generator-0.4.0/src/ont_bed_generator/io_inputs.py +128 -0
  19. ont_bed_generator-0.4.0/src/ont_bed_generator/io_outputs.py +30 -0
  20. ont_bed_generator-0.4.0/src/ont_bed_generator/model.py +56 -0
  21. ont_bed_generator-0.4.0/src/ont_bed_generator/ordering.py +20 -0
  22. ont_bed_generator-0.4.0/src/ont_bed_generator/resolve.py +57 -0
  23. ont_bed_generator-0.4.0/tests/conftest.py +23 -0
  24. ont_bed_generator-0.4.0/tests/data/mini.gff3 +7 -0
  25. ont_bed_generator-0.4.0/tests/data/mini.len +3 -0
  26. ont_bed_generator-0.4.0/tests/data/mini_genelist.tsv +6 -0
  27. ont_bed_generator-0.4.0/tests/test_intervals.py +120 -0
  28. ont_bed_generator-0.4.0/tests/test_io.py +51 -0
  29. ont_bed_generator-0.4.0/tests/test_resolve.py +49 -0
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ pull_request:
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+ with:
19
+ fetch-depth: 0 # required for hatch-vcs (tags)
20
+
21
+ - uses: actions/setup-python@v6
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install bedtools (parity test)
26
+ run: sudo apt-get update && sudo apt-get install -y bedtools
27
+
28
+ - name: Install package
29
+ run: pip install -e '.[dev]'
30
+
31
+ - name: Lint
32
+ run: ruff check .
33
+
34
+ - name: Type-check
35
+ run: mypy
36
+
37
+ - name: Tests
38
+ run: pytest -ra
@@ -0,0 +1,49 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"] # étape 1 : dry-run TestPyPI
6
+ release:
7
+ types: [published] # étape 2 : production PyPI
8
+ workflow_dispatch: # dry-run TestPyPI manuel (voir la note sur v0.3.0)
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0 # tags requis par hatch-vcs
17
+ - uses: actions/setup-python@v5
18
+ with: { python-version: "3.x" }
19
+ - run: python -m pip install build
20
+ - run: python -m build
21
+ - run: pipx run twine check dist/*
22
+ - uses: actions/upload-artifact@v4
23
+ with: { name: dist, path: dist/ }
24
+
25
+ testpypi:
26
+ needs: build
27
+ if: github.event_name != 'release' # tag push OU dispatch manuel
28
+ runs-on: ubuntu-latest
29
+ environment: testpypi
30
+ permissions:
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/download-artifact@v4
34
+ with: { name: dist, path: dist/ }
35
+ - uses: pypa/gh-action-pypi-publish@release/v1
36
+ with:
37
+ repository-url: https://test.pypi.org/legacy/
38
+
39
+ pypi:
40
+ needs: build
41
+ if: github.event_name == 'release' # Release GitHub publiée
42
+ runs-on: ubuntu-latest
43
+ environment: pypi
44
+ permissions:
45
+ id-token: write
46
+ steps:
47
+ - uses: actions/download-artifact@v4
48
+ with: { name: dist, path: dist/ }
49
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .eggs/
5
+ build/
6
+ dist/
7
+ .pytest_cache/
8
+ .mypy_cache/
9
+ .ruff_cache/
10
+ .venv/
11
+ venv/
12
+ # version file generated by hatch-vcs
13
+ src/ont_bed_generator/_version.py
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
5
+ versioning: [SemVer](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+ ### Added
9
+ - Transparent gzip (`.gz`) support for all input files (genome, genelist, GFF,
10
+ Entrez map).
11
+
12
+ ### Changed
13
+ - **Breaking:** simplified the genelist format to three columns
14
+ `Gene | Left_extension_bp | Right_extension_bp` (dropped the Chromosome,
15
+ Extended_region and Comment columns). The extended-region flag is now derived
16
+ (a gene is extended iff Left or Right is non-zero); a header row is
17
+ auto-detected. Existing six-column lists must be converted.
18
+ - Output BEDs are now sorted in canonical karyotypic order (chr1..chrN, then
19
+ X, Y, then M/MT, contigs last), organism-agnostic. The genome file's line
20
+ order no longer affects the output; `read_genome` returns sizes only and the
21
+ internal `rank` ordering was removed in favour of `ordering.chrom_sort_key`.
22
+
23
+ ## [0.1.0] - TBD
24
+ ### Added
25
+ - Generation of `targets.bed` and `merged-extended.bed`.
26
+ - Symbol resolution restricted to official HGNC symbols via the Entrez key
27
+ (GFF `Name=`), handling pseudoautosomal regions and IG/TCR loci.
28
+ - Reporting of invalid / ambiguous symbols (`--strict`).
29
+ - Unit tests + optional `bedtools merge` parity test.
30
+
31
+ ## [0.2.0] - 2026-07-12
32
+
33
+ ### Added
34
+ - Structural invariant tests: merged intervals never overlap within a
35
+ `(chromosome, strand)` group, every interval stays within `[0, chrom_size]`,
36
+ and per-strand merging is idempotent.
37
+
38
+ ### Changed
39
+ - **Breaking — genelist format** is now `Gene | Left_extension_bp |
40
+ Right_extension_bp` with an auto-detected header. The Chromosome,
41
+ Extended_region and Comment columns were dropped; the extended-region flag is
42
+ now derived (a gene is extended iff Left or Right is non-zero).
43
+ - Output BEDs are sorted in canonical karyotypic order, independent of the
44
+ genome file's line order; `read_genome` now returns chromosome sizes only.
45
+ - `GffIndex.by_geneid` renamed to `geneid_to_features`.
46
+ - (internal) Split-line variable unified to `fields` across the readers.
47
+
48
+ ### Removed
49
+ - Dead internal state: `GffGene.strand` and the never-read `geneid_name` index.
50
+
51
+ ## [0.3.0] - 2026-07-13
52
+
53
+ ### Added
54
+ - **Annotation dataset build pipeline** (`annotation/`). A scripted, reproducible
55
+ chain (`build_gene_gff.sh`) that derives a gene-feature-only, `chr`-named GFF3
56
+ for T2T-CHM13v2.0 from the official NCBI RefSeq release (RS_2025_08): it keeps
57
+ only `gene` features, renames RefSeq accessions to `chr` names via the
58
+ assembly report, and restores the pseudoautosomal chrX copy of *P2RY8*
59
+ (absent from the NCBI build) from the curated `NM_178129.5` coordinates under
60
+ the shared `GeneID:286530`, so *P2RY8* resolves on both chrX and chrY like
61
+ *CRLF2*. The built asset is archived on Zenodo
62
+ (DOI [10.5281/zenodo.21341240](https://doi.org/10.5281/zenodo.21341240)); the
63
+ pipeline and its documentation live in `annotation/`. No change to the package
64
+ code or CLI.
65
+
66
+ ## [0.4.0] - 2026-07-14
67
+
68
+ ### Added
69
+ - **Automated PiPy publishing workflow** (`.github/workflows/release.yml`).
70
+
@@ -0,0 +1,16 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use this software, please cite it as below."
3
+ title: "ont-bed-generator"
4
+ abstract: "Generate BED files for Oxford Nanopore adaptive sampling from a gene list and a RefSeq GFF3."
5
+ type: software
6
+ authors:
7
+ - family-names: Antoniewski
8
+ given-names: Christophe
9
+ orcid: "https://orcid.org/0000-0001-7709-2116"
10
+ license: MIT
11
+ repository-code: "https://github.com/CHANGE-ME/ont-bed-generator"
12
+ keywords:
13
+ - nanopore
14
+ - adaptive-sampling
15
+ - bioinformatics
16
+ - genomics
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Christophe Antoniewski
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.
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: ont-bed-generator
3
+ Version: 0.4.0
4
+ Summary: Generate BED files for Oxford Nanopore adaptive sampling from a gene list and a RefSeq GFF3.
5
+ Project-URL: Homepage, https://github.com/Institut-Leucemie/ont-bed-generator
6
+ Project-URL: Issues, https://github.com/Institut-Leucemie/ont-bed-generator/issues
7
+ Author: Christophe Antoniewski
8
+ License: MIT License
9
+
10
+ Copyright (c) 2026 Christophe Antoniewski
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+ License-File: LICENSE
30
+ Keywords: adaptive-sampling,bed,bioinformatics,genomics,nanopore
31
+ Classifier: Intended Audience :: Science/Research
32
+ Classifier: License :: OSI Approved :: MIT License
33
+ Classifier: Operating System :: OS Independent
34
+ Classifier: Programming Language :: Python :: 3
35
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
36
+ Requires-Python: >=3.10
37
+ Provides-Extra: dev
38
+ Requires-Dist: build>=1.2; extra == 'dev'
39
+ Requires-Dist: mypy>=1.8; extra == 'dev'
40
+ Requires-Dist: pytest>=7; extra == 'dev'
41
+ Requires-Dist: ruff>=0.4; extra == 'dev'
42
+ Description-Content-Type: text/markdown
43
+
44
+ ![CI](https://github.com/Institut-Leucemie/ont-bed-generator/actions/workflows/ci.yml/badge.svg)
45
+
46
+ # ont-bed-generator
47
+
48
+ Generate **BED** files for **Oxford Nanopore adaptive sampling** from a gene
49
+ list and a RefSeq GFF3. Standalone reimplementation (Python standard library
50
+ only, **no runtime dependencies**) of the Galaxy workflow "Adaptative ONT BED
51
+ file generation" (which replaced BED-Craft).
52
+
53
+ Given a list of target genes and a GFF3 annotation, the tool produces:
54
+
55
+ - `targets.bed` — the raw locus of each gene (BED6);
56
+ - `merged-extended.bed` — two intervals per locus (`+` / `-` strands),
57
+ extended, clamped to chromosome bounds, then merged per strand.
58
+
59
+ ## Installation
60
+
61
+ ```bash
62
+ # from source
63
+ git clone https://github.com/CHANGE-ME/ont-bed-generator.git
64
+ cd ont-bed-generator
65
+ pip install .
66
+ ```
67
+
68
+ Conda development environment (includes `bedtools`, used only by the parity
69
+ test):
70
+
71
+ ```bash
72
+ conda env create -f environment.yml # or: mamba/micromamba env create -f environment.yml
73
+ conda activate ont-bed-generator
74
+ ```
75
+
76
+ ## Usage
77
+
78
+ ```bash
79
+ ont-bed-generator \
80
+ --genelist genelist.tsv \
81
+ --gff annotation.genes.gff3 \
82
+ --genome hs1.len \
83
+ --out-targets targets.bed \
84
+ --out-merged merged-extended.bed
85
+ # or: python -m ont_bed_generator --genelist ... --gff ... --genome ...
86
+ ```
87
+
88
+ ### Inputs
89
+
90
+ 1. **genelist TSV** — columns `Gene | Left_extension_bp | Right_extension_bp`,
91
+ with an (auto-detected) header row. Coordinates come from the GFF, so no
92
+ chromosome column is needed; a gene is treated as an extended region when
93
+ Left or Right is non-zero (no separate flag). A bare `Gene` line (no
94
+ extensions) is valid and gets only the default flank. Symbols must be
95
+ **official HGNC symbols** (check them with the
96
+ [multi-symbol checker](https://www.genenames.org/tools/multi-symbol-checker/)).
97
+ 2. **GFF3** — a RefSeq GFF3 whose `gene` features carry `Name=` and
98
+ `Dbxref=GeneID:`. The **full NCBI annotation works as-is**: the tool reads
99
+ only `gene` features and ignores everything else, so pre-extracting them is
100
+ just an optional speed-up. Gzip-compressed (`.gz`) input is read transparently
101
+ (this applies to every input file). Example (T2T-CHM13v2.0 / hs1):
102
+ ```bash
103
+ curl -sO https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz
104
+ ```
105
+ 3. **genome sizes** — `chrom<TAB>size`, one line per chromosome. Used for
106
+ telomere clamping only; the line order does not matter (output BEDs are
107
+ sorted in canonical karyotypic order).
108
+ ```bash
109
+ curl -sO https://hgdownload.soe.ucsc.edu/goldenPath/hs1/bigZips/hs1.chrom.sizes
110
+ ```
111
+
112
+ ### Symbol resolution
113
+
114
+ Official symbol → GeneID (GFF `Name=`, or external `--entrez-map`) → collect
115
+ **all** loci carrying that GeneID. The Entrez key handles pseudoautosomal
116
+ regions (one GeneID on chrX and chrY yields two loci) and IG/TCR loci. A symbol
117
+ that is not found, or that maps to several GeneIDs, is **reported** (on stderr),
118
+ never guessed. `--strict` returns a non-zero exit code if any symbol is invalid
119
+ or ambiguous.
120
+
121
+ ## Development
122
+
123
+ ```bash
124
+ pip install -e '.[dev]'
125
+ pytest # unit tests (+ bedtools parity if bedtools is present)
126
+ ruff check .
127
+ mypy
128
+ ```
129
+
130
+ Versioning is driven by git tags (`hatch-vcs`): a release is
131
+ `git tag vX.Y.Z && git push --tags`.
132
+
133
+ ## Intentional differences from the original Galaxy workflow
134
+
135
+ - The workflow patched non-official symbols (`MKL1→MKLN1`, a bug — MKLN1 is a
136
+ different gene; `LYL→LYL1`). Here **no patching**: such symbols are reported
137
+ for correction at the source.
138
+ - The Galaxy output contained a missing merge (`bedtools merge` on
139
+ genome-order-sorted input without `-g`). This tool performs the correct merge.
140
+
141
+ ## License
142
+
143
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,100 @@
1
+ ![CI](https://github.com/Institut-Leucemie/ont-bed-generator/actions/workflows/ci.yml/badge.svg)
2
+
3
+ # ont-bed-generator
4
+
5
+ Generate **BED** files for **Oxford Nanopore adaptive sampling** from a gene
6
+ list and a RefSeq GFF3. Standalone reimplementation (Python standard library
7
+ only, **no runtime dependencies**) of the Galaxy workflow "Adaptative ONT BED
8
+ file generation" (which replaced BED-Craft).
9
+
10
+ Given a list of target genes and a GFF3 annotation, the tool produces:
11
+
12
+ - `targets.bed` — the raw locus of each gene (BED6);
13
+ - `merged-extended.bed` — two intervals per locus (`+` / `-` strands),
14
+ extended, clamped to chromosome bounds, then merged per strand.
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ # from source
20
+ git clone https://github.com/CHANGE-ME/ont-bed-generator.git
21
+ cd ont-bed-generator
22
+ pip install .
23
+ ```
24
+
25
+ Conda development environment (includes `bedtools`, used only by the parity
26
+ test):
27
+
28
+ ```bash
29
+ conda env create -f environment.yml # or: mamba/micromamba env create -f environment.yml
30
+ conda activate ont-bed-generator
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```bash
36
+ ont-bed-generator \
37
+ --genelist genelist.tsv \
38
+ --gff annotation.genes.gff3 \
39
+ --genome hs1.len \
40
+ --out-targets targets.bed \
41
+ --out-merged merged-extended.bed
42
+ # or: python -m ont_bed_generator --genelist ... --gff ... --genome ...
43
+ ```
44
+
45
+ ### Inputs
46
+
47
+ 1. **genelist TSV** — columns `Gene | Left_extension_bp | Right_extension_bp`,
48
+ with an (auto-detected) header row. Coordinates come from the GFF, so no
49
+ chromosome column is needed; a gene is treated as an extended region when
50
+ Left or Right is non-zero (no separate flag). A bare `Gene` line (no
51
+ extensions) is valid and gets only the default flank. Symbols must be
52
+ **official HGNC symbols** (check them with the
53
+ [multi-symbol checker](https://www.genenames.org/tools/multi-symbol-checker/)).
54
+ 2. **GFF3** — a RefSeq GFF3 whose `gene` features carry `Name=` and
55
+ `Dbxref=GeneID:`. The **full NCBI annotation works as-is**: the tool reads
56
+ only `gene` features and ignores everything else, so pre-extracting them is
57
+ just an optional speed-up. Gzip-compressed (`.gz`) input is read transparently
58
+ (this applies to every input file). Example (T2T-CHM13v2.0 / hs1):
59
+ ```bash
60
+ curl -sO https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz
61
+ ```
62
+ 3. **genome sizes** — `chrom<TAB>size`, one line per chromosome. Used for
63
+ telomere clamping only; the line order does not matter (output BEDs are
64
+ sorted in canonical karyotypic order).
65
+ ```bash
66
+ curl -sO https://hgdownload.soe.ucsc.edu/goldenPath/hs1/bigZips/hs1.chrom.sizes
67
+ ```
68
+
69
+ ### Symbol resolution
70
+
71
+ Official symbol → GeneID (GFF `Name=`, or external `--entrez-map`) → collect
72
+ **all** loci carrying that GeneID. The Entrez key handles pseudoautosomal
73
+ regions (one GeneID on chrX and chrY yields two loci) and IG/TCR loci. A symbol
74
+ that is not found, or that maps to several GeneIDs, is **reported** (on stderr),
75
+ never guessed. `--strict` returns a non-zero exit code if any symbol is invalid
76
+ or ambiguous.
77
+
78
+ ## Development
79
+
80
+ ```bash
81
+ pip install -e '.[dev]'
82
+ pytest # unit tests (+ bedtools parity if bedtools is present)
83
+ ruff check .
84
+ mypy
85
+ ```
86
+
87
+ Versioning is driven by git tags (`hatch-vcs`): a release is
88
+ `git tag vX.Y.Z && git push --tags`.
89
+
90
+ ## Intentional differences from the original Galaxy workflow
91
+
92
+ - The workflow patched non-official symbols (`MKL1→MKLN1`, a bug — MKLN1 is a
93
+ different gene; `LYL→LYL1`). Here **no patching**: such symbols are reported
94
+ for correction at the source.
95
+ - The Galaxy output contained a missing merge (`bedtools merge` on
96
+ genome-order-sorted input without `-g`). This tool performs the correct merge.
97
+
98
+ ## License
99
+
100
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,96 @@
1
+ # T2T-CHM13v2.0 gene annotation asset for ont-bed-generator
2
+
3
+ `T2T-CHM13v2.0_genes.chr.gff3.gz` — a **gene-feature-only**, **`chr`-named** GFF3
4
+ derived from the official NCBI RefSeq annotation of T2T-CHM13v2.0, with one
5
+ documented addition (the chrX pseudoautosomal copy of *P2RY8*).
6
+
7
+ It is the annotation input for `ont-bed-generator --gff`. Everything below is
8
+ reproducible with `build_gene_gff.sh`; nothing is hand-edited except the single,
9
+ sourced line described in step 3.
10
+
11
+ > **The pre-built asset is archived on Zenodo:**
12
+ > [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.21341240.svg)](https://doi.org/10.5281/zenodo.21341240)
13
+ > Download it there, or rebuild it byte-for-byte with `build_gene_gff.sh`.
14
+
15
+ ## Source
16
+
17
+ | | |
18
+ |---|---|
19
+ | Assembly | T2T-CHM13v2.0 (`GCF_009914755.1`) |
20
+ | Annotation release | NCBI RefSeq `RS_2025_08` |
21
+ | GFF | `.../GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz` |
22
+ | Assembly report | `.../GCF_009914755.1_T2T-CHM13v2.0_assembly_report.txt` |
23
+
24
+ Base URL: `https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0`
25
+
26
+ ## Production chain (`build_gene_gff.sh`)
27
+
28
+ 1. **Contig map.** Build a `RefSeq-accession -> chr` table from the official
29
+ `assembly_report.txt` (column *RefSeq-Accn* -> column *UCSC-style-name*). No
30
+ hard-coded list: the mapping is read from NCBI's own file.
31
+ 2. **Filter + rename.** Keep only `gene` features (column 3 == `gene`; the only
32
+ thing ont-bed-generator reads) and rename column 1 from the RefSeq accession
33
+ to the `chr` name using the map. Comment/header lines are dropped. This turns
34
+ the ~78 MB full annotation into a ~2 MB gene-only file (41 561 genes).
35
+ 3. **PAR patch — one added line, fully sourced.** The NCBI `genomic.gff` build
36
+ annotates *P2RY8* only on chrY, although *P2RY8* is a **PAR1 gene** and is
37
+ therefore present on both sex chromosomes (its neighbour *CRLF2*, also PAR1,
38
+ *is* annotated on both by NCBI). We add the missing chrX copy:
39
+
40
+ ```
41
+ chrX NCBI_RefSeq_curated_NM_178129.5_PAR1 gene 1304499 1338509 . - . \
42
+ ID=gene-P2RY8-chrX-PAR1;Dbxref=GeneID:286530;Name=P2RY8;gene_biotype=protein_coding
43
+ ```
44
+
45
+ - **Coordinates are not invented.** They are the alignment of NCBI's curated
46
+ transcript `NM_178129.5` to chrX of hs1, as distributed by UCSC
47
+ (`chrX:1304499-1338509`). Confirmed against HGNC (symbol `P2RY8` <-> `ENSG`
48
+ <-> Entrez `286530`) and against the PAR1 gene lists.
49
+ - **Same `GeneID:286530` as the chrY copy**, so ont-bed-generator groups both
50
+ loci under one gene and resolves *P2RY8* to **both** chrX and chrY (it is
51
+ *not* flagged ambiguous — same mechanism as *CRLF2*).
52
+ - The `source` column records the provenance so the line is auditable in-file.
53
+
54
+ 4. **Compress.** `gzip` the result. Feature order is irrelevant —
55
+ ont-bed-generator sorts karyotypically itself.
56
+
57
+ ## Get the asset
58
+
59
+ Either download the archived build from Zenodo
60
+ ([10.5281/zenodo.21341240](https://doi.org/10.5281/zenodo.21341240)), or
61
+ regenerate it:
62
+
63
+ ```bash
64
+ bash build_gene_gff.sh # -> T2T-CHM13v2.0_genes.chr.gff3.gz
65
+ ```
66
+
67
+ Both routes yield the same file for a given NCBI release.
68
+
69
+ ## Verification (performed on this asset)
70
+
71
+ - 41 562 lines, **all** `gene` features (0 non-gene).
72
+ - `P2RY8` present on chrX (1304499-1338509) **and** chrY (1325951-1401516).
73
+ - `ont-bed-generator` resolves both `P2RY8` and `CRLF2` to two loci each, with
74
+ **no** invalid and **no** ambiguous symbols.
75
+
76
+ ## Scope & limitations
77
+
78
+ - Only *P2RY8* is patched. *CRLF2* needs no patch (NCBI annotates it on both X
79
+ and Y natively). No other PAR1 gene in the target panels required a chrX/chrY
80
+ copy; audit the PAR1 gene list against this file if your panel adds one.
81
+ - PAR-gene annotation is **inconsistent across all sources** (NCBI, UCSC,
82
+ Ensembl each differ and each is incomplete for PAR1). This asset takes the
83
+ NCBI annotation as the traceable base and adds the single, biologically
84
+ required, NCBI-sourced chrX *P2RY8* copy — rather than switching to a source
85
+ with its own, different PAR gaps.
86
+ - Tied to NCBI release `RS_2025_08`. Regenerate (and deposit a new Zenodo
87
+ version) when NCBI publishes a new annotation release — ideally after the
88
+ upstream *P2RY8* chrX omission is fixed, at which point step 3 becomes
89
+ unnecessary.
90
+
91
+ ## Citation
92
+
93
+ If you use this asset, please cite the Zenodo record:
94
+ **DOI [10.5281/zenodo.21341240](https://doi.org/10.5281/zenodo.21341240)**.
95
+ It derives from the NCBI RefSeq annotation of T2T-CHM13v2.0 (`GCF_009914755.1`,
96
+ release RS_2025_08); please also credit NCBI RefSeq as the primary source.
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+ # Produce the gene-only, chr-named, PAR-patched GFF3 asset consumed by
3
+ # ont-bed-generator, from the official NCBI RefSeq T2T-CHM13v2.0 annotation.
4
+ set -euo pipefail
5
+
6
+ BASE="https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/009/914/755/GCF_009914755.1_T2T-CHM13v2.0"
7
+ GFF_URL="$BASE/GCF_009914755.1_T2T-CHM13v2.0_genomic.gff.gz"
8
+ REPORT_URL="$BASE/GCF_009914755.1_T2T-CHM13v2.0_assembly_report.txt"
9
+ OUT="T2T-CHM13v2.0_genes.chr.gff3.gz"
10
+
11
+ # 1) accession -> chr map, from the official assembly report
12
+ curl -s "$REPORT_URL" | tr -d '\r' \
13
+ | awk -F'\t' '!/^#/ && $7!="na"{print $7"\t"$10}' > map.tsv
14
+
15
+ # 2) keep only 'gene' features + rename column 1 (accession -> chr); drop comments
16
+ curl -s "$GFF_URL" | zcat \
17
+ | awk -F'\t' -v OFS='\t' '
18
+ NR==FNR { m[$1]=$2; next }
19
+ /^#/ { next }
20
+ $3=="gene" { if ($1 in m) $1=m[$1]; print }
21
+ ' map.tsv - > genes.chr.gff3
22
+
23
+ # 3) append the chrX PAR1 copy of P2RY8 (absent from the NCBI annotation build).
24
+ # Coordinates = NCBI curated transcript NM_178129.5 aligned to chrX (hs1),
25
+ # same GeneID:286530 as the chrY copy -> ont-bed resolves both loci, not ambiguous.
26
+ STRAND=$(awk -F'\t' 'index($9,"Name=P2RY8;"){print $7; exit}' genes.chr.gff3)
27
+ printf 'chrX\tNCBI_RefSeq_curated_NM_178129.5_PAR1\tgene\t1304499\t1338509\t.\t%s\t.\tID=gene-P2RY8-chrX-PAR1;Dbxref=GeneID:286530;Name=P2RY8;gene_biotype=protein_coding\n' "$STRAND" >> genes.chr.gff3
28
+
29
+ # 4) compress (order is irrelevant; ont-bed-generator sorts karyotypically itself)
30
+ gzip -c genes.chr.gff3 > "$OUT"
31
+ echo "written: $OUT"
@@ -0,0 +1,11 @@
1
+ name: ont-bed-generator
2
+ channels:
3
+ - conda-forge
4
+ - bioconda
5
+ dependencies:
6
+ - python>=3.10
7
+ - pip
8
+ # bedtools is used ONLY by the parity test (the package has no runtime dep on it)
9
+ - bedtools>=2.31
10
+ - pip:
11
+ - -e .[dev]
@@ -0,0 +1,63 @@
1
+ [build-system]
2
+ requires = ["hatchling", "hatch-vcs"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "ont-bed-generator"
7
+ description = "Generate BED files for Oxford Nanopore adaptive sampling from a gene list and a RefSeq GFF3."
8
+ readme = "README.md"
9
+ license = { file = "LICENSE" }
10
+ requires-python = ">=3.10"
11
+ authors = [{ name = "Christophe Antoniewski" }]
12
+ keywords = ["nanopore", "adaptive-sampling", "bed", "bioinformatics", "genomics"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Intended Audience :: Science/Research",
17
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
18
+ "Operating System :: OS Independent",
19
+ ]
20
+ # No runtime dependencies: standard library only.
21
+ dependencies = []
22
+ dynamic = ["version"]
23
+
24
+ [project.urls]
25
+ Homepage = "https://github.com/Institut-Leucemie/ont-bed-generator"
26
+ Issues = "https://github.com/Institut-Leucemie/ont-bed-generator/issues"
27
+
28
+ [project.optional-dependencies]
29
+ dev = ["pytest>=7", "ruff>=0.4", "mypy>=1.8", "build>=1.2"]
30
+
31
+ [project.scripts]
32
+ ont-bed-generator = "ont_bed_generator.cli:main"
33
+
34
+ # ── Versioning driven by git tags (hatch-vcs) ──
35
+ [tool.hatch.version]
36
+ source = "vcs"
37
+
38
+ [tool.hatch.build.hooks.vcs]
39
+ version-file = "src/ont_bed_generator/_version.py"
40
+
41
+ [tool.hatch.build.targets.wheel]
42
+ packages = ["src/ont_bed_generator"]
43
+
44
+ # ── Quality tools ──
45
+ [tool.ruff]
46
+ line-length = 100
47
+ target-version = "py310"
48
+
49
+ [tool.ruff.lint]
50
+ select = ["E", "F", "I", "UP", "B"]
51
+
52
+ [tool.mypy]
53
+ python_version = "3.10"
54
+ strict = true
55
+ files = ["src"]
56
+
57
+ [[tool.mypy.overrides]]
58
+ module = "ont_bed_generator._version"
59
+ ignore_missing_imports = true
60
+
61
+ [tool.pytest.ini_options]
62
+ testpaths = ["tests"]
63
+ addopts = "-ra"