Resistance interpretation
Turning variant calls into HIV-1 drug-resistance calls. The scoring engine reproduces 3,348 published Stanford expectations exactly; see validation.
Positions must be in whole-genome HXB2 K03455 coordinates. A reference numbered any other way — a pol-relative one is the case that matters — is refused before any compute, as a ReferenceFrameError; declare the frame it is numbered along with lg.reference(..., frame=(...)). This was silent until the SAWA evaluation found it.
ResistanceReport
class ResistanceReport(core: '_core.Dataset') -> 'None'An interpreted drug-resistance report.
ResistanceReport.applicable
applicable: tuple[str, ...] # propertyThe dimensions that mean anything for this kind of data.
A dimension outside this set is not a gap to be filled in: asking a FASTA for its quality encoding is a category error.
ResistanceReport.contigs
contigs: list[Contig] | None # propertyThe contigs of the reference this data is on, in file order.
ResistanceReport.dimension
dimension(self, name: 'str') -> 'DimensionValue | None'One dimension’s value, or None if it is unknown or inapplicable.
ResistanceReport.dimensions
dimensions: Mapping[str, DimensionValue] # propertyEvery dimension that has a known value, by name.
ResistanceReport.file
file: str # propertyThe file this data is, for code that has to open it.
path is the honest answer to “where did this come from, if
anywhere?”, so it can be None — a step’s output carries dimensions
worked out before anything ran, and has no file of its own until it
does. This is the answer for the other question, the one a
lg.write body asks:
return lg.write(lambda out: interpret(v.file, out))
Inside that function the steps above have run, so there is a file, and saying so in the type is what keeps a body from having to prove it.
Raises
| Raises | When |
|---|---|
ValueError | If this data has no file behind it at all. |
ResistanceReport.files
files: tuple[str, ...] # propertyEvery file this data is, in order.
One for most kinds and two for a pair of FASTQ mates, in mate
order. file names the primary one, which is what a message
quotes; this is what code that has to open all of them wants.
ResistanceReport.kind
kind: str # propertyThe name of the kind of data this holds.
ResistanceReport.notes
notes: tuple[str, ...] # propertyWhat loading this noticed, as one sentence each.
Usually empty. A note is not a failure and never stops anything: it is something true of the data that you cannot act on without being told. A gene list is the file this exists for — its symbols can arrive already corrupted by a spreadsheet, which is a fact about the input rather than about any step, so no step’s output could report it.
ResistanceReport.origin
origin: RemoteOrigin | None # propertyWhere this was fetched from, or None if it was not fetched.
The overwhelming majority of inputs are files somebody has, and for
those this says nothing by being None.
ResistanceReport.path
path: str | None # propertyThe file this was loaded from.
ResistanceReport.samples
samples: list[str] | None # propertyThe samples this data covers, in order.
ResistanceReport.unknown_reason
unknown_reason(self, name: 'str') -> 'str | None'Why an applicable dimension has no value.
None when the dimension is known, or when it does not apply to this kind of data at all.
hivdb.interpret
interpret(
variants: 'Variants',
reference: 'Reference',
*,
coverage: 'Alignment | None' = None,
algorithm: 'str' = 'HIVDB_9.8',
mixture: 'float' = 0.15,
depth: 'int' = 100,
gene_coverage: 'float' = 0.8,
) -> 'ResistanceReport'Score a sample’s variants against a vendored resistance algorithm.
Parameters
| Parameter | Description |
|---|---|
variants | The calls to interpret. |
reference | The reference they were called against. Required: codons cannot be assembled without it. |
coverage | The alignment the calls came from. Without it no position can be known to be unread and no codon can be phased, and the reading notes both assumptions — which the run report then says and pipe.run() carries on the step’s notes. |
algorithm | Which vendored algorithm to use, from ALGORITHMS. |
mixture | The fraction of reads an allele must reach to count as present. Where both the reference and an alternate reach it the codon holds both amino acids, exactly as an ambiguous base does to Stanford’s own interpreter — taking the majority instead would discard the minority resistance that deep sequencing exists to find. With an alignment it also decides which combinations of those alleles are real: a VCF says what is at each position and not what travels together, so reads spanning a codon are counted as the triplets they carry and the codon holds the amino acids reaching this fraction of them. |
depth | The depth a position must reach to count as read. A codon whose bases do not all reach it is reported as unread rather than as reference. |
gene_coverage | The share of a gene’s scored codons — the ones algorithm’s rules name — that must be read for the gene to be assessed at all. A gene below it is reported as not assessed rather than scored against the little that was seen, because a gene whose scored positions are mostly unread scores zero, and zero reads as susceptible. Counted over the scored codons rather than the gene because a position no rule names cannot change an answer. |
Returns
A recipe, typed as the report the step declares.
Raises
| Raises | When |
|---|---|
ValueError | If algorithm is not one the engine ships. The error names the ones it does. |
ReferenceFrameError | When the recipe runs, if reference cannot be the frame the gene windows are stated in. A pipeline is refused earlier than this, by check(), where the reference’s declared frame is known. |
hivdb.fingerprint
fingerprint() -> 'str'What the vendored algorithms are, and which engine reads them.
This is what a step declaring tool="hivdb" records as its tool
version, so it is what puts the rules into the cache key. It names
every vendored algorithm rather than only the one in use, because the
engine probes versions before any step body has said which it wants.
It ends with this engine’s own version, because the rules are only half of what the step is: the other half is the engine’s judgements about reading them — which codons count as read, how much of a gene has to be — and those move between releases.
Returns
A line naming each algorithm, its version, its date and the BLAKE3 of its rules, then the version of the engine reading them.
hivdb.ALGORITHMS
hivdb.ALGORITHMS: tuple = ('HIVDB_10.2', 'HIVDB_9.8')hivdb.DEFAULT
hivdb.DEFAULT: str = 'HIVDB_9.8'hivdb.MIXTURE
hivdb.MIXTURE: float = 0.15hivdb.DEPTH
hivdb.DEPTH: int = 100hivdb.GENE_COVERAGE
hivdb.GENE_COVERAGE: float = 0.8