clinvar_classification() gains allele, the protein change you mean, such
as "V600E" or "p.Val600Glu" (#40). ClinVar's search often matches several
records, and the first is not always the variant you asked for: rs113488022
lists BRAF V600G before V600E, the HGVS name of V600E lists BRAF I208V first,
and rs121913343 lists TP53 R273G before R273C. With allele, the record
that has that protein change is returned, or no_data when none has it.n_matches: how many records fit the request.
A value above 1 means the row may be for a different variant from the one
you meant. Without allele the first record is still returned, so existing
code keeps working.mygene_gene() and mygene_genes() now return an Ensembl id for genes that
MyGene maps to more than one id, such as PTEN and MUC16. Before this,
ensembl_gene was NA for all of them (#39). The extra ids sit on assembly
patches or alternate haplotypes, and the one on a reference chromosome is
kept. Taking the first id would not work: for HLA-A it is on an alternate
haplotype. A gene whose ids all sit off the reference chromosomes, such as
HLA-DRB3, gets NA. Lookups that start from ensembl_gene, such as
opentargets_gene_diseases() and hpa_gene(), now work for these genes.input line and on vcf_string
rather than on a key rebuilt from the reported coordinates. VEP left-trims
and renumbers indels, so the rebuilt key matched only SNVs and every indel
came back as an empty row.vep_variants() takes an options list of request flags, defaulting to
vep_default_options(). dbNSFP is refused.vep_parse_element() adds transcript, gene_id, biotype, hgvsc,
hgvsp, canonical, codons, amino_acids, cadd_phred, cadd_raw,
revel, the four spliceai_ds_* scores, spliceai_max and lof.vep_parse_colocated() reads the dbSNP record beside a variant: rsid,
gnomAD genome and exome frequencies with their per-population maximum, and
the clinical significance of the allele asked. vep_parse_batch() carries
these columns.vep_variants_all() takes any number of variants, chunks them at the
200 VEP accepts per POST and dispatches the chunks through
biohttp::post_json_many(). One row per input in input order; a failed
chunk becomes rows of NA carrying the envelope status in status.vep_variants_all() puts the input in genome order and sends a repeated
variant once, before chunking, rather than once per occurrence. A
duplicate now always carries the same answer at every position it was
asked at, which was not guaranteed before when duplicates could land in
different chunks and see different transient failures. chunk_size and
the row count and order the contract promises are unchanged. It also
applies a default throttle (one request per second) so an unpaced burst
does not trip Ensembl's rate limiter; pass throttle = NULL to disable
it.gnomad_frequency_by_id() looks a variant up by chrom-pos-ref-alt,
which names one allele where an rsID names a site, and gnomad_frequencies()
does the same for many ids, alias-batched and chunked like
gnomad_constraints(). gnomad_variant_id() builds the id. The flat row
from gnomad_parse_variant() carries exome and genome af, ac, an and
nhomalt, a derived grpmax, faf95 and filters.clinvar_classification() throttles by default at the documented
E-utilities rate, 3 requests a second or 10 when NCBI_API_KEY is set, and
sends tool and email read from BIOHTTP_CALLER_IDENTITY and
BIOHTTP_CONTACT_EMAIL when they are set.mygene_genes() chunks a list longer than the 1000 identifiers MyGene
takes per POST, dispatches the chunks through biohttp::post_json_many()
and merges the hits back in input order.Everything below is for the CRAN submission. Nothing here changes how the package behaves, and no function's arguments or output shape moved.
Every example that calls a service now runs under \donttest{} rather than
\dontrun{}, 56 of them. \dontrun{} is for an example that genuinely
cannot be executed, which none of these are: they are keyless public
requests, a client returns an envelope rather than raising, and biohttp's
disk cache is off unless a caller turns it on. So an example run with no
network prints NULL and writes nothing.
Every help page now cites the service behind it. The 29 service files each
carry the canonical publication with a DOI and the service's own
documentation URL, and the other topics in the file inherit it, so all 134
exported topics have a References section. Each DOI was resolved through
CrossRef and checked against the title, author and pagination written here.
uniprot_features() carries two, because it calls the EBI Proteins API on a
different host to the rest of the file and both are worth naming.
The Description field cites five of those references, for Ensembl, UniProt,
gnomAD, Open Targets and AlphaFold DB, in the form CRAN asks for.
biohttp is on CRAN now, at 0.1.2. So the Remotes: line is gone and we
ask for biohttp (>= 0.1.2) instead. I ran the tests against the CRAN
build rather than the newer one on GitHub, to be sure nothing here needs a
version CRAN cannot give you.
cran-comments.md records the submission notes.
First release. 29 clients, 125 exported functions, and the behaviour they depend on checked against the live services rather than only against stored responses. 28 of the 29 confirmed; see "Known limits" for the one that did not, which was down at the time rather than wrong.
The envelope contract comes from biohttp and is fixed. What can still move is
the shape of a parser's output, since a service adding a field is a reason to
carry it. Anything that changes an existing column is a breaking change and gets
a version to say so.
NULL when there is genuinely nothing there. It
touches no network, so it is tested directly against a stored response.biohttp, passes a failing envelope straight through,
turns a NULL parse into no_data, and wraps a success in ok. No client
writes its own tryCatch().NA for a miss. A shorter table would
silently shift every row after it onto the wrong gene.These cost real debugging time to establish in the apps and are easy to lose in a port, so each one has a comment at the call site and a test where it is testable.
Everything below has now been confirmed against the live service, not only
against a stored response. tests/testthat/test-live.R is where that happens.
It calls all 29 services once and then makes the specific assertions the claims
below depend on. It never runs on its own, and no CI job turns it on:
BIOCLIENTS_LIVE=true Rscript -e 'devtools::test("pkg-r", filter = "live")'
notfound for GRCh38 coordinates when the
request omits assembly=hg38. Silent, not an error, which is exactly why it
needs a test.genotype-phenotype core has no human_gene_symbol field, so
querying it by symbol returns HTTP 200 with zero documents. A miss is
no_data and never 0, because a gene never phenotyped and a gene phenotyped
with no significant result are not the same answer.ok. A
gene with no literature is not an outage.HGNC, upper case. Asking for hgnc
returns nothing at all.HGNC:11998 must reach it
as-is rather than as HGNC%3A11998.search parameter does not filter, and Reactome answers
a gene it does not know with a 404 rather than an empty array.text/json, so the content type check has to be off.content-type as a query parameter, not a header. Leave it
out and Ensembl serves its HTML browser page with HTTP 200, so the call looks
like a success until the JSON parser reaches the first tag.clinvar_classification() picks up NCBI_API_KEY from the environment at
call time and passes it through biohttp's secret_query, which attaches it
at dispatch. The key never reaches the cache key, a printed request, or an
error message. It is optional; without it NCBI allows 3 requests a second
instead of 10.Four of the five behaviours that had never been checked against a real server
held exactly as the port described them: MyGene's upper case HGNC, Reactome's
404, PanelApp's search that does not filter, and Ensembl's array wrapping a
single record.
The fifth did not, and it was the one with an action already written into it.
Monarch was being called on two hosts, api-v3.monarchinitiative.org for search
and association and api.monarchinitiative.org for the entity route, because
that was how the apps did it and nobody had checked whether they were
interchangeable. They are. All three routes answer on both, and the entity
payload is identical between them down to the order of the ids. So Monarch is
one host now, which also means one circuit breaker instead of two. A host going
down used to open only half of them.
biohttp is not on CRAN, so DESCRIPTION carries a Remotes: line.