Skip to content

iris.genomics — CLI + Librería Fase 4

Typer · pysam · bcftools 1.23.1 · tabix 1.23.1 · micromamba genomics-core


1. Dependencias

Agregadas como optional group genomics en pyproject.toml:

uv add --optional genomics pysam zarr typer

Binarios externos requeridos (detectados automáticamente via shutil.which()):

# Activar env con bcftools y tabix
micromamba activate genomics-core

which bcftools  # /home/fenan/micromamba/envs/genomics-core/bin/bcftools
which tabix     # /home/fenan/micromamba/envs/genomics-core/bin/tabix

Entrypoint registrado en pyproject.toml:

[project.scripts]
iris-genomics = "iris.applications.genomics.cli:app"

2. Estructura

src/iris/applications/genomics/
├── __init__.py
├── cli.py                      # Entrypoint principal Typer
├── commands/
│   ├── __init__.py
│   ├── vcf.py                  # iris genomics vcf filter / region
│   ├── tabix.py                # iris genomics tabix index / query / header
│   ├── bcftools.py             # iris genomics bcftools stats / view / norm / sort / concat
│   └── store.py                # iris genomics store pull / verify
└── use_cases/
    ├── __init__.py
    ├── filter_variants.py      # Filtra variantes de un VCF
    ├── annotate_vcf.py         # Anota variantes con cadena de anotadores
    ├── fetch_region.py         # Extrae variantes de una región genómica
    └── sync_store.py           # Sincroniza store remoto a local

3. Use Cases — funciones puras importables

Los use cases no saben que existe un CLI. Son importables directamente desde otras apps.

filter_variants

from iris.applications.genomics.use_cases.filter_variants import filter_variants
from iris.adapters.driven.readers.vcf import VcfReader
from iris.domain.genomics.filters import AllOf, MaxPopulationFrequency, HighImpactConsequence

results = filter_variants(
    path="sample.vcf.gz",
    filter=AllOf(filters=(
        MaxPopulationFrequency(max_af=0.01, absent_passes=True),
        HighImpactConsequence(),
    )),
    sample_id="NA12878",   # opcional — filtra por genotipo
    store_info=False,       # opcional — serializa INFO en Metadata
)
# → list[VariantAnnotation]

annotate_vcf

from iris.applications.genomics.use_cases.annotate_vcf import annotate_vcf
from iris.adapters.driven.annotators.cadd import CaddAnnotator
from iris.adapters.driven.annotators.dbnsfp import DbNsfpAnnotator

annotated = annotate_vcf(
    variants=results,
    annotators=[
        CaddAnnotator(path="/data/cadd/whole_genome_SNVs.tsv.gz"),
        DbNsfpAnnotator(path="/data/dbnsfp/dbNSFP4.7a.gz"),
    ],
)
# → list[VariantAnnotation]

El orden de los anotadores importa — cada uno ve el resultado del anterior.

fetch_region

from iris.applications.genomics.use_cases.fetch_region import fetch_region
from iris.domain.genomics.objects import GenomicPosition

variants = fetch_region(
    path="sample.vcf.gz",
    region=GenomicPosition(chromosome="chr1", start=1_000_000, end=2_000_000),
    sample_id="NA12878",  # opcional
)
# → list[VariantAnnotation]

sync_store

from iris.applications.genomics.use_cases.sync_store import sync_store

result = sync_store(
    remote_url="https://storage.iris-lib.click/org-1/",
    local_path=Path("/data/genomics/org-1"),
    patterns=["*.vcf.gz", "*.vcf.gz.tbi"],
    verify=True,
    force=False,
)
# → SyncResult(downloaded, skipped, failed)
print(result.success)  # True si no hubo fallos

4. CLI — comandos disponibles

iris-genomics --help
Commands:
  vcf       Operaciones sobre archivos VCF/BCF.
  tabix     Operaciones tabix sobre archivos bgzipped.
  bcftools  Operaciones bcftools sobre archivos VCF/BCF.
  store     Gestión del store de archivos genómicos.

vcf

# Filtrar variantes por frecuencia y consecuencia
iris-genomics vcf filter sample.vcf.gz \
  --max-af 0.01 \
  --high-impact \
  --sample NA12878 \
  -o filtered.tsv

# Extraer variantes de una región
iris-genomics vcf region sample.vcf.gz \
  --chrom chr1 \
  --start 1000000 \
  --end 2000000 \
  -o region.tsv

