Source code for hpotk.annotations._base

import abc
import enum
import typing

from hpotk.model import Identified, Named, TermId
from hpotk.model import CURIE_OR_TERM_ID
from ._api import FrequencyAwareFeature, AnnotatedItem, AnnotatedItemContainer


[docs] class EvidenceCode(enum.Enum): """ An enumeration with evidence codes. """ IEA = enum.auto() """ Inferred from electronic evidence. """ TAS = enum.auto() """ Traceable author statement. """ PCS = enum.auto() """ Published clinical study. """
[docs] @staticmethod def parse(value: str): """ Parse evidence code from `str` value. :param value: a str with the evidence code. :return: the parsed enum member or `None` if `value` is not valid `EvidenceCode` value. """ value = value.upper() if value == 'IEA': return EvidenceCode.IEA elif value == 'TAS': return EvidenceCode.TAS elif value == 'PCS': return EvidenceCode.PCS else: return None
[docs] class Sex(enum.Enum): """ An enum representing values of apparent biological sex. .. note:: We do not attempt to model all contemporary complexities of the sex. """ UNKNOWN = enum.auto() MALE = enum.auto() FEMALE = enum.auto()
[docs] @staticmethod def parse(value: str): """ Parse :class:`Sex` from a `str` value. :param value: a `str` with the sex code. :return: the parsed enum member or `None` if `value` is not valid :class:`Sex` value. """ value = value.upper() if value == 'MALE': return Sex.MALE elif value == 'FEMALE': return Sex.FEMALE elif value == 'UNKNOWN': return Sex.UNKNOWN else: return None
[docs] class AnnotationReference(Identified): def __init__(self, identifier: TermId, evidence_code: EvidenceCode): if not isinstance(identifier, TermId): raise ValueError(f'Identifier {identifier} is not a `TermId`') if not isinstance(evidence_code, EvidenceCode): raise ValueError(f'Evidence code {evidence_code} is not an `EvidenceCode`') self._identifier = identifier self._evidence_code = evidence_code @property def identifier(self) -> TermId: return self._identifier @property def evidence_code(self) -> EvidenceCode: return self._evidence_code def __eq__(self, other): return isinstance(other, AnnotationReference) \ and self.identifier == other.identifier \ and self.evidence_code == other.evidence_code def __hash__(self): return hash((self._identifier, self._evidence_code)) def __str__(self): return f"AnnotationReference(" \ f"identifier={self._identifier}, " \ f"evidence_code={self._evidence_code})" def __repr__(self): return f"AnnotationReference(" \ f"identifier={repr(self._identifier)}, " \ f"evidence_code={repr(self._evidence_code)})"
[docs] class HpoDiseaseAnnotation(Identified, FrequencyAwareFeature, metaclass=abc.ABCMeta): """ `HpoDiseaseAnnotation` models data of a single disease annotation. The annotation has the following attributes: * `identifier` - annotation ID, e.g. `HP:0001250` * frequency-related attributes of the annotation, such as `frequency` (see :class:`FrequencyAwareFeature` for more info) * `references` - a sequence of cross-references that support presence/absence of the annotation * `modifiers` - a sequence of clinical modifiers of the annotation, such as age of onset, severity, laterality, ... """ @property @abc.abstractmethod def references(self) -> typing.Sequence[AnnotationReference]: """ :return: a list of annotation references that support presence/absence of the disease annotation """ pass @property @abc.abstractmethod def modifiers(self) -> typing.Sequence[TermId]: """ :return: a list of disease annotation modifiers """ pass def __str__(self): return f"HpoDiseaseAnnotation(" \ f"identifier={self.identifier.value}, " \ f"frequency={self.numerator}/{self.denominator}, " \ f"references={self.references}, " \ f"modifiers={self.modifiers})" def __repr__(self): return f"HpoDiseaseAnnotation(" \ f"identifier={self.identifier}, " \ f"numerator={self.numerator}, " \ f"denominator={self.denominator}, " \ f"references={self.references}, " \ f"modifiers={self.modifiers})"
[docs] class HpoDisease(AnnotatedItem[HpoDiseaseAnnotation], Identified, Named, metaclass=abc.ABCMeta): """ `HpoDisease` represents a computational model of a rare disease. The model includes attributes: * `identifier` - disease ID, e.g. `OMIM:256000` * `name` - human-readable disease name, e.g. `LEIGH SYNDROME; LS` * `annotations` - the phenotype annotations of the disease. See :class:`AnnotatedItem` for more details on *all* annotation-related methods * `modes_of_inheritance` - a collection of the modes of inheritance associated with the disease """ @property @abc.abstractmethod def modes_of_inheritance(self) -> typing.Collection[TermId]: """ :return: a collection of modes of inheritance associated with the disease. """ pass def __str__(self): return f"HpoDisease(" \ f"identifier={self.identifier}, " \ f"name={self.name}, " \ f"n_annotations={len(self.annotations)})"
[docs] class HpoDiseases(AnnotatedItemContainer[HpoDiseaseAnnotation], metaclass=abc.ABCMeta): """ A container for HPO diseases that allows iteration over all diseases, knows about the number of diseases in the container, and supports retrieval of the disease by its identifier. """ @abc.abstractmethod def __getitem__(self, disease_id: CURIE_OR_TERM_ID) -> typing.Optional[HpoDisease]: """ Get :class:`HpoDisease` based on given `disease_id` or `None` if the disease for the identifier is not present in the container. :param disease_id: a CURIE `str` or a :class:`TermId` of the disease identifier. :return: :class:`HpoDisease` or `None` """ pass def __str__(self): return f"HpoDiseases(n_diseases={len(self)}, " \ f"version={self.version})"