triohap 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.
- triohap-0.4.0/CHANGELOG.md +46 -0
- triohap-0.4.0/GVCF.md +103 -0
- triohap-0.4.0/LICENSE +21 -0
- triohap-0.4.0/MANIFEST.in +14 -0
- triohap-0.4.0/PKG-INFO +345 -0
- triohap-0.4.0/PUBLISHING.md +98 -0
- triohap-0.4.0/README.md +312 -0
- triohap-0.4.0/SCN5A.md +112 -0
- triohap-0.4.0/VALIDATION.txt +53 -0
- triohap-0.4.0/examples/gvcf/README.md +36 -0
- triohap-0.4.0/examples/gvcf/all-sites.vcf +12 -0
- triohap-0.4.0/examples/gvcf/child.vcf +12 -0
- triohap-0.4.0/examples/gvcf/father.vcf +12 -0
- triohap-0.4.0/examples/gvcf/joint.vcf +12 -0
- triohap-0.4.0/examples/gvcf/mother.vcf +12 -0
- triohap-0.4.0/examples/gvcf/panel.tsv +4 -0
- triohap-0.4.0/examples/individual/child.vcf +16 -0
- triohap-0.4.0/examples/individual/father.vcf +16 -0
- triohap-0.4.0/examples/individual/mother.vcf +16 -0
- triohap-0.4.0/examples/panel.tsv +10 -0
- triohap-0.4.0/examples/trio.vcf +16 -0
- triohap-0.4.0/examples/unfazed.vcf +8 -0
- triohap-0.4.0/pyproject.toml +48 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/CITATION.cff +40 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/LICENSE +21 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/README.md +21 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/config/config.yaml +68 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/provenance.yaml +26 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/tables/haplotype_assignments.core.tsv +464 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/tables/haplotype_matrix.core.tsv +464 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/tables/haplotypes.core.tsv +47 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/tables/summary.core.json +16 -0
- triohap-0.4.0/reference-data/scn5a-promoter-pangenome/results/tables/variant_sites.core.tsv +46 -0
- triohap-0.4.0/scn5a-panel/audit.json +151 -0
- triohap-0.4.0/scn5a-panel/catalogue.json +5756 -0
- triohap-0.4.0/scn5a-panel/markers.snps.bed +37 -0
- triohap-0.4.0/scn5a-panel/panel.snps.tsv +38 -0
- triohap-0.4.0/scn5a-panel/validation.json +12 -0
- triohap-0.4.0/scripts/validate_distribution.py +227 -0
- triohap-0.4.0/scripts/validate_gvcf.py +186 -0
- triohap-0.4.0/scripts/validate_synthetic.py +168 -0
- triohap-0.4.0/setup.cfg +4 -0
- triohap-0.4.0/tests/test_catalogue.py +121 -0
- triohap-0.4.0/tests/test_gvcf.py +373 -0
- triohap-0.4.0/tests/test_individual_vcfs.py +253 -0
- triohap-0.4.0/tests/test_inference.py +312 -0
- triohap-0.4.0/tests/test_origin.py +48 -0
- triohap-0.4.0/tests/test_source_provenance.py +16 -0
- triohap-0.4.0/triohap/__init__.py +2 -0
- triohap-0.4.0/triohap/__main__.py +3 -0
- triohap-0.4.0/triohap/catalogue.py +297 -0
- triohap-0.4.0/triohap/catalogue_plot.py +248 -0
- triohap-0.4.0/triohap/cli.py +73 -0
- triohap-0.4.0/triohap/core.py +320 -0
- triohap-0.4.0/triohap/gvcf.py +261 -0
- triohap-0.4.0/triohap/origin.py +85 -0
- triohap-0.4.0/triohap/report.py +261 -0
- triohap-0.4.0/triohap/vcf.py +431 -0
- triohap-0.4.0/triohap.egg-info/PKG-INFO +345 -0
- triohap-0.4.0/triohap.egg-info/SOURCES.txt +64 -0
- triohap-0.4.0/triohap.egg-info/dependency_links.txt +1 -0
- triohap-0.4.0/triohap.egg-info/entry_points.txt +2 -0
- triohap-0.4.0/triohap.egg-info/requires.txt +8 -0
- triohap-0.4.0/triohap.egg-info/top_level.txt +1 -0
- triohap-0.4.0/validation/gvcf_summary.json +14 -0
- triohap-0.4.0/validation/synthetic_summary.json +13 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
- License TrioHap under MIT and include the licence in both PyPI distributions.
|
|
6
|
+
- Prepare the first PyPI distribution under the name `triohap` (previous local
|
|
7
|
+
wheels used `triohap-prototype`); the Python import and command stay `triohap`.
|
|
8
|
+
- Add Trusted Publishing, wheel/source-archive validation, project metadata,
|
|
9
|
+
complete source-distribution test fixtures, and `triohap --version`.
|
|
10
|
+
- Automatically detect VCF and conventional END-based gVCF input from content,
|
|
11
|
+
using the existing joint and three-file arguments; mixed input is supported.
|
|
12
|
+
- Materialize explicit homozygous-reference block evidence only at panel SNPs
|
|
13
|
+
and explicit trio SNP anchors, with per-sample quality and coverage checks.
|
|
14
|
+
- Preserve unknown calls, explicit-record precedence, wildcard allele indices,
|
|
15
|
+
and overlapping unsupported-variant exclusions. Reject ambiguous blocks and
|
|
16
|
+
unsupported sample-specific FORMAT/LEN blocks rather than guessing calls.
|
|
17
|
+
- Report detected formats, reference-block processing counts, and call sources.
|
|
18
|
+
- Add synthetic VCF/gVCF equivalence tests and reproducible examples.
|
|
19
|
+
|
|
20
|
+
## 0.3.0
|
|
21
|
+
|
|
22
|
+
- Preserve the original SCN5A source-table line endings so saved byte checksums
|
|
23
|
+
remain reproducible after checkout; test exact catalogue reimport.
|
|
24
|
+
|
|
25
|
+
- Establish `comparativechrono/TrioHap` as the project repository.
|
|
26
|
+
- Accept either a joint VCF or three individual VCFs with explicit role/sample
|
|
27
|
+
selections. Decode each file's REF/ALT allele dictionary independently.
|
|
28
|
+
- Preserve child phase sets and the same quality filters in both input modes.
|
|
29
|
+
Absent records remain unknown; only complete usable trio sites are scored.
|
|
30
|
+
- Report input files, per-file metadata and exclusions. Reject incompatible
|
|
31
|
+
references and contig lengths before combining individual inputs.
|
|
32
|
+
- Add deterministic synthetic equivalence and truth-recovery validation, plus
|
|
33
|
+
automated unit tests and report-generation checks.
|
|
34
|
+
- Result schema is now `0.2`: individual inputs use a structured `sources.trio`
|
|
35
|
+
object; joint inputs retain the original path string.
|
|
36
|
+
|
|
37
|
+
## 0.2.0
|
|
38
|
+
|
|
39
|
+
- Import the SCN5A source catalogue, retaining all 46 class identities and
|
|
40
|
+
full-variant graph topology while matching on the 37 supported SNP records.
|
|
41
|
+
- Preserve SNP-equivalent candidate sets and panel provenance.
|
|
42
|
+
|
|
43
|
+
## 0.1.0
|
|
44
|
+
|
|
45
|
+
- Initial joint-trio SNP matcher, phase-block handling, ambiguity-aware ranking,
|
|
46
|
+
optional Unfazed annotation, and self-contained reports.
|
triohap-0.4.0/GVCF.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Automatic VCF and gVCF input
|
|
2
|
+
|
|
3
|
+
The same `--trio` or `--child-vcf` / `--mother-vcf` / `--father-vcf` arguments
|
|
4
|
+
accept ordinary VCFs and conventional gVCFs. No format flag is required. The
|
|
5
|
+
three individual inputs may use different encodings, and compressed input is
|
|
6
|
+
supported. Explicit child GT order and PS blocks retain their existing meaning.
|
|
7
|
+
|
|
8
|
+
## Detection and supported records
|
|
9
|
+
|
|
10
|
+
Detection uses observed `<NON_REF>` or `<*>` alleles, GVCFBlock metadata, and
|
|
11
|
+
nonvariant END records. A filename or a standalone NON_REF ALT declaration in
|
|
12
|
+
the header is insufficient. Genotyped VCFs can retain that declaration without
|
|
13
|
+
containing any gVCF blocks.
|
|
14
|
+
|
|
15
|
+
The supported compressed representation is a nonvariant record with one
|
|
16
|
+
reference base, `INFO/END`, and no literal alternate allele: `ALT=<NON_REF>`,
|
|
17
|
+
`ALT=<*>`, or `ALT=.`. Both block endpoints are included. Unbanded wildcard
|
|
18
|
+
reference records can also contribute evidence at their explicit position.
|
|
19
|
+
END on a deletion or another structural variant is not a reference block.
|
|
20
|
+
|
|
21
|
+
A SNP record with `ALT=C,<NON_REF>` and `GT=0/1` has a literal A/C call when
|
|
22
|
+
REF is A. The unused symbolic allele is not scored. `GT=0/2` at the same record
|
|
23
|
+
is unresolved and excluded. Allele indices are decoded before symbols are
|
|
24
|
+
handled; they are never renumbered by stripping the ALT list. Bare `*` is a
|
|
25
|
+
spanning-deletion allele and is not interchangeable with `<*>`.
|
|
26
|
+
|
|
27
|
+
## Reference-call requirements
|
|
28
|
+
|
|
29
|
+
Each selected sample is evaluated independently, including samples in a joint
|
|
30
|
+
file. An expanded call requires:
|
|
31
|
+
|
|
32
|
+
- A complete diploid homozygous-reference GT (`0/0` or `0|0`).
|
|
33
|
+
- FILTER and sample FT equal to PASS, dot, or absent where allowed.
|
|
34
|
+
- At least one supplied, finite, positive GQ, RGQ, or GQX value. The minimum
|
|
35
|
+
available value must meet `--min-gq`; zero-quality reference calls remain
|
|
36
|
+
unknown even when the requested threshold is zero.
|
|
37
|
+
- No known zero DP or MIN_DP. Missing depth can be retained with usable
|
|
38
|
+
quality, but its absence is reported in provenance. MED_DP is not used as a
|
|
39
|
+
substitute for minimum depth.
|
|
40
|
+
|
|
41
|
+
Malformed quality, depth, and interval fields are errors rather than invented
|
|
42
|
+
confidence. Missing quality, failed filters, incomplete/non-reference GTs,
|
|
43
|
+
and low quality produce exclusions. The program does not estimate missing
|
|
44
|
+
genotypes from likelihoods or population frequency.
|
|
45
|
+
|
|
46
|
+
For explicit SNP records, GQX is also honored alongside GQ, using the lower
|
|
47
|
+
available value. RGQ applies to homozygous-reference genotypes. As in earlier
|
|
48
|
+
versions, explicit SNP calls lacking quality fields are retained but counted
|
|
49
|
+
as lacking quality; a threshold cannot validate missing quality.
|
|
50
|
+
|
|
51
|
+
## Coordinates, precedence, and phasing
|
|
52
|
+
|
|
53
|
+
Only panel SNPs and explicit SNPs from the trio are considered as targets.
|
|
54
|
+
This retains trio-only phase anchors without expanding every base in a
|
|
55
|
+
reference block. A block starting before the selected region can cover a
|
|
56
|
+
target inside it. END is inclusive.
|
|
57
|
+
|
|
58
|
+
The block REF identifies the nucleotide at its start only. For an interior
|
|
59
|
+
target, the reference base comes from the panel or an explicit SNP record at
|
|
60
|
+
that position. Inputs must share reference build and contig naming. Known
|
|
61
|
+
build/contig-length conflicts and REF disagreements are rejected; no FASTA
|
|
62
|
+
validation or liftover is performed.
|
|
63
|
+
|
|
64
|
+
An explicit record always takes precedence at its position, including a
|
|
65
|
+
no-call, failed filter, or unsupported variant. Unsupported variant spans
|
|
66
|
+
also prevent a reference block from filling affected positions. Overlapping
|
|
67
|
+
reference blocks in one input are rejected so a conflicting quality or call
|
|
68
|
+
cannot be selected arbitrarily.
|
|
69
|
+
|
|
70
|
+
Reference blocks provide homozygous calls, not new heterozygous phase links.
|
|
71
|
+
Existing child variant GT/PS evidence is preserved. A trio-only SNP may orient
|
|
72
|
+
a child phase block when the other members have usable covering reference
|
|
73
|
+
blocks; a missing or rejected parental call cannot provide that anchor.
|
|
74
|
+
|
|
75
|
+
## Reporting and API
|
|
76
|
+
|
|
77
|
+
`input_metadata` in `matches.json` records each file's detected format,
|
|
78
|
+
detection evidence, block count, and materialized/excluded reference-call
|
|
79
|
+
counts. These input-processing counts precede the final shared-marker and
|
|
80
|
+
Mendelian filters. Retained SNP records with expanded calls include
|
|
81
|
+
`call_sources` identifying the contributing block. The HTML report summarizes
|
|
82
|
+
input detection; detailed exclusions remain available in JSON and TSV.
|
|
83
|
+
|
|
84
|
+
Python callers can pass `reference_sites=panel['records']` to either
|
|
85
|
+
`read_trio_vcf` or `read_trio_vcfs`. Without this argument, only explicit trio
|
|
86
|
+
SNP targets can be recovered; reference blocks do not supply an entire local
|
|
87
|
+
reference sequence. The CLI passes the panel's sites automatically.
|
|
88
|
+
|
|
89
|
+
## Limits and sources
|
|
90
|
+
|
|
91
|
+
Newer VCF 4.5 sample-specific FORMAT/LEN blocks and implicit GT inheritance are
|
|
92
|
+
not implemented and produce an explicit unsupported-encoding error. This
|
|
93
|
+
restriction avoids applying sample-specific intervals as if they were shared
|
|
94
|
+
END blocks. BCF and indexed random access remain future work.
|
|
95
|
+
|
|
96
|
+
The implementation uses hard genotypes and confidence fields; it is not a
|
|
97
|
+
replacement for a joint variant caller. It still matches diploid autosomal
|
|
98
|
+
SNP backgrounds and has been tested only on synthetic trios.
|
|
99
|
+
|
|
100
|
+
- [GATK gVCF format](https://gatk.broadinstitute.org/hc/en-us/articles/360035531812-GVCF-Genomic-Variant-Call-Format)
|
|
101
|
+
- [DeepVariant gVCF support](https://github.com/google/deepvariant/blob/r1.10/docs/deepvariant-gvcf-support.md)
|
|
102
|
+
- [Illumina gVCF conventions](https://help.basespace.illumina.com/files-used-by-basespace/gvcf-files)
|
|
103
|
+
- [VCF 4.5 specification, reference blocks](https://samtools.github.io/hts-specs/VCFv4.5.pdf)
|
triohap-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 comparativechrono and TrioHap contributors
|
|
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,14 @@
|
|
|
1
|
+
include README.md CHANGELOG.md GVCF.md SCN5A.md PUBLISHING.md VALIDATION.txt
|
|
2
|
+
include MANIFEST.in LICENSE
|
|
3
|
+
recursive-include tests *.py
|
|
4
|
+
recursive-include scripts *.py
|
|
5
|
+
recursive-include examples *.vcf *.tsv *.md
|
|
6
|
+
recursive-include reference-data/scn5a-promoter-pangenome *.md *.cff *.yaml *.tsv *.json
|
|
7
|
+
include reference-data/scn5a-promoter-pangenome/LICENSE
|
|
8
|
+
include scn5a-panel/catalogue.json
|
|
9
|
+
include scn5a-panel/panel.snps.tsv
|
|
10
|
+
include scn5a-panel/markers.snps.bed
|
|
11
|
+
include scn5a-panel/audit.json
|
|
12
|
+
include scn5a-panel/validation.json
|
|
13
|
+
recursive-include validation *.json
|
|
14
|
+
global-exclude __pycache__ *.py[cod]
|
triohap-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: triohap
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Trio-aware matching of VCF and gVCF genotypes to regional pangenome haplotypes
|
|
5
|
+
Maintainer: comparativechrono
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/comparativechrono/TrioHap
|
|
8
|
+
Project-URL: Documentation, https://github.com/comparativechrono/TrioHap/blob/main/README.md
|
|
9
|
+
Project-URL: Source, https://github.com/comparativechrono/TrioHap
|
|
10
|
+
Project-URL: Issues, https://github.com/comparativechrono/TrioHap/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/comparativechrono/TrioHap/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: bioinformatics,pangenome,haplotype,trio,VCF,gVCF
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
23
|
+
Requires-Python: >=3.10
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Provides-Extra: plots
|
|
27
|
+
Requires-Dist: numpy>=1.24; extra == "plots"
|
|
28
|
+
Requires-Dist: matplotlib>=3.7; extra == "plots"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
31
|
+
Requires-Dist: twine>=6.1; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# TrioHap
|
|
35
|
+
|
|
36
|
+
Rank assembly-derived regional haplotype matches for a child using the child,
|
|
37
|
+
mother and father's SNP genotypes. Show the maternal and paternal assignments
|
|
38
|
+
on a marker-similarity network, preserving ambiguous matches and extra variants.
|
|
39
|
+
|
|
40
|
+
This is a small, inspectable research prototype, not a clinically validated
|
|
41
|
+
genotyper. Development lives in
|
|
42
|
+
[comparativechrono/TrioHap](https://github.com/comparativechrono/TrioHap).
|
|
43
|
+
The matching engine uses Python's standard library. Plots require NumPy and
|
|
44
|
+
Matplotlib. The PyPI distribution is named **`triohap`**.
|
|
45
|
+
|
|
46
|
+
Version 0.4 automatically detects VCF and conventional gVCF input, including
|
|
47
|
+
mixed individual files. Both input modes feed the same trio inference model
|
|
48
|
+
and produce the same rankings for equivalent evidence. SCN5A catalogue import
|
|
49
|
+
preserves full haplotype identities and graph topology; see [SCN5A.md](https://github.com/comparativechrono/TrioHap/blob/main/SCN5A.md).
|
|
50
|
+
All trio testing so far is synthetic.
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
Install with Python 3.10 or newer:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
python -m pip install 'triohap[plots]'
|
|
58
|
+
triohap --version
|
|
59
|
+
triohap --help
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
For the standard-library matching engine without graph dependencies, install
|
|
63
|
+
`triohap` and pass `--no-plot`. Plotting is optional, but enabled by default in
|
|
64
|
+
the command, so the `[plots]` installation is recommended for normal use.
|
|
65
|
+
|
|
66
|
+
The package name, command, and Python import are all `triohap`. Older local
|
|
67
|
+
prototype wheels were called `triohap-prototype`; uninstall that distribution
|
|
68
|
+
before installing `triohap`, because both contain the same Python package.
|
|
69
|
+
The wheel contains the application. The source distribution also contains the
|
|
70
|
+
examples, tests, documentation, and SCN5A provenance fixtures; these are not
|
|
71
|
+
installed into Python's package directory. The source archive can be unpacked
|
|
72
|
+
to run the examples below, or use a repository checkout.
|
|
73
|
+
|
|
74
|
+
## Run the synthetic example
|
|
75
|
+
|
|
76
|
+
From this directory, with Python 3.10 or newer:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
python -m pip install '.[plots]'
|
|
80
|
+
python -m triohap \
|
|
81
|
+
--trio examples/trio.vcf --panel examples/panel.tsv \
|
|
82
|
+
--child child --mother mother --father father \
|
|
83
|
+
--region chr1:100-290 --build synthetic \
|
|
84
|
+
--unfazed-vcf examples/unfazed.vcf \
|
|
85
|
+
--title 'Synthetic example: two inherited backgrounds' \
|
|
86
|
+
--out example-run
|
|
87
|
+
python -m unittest discover -s tests -v
|
|
88
|
+
python scripts/validate_synthetic.py
|
|
89
|
+
python scripts/validate_gvcf.py
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The expected result is maternal **H1/H1_like** (indistinguishable on observed
|
|
93
|
+
SNPs), paternal **H2**, with an inherited mismatch at position 200. Position
|
|
94
|
+
220 is Mendelian-inconsistent and excluded from the matching score; the
|
|
95
|
+
separate synthetic Unfazed file places its alternate allele on the paternal
|
|
96
|
+
background. Position 240 is present only in the trio file. Position 260 is
|
|
97
|
+
present only in the panel and must not distinguish H1 from H1_like. Position
|
|
98
|
+
280 has a missing father genotype and is excluded.
|
|
99
|
+
|
|
100
|
+
## Inputs
|
|
101
|
+
|
|
102
|
+
1. A joint trio VCF/gVCF (`--trio`), or three individual files (`--child-vcf`,
|
|
103
|
+
`--mother-vcf`, `--father-vcf`), with explicit diploid GTs. VCF versus gVCF
|
|
104
|
+
is detected automatically from content; no type flag is required. Plain and
|
|
105
|
+
gzip-compressed inputs are supported. Specify sample names through `--child`,
|
|
106
|
+
`--mother` and `--father`. Genotype quality filtering is available with
|
|
107
|
+
`--min-gq`; genotype likelihoods are not used.
|
|
108
|
+
2. A panel VCF with phased diploid or haploid samples, or a tab-separated allele
|
|
109
|
+
matrix. Each panel column identifies an assembly haplotype. In a diploid VCF,
|
|
110
|
+
the two phased sample chromosomes become separate panel entries.
|
|
111
|
+
3. One autosomal region, using `CHROM:START-END` (1-based, inclusive).
|
|
112
|
+
4. `--build` records the coordinate reference you assert the inputs use. It is
|
|
113
|
+
provenance, **not** a liftover or reference-sequence validation procedure.
|
|
114
|
+
|
|
115
|
+
Panel TSV example:
|
|
116
|
+
|
|
117
|
+
```text
|
|
118
|
+
CHROM POS REF assembly_A_hap1 assembly_B_hap2
|
|
119
|
+
chr1 100 A G A
|
|
120
|
+
chr1 120 C C T
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Use real tabs, A/C/G/T alleles, and `.` for missing. The same locus/reference
|
|
124
|
+
coordinates must be used in both files. A VCF REF disagreement is an error.
|
|
125
|
+
Allele order may differ: actual nucleotides, not numeric ALT indices, are
|
|
126
|
+
compared. Duplicate positions must be reconciled upstream; this prototype
|
|
127
|
+
does not silently combine split multiallelic records.
|
|
128
|
+
|
|
129
|
+
Only shared usable SNP calls enter the matching calculation. Missing VCF
|
|
130
|
+
records are **unknown**, never automatically homozygous reference. For gVCFs,
|
|
131
|
+
explicit reference-confidence blocks can supply calls at the panel's SNP
|
|
132
|
+
positions and explicit trio SNP anchors. Blocks must pass the checks described
|
|
133
|
+
below; uncovered positions remain unknown.
|
|
134
|
+
The panel must supply complete calls at each used marker across all candidate
|
|
135
|
+
haplotypes; incomplete markers are dropped globally, with diagnostics.
|
|
136
|
+
|
|
137
|
+
### Three individual VCFs
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
python -m triohap \
|
|
141
|
+
--child-vcf examples/individual/child.vcf \
|
|
142
|
+
--mother-vcf examples/individual/mother.vcf \
|
|
143
|
+
--father-vcf examples/individual/father.vcf \
|
|
144
|
+
--child child --mother mother --father father \
|
|
145
|
+
--panel examples/panel.tsv \
|
|
146
|
+
--region chr1:100-290 --build synthetic \
|
|
147
|
+
--out example-run-individual
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Supply all three paths together; they cannot be mixed with `--trio`. Each
|
|
151
|
+
sample ID selects a column in its corresponding file. Files may contain
|
|
152
|
+
additional samples. The same sample name (for example `SAMPLE`) is allowed
|
|
153
|
+
in different files; the CLI role specifies which family member it represents.
|
|
154
|
+
|
|
155
|
+
The reader compares coordinates and REF alleles, decodes each file's ALT
|
|
156
|
+
indices independently, and preserves the child's GT order and PS values.
|
|
157
|
+
Different ALT ordering or different called alternate alleles do not require
|
|
158
|
+
a joint-genotyping step. Known build/contig-length conflicts or disagreeing
|
|
159
|
+
REF alleles are errors; no liftover or allele normalization is performed.
|
|
160
|
+
|
|
161
|
+
Only sites with usable evidence for **all three** people enter the
|
|
162
|
+
current model. A missing parent record, `./.`, a failed FILTER/FT, or a call
|
|
163
|
+
below the requested GQ threshold cannot be replaced by `0/0`. Exclusions are
|
|
164
|
+
reported. This means variant-only individual VCFs can provide much less
|
|
165
|
+
evidence than joint VCFs with reference calls. Supply gVCFs, explicit all-sites
|
|
166
|
+
VCFs, or targeted genotypes when reference evidence is needed. An explicit
|
|
167
|
+
failed or missing call takes precedence over a covering reference block.
|
|
168
|
+
|
|
169
|
+
The three-file mode preserves parental uncertainty in exactly the same way
|
|
170
|
+
as the joint mode. It does not infer parental phase from the order of alleles
|
|
171
|
+
in unphased GTs, and it does not equate phase-set numbers across family members.
|
|
172
|
+
|
|
173
|
+
### Automatic gVCF input
|
|
174
|
+
|
|
175
|
+
Use the same arguments for `.vcf`, `.g.vcf`, `.gvcf`, or their gzip-compressed
|
|
176
|
+
versions. The filename does not decide the input type. For example:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
triohap \
|
|
180
|
+
--child-vcf child.g.vcf.gz --mother-vcf mother.g.vcf.gz --father-vcf father.vcf.gz \
|
|
181
|
+
--child CHILD --mother MOTHER --father FATHER \
|
|
182
|
+
--panel scn5a-panel/catalogue.json \
|
|
183
|
+
--region chr3:38649188-38652187 --build GRCh38 \
|
|
184
|
+
--min-gq 20 --out family-scn5a
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Conventional `INFO/END` blocks with `<NON_REF>`, `<*>`, or nonvariant `ALT=.`
|
|
188
|
+
are supported. Block calls require diploid `0/0`, usable FILTER/FT, and a
|
|
189
|
+
present positive quality meeting `--min-gq`. The most conservative available
|
|
190
|
+
GQ/RGQ/GQX is used for blocks. Known zero DP or MIN_DP excludes a block call;
|
|
191
|
+
missing depth is recorded but does not by itself override usable quality.
|
|
192
|
+
Explicit SNP records may contain an unused wildcard ALT without losing their
|
|
193
|
+
literal genotype calls. Calling the wildcard itself remains unresolved.
|
|
194
|
+
|
|
195
|
+
Blocks are queried only at relevant SNP positions, including blocks beginning
|
|
196
|
+
before the requested region. Interior reference bases come from the same-build
|
|
197
|
+
panel or explicit SNP records, not the block's first base. The report shows
|
|
198
|
+
detected formats and reference-call counts; JSON records each expanded call's
|
|
199
|
+
source. See [GVCF.md](https://github.com/comparativechrono/TrioHap/blob/main/GVCF.md) for the precise rules and supported encodings.
|
|
200
|
+
|
|
201
|
+
This consumes hard-called evidence; it does not perform joint genotyping or
|
|
202
|
+
use PL/GL likelihoods. Newer VCF 4.5 sample-specific `FORMAT/LEN` blocks are
|
|
203
|
+
currently rejected with an explicit error. Indel/SV genotypes remain outside
|
|
204
|
+
the matching model.
|
|
205
|
+
|
|
206
|
+
The prototype accepts neither raw unaligned haplotype FASTA nor a GFA graph.
|
|
207
|
+
First project assembly haplotypes to comparable SNP coordinates, retaining
|
|
208
|
+
their original assembly IDs. FASTA-to-panel preparation is a separate proposed
|
|
209
|
+
module; it must resolve orthology, coordinate mapping and paralog ambiguity.
|
|
210
|
+
|
|
211
|
+
## Inference
|
|
212
|
+
|
|
213
|
+
At each Mendelian-consistent SNP, enumerate possible maternal and paternal
|
|
214
|
+
transmitted alleles conditional on the trio GTs. Do not force origin when all
|
|
215
|
+
three are heterozygous. For each ordered pair of panel haplotypes, sum over
|
|
216
|
+
the possible transmissions using mismatch-tolerant emissions. A match has
|
|
217
|
+
weight `1-epsilon`; a different nucleotide has weight `epsilon/3`.
|
|
218
|
+
|
|
219
|
+
For externally phased child SNPs, marginalize two **whole-block** orientations.
|
|
220
|
+
Informative trio SNPs anchor a block to parental origin. The first GT allele
|
|
221
|
+
is not inherently maternal. Separate PS blocks orient independently. Following
|
|
222
|
+
VCF semantics, phased GTs without PS share an implicit phase set on a chromosome.
|
|
223
|
+
Contradictory Mendelian anchors in one phase block cause an explicit error;
|
|
224
|
+
`--ignore-phase` deliberately discards external phase when investigating it.
|
|
225
|
+
Parent GT phase blocks are not modeled in this first version.
|
|
226
|
+
|
|
227
|
+
Panel haplotypes identical at the observed, scored markers form one equivalence
|
|
228
|
+
class. Ranking gives each distinct observed class equal prior weight; adding
|
|
229
|
+
duplicate assemblies does not inflate support. Pair scores are normalized
|
|
230
|
+
across **all** ordered class pairs before the top-N rows are reported.
|
|
231
|
+
|
|
232
|
+
The resulting relative weights are conditional on the chosen panel, markers,
|
|
233
|
+
hard calls, phase and mismatch parameter. They are **not calibrated clinical
|
|
234
|
+
posterior probabilities**. SNPs in LD are not independent observations of an
|
|
235
|
+
ancestral history. The score does not establish unobserved SVs or prove identity
|
|
236
|
+
to an entire assembly sequence. There is no 'none of the above' model: inspect
|
|
237
|
+
absolute mismatches and marker coverage even when relative weight is high.
|
|
238
|
+
|
|
239
|
+
## Outputs
|
|
240
|
+
|
|
241
|
+
- `matches.json`: model, provenance, classes, top ordered pairs, marginal
|
|
242
|
+
rankings, marker evidence and diagnostics. It records input mode and file
|
|
243
|
+
provenance. Under result schema `0.2`, `sources.trio` is a path for joint
|
|
244
|
+
input and a role/file/sample object for individual input.
|
|
245
|
+
- `ranked_pairs.tsv`: best maternal/paternal class combinations.
|
|
246
|
+
- `diagnostics.tsv`: omitted, unmatched and problematic records.
|
|
247
|
+
- `mismatches.tsv`: observed alleles differing from the first best-scoring pair.
|
|
248
|
+
- `haplotype_graph.svg` / `.png`: SNP similarity network and observed-allele
|
|
249
|
+
comparison, with two virtual proband chromosome nodes.
|
|
250
|
+
- `report.html`: self-contained report containing the graph and results.
|
|
251
|
+
|
|
252
|
+
Graph edges between panel nodes show a deterministic minimum spanning tree
|
|
253
|
+
of Hamming distances over the scored marker signatures. Edge labels count
|
|
254
|
+
different marker alleles. This is a compact similarity network, not a
|
|
255
|
+
genealogy, recombination graph or sequence-level pangenome graph. Dashed colored
|
|
256
|
+
links show leading marginal placements of each proband chromosome, including
|
|
257
|
+
ties. For large panels the image displays a stated subset; the JSON retains
|
|
258
|
+
all classes and marginals. The first listed pair in a tie is not a unique call.
|
|
259
|
+
|
|
260
|
+
## Optional Unfazed integration
|
|
261
|
+
|
|
262
|
+
The PyPI package matching the discussion appears to be
|
|
263
|
+
[unfazed-bioinformatics](https://pypi.org/project/unfazed-bioinformatics/), the
|
|
264
|
+
maintained fork of Jonathan Belyeu's Unfazed. Its identity as the user's package
|
|
265
|
+
has not been independently confirmed. It phases de novo variants to parental
|
|
266
|
+
origin; it is not a general regional haplotype matching program.
|
|
267
|
+
|
|
268
|
+
`--unfazed-vcf` accepts its documented parent-ordered VCF output as **annotation**
|
|
269
|
+
of additional variants. A provenance header stating `1|0 is paternal, 0|1 is
|
|
270
|
+
maternal` is required. Only confident evidence types UET 0/1/2 with phased GTs
|
|
271
|
+
are assigned to a parental background. Ambiguous evidence is retained without
|
|
272
|
+
an assignment. Sex-chromosome autophasing is outside this prototype. UOPS is
|
|
273
|
+
reported as a count, not converted to probability. These annotations do not
|
|
274
|
+
alter the panel ranking, avoiding double-counting the same reads/markers.
|
|
275
|
+
Sample FT filters, obvious declared build conflicts, and disagreements with
|
|
276
|
+
overlapping trio REF/GT calls are checked. Where metadata or trio calls are
|
|
277
|
+
absent, annotation consistency cannot be established from this file alone.
|
|
278
|
+
|
|
279
|
+
## Scope and next development steps
|
|
280
|
+
|
|
281
|
+
The current model is diploid, autosomal, SNP-based and fixed to one panel
|
|
282
|
+
haplotype per parental chromosome across the selected region. It excludes
|
|
283
|
+
Mendelian-inconsistent sites rather than estimating de novo or genotyping-error
|
|
284
|
+
probabilities. Indels/SVs/CNVs, sex chromosomes, mosaicism, PL/GL integration,
|
|
285
|
+
within-region recombination, parent phase propagation and a sparse-panel
|
|
286
|
+
missingness model remain future work. FASTA/GFA panel preparation and indexed
|
|
287
|
+
BCF/VCF access are also future work. Large files are streamed but not region
|
|
288
|
+
indexed. The pair search scales quadratically in distinct haplotype classes. Deterministic
|
|
289
|
+
phase contributions are cached; ambiguous-block work is capped at 25 million
|
|
290
|
+
pair/block combinations in this prototype.
|
|
291
|
+
|
|
292
|
+
Before clinical use: test on independent trios with assembly/long-read truth;
|
|
293
|
+
leave entire families out of the panel; evaluate private variants, phase-switch
|
|
294
|
+
errors, ancestry representation and missingness; calibrate no-call/ambiguity
|
|
295
|
+
criteria and sensitivity to epsilon. Do not infer clinical correctness from
|
|
296
|
+
the synthetic unit tests.
|
|
297
|
+
|
|
298
|
+
## Development and reproducibility
|
|
299
|
+
|
|
300
|
+
Run `python -m unittest discover -s tests -v` and
|
|
301
|
+
`python scripts/validate_synthetic.py` from the repository root. The latter
|
|
302
|
+
constructs known inherited haplotypes and independently encodes equivalent
|
|
303
|
+
joint and individual VCFs, then checks truth recovery and matching equivalence.
|
|
304
|
+
It also checks deliberate missingness. These are software correctness checks,
|
|
305
|
+
not estimates of performance on clinical data.
|
|
306
|
+
|
|
307
|
+
GitHub Actions runs the test suite on Python 3.10–3.13 and exercises graph
|
|
308
|
+
generation separately. `demo-output/` and `demo-individual-output/` contain equivalent synthetic
|
|
309
|
+
reports from the two input modes;
|
|
310
|
+
`scn5a-panel/` contains the imported reference catalogue and its panel audit.
|
|
311
|
+
Source tables used to create that catalogue are retained under
|
|
312
|
+
`reference-data/scn5a-promoter-pangenome/`, with their supplied license and
|
|
313
|
+
provenance. See [CHANGELOG.md](https://github.com/comparativechrono/TrioHap/blob/main/CHANGELOG.md)
|
|
314
|
+
and [VALIDATION.txt](https://github.com/comparativechrono/TrioHap/blob/main/VALIDATION.txt).
|
|
315
|
+
|
|
316
|
+
Release preparation and the exact PyPI Trusted Publisher settings are in
|
|
317
|
+
[PUBLISHING.md](https://github.com/comparativechrono/TrioHap/blob/main/PUBLISHING.md).
|
|
318
|
+
Packaging CI builds a wheel from the source archive, checks PyPI metadata,
|
|
319
|
+
and tests the installed wheel outside the checkout, including graph generation.
|
|
320
|
+
The project version is maintained in `triohap/__init__.py`.
|
|
321
|
+
|
|
322
|
+
TrioHap is licensed under the
|
|
323
|
+
[MIT licence](https://github.com/comparativechrono/TrioHap/blob/main/LICENSE).
|
|
324
|
+
The supplied SCN5A reference-data subset retains its own licence and attribution
|
|
325
|
+
under `reference-data/scn5a-promoter-pangenome/`.
|
|
326
|
+
|
|
327
|
+
The gVCF examples are in `examples/gvcf/`, with a rendered report in
|
|
328
|
+
`demo-gvcf-output/`. Run `python scripts/validate_gvcf.py` to compare known
|
|
329
|
+
synthetic families across ordinary VCF, joint gVCF, individual gVCF, and mixed
|
|
330
|
+
inputs, including deliberate reference-block gaps. The saved summary is
|
|
331
|
+
`validation/gvcf_summary.json`.
|
|
332
|
+
|
|
333
|
+
## Related components and specifications
|
|
334
|
+
|
|
335
|
+
- [Osprey](https://github.com/broadinstitute/Osprey): phased SNP reference
|
|
336
|
+
haplotype matching for CNV/VNTR imputation. Its documented matching uses SNPs
|
|
337
|
+
outside the target interval; it does not supply this combined trio workflow.
|
|
338
|
+
- [trioPhaser](https://pmc.ncbi.nlm.nih.gov/articles/PMC8607709/): trio-based
|
|
339
|
+
phasing using Mendelian rules plus statistical phasing.
|
|
340
|
+
- [VCF 4.5 specification](https://samtools.github.io/hts-specs/VCFv4.5.pdf): phase
|
|
341
|
+
set and genotype semantics.
|
|
342
|
+
- [Unfazed paper](https://academic.oup.com/bioinformatics/article/37/24/4860/6306405)
|
|
343
|
+
and the maintained PyPI distribution linked above.
|
|
344
|
+
|
|
345
|
+
No external tool's implementation is incorporated into the matching engine.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Publishing TrioHap to PyPI
|
|
2
|
+
|
|
3
|
+
The first PyPI release is `triohap` version `0.4.0`. The older
|
|
4
|
+
GitHub-only wheels used the distribution name `triohap-prototype`. The import
|
|
5
|
+
package and executable remain `triohap`. Preparing or merging this workflow
|
|
6
|
+
does not publish a package.
|
|
7
|
+
|
|
8
|
+
## Register the pending publisher
|
|
9
|
+
|
|
10
|
+
At <https://pypi.org/manage/account/publishing/>, select **GitHub** and enter:
|
|
11
|
+
|
|
12
|
+
| Field | Exact value |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| PyPI project name | `triohap` |
|
|
15
|
+
| Owner | `comparativechrono` |
|
|
16
|
+
| Repository name | `TrioHap` |
|
|
17
|
+
| Workflow name | `publish.yml` |
|
|
18
|
+
| Environment name | `pypi` |
|
|
19
|
+
|
|
20
|
+
Enter only `publish.yml`, not `.github/workflows/publish.yml` and not the workflow
|
|
21
|
+
display title. The workflow lives at `.github/workflows/publish.yml`.
|
|
22
|
+
There is no PyPI API token or GitHub secret to create. The pending publisher
|
|
23
|
+
creates the PyPI project on its first successful use; it does not reserve the
|
|
24
|
+
name. The project name in PyPI must match the distribution metadata.
|
|
25
|
+
|
|
26
|
+
The GitHub environment `pypi` is configured to allow tags matching `v*` only.
|
|
27
|
+
No secrets are needed. The current private-repository settings do not offer a
|
|
28
|
+
required-reviewer gate; publishing a GitHub release is the deliberate publishing
|
|
29
|
+
action. Keep release and workflow changes restricted to trusted maintainers.
|
|
30
|
+
|
|
31
|
+
## Validate without publishing
|
|
32
|
+
|
|
33
|
+
The **Build and publish to PyPI** workflow offers **Run workflow**. A manual run
|
|
34
|
+
builds and validates the distributions and saves them as a workflow artifact;
|
|
35
|
+
its publishing job is always skipped. Pushes and pull requests also run the
|
|
36
|
+
distribution checks in the ordinary CI workflow.
|
|
37
|
+
|
|
38
|
+
To run the same checks locally, from a clean checkout and virtual environment:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
python -m pip install '.[dev]'
|
|
42
|
+
python -m build
|
|
43
|
+
python -m twine check --strict dist/*
|
|
44
|
+
python scripts/validate_distribution.py --dist-dir dist --tag v0.4.0 --plots
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Use an empty `dist/` directory for each version. `python -m build` creates a
|
|
48
|
+
source archive and builds the wheel from that archive. Validation checks
|
|
49
|
+
metadata, the entry point, runtime version, source/wheel module equality,
|
|
50
|
+
reproducibility fixtures, and installed command behavior. It runs the complete
|
|
51
|
+
unit suite against an isolated wheel installation outside the checkout,
|
|
52
|
+
exercises joint VCF and individual gVCF inputs, and checks plot generation.
|
|
53
|
+
The source archive is rebuilt independently, compared with the release wheel,
|
|
54
|
+
and checked in a separate installation with both CLI examples. Plot dependencies
|
|
55
|
+
are optional at runtime.
|
|
56
|
+
|
|
57
|
+
## Publish a version
|
|
58
|
+
|
|
59
|
+
1. Register the pending publisher above before publishing the first release.
|
|
60
|
+
2. Preserve the root MIT `LICENSE` and the `MIT` SPDX expression in project
|
|
61
|
+
metadata. The source and wheel archives must include that licence. The
|
|
62
|
+
supplied reference-data subset retains its separate MIT licence and
|
|
63
|
+
attribution under `reference-data/scn5a-promoter-pangenome/`.
|
|
64
|
+
3. Set `__version__` in `triohap/__init__.py` and update `CHANGELOG.md`. Package
|
|
65
|
+
metadata reads that version automatically. For the first release it is
|
|
66
|
+
`0.4.0`, and the tag must be exactly `v0.4.0`.
|
|
67
|
+
4. Merge the release changes into `main` and confirm CI passes.
|
|
68
|
+
5. Publish a GitHub release with the matching tag, targeting the tested commit.
|
|
69
|
+
A draft does not publish. Both published releases and published GitHub
|
|
70
|
+
prereleases trigger uploading; the Python version controls whether PyPI
|
|
71
|
+
treats the distribution as a prerelease. Use a version such as `0.4.1rc1`
|
|
72
|
+
for an actual Python prerelease, with tag `v0.4.1rc1`.
|
|
73
|
+
6. Confirm the **Build and publish to PyPI** run succeeds and inspect the new
|
|
74
|
+
PyPI project/version. Then test installation in a fresh environment:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
python -m pip install 'triohap[plots]==0.4.0'
|
|
78
|
+
triohap --version
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The build job checks the release tag against the built metadata and runtime
|
|
82
|
+
version. Only its validated wheel and source archive are handed to the separate
|
|
83
|
+
publishing job. That job runs in `pypi`, requests a short-lived OIDC identity,
|
|
84
|
+
and uses PyPA's publishing action with attestations enabled by default. It does
|
|
85
|
+
not execute the source checkout or hold a persistent PyPI token. Actions are
|
|
86
|
+
pinned to reviewed upstream commits.
|
|
87
|
+
|
|
88
|
+
Pushing a tag alone, pushing a branch, opening a pull request, and manually
|
|
89
|
+
running the validation workflow do not publish. The existing `v0.3.0` release
|
|
90
|
+
does not trigger retroactively. Do not reuse a version already uploaded to
|
|
91
|
+
PyPI; publish a new version for corrections. No TestPyPI publisher is configured.
|
|
92
|
+
|
|
93
|
+
## References
|
|
94
|
+
|
|
95
|
+
- [PyPI pending publishers](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/)
|
|
96
|
+
- [PyPA release workflow guidance](https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/)
|
|
97
|
+
- [PyPI Trusted Publishing security model](https://docs.pypi.org/trusted-publishers/security-model/)
|
|
98
|
+
- [PyPA publishing action](https://github.com/pypa/gh-action-pypi-publish)
|