Skip to content

Commit

Permalink
Adding ability to retrieve axiom annotations on relationships (axiom …
Browse files Browse the repository at this point in the history
…annotations) (#656)

* Adding ability to retrieve axiom annotations on relationships (axiom annotations)

Fixes #654

* lint
  • Loading branch information
cmungall authored Sep 22, 2023
1 parent 56eaf20 commit 09a1cf6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 10 deletions.
44 changes: 34 additions & 10 deletions src/oaklib/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import yaml
from kgcl_schema.datamodel import kgcl
from linkml_runtime.dumpers import json_dumper, yaml_dumper
from linkml_runtime.loaders import yaml_loader
from linkml_runtime.utils.introspection import package_schemaview
from prefixmaps.io.parser import load_multi_context
from pydantic import BaseModel
Expand Down Expand Up @@ -151,6 +152,7 @@
DisjointnessInducerConfig,
generate_disjoint_class_expressions_axioms,
)
from oaklib.utilities.basic_utils import pairs_as_dict
from oaklib.utilities.iterator_utils import chunk
from oaklib.utilities.kgcl_utilities import (
generate_change_id,
Expand Down Expand Up @@ -876,6 +878,11 @@ def chain_results(v):
"--requests-cache-db",
help="If specified, all http requests will be cached to this sqlite file",
)
@click.option(
"--wrap-adapter",
"-W",
help="Wrap the input adapter using another adapter (e.g. llm or semsimian).",
)
@input_option
@input_type_option
@add_option
Expand All @@ -890,6 +897,7 @@ def main(
quiet: bool,
stacktrace: bool,
input: str,
wrap_adapter: str,
input_type: str,
add: List,
merge: bool,
Expand Down Expand Up @@ -940,11 +948,8 @@ def main(
setattr(settings, k, v)
logging.info(f"Settings = {settings}")
if input:
# impl_class: Type[OntologyInterface]
# resource = get_resource_from_shorthand(input, format=input_type, import_depth=import_depth)
# impl_class = resource.implementation_class
# logging.info(f"RESOURCE={resource}")
# settings.impl = impl_class(resource)
if wrap_adapter:
input = wrap_adapter + ":" + input
settings.impl = get_adapter(input)
settings.impl.autosave = autosave
if merge and not add:
Expand Down Expand Up @@ -1557,6 +1562,11 @@ def term_metadata(terms, predicates, additional_metadata: bool, output_type: str
"-R",
help="path to rules file. Conforms to https://w3id.org/oak/mapping-rules-datamodel",
)
@click.option(
"--configuration-file",
"-C",
help="path to config file. Conforms to https://w3id.org/oak/test-annotation",
)
@output_option
@output_type_option
def annotate(
Expand All @@ -1567,6 +1577,7 @@ def annotate(
include_aliases: bool,
exclude_tokens: str,
rules_file: str,
configuration_file: str,
text_file: TextIO,
model: str,
output_type: str,
Expand All @@ -1578,8 +1589,6 @@ def annotate(
runoak -i bioportal: annotate "enlarged nucleus in T-cells from peripheral blood"
Currently most implementations do not yet support annotation.
See the ontorunner framework for plugins for SciSpacy and OGER - these will
later become plugins.
Expand Down Expand Up @@ -1633,7 +1642,10 @@ def annotate(
save_lexical_index(impl.lexical_index, lexical_index_file)
else:
impl.lexical_index = load_lexical_index(lexical_index_file)
configuration = TextAnnotationConfiguration(matches_whole_text=matches_whole_text)
if configuration_file:
configuration = yaml_loader.load(configuration_file, TextAnnotationConfiguration)
else:
configuration = TextAnnotationConfiguration(matches_whole_text=matches_whole_text)
if exclude_tokens:
token_exclusion_list = get_exclusion_token_list(exclude_tokens)
configuration.token_exclusion_list = token_exclusion_list
Expand Down Expand Up @@ -3134,6 +3146,12 @@ def definitions(
show_default=True,
help="Include instance relationships (class and object property assertions)",
)
@click.option(
"--include-metadata/--no-include-metadata",
default=False,
show_default=True,
help="Include metadata (axiom annotations)",
)
def relationships(
terms,
predicates: str,
Expand All @@ -3146,6 +3164,7 @@ def relationships(
include_entailed: bool,
include_tbox: bool,
include_abox: bool,
include_metadata: bool,
):
"""
Show all relationships for a term or terms
Expand Down Expand Up @@ -3231,9 +3250,14 @@ def relationships(
has_relationships[rel[2]] = True
if if_absent and if_absent == IfAbsent.absent_only.value:
continue
label_fields = ["subject", "predicate", "object"]
obj = {k: rel[i] for i, k in enumerate(label_fields)}
if include_metadata:
metadata_tuples = list(impl.relationships_metadata([rel]))[0][1]
obj["metadata"] = dict(pairs_as_dict(metadata_tuples))
writer.emit(
dict(subject=rel[0], predicate=rel[1], object=rel[2]),
label_fields=["subject", "predicate", "object"],
obj,
label_fields=label_fields,
)
if if_absent and if_absent == IfAbsent.absent_only.value:
for curie in curies:
Expand Down
7 changes: 7 additions & 0 deletions src/oaklib/implementations/sqldb/sql_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,13 @@ def _rbox_relationships(
for row in q:
yield row.subject, row.predicate, row.object

def relationships_metadata(
self, relationships: Iterable[RELATIONSHIP], **kwargs
) -> Iterator[Tuple[RELATIONSHIP, List[Tuple[PRED_CURIE, Any]]]]:

This comment has been minimized.

Copy link
@joeflack4

joeflack4 Sep 25, 2023

Contributor

I think this should be:
Iterator[Tuple[RELATIONSHIP, List[Tuple[om.Annotation]]]]

i.e. replace PRED_CURIE, Any with om.Annotation

edit: I was wrong; disregard

for rel in relationships:
anns = [(ann.predicate, ann.object) for ann in self._axiom_annotations(*rel)]
yield rel, anns

def node_exists(self, curie: CURIE) -> bool:
return self.session.query(Statements).filter(Statements.subject == curie).count() > 0

Expand Down
23 changes: 23 additions & 0 deletions src/oaklib/interfaces/basic_ontology_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,29 @@ def relationships(
continue
yield subject, this_predicate, this_object

def relationships_metadata(
self, relationships: Iterable[RELATIONSHIP], **kwargs
) -> Iterator[Tuple[RELATIONSHIP, List[Tuple[PRED_CURIE, Any]]]]:
"""
given collection of relationships, yield relationships with metadata attached.
>>> from oaklib import get_adapter
>>> adapter = get_adapter("sqlite:obo:mondo")
>>> rels = list(adapter.relationships(["MONDO:0009831"]))
>>> for rel, metadatas in adapter.relationships_metadata(rels):
... for p, v in metadatas:
... print(rel, p, v)
<BLANKLINE>
...
('MONDO:0009831', 'rdfs:subClassOf', 'MONDO:0002516') oio:source NCIT:C9005
...
:param relationships: collection of subject-predicate-object tuples
:param kwargs:
:return: yields relationships with property-value metadata
"""
raise NotImplementedError

def hierarchical_parents(self, curie: CURIE, isa_only: bool = False) -> List[CURIE]:
"""
Returns all hierarchical parents.
Expand Down

0 comments on commit 09a1cf6

Please sign in to comment.