Skip to content

Commit f1403d0

Browse files
authored
Add function and CLI command for serving SSSOM from SPARQL (#619)
1 parent 0f0b1fd commit f1403d0

File tree

6 files changed

+301
-2
lines changed

6 files changed

+301
-2
lines changed

poetry.lock

Lines changed: 185 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ docs = [
4444
"sphinx-click>=4.3.0",
4545
"myst-parser>=0.18.1",
4646
]
47+
rdflib-endpoint = [
48+
"uvicorn",
49+
"fastapi",
50+
"rdflib-endpoint",
51+
"httpx", # only used in tests, but this is small
52+
]
4753

4854
[project.scripts]
4955
sssom = "sssom.cli:main"

src/sssom/cli.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
sort_df_rows_columns,
6363
to_mapping_set_dataframe,
6464
)
65-
from .writers import WRITER_FUNCTIONS, write_table
65+
from .writers import WRITER_FUNCTIONS, get_rdflib_endpoint_app, write_table
6666

6767
logging = _logging.getLogger(__name__)
6868

@@ -816,5 +816,25 @@ def invert(
816816
write_table(msdf, output)
817817

818818

819+
@main.command(name="serve-rdf")
820+
@input_argument
821+
@click.option(
822+
"--hydrate/--no-hydrate",
823+
is_flag=True,
824+
default=True,
825+
show_default=True,
826+
help="Infer S-P-O simple triples from axioms. On by default.",
827+
)
828+
@click.option("--host", default="127.0.0.1", show_default=True)
829+
@click.option("--port", type=int, default=8000, show_default=True)
830+
def serve_rdf(input: str, host: str, port: int, hydrate: bool) -> None:
831+
"""Serve the SSSOM file as an RDF SPARQL endpoint."""
832+
import uvicorn
833+
834+
msdf = parse_sssom_table(input)
835+
app = get_rdflib_endpoint_app(msdf, hydrate=hydrate)
836+
uvicorn.run(app, host=host, port=port)
837+
838+
819839
if __name__ == "__main__":
820840
main()

src/sssom/writers.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
"""Serialization functions for SSSOM."""
22

3+
from __future__ import annotations
4+
35
import json
46
import logging as _logging
57
from contextlib import contextmanager
68
from pathlib import Path
79
from typing import (
10+
TYPE_CHECKING,
811
Any,
912
Callable,
1013
Collection,
@@ -45,6 +48,9 @@
4548
sort_df_rows_columns,
4649
)
4750

51+
if TYPE_CHECKING:
52+
import rdflib_endpoint
53+
4854
logging = _logging.getLogger(__name__)
4955

5056
# noinspection PyProtectedMember
@@ -362,6 +368,45 @@ def to_rdf_graph(msdf: MappingSetDataFrame, *, hydrate: bool = False) -> Graph:
362368
return cast(Graph, graph)
363369

364370

371+
EXAMPLE_SPARQL_QUERY = """\
372+
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
373+
PREFIX owl: <http://www.w3.org/2002/07/owl#>
374+
PREFIX sssom: <https://w3id.org/sssom/>
375+
PREFIX obo: <http://purl.obolibrary.org/obo/>
376+
PREFIX semapv: <https://w3id.org/semapv/vocab/>
377+
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
378+
PREFIX pav: <http://purl.org/pav/>
379+
PREFIX orcid: <https://orcid.org/>
380+
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
381+
382+
SELECT ?s ?p ?o ?justification {
383+
[] a owl:Axiom ;
384+
owl:annotatedSource ?s ;
385+
owl:annotatedProperty ?p ;
386+
owl:annotatedTarget ?o ;
387+
sssom:mapping_justification ?justification ;
388+
}
389+
LIMIT 50
390+
"""
391+
392+
393+
def get_rdflib_endpoint_app(
394+
msdf: MappingSetDataFrame, *, hydrate: bool = True
395+
) -> rdflib_endpoint.SparqlEndpoint:
396+
"""Get a FastAPI app that serves the mappings from a SPARQL endpoint."""
397+
from rdflib_endpoint import SparqlEndpoint
398+
399+
graph = to_rdf_graph(msdf, hydrate=hydrate)
400+
app = SparqlEndpoint(
401+
graph=graph,
402+
cors_enabled=True,
403+
title=f"SSSOM SPARQL Endpoint for {msdf.metadata['mapping_set_id']}",
404+
description=msdf.metadata.get("mapping_set_description"),
405+
example_query=EXAMPLE_SPARQL_QUERY,
406+
)
407+
return app
408+
409+
365410
def to_fhir_json(msdf: MappingSetDataFrame) -> Dict[str, Any]:
366411
"""Convert a mapping set dataframe to a JSON object.
367412

0 commit comments

Comments
 (0)