Skip to main content

A samtools/bedtools-style command-line toolkit and library for GA4GH Phenopackets

Project description

phenopacket-toolkit (phenotk)

A samtools/bedtools-style command-line toolkit and Python library for working with GA4GH Phenopackets and Family JSON files. One verb per subcommand, composable over pipes, structured output, CI-friendly exit codes.

It reads files produced by different tools (including the abusua2ga4gh and studio2ga4gh dialects) and anyone else's GA4GH-compliant phenopackets, normalises them, slices them down to chosen phenotypes, de-identifies them, validates them, and converts between structural variants.

  • Zero-dependency core. read/write/validate/view/stats/filter/deidentify/ diff/sort/convert/split/merge/ped need nothing beyond the standard library.
  • Tolerant reader, configurable writer, lossless round-trip. Unknown fields are preserved; dialect quirks are reconciled on read and restored on write.
  • No-guess ontology contract. Ontology IDs are only ever filled by the normalise step, under an explicit auto-accept policy.

Install

pip install phenopacket-toolkit                 # zero-dependency core
pip install 'phenopacket-toolkit[normalise]'    # + hponorm / mondonorm
pip install 'phenopacket-toolkit[all]'          # + rapidfuzz, PyYAML, protobuf validation

Requires Python >= 3.9.

Quick start (CLI)

phenotk view family.json                       # readable table
phenotk validate family.json --level reference # layered checks; non-zero exit on error
phenotk stats family.json --format json        # counts + term frequency

# fill ontology ids from a curated mapping, leaving anything unmatched empty
phenotk normalise family.json --no-online \
    --mapping labels.json --log decisions.json -o family.norm.json

# cut a family down to a phenotype, expanding to descendant terms via an OBO file
phenotk filter family.json --term HP:0001626 --include-descendants \
    --backend obo --hpo-file hp.obo -o subset.json

# enrich the proband with data a pedigree never carries: onset, a variant, demographics
phenotk add family.json --target proband \
    --phenotype "HP:0001657=Prolonged QT interval" --onset P14Y --severity "HP:0012828=Severe" \
    --variant --gene "HGNC:6294=KCNQ1" --hgvs "NM_000218.3:c.569G>A" \
        --zygosity heterozygous --acmg PATHOGENIC --diagnosis "MONDO:0011382=sickle cell disease" \
    --karyotypic-sex XY --age P14Y --external-ref "PMID:31479590;;index case" \
    -o enriched.json

# de-identify: drop DOB, remap every id consistently, keep a reversible crosswalk
phenotk deidentify family.json --remap-ids seq --keyfile key.json -o deid.json

phenotk convert family.json --to ped           # 6-column PED
phenotk convert family.json --to tsv           # one row per (individual, term)
phenotk diff a.json b.json                      # structural+semantic diff
phenotk split family.json --out-dir out/ --affected-only

Most commands read - for stdin and write stdout, so they compose:

cat family.json | phenotk filter - --affected | phenotk deidentify - -o clean.json

Quick start (library)

from phenopacket_toolkit import read, write
from phenopacket_toolkit.ops import normalise, filter_document, deidentify, validate

doc = read("family.json")                       # auto-detects format + dialect

doc, log = normalise(doc, mapping={"diabetes": "MONDO:0005015"}, use_ontology=False)
doc = filter_document(doc, terms=["MONDO:0005015"])
result = deidentify(doc, drop_dob=True, remap_ids="seq")

report = validate(result.document, level="reference")
if report.ok:
    write(result.document, "clean.json", dialect="ga4gh")

Dialects

Dialect Source Reconciled on read
ga4gh spec-compliant (canonical)
abusua abusua2ga4gh *.family.json vital_status -> vitalStatus
studio studio2ga4gh *_phenopackets.json Family metaData inherited into each phenopacket

Choose the output dialect with --to-dialect (CLI) or dialect= (library); --to-dialect preserve re-emits in the source dialect. New dialects can be registered without touching the core via phenopacket_toolkit.io.dialects.register.

Verbs

view, validate, normalise, filter, add, deidentify, convert, merge, split, stats, diff, sort, ped. Run phenotk <verb> --help for options.

Adding fields a pedigree never carries

A pedigree conversion gives you structure, sex, affected status and bare phenotype/disease labels. add lets you layer on the richer Phenopacket v2 content, targeting the proband, all, affected/unaffected, or a specific subject id:

  • Age / onset on phenotypes and diseases (--onset P14Y, an onset CURIE, or a timestamp), plus severity and excluded status.
  • Genomic interpretations — a variant with gene context, HGVS expression, zygosity (GENO) and ACMG pathogenicity, wrapped in a diagnosis.
  • Measurements — quantitative or categorical lab values (--measurement-json).
  • Vital status detailDECEASED, cause of death, survival time.
  • Subject demographicsdateOfBirth, age (timeAtLastEncounter), karyotypicSex, gender, taxonomy.
  • External references (PMIDs etc.) and files (e.g. a linked VCF).
  • Anything else via generic --set PATH=JSON, --merge, --append, or a whole-object --from-json PATCH.

In the library these are typed builders in phenopacket_toolkit.model.builders plus phenopacket_toolkit.ops.add.

Hierarchy-aware filtering

filter --include-descendants keeps a term and any of its subclasses. The descendant set is resolved by --backend: obo parses an hp.obo / mondo.obo file (--hpo-file / --mondo-file, fully offline), ols queries the EBI Ontology Lookup Service, and auto tries a local source then falls back to OLS.

Normalisation and ontologies

normalise fills empty term ids in this order: an explicit --mapping (label -> CURIE) always wins; remaining empties are resolved via hponorm (phenotypes) and mondonorm (diseases) when the [normalise] extra is installed; anything that does not clear the score --threshold (default 0.9) is left empty and recorded in the decision log. --structure additionally canonicalises CURIE prefixes, de-duplicates terms, and rebuilds metaData.resources from the ontologies in use.

Development

pip install -e . --no-build-isolation
python run_tests.py tests/test_toolkit.py    # offline runner (no pytest needed)
pytest                                       # if pytest is available

The test suite is driven by real example families in tests/data/ and checks round-trip fidelity, cross-dialect equivalence, pedigree-graph validation, graph-consistent de-identification, and idempotent no-guess normalisation.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phenopacket_toolkit-0.2.0.tar.gz (41.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

phenopacket_toolkit-0.2.0-py3-none-any.whl (47.3 kB view details)

Uploaded Python 3

File details

Details for the file phenopacket_toolkit-0.2.0.tar.gz.

File metadata

  • Download URL: phenopacket_toolkit-0.2.0.tar.gz
  • Upload date:
  • Size: 41.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for phenopacket_toolkit-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ee40a3eaaf6f2c0f22cfc8f38130f7a13aacde636757dede96e4a7d98fee6b85
MD5 8fce1a9340eb881bbbef1542aed75994
BLAKE2b-256 62c9585fbcc47c27b7544315a3e2edd2a5d35b67cc2bf4d0ffe15dc069f07563

See more details on using hashes here.

File details

Details for the file phenopacket_toolkit-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for phenopacket_toolkit-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 666657c81fc153e1cf5d297555d662a2887e0f233a67a8365124e6b6c5c81395
MD5 690daaf7b05460d331274e71cb12e808
BLAKE2b-256 7674d2c1bd0bfee0e4955402cd11600c3459d0b41828a56fa7edece1401f6cd9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page