Salida TSV:

chrom   pos     ref     alt     type
1       1001334 G       T       snv
1       1007230 T       C       snv

tabix

# Indexar un VCF bgzipped
iris-genomics tabix index sample.vcf.gz
iris-genomics tabix index sample.vcf.gz --preset vcf --force

# Consultar una región
iris-genomics tabix query sample.vcf.gz --region chr1:1000000-2000000
iris-genomics tabix query sample.vcf.gz \
  --region chr1:1000000-2000000 \
  -o region.vcf \
  --no-header

# Ver header
iris-genomics tabix header sample.vcf.gz

bcftools

# Estadísticas
iris-genomics bcftools stats sample.vcf.gz
iris-genomics bcftools stats sample.vcf.gz -o stats.txt --sample NA12878

# Filtrar/convertir
iris-genomics bcftools view sample.vcf.gz \
  --include 'QUAL>30' \
  --output-type z \
  -o filtered.vcf.gz

# Normalizar
iris-genomics bcftools norm sample.vcf.gz \
  --reference hg38.fa \
  --multiallelics - \
  -o normalized.vcf.gz

# Ordenar
iris-genomics bcftools sort unsorted.vcf.gz -o sorted.vcf.gz

# Concatenar
iris-genomics bcftools concat chr1.vcf.gz chr2.vcf.gz -o merged.vcf.gz

store

# Descargar archivos del store remoto
iris-genomics store pull https://storage.iris-lib.click/org-1/ \
  --local /data/genomics/org-1 \
  --patterns "*.vcf.gz,*.vcf.gz.tbi" \
  --force

# Verificar integridad del store local
iris-genomics store verify /data/genomics/org-1
iris-genomics store verify /data/genomics/org-1 --patterns "*.vcf.gz"

5. Diseño — separación commands / use_cases

use_cases/          commands/
filter_variants  ←  vcf filter      (llama filter_variants internamente)
fetch_region     ←  vcf region      (llama fetch_region internamente)
annotate_vcf     ←  (sin command propio — usado por BACKAPP genómica)
sync_store       ←  store pull      (llama sync_store internamente)

Los commands son wrappers delgados — solo parsean argumentos CLI y delegan a los use_cases. Los use_cases son funciones puras sin dependencia de Typer.

La BACKAPP genómica importa los use_cases directamente:

from iris.applications.genomics.use_cases.filter_variants import filter_variants
from iris.applications.genomics.use_cases.annotate_vcf import annotate_vcf

6. Detección de binarios externos

bcftools.py y tabix.py detectan los binarios via shutil.which(). Si no se encuentran en PATH, muestran un mensaje claro:

✗ bcftools no encontrado en PATH.
  Instala bcftools o activa el env: micromamba activate genomics-core

Para asegurar que el env correcto esté activo al usar el CLI:

micromamba activate genomics-core
uv run iris-genomics bcftools stats sample.vcf.gz

7. Verificación end-to-end

Prueba real con VCF de array SNV

# Extraer región chr1:1M-2M
uv run iris-genomics vcf region \
  /home/fenan/Downloads/209583890164_R01C01.snv.vcf.gz \
  --chrom chr1 \
  --start 1000000 \
  --end 2000000 \
  -o /tmp/test_region.tsv

# → ✓ 1325 variantes en la región.
# → ✓ Guardado en /tmp/test_region.tsv
# Estadísticas con bcftools
uv run iris-genomics bcftools stats \
  /home/fenan/Downloads/209583890164_R01C01.snv.vcf.gz \
  | head -20

# → bcftools stats (1.23.1+htslib-1.23.1) output correcto

8. Notas

CoordenadasVcfReader usa coordenadas 1-based internamente (igual que GenomicPosition). pysam usa 0-based internamente pero la conversión es transparente en el reader.

Nomenclatura cromosómica — el VCF de prueba usa 1 sin prefijo chr. TabixAnnotator maneja automáticamente el mismatch chr11 via _resolve_chrom().

Salida TSV — el formato actual es mínimo (chrom, pos, ref, alt, type). En la BACKAPP genómica se extenderá con campos de anotación (CADD, dbNSFP, frecuencias).

Pipeline completo:

variants = filter_variants(path, filter=my_filter)
annotated = annotate_vcf(variants, annotators=[cadd, dbnsfp, mcps])
# → list[VariantAnnotation] con scores, frecuencias, clasificaciones