---
name: myvariant-info-client-conventions
source: https://app.decimal.ai/s/myvariant-info-client-conventions@1/SKILL.md
source_sha256: c627529fb5d8
---

# MyVariant.info Python client — calling conventions

## Contract
Enforce the BioThings `myvariant` client convention when code imports `myvariant` to fetch
variant annotations from MyVariant.info: the correct client object, the right method for each
kind of input identifier, the HGVS `_id` string format, dotted-path `fields` selection, and
`as_dataframe`. Apply to any Python that annotates variants through this library.

## Rules
1. **Client object.** Create the client as `mv = myvariant.MyVariantInfo()`. Never
   `myvariant.MyVariant()`, `myvariant.Client()`, `MyVariantInfo.connect()`,
   `MyVariantClient()`, and never hand-roll `requests.get` against the REST endpoint.

2. **`get*` take an HGVS `_id`, not an rsID.** `getvariant(id)` and `getvariants([ids])`
   accept an HGVS-based variant id, format `chr<N>:g.<pos><ref>><alt>` for an SNV, e.g.
   `chr9:g.107620835G>A`. Chromosome tokens are `chr1`..`chr22`, `chrX`, `chrY`. Build this
   string from coordinates + alleles; do NOT pass a bare `rs…` id to `get*`.

3. **rsID lookup goes through `query`/`querymany`.** To look up variants by dbSNP rsID, use
   `query('dbsnp.rsid:<rsid>')` for one/Lucene, or `querymany(rsids, scopes='dbsnp.rsid')`
   for a list. `getvariant('rs…')` misses (rsIDs are not the `_id` scope).

4. **`scopes=` names the input namespace.** For `querymany`, `scopes` declares what kind of
   identifiers the inputs are: `'dbsnp.rsid'`, `'clinvar.rcv_accession'`, `'cosmic.cosmic_id'`.
   Several kinds in one call → one comma-separated string, e.g.
   `scopes='dbsnp.rsid,clinvar.rcv_accession,cosmic.cosmic_id'`.

5. **`fields=` is a comma-string or list of dotted paths.** Select the returned subtree with
   `fields='dbsnp.rsid,cadd.phred'` or `fields=['cosmic.tumor_site','clinvar.rcv.clinical_significance']`.
   Dotted paths pick nested leaves; `fields='all'` returns everything. Not `columns=`, not
   `select=`, not a positional second arg.

6. **Batch in ONE call.** A list of HGVS ids → `getvariants([...])` (plural; also accepts a
   tuple or a comma-joined string). A list of rsIDs/other ids → `querymany([...], scopes=…)`.
   Do not loop `getvariant` once per id.

7. **DataFrame output → `as_dataframe=True`.** Pass `as_dataframe=True` to `getvariants` /
   `querymany` to get a pandas DataFrame back; don't assemble one by hand from the dict list.

8. **Range / field search → `query`.** Genomic window: `query('chr1:69000-70000')`. Field
   filter: `query('dbnsfp.genename:CDK2')`. Iterate ALL hits with `query(..., fetch_all=True)`
   (a generator); cap a page with `size=`.

## Worked examples
- Look up by rsID (single):
  `mv.getvariant('rs1042522')`  →  `mv.query('dbsnp.rsid:rs1042522')` (or `mv.querymany(['rs1042522'], scopes='dbsnp.rsid')`).
- Look up by rsID (batch):
  `[mv.getvariant(r) for r in rs_list]`  →  `mv.querymany(rs_list, scopes='dbsnp.rsid', fields='clinvar.rcv.clinical_significance')`.
- From coordinates:
  `mv.getvariant(chrom=17, pos=7676154, ref='G', alt='A')`  →  `mv.getvariant('chr17:g.7676154G>A')`.
- Batch of coordinate variants:
  a loop of `getvariant`  →  `mv.getvariants(['chr17:g.7676154G>A','chr7:g.55019278T>G'], fields='cadd.phred')`.
- Pick specific subfields:
  `mv.getvariant('chr7:g.140753336A>T', fields=['dbsnp','gnomad_exome'])`  →  `..., fields='dbsnp.rsid,gnomad_exome.af.af'`.
- DataFrame:
  `pd.DataFrame([mv.getvariant(v) for v in ids])`  →  `mv.getvariants(ids, fields='cadd.phred,dbsnp.rsid', as_dataframe=True)`.
- ClinVar accessions:
  `mv.getvariants(rcv_list)`  →  `mv.querymany(rcv_list, scopes='clinvar.rcv_accession')`.
- Genomic range:
  `mv.getvariant('chr1:69000-70000')`  →  `mv.query('chr1:69000-70000')` (add `fetch_all=True` to page all hits).

## Edge cases
- **Single rsID.** `query('dbsnp.rsid:rs…')` returns a hit list (`res['hits']`); a one-item
  `querymany([...], scopes='dbsnp.rsid')` also works. Either is fine — just not `getvariant`.
- **rsID → full annotation.** Read the `_id` (HGVS) from the query hit, then pass THAT to
  `getvariant` if you need the complete record.
- **Missing / duplicate inputs.** `querymany` marks unmatched inputs with `notfound: True`;
  pass `returnall=True` to also get the missing/duplicate breakdown.
- **Sex chromosomes.** Build the id as `chrX:g.<pos><ref>><alt>` / `chrY:g.…` (still `g.`).

## Do / Don't
- DO `mv = myvariant.MyVariantInfo()`. DON'T `myvariant.MyVariant()` / `Client()`.
- DO `querymany(rsids, scopes='dbsnp.rsid')`. DON'T `getvariants(rsids)` with rsIDs.
- DO build `chr7:g.140753336A>T`. DON'T pass chrom/pos/ref/alt as separate `getvariant` kwargs.
- DO `fields='dbsnp.rsid,cadd.phred'` (dotted). DON'T `columns=` / `select=`.
- DO `as_dataframe=True`. DON'T hand-build a DataFrame from the returned dicts.
- DO `query('chr1:69000-70000')` for a window. DON'T `getvariant` on a range.

## Common mistakes
- Feeding rsIDs to `getvariant`/`getvariants` (they take HGVS `_id`s → `notfound`).
- Inventing methods that don't exist: `mv.get_rsid()`, `mv.lookup()`, `mv.fetch()`,
  `mv.get_by_rsid()`, `mv.annotate()`, `mv.search()`.
- Dropping `scopes` on `querymany`, so rsIDs are matched against the default `_id` scope and miss.
- Using `columns=` / `select=` instead of `fields=`, or passing fields positionally.
- Looping `getvariant` per id instead of one `getvariants` / `querymany` batch call.

## Checklist
- [ ] client = `myvariant.MyVariantInfo()`
- [ ] rsID inputs → `query('dbsnp.rsid:…')` or `querymany(scopes='dbsnp.rsid')`
- [ ] `getvariant`/`getvariants` only for HGVS `chr<N>:g.<pos><ref>><alt>` ids
- [ ] `fields=` comma-string / list of dotted paths (or `'all'`)
- [ ] batch = `getvariants([...])` / `querymany([...])` in one call
- [ ] `as_dataframe=True` for a pandas DataFrame
- [ ] range / field search = `query(...)`; `fetch_all=True` to page all hits
