Skip to content

Commit

Permalink
Add cross-references to Term's definition.
Browse files Browse the repository at this point in the history
  • Loading branch information
ielis committed Mar 12, 2024
1 parent 71d333b commit 1b2eedd
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 16 deletions.
6 changes: 5 additions & 1 deletion docs/user-guide/load-ontology.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,12 @@ So, now we can access the definition of the seizure:
.. doctest:: load-ontology

>>> seizure = hpo.get_term('HP:0001250')
>>> seizure.definition
>>> definition = seizure.definition
>>> definition.definition
'A seizure is an intermittent abnormality of nervous system physiology characterised by a transient occurrence of signs and/or symptoms due to abnormal excessive or synchronous neuronal activity in the brain.'
>>> definition.xrefs
('https://orcid.org/0000-0002-0736-9199', 'PMID:15816939')


or check out seizure's synonyms:

Expand Down
4 changes: 2 additions & 2 deletions src/hpotk/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from ._term_id import TermId
from ._base import Identified, ObservableFeature, FrequencyAwareFeature, Named, Versioned, MetadataAware
from ._term import MinimalTerm, Term, Synonym, SynonymType, SynonymCategory
from ._term import MinimalTerm, Term, Synonym, SynonymType, SynonymCategory, Definition

# Types
ID = typing.TypeVar('ID', bound=TermId)
Expand All @@ -18,6 +18,6 @@
__all__ = [
'TermId', 'MinimalTerm', 'Term',
'Identified', 'ObservableFeature', 'FrequencyAwareFeature', 'Named', 'Versioned', 'MetadataAware',
'Synonym', 'SynonymType', 'SynonymCategory',
'Synonym', 'SynonymType', 'SynonymCategory', 'Definition',
'ID', 'CURIE_OR_TERM_ID', 'CURIE_OR_TERM_ID_OR_IDENTIFIED', 'MINIMAL_TERM', 'TERM'
]
68 changes: 60 additions & 8 deletions src/hpotk/model/_term.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def xrefs(self) -> typing.Optional[typing.Sequence[TermId]]:
return self._xrefs

def __eq__(self, other):
isinstance(other, Synonym) \
return isinstance(other, Synonym) \
and self.name == other.name \
and self.category == other.category \
and self.synonym_type == other.synonym_type \
Expand All @@ -190,13 +190,63 @@ def __repr__(self):
return str(self)


class Definition:
"""
`Definition` includes a definition and the cross-references.
:param definition: a definition,
e.g. *Abnormally long and slender fingers ("spider fingers").* for *Arachnodactyly*.
:param xrefs: an iterable with definition cross-references,
e.g. `('https://orcid.org/0000-0002-0736-9199',)` for *Arachnodactyly*.
"""

def __init__(
self,
definition: str,
xrefs: typing.Iterable[str],
):
self._definition = hpotk.util.validate_instance(definition, str, 'definition')
self._xrefs = tuple(xrefs)

@property
def definition(self) -> str:
"""
Get a `str` with the term definition.
For instance, *Abnormally long and slender fingers ("spider fingers").* for *Arachnodactyly*.
"""
return self._definition

@property
def xrefs(self) -> typing.Sequence[str]:
"""
Get definition of cross-references of a definition.
For instance, `('https://orcid.org/0000-0002-0736-9199',)` for *Arachnodactyly*.
"""
return self._xrefs

def __eq__(self, other):
return isinstance(other, Definition) \
and self.definition == other.definition \
and self.xrefs == other.xrefs

def __str__(self):
return f'Definition(' \
f'definition="{self.definition}", ' \
f'xrefs={self.xrefs}")'

def __repr__(self):
return str(self)


class Term(MinimalTerm, metaclass=abc.ABCMeta):
"""
A comprehensive representation of an ontology concept.
`Term` has all attributes of the :class:`MinimalTerm` plus the following:
* `definition` - an optional verbose definition of the term
* `definition` - an optional verbose definition of the term, including the cross-references
* `comment` - an optional comment
* `synonyms` - an optional sequence of term synonyms
* `cross-references` - an optional sequence of cross-references
Expand All @@ -212,7 +262,7 @@ def create_term(identifier: typing.Union[TermId, str],
name: str,
alt_term_ids: typing.Iterable[typing.Union[TermId, str]],
is_obsolete: bool,
definition: typing.Optional[str],
definition: typing.Optional[typing.Union[Definition, str]],
comment: typing.Optional[str],
synonyms: typing.Optional[typing.Iterable[Synonym]],
xrefs: typing.Optional[typing.Iterable[TermId]]):
Expand All @@ -223,17 +273,19 @@ def create_term(identifier: typing.Union[TermId, str],
:param name: term name (e.g. Seizure).
:param alt_term_ids: an iterable with term IDs that represent the alternative IDs of the term.
:param is_obsolete: `True` if the `MinimalTerm` has been obsoleted, or `False` otherwise.
:param definition: an optional definition of the term.
:param definition: an optional `str` with a definition of the term or a :class:`Definition` with the full info.
:param comment: an optional comment of the term.
:param synonyms: an optional iterable with all synonyms of the term.
:param xrefs: an optional iterable with all the cross-references.
:return: the created term.
"""
if isinstance(definition, str):
definition = Definition(definition, ())
return DefaultTerm(identifier, name, alt_term_ids, is_obsolete, definition, comment, synonyms, xrefs)

