Metadata-Version: 2.5
Name: altar-alphamissense
Version: 0.3.0rc1
Summary: AlphaMissense annotation-source binding for Altar
Project-URL: Documentation, https://kundajelab.github.io/altar/
Author: Riya Sinha
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: altar<0.4,>=0.3.0rc1
Provides-Extra: test
Requires-Dist: pytest-asyncio>=0.24; extra == 'test'
Requires-Dist: pytest>=8; extra == 'test'
Description-Content-Type: text/markdown

# AlphaMissense binding

`altar-alphamissense` exposes precomputed AlphaMissense evidence through Altar's
`AnnotationSource` contract. AlphaMissense is a lookup source here, not a model
execution plugin: the published missense predictions already exist before an
Altar analysis begins.

The binding separates scientific normalization from storage. `AlphaMissenseSource`
aggregates transcript records into the stable per-variant columns consumed by
materialization, while an injected `AllelicRecordBackend` retrieves projected
native rows. Altar's generic `ParquetAllelicRecordBackend` is shared with
SpliceAI and other allelic sources; it contains no AlphaMissense logic.

```python
from altar.sources import AllelicKeyColumns, ParquetAllelicRecordBackend
from altar_alphamissense import AlphaMissenseRelease, AlphaMissenseSource

backend = ParquetAllelicRecordBackend(
    "./alphamissense",
    key_columns=AllelicKeyColumns("chr", "pos", "ref", "alt"),
)
release = AlphaMissenseRelease(genome_build="hg38", source_release="zenodo-v1")
source = AlphaMissenseSource(backend, release=release, genome_build="hg38")
annotations = await source.annotate(["chr1:123:A:G"])
```

The dataset can also be read in place where it is hosted. Pass a URI instead of
a path (`gs://`, `s3://`, `az://`, `https://`, `hf://`), with any non-secret
fsspec options as `storage_options`; credentials stay ambient. The provider's
extra must be installed, such as `altar[gcs]` or `altar[http]`:

```python
source = AlphaMissenseSource.from_dataset(
    "gs://BUCKET/alphamissense",
    storage_options={"token": "anon"},
)
```

## Genome build and release

DeepMind publishes separate hg19 and hg38 files. `AlphaMissenseRelease` records
which one a backend serves and the exact upstream release. `genome_build` on the
source is the assembly of the variant IDs you will look up. The constructor
raises `ValueError` if it differs from the release's build.

The source also reads the native `genome` column of every record. If a record's
build differs from the release, `annotate` raises `ValueError` rather than
returning scores for the wrong assembly. A table that holds both builds must be
filtered to one, for example with `filters={"genome": "hg38"}` on the BigQuery
backend.

Every annotation carries `am_genome_build` and `am_source_release`, so
persisted AlphaMissense columns keep the build and release they came from.

The columns form the published `ALPHAMISSENSE_ANNOTATIONS` contract
(`org.kundajelab.altar.annotation.alphamissense`, version 1.0.0).
`source.identity()` returns that contract with the release's `source_release`
and genome build. A host table that holds the same columns can declare the same
contract.

For AlphaMissense records stored in BigQuery, use Altar's generic
`BigQueryAllelicRecordBackend`. The table needs the four key columns plus
`genome`, `uniprot_id`, `transcript_id`, `protein_variant`, `am_pathogenicity`,
and `am_class`. Its chromosome column must use the `chr`-prefixed spelling the
binding requests, such as `chr1`. A table spelled `1` makes staging raise
`ValueError`.

To include AlphaMissense in `BigQueryScoreStore` materialization and exports,
use `staged_annotation_source`. It runs the binding for the job's variants that
have AlphaMissense records and yields a source the store joins in SQL:

```python
from altar.sources import AllelicKeyColumns, BigQueryAllelicRecordBackend, staged_annotation_source
from altar_alphamissense import AlphaMissenseRelease, AlphaMissenseSource

backend = BigQueryAllelicRecordBackend(
    client,
    "project.reference.alphamissense",
    key_columns=AllelicKeyColumns("chr", "pos", "ref", "alt"),
    filters={"genome": "hg38"},
)
release = AlphaMissenseRelease(genome_build="hg38", source_release="zenodo-v1")
async with staged_annotation_source(
    AlphaMissenseSource(backend, release=release, genome_build="hg38"),
    client,
    staging_dataset="project.scratch",
    variants_relation="`project.scratch.job_variants`",
    coverage=backend,
) as source:
    ...  # pass `source` to the store's materialize and export calls
```

