Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add definition method to OLS implementation #831

Merged
merged 7 commits into from
Mar 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ gendoc-itemlist: src/oaklib/datamodels/item_list.yaml
$(RUN_GENDOC) $< -d docs/datamodels/item-list
gendoc-ce: src/oaklib/datamodels/class_enrichment.yaml
$(RUN_GENDOC) $< -d docs/datamodels/class-enrichment
gendoc-vsc: src/oaklib/datamodels/value_set_configuration.yaml
$(RUN_GENDOC) $< -d docs/datamodels/value-set-configuration

nb:
$(RUN) jupyter notebook
Expand Down
4 changes: 2 additions & 2 deletions src/oaklib/conf/lexmatch-rules-oboinowl-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,13 @@ rules:
weight: 2.0

- synonymizer:
the_rule: Remove parentheses bound info from the label.
description: Remove parentheses bound info from the label.
match: r'\([^)]*\)'
match_scope: "*"
replacement: ""

- synonymizer:
the_rule: Remove box brackets bound info from the label.
description: Remove box brackets bound info from the label.
match: r'\[[^)]*\]'
match_scope: "*"
replacement: ""
Expand Down
8 changes: 5 additions & 3 deletions src/oaklib/datamodels/value_set_configuration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ id: https://w3id.org/linkml/value-set-configuration
title: Value Set Configuration
name: value-set-configuration
description: >-
A datamodel for configuring value sets and value set expabsions
A datamodel for configuring value sets and value set expansions
license: https://creativecommons.org/publicdomain/zero/1.0/

prefixes:
Expand All @@ -24,11 +24,12 @@ imports:
#==================================
classes:
ValueSetConfiguration:
description: configuration for value sets
description: configuration for value set expansion
attributes:
default_resolver:
range: Resolver
inlined: true
description: The default resolver to use for value set expansion
resource_resolvers:
range: Resolver
multivalued: true
Expand All @@ -37,6 +38,7 @@ classes:
range: Resolver
multivalued: true
inlined: true
description: Mapping of prefixes to resolvers

Resolver:
description: A mechanism for resolving using an ontology
Expand All @@ -47,7 +49,7 @@ classes:
description: The name of the resource or prefix
shorthand_prefix:
shorthand:
description: A shorthand for the resolver, using the OAK shorthand syntax
description: A shorthand for the resolver, using the OAK shorthand syntax, for example, 'obo:sqlite:cl'
method:
range: ResolverMethod
description: >-
Expand Down
86 changes: 81 additions & 5 deletions src/oaklib/implementations/ols/ols_implementation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import ChainMap
from dataclasses import dataclass, field
from typing import Any, ClassVar, Dict, Iterable, Iterator, List, Tuple, Union
from typing import Any, ClassVar, Dict, Iterable, Iterator, List, Optional, Tuple, Union

import requests
from ols_client import Client, EBIClient, TIBClient
Expand All @@ -18,7 +18,7 @@
from oaklib.interfaces.mapping_provider_interface import MappingProviderInterface
from oaklib.interfaces.search_interface import SearchInterface
from oaklib.interfaces.text_annotator_interface import TextAnnotatorInterface
from oaklib.types import CURIE, PRED_CURIE
from oaklib.types import CURIE, LANGUAGE_TAG, PRED_CURIE

__all__ = [
# Abstract classes
Expand All @@ -40,13 +40,14 @@


@dataclass
class BaseOlsImplementation(TextAnnotatorInterface, SearchInterface, MappingProviderInterface):
class BaseOlsImplementation(MappingProviderInterface, TextAnnotatorInterface, SearchInterface):
"""
Implementation over OLS and OxO APIs
"""

ols_client_class: ClassVar[type[Client]]
label_cache: Dict[CURIE, str] = field(default_factory=lambda: {})
definition_cache: Dict[CURIE, str] = field(default_factory=lambda: {})
base_url = "https://www.ebi.ac.uk/spot/oxo/api/mappings"
_prefix_map: Dict[str, str] = field(default_factory=lambda: {})
focus_ontology: str = None
Expand All @@ -66,9 +67,84 @@ def add_prefix(self, curie: str, uri: str):
def prefix_map(self) -> PREFIX_MAP:
return ChainMap(super().prefix_map(), self._prefix_map)

def labels(self, curies: Iterable[CURIE]) -> Iterable[Tuple[CURIE, str]]:
def label(self, curie: CURIE, lang: Optional[LANGUAGE_TAG] = None) -> Optional[str]:
"""
Fetch the label for a CURIE from OLS.

:param curie: The CURIE to fetch the label for
:param lang: Optional language tag (not currently supported by this implementation)
:return: The label for the CURIE, or None if not found
"""
if curie in self.label_cache:
return self.label_cache[curie]

ontology = self.focus_ontology
iri = self.curie_to_uri(curie)
term = self.client.get_term(ontology=ontology, iri=iri)
if term and "label" in term:
self.label_cache[curie] = term["label"]
return term["label"]
return None

def labels(
self, curies: Iterable[CURIE], allow_none=True, lang: LANGUAGE_TAG = None
) -> Iterable[Tuple[CURIE, str]]:
"""
Fetch labels for multiple CURIEs.

:param curies: The CURIEs to fetch labels for
:param allow_none: Whether to include CURIEs with no label
:param lang: Optional language tag (not currently supported by this implementation)
:return: Iterator of (CURIE, label) tuples
"""
for curie in curies:
label = self.label(curie, lang)
if label is None and not allow_none:
continue
yield curie, label

def definition(self, curie: CURIE, lang: Optional[LANGUAGE_TAG] = None) -> Optional[str]:
"""
Fetch the definition for a CURIE from OLS.

:param curie: The CURIE to fetch the definition for
:param lang: Optional language tag (not currently supported by this implementation)
:return: The definition for the CURIE, or None if not found
"""
if curie in self.definition_cache:
return self.definition_cache[curie]

ontology = self.focus_ontology
iri = self.curie_to_uri(curie)
term = self.client.get_term(ontology=ontology, iri=iri)
if term and "description" in term and term["description"]:
self.definition_cache[curie] = term["description"]
return term["description"]
return None

def definitions(
self,
curies: Iterable[CURIE],
include_metadata=False,
include_missing=False,
lang: Optional[LANGUAGE_TAG] = None,
) -> Iterator[Tuple[CURIE, Optional[str], Dict]]:
"""
Fetch definitions for multiple CURIEs from OLS.

:param curies: The CURIEs to fetch definitions for
:param include_metadata: Whether to include metadata (currently not supported)
:param include_missing: Whether to include CURIEs with no definition
:param lang: Optional language tag (not currently supported by this implementation)
:return: Iterator of (CURIE, definition, metadata) tuples
"""
for curie in curies:
yield curie, self.label_cache[curie]
definition = self.definition(curie, lang)
if definition is None and not include_missing:
continue
# Currently OLS doesn't provide metadata for definitions through the API
# So we're just returning an empty dict
yield curie, definition, {}

def annotate_text(self, text: str) -> Iterator[TextAnnotation]:
raise NotImplementedError
Expand Down
1 change: 1 addition & 0 deletions src/oaklib/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
SUBSET_CURIE = CURIE
CATEGORY_CURIE = CURIE
TAXON_CURIE = CURIE
LANGUAGE_TAG = str
COUNT_MAP = Mapping[CURIE, int]
Loading