@property
@abc.abstractmethod
def definition(self) -> typing.Optional[str]:
def definition(self) -> typing.Optional[Definition]:
"""
Get the definition of the ontology concept.
"""
Expand Down Expand Up @@ -381,19 +433,19 @@ def __init__(self, identifier: typing.Union[TermId, str],
name: str,
alt_term_ids: typing.Iterable[typing.Union[TermId, str]],
is_obsolete: bool,
definition: typing.Optional[str],
definition: typing.Optional[Definition],
comment: typing.Optional[str],
synonyms: typing.Optional[typing.Iterable[Synonym]],
xrefs: typing.Optional[typing.Iterable[typing.Union[TermId, str]]]):
DefaultMinimalTerm.__init__(self, identifier=identifier, name=name,
alt_term_ids=alt_term_ids, is_obsolete=is_obsolete)
self._definition = hpotk.util.validate_optional_instance(definition, str, 'definition')
self._definition = hpotk.util.validate_optional_instance(definition, Definition, 'definition')
self._comment = hpotk.util.validate_optional_instance(comment, str, 'comment')
self._synonyms = validate_synonyms(synonyms)
self._xrefs = tuple(map(map_to_term_id, xrefs)) if xrefs is not None else None

@property
def definition(self) -> typing.Optional[str]:
def definition(self) -> typing.Optional[Definition]:
return self._definition

@property
Expand Down
9 changes: 7 additions & 2 deletions src/hpotk/ontology/load/obographs/_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import re
import typing

from hpotk.model import TermId, Term, MinimalTerm, Synonym, SynonymType, SynonymCategory
from hpotk.model import TermId, Term, MinimalTerm, Synonym, SynonymType, SynonymCategory, Definition
from ._model import Node, Meta, SynonymPropertyValue

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -138,7 +138,12 @@ class TermFactory(ObographsTermFactory[Term]):

def create_term(self, term_id: TermId, node: Node) -> typing.Optional[Term]:
if node.meta:
definition = node.meta.definition.val if node.meta.definition else None
if node.meta.definition is not None:
d = node.meta.definition.val
xrefs = node.meta.definition.xrefs
definition = Definition(d, xrefs)
else:
definition = None
comment = ', '.join(node.meta.comments) if len(node.meta.comments) > 0 else None
alt_term_ids = create_alt_term_ids(node)
synonyms = create_synonyms(node.meta)
Expand Down
4 changes: 3 additions & 1 deletion tests/ontology/load/test_obographs.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ def test_term_properties(self, toy_ontology: hpotk.Ontology):

assert term.identifier.value == 'HP:0001626'
assert term.name == 'Abnormality of the cardiovascular system'
assert term.definition == 'Any abnormality of the cardiovascular system.'
definition = term.definition
assert definition.definition == 'Any abnormality of the cardiovascular system.'
assert definition.xrefs == ('HPO:probinson',)
assert term.comment == 'The cardiovascular system consists of the heart, vasculature, and the lymphatic system.'

assert not term.is_obsolete
Expand Down
4 changes: 3 additions & 1 deletion tests/test_obographs.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ def test_term_properties(self, toy_hpo: hpotk.Ontology):

assert term.identifier.value == 'HP:0001626'
assert term.name == 'Abnormality of the cardiovascular system'
assert term.definition == 'Any abnormality of the cardiovascular system.'
definition = term.definition
assert definition.definition == 'Any abnormality of the cardiovascular system.'
assert definition.xrefs == ('HPO:probinson',)
assert term.comment == 'The cardiovascular system consists of the heart, vasculature, and the lymphatic system.'
assert not term.is_obsolete
assert term.alt_term_ids == (hpotk.TermId.from_curie('HP:0003116'),)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_term.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def test_equal_terms_are_equal(self):
name="First",
alt_term_ids=[TermId.from_curie("HP:1111111")],
is_obsolete=False,
definition="First term definition",
definition=Definition("First term definition", ()),
comment="First comment",
synonyms=[one_syn], xrefs=[TermId.from_curie("SNOMED_CT:123456")])
assert one == two
Expand Down

0 comments on commit 1b2eedd

Please sign in to comment.