`ParquetAlphaMissenseBackend` remains as a thin compatibility preset for one
release window; new integrations should use the shared adapter directly.

## Build the dataset

`altar-alphamissense-build` streams DeepMind's TSV release into Parquet, one row
per transcript record, keyed by the canonical `chr:pos:ref:alt`:

```console
altar-alphamissense-build --genome-build hg38 --source-release zenodo-v1 \
  --input AlphaMissense_hg38.tsv.gz \
  --output ./alphamissense-hg38
```

`--genome-build` and `--source-release` are the `AlphaMissenseRelease` the
dataset will be read with. `--input` and `--output` also take URIs (`gs://`,
`https://`, `s3://`, `hf://`, ...), so a build reads the release where DeepMind
hosts it and writes where it will be read, with no download and no copy step:

```console
altar-alphamissense-build --genome-build hg38 --source-release zenodo-v1 \
  --input gs://dm_alphamissense/AlphaMissense_hg38.tsv.gz \
  --input-storage-option token=anon \
  --output gs://my-bucket/alphamissense-hg38/
```

The builder shares the input, output, retry and resume rules of the
[gnomAD](https://pypi.org/project/altar-popfreq/)
and [ClinVar](https://pypi.org/project/altar-clinvar/)
builders, with the same flags: a URI needs its provider's Altar extra, such as
`altar[gcs]`; a remote input whose stream fails or ends early is read again, up
to `--input-attempts` times; an `--output` URI receives each input's files as
they finish and keeps `_altar_build/` until the build does, so running the same
command again resumes a crashed build; `--input-storage-option` and
`--output-storage-option` pass non-secret fsspec options; `--overwrite`
replaces a previous build; and `--input -` reads standard input, named by
`--stdin-name`.

It writes `<output>/chr=<chromosome>/<input name>.parquet`. Each file has
`variant_id`, the key columns `chr`, `pos`, `ref`, `alt`, and the native
`genome`, `uniprot_id`, `transcript_id`, `protein_variant`, `am_pathogenicity`
and `am_class`, written with zstd in row groups of 32,000 rows, so a point
lookup reads one small row group per variant it finds. These are also the
columns of a BigQuery table loaded from the dataset with `altar pull
--bigquery`, which `BigQueryAllelicRecordBackend` reads with the key columns
`chr`, `pos`, `ref` and `alt`, as above.

Every file records `altar_alphamissense.release`,
`altar_alphamissense.genome_build`, `altar_alphamissense.layout` and
`altar_alphamissense.builder_version` in its Parquet metadata.
`AlphaMissenseSource` over a `ParquetAllelicRecordBackend` reads that metadata
and refuses a dataset built for another release or build, or one that records
no release at all. It reads the first file in sorted order only, so opening a
remote dataset costs one footer. A host's own export must carry the same keys;
`altar_alphamissense.RELEASE_METADATA.write(release_fields(release))` returns
them.

The builder:

- skips DeepMind's comment lines and requires the header line to name the
  release's ten columns;
- requires every record's `genome` to be `--genome-build`, and an input named
  like DeepMind's files, `AlphaMissense_<build>.tsv.gz`, to name it;
- writes chromosomes with the canonical `chr` spelling, and an empty
  `uniprot_id`, `transcript_id` or `protein_variant` as null;
- skips and counts records whose REF or ALT is not an ACGT allele other than
  the other;
- rejects input that is not sorted by position within each chromosome, as
  DeepMind's file is, and a variant scored twice for one transcript across all
  inputs;
- rejects a build that writes no rows.

### Datasets of the first builder

`altar-alphamissense` 0.1.0 built a different layout: `CHROM=<chromosome>/`
partitions whose files held neither the chromosome nor `variant_id`, keyed by
`CHROM`, `POS`, `REF` and `ALT`. `altar pull --bigquery` cannot load it and
the source cannot read it. `AlphaMissenseSource` refuses such a dataset with a
`ValueError` that names the builder to rebuild it with; rebuild it from the
TSV release with the command above.

`am_transcript_scores` is a typed, repeated struct that preserves every
matching transcript in descending pathogenicity order, with ties ordered by
transcript, UniProt accession, and protein variant. Each record has
`uniprot_id`, `transcript_id`, `protein_variant`, `am_pathogenicity`, and
`am_class`. Stores with native nested types keep it as an array of records;
SQLite stores it as JSON text without changing the logical schema.
`am_pathogenicity` and `am_class` are the summary from the most pathogenic
transcript and remain convenient scalar columns for filtering and
prioritization.
