Forráskód Böngészése

Create bridge to outlier data endpoint

Arkadiusz Ryś 3 éve
szülő
commit
dfb83f80c2

+ 2 - 1
requirements.txt

@@ -2,11 +2,12 @@
 arklog            ~= 0.5.1
 rdflib            ~= 6.2.0
 fastapi           ~= 0.92
+requests          ~= 2.28.2
 starlette         ~= 0.25.0
 python-magic      ~= 0.4.27
 uvicorn[standard] ~= 0.20.0
 # Test
-pytest        ~= 7.2.1
+pytest        ~= 7.2.2
 sparqlwrapper ~= 2.0.0
 # Doc
 sphinx ~= 6.1.3

+ 43 - 0
spendpoint/bridge.py

@@ -0,0 +1,43 @@
+import logging
+import arklog
+import requests
+from rdflib import Graph
+from typing import Union
+
+arklog.set_config_logging()
+
+
+def fetch_outliers(
+        file_name: str = "rotation.csv",
+        column: Union[str, int] = 2,
+        iri: str = "<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>"
+    ) -> Graph:
+    """"""
+    outlier_service_url = "http://127.0.0.1:9090/api/csv/outlier"
+    try:
+        column = column if isinstance(column, int) else int(column)
+    except ValueError as e:
+        logging.error(f"Column '{column}' is not parseable to an integer.")
+        raise
+    parameters = {"iri": iri, "column" : column, "file" : file_name}
+    try:
+        outliers_result = requests.post(outlier_service_url, json=parameters, timeout=5)
+        outliers_result.raise_for_status()
+    except requests.exceptions.InvalidSchema as e:
+        logging.error(f"Invalid schema for '{outlier_service_url}'.")
+        raise
+    except requests.exceptions.ConnectTimeout as e:
+        logging.error(f"Request for '{outlier_service_url}' timed out.")
+        raise
+    except requests.exceptions.HTTPError as e:
+        logging.error(f"Service at '{outlier_service_url}' returned an error.")
+        raise
+    except requests.exceptions.ConnectionError as e:
+        logging.error(f"Service at '{outlier_service_url}' is unreachable.")
+        raise
+    # logging.debug(outliers_result.content)
+    # for stmt in outliers_result.content.decode().split("\n"):
+    #     logging.debug(stmt)
+    outlier_graph = Graph()
+    outlier_graph.parse(data=outliers_result.content.decode(encoding="UTF-8"), format="n3")
+    return outlier_graph

+ 4 - 2
spendpoint/main.py

@@ -1,13 +1,15 @@
+import arklog
 from spendpoint.endpoint import SparqlEndpoint
 from spendpoint import __version__
+from spendpoint.service import outlier_service, example_service
 
-from spendpoint.service import outlier_service
-
+arklog.set_config_logging()
 
 app = SparqlEndpoint(
     version = __version__,
     functions = {
         "https://ontology.rys.app/dt/function/outlier": outlier_service,
+        "https://ontology.rys.app/dt/function/example": example_service,
     },
     title = "SPARQL endpoint for storage and services",
     description = "/n".join(("SPARQL endpoint.",))

+ 42 - 2
spendpoint/service.py

@@ -1,11 +1,12 @@
 import logging
-
+import arklog
 import rdflib
 from rdflib import Literal
 from rdflib.plugins.sparql.evalutils import _eval
 from dataclasses import dataclass
 
-logging.basicConfig(encoding="utf-8", level=logging.DEBUG)
+from spendpoint.bridge import fetch_outliers
+arklog.set_config_logging()
 
 
 @dataclass(init=True, repr=True, order=False, frozen=True)
@@ -14,6 +15,45 @@ class Outlier:
     value: str
 
 def outlier_service(query_results, ctx, part, eval_part):
+    """
+
+    Example query:
+    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
+    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
+    PREFIX dtf:  <https://ontology.rys.app/dt/function/>
+    PREFIX owl:  <http://www.w3.org/2002/07/owl#>
+
+    SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+      SERVICE <http://127.0.0.1:8000/> {
+        SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+          BIND(dtf:outlier("rotation.csv", "2", "<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>") AS ?outlier)
+        }
+      }
+    }
+
+    :param query_results:
+    :param ctx:
+    :param part:
+    :param eval_part:
+    :return:
+    """
+    logging.debug(f"Outlier service.")
+    file_name = str(_eval(part.expr.expr[0], eval_part.forget(ctx, _except=part.expr._vars)))
+    column = str(_eval(part.expr.expr[1], eval_part.forget(ctx, _except=part.expr._vars)))
+    iri = str(_eval(part.expr.expr[2], eval_part.forget(ctx, _except=part.expr._vars)))
+    logging.info(f"Looking for outlier in '{file_name}' at column '{column}' for '{iri}'.")
+    outlier_graph = fetch_outliers(file_name, column, iri)
+    for stmt in outlier_graph:
+        query_results.append(eval_part.merge({
+            part.var: stmt[0],
+            rdflib.term.Variable(part.var + "_relation") : stmt[1],
+            rdflib.term.Variable(part.var + "_value") : stmt[2],
+        }))
+    return query_results, ctx, part, eval_part
+
+
+def example_service(query_results, ctx, part, eval_part):
     """"""
     logging.debug(f"{query_results=}")
     logging.debug(f"{ctx=}")

+ 2 - 0
tests/conftest.py

@@ -0,0 +1,2 @@
+import pytest
+from tests.fixtures.state import test_data

+ 0 - 0
tests/fixtures/__init__.py


+ 6 - 0
tests/fixtures/state.py

@@ -0,0 +1,6 @@
+import pytest
+
+
+@pytest.fixture(params=["http://localhost:8000"])
+def test_data(request):
+    return request.params

+ 100 - 0
tests/test_query_endpoint.py

@@ -0,0 +1,100 @@
+import logging
+from urllib.error import URLError
+import arklog
+from SPARQLWrapper import SPARQLWrapper, JSON
+
+arklog.set_config_logging()
+
+prefixes = "\n".join((
+    "PREFIX dtf:  <https://ontology.rys.app/dt/function/>",
+    "PREFIX owl:  <http://www.w3.org/2002/07/owl#>",
+    "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>",
+    "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>",
+    "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>",
+))
+
+
+# TODO Convert to test
+def query_0():
+    """"""
+    sparql = SPARQLWrapper("http://localhost:8000")
+    sparql.setReturnFormat(JSON)
+    sparql.setQuery(
+        prefixes +
+        """
+        SELECT ?outlier ?outlier_value WHERE {
+            BIND(dtf:outlier("data.csv", "2") AS ?outlier)
+        }
+        """
+    )
+    try:
+        ret = sparql.query().convert()
+    except URLError as e:
+        logging.error(e)
+        return
+    if not ret:
+        logging.info("No outliers!")
+    for r in ret["results"]["bindings"]:
+        logging.info(r)
+
+
+# TODO Convert to test
+def query_1():
+    """"""
+    sparql = SPARQLWrapper("http://localhost:8000")
+    sparql.setReturnFormat(JSON)
+    sparql.setQuery(
+        prefixes +
+        """
+        SELECT ?outlier WHERE {
+            SERVICE <http://localhost:8000/> {
+                SELECT ?outlier ?outlier_value WHERE {
+                    BIND(dtf:outlier("data2.csv", "1") AS ?outlier)
+                }
+            }
+        }
+        """
+    )
+    try:
+        ret = sparql.query().convert()
+    except URLError as e:
+        logging.error(e)
+        return
+    if not ret:
+        logging.info("No outliers!")
+    for r in ret["results"]["bindings"]:
+        logging.info(r)
+
+
+# TODO Convert to test
+def query_2():
+    """"""
+    sparql = SPARQLWrapper("http://localhost:8000")
+    sparql.setReturnFormat(JSON)
+    sparql.setQuery(
+        prefixes +
+        """
+        SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+            SERVICE <http://127.0.0.1:8000/> {
+                SELECT ?outlier ?outlier_relation ?outlier_value WHERE {
+                    BIND(dtf:outlier("rotation.csv", "2", "<http://ua.be/drivetrain/description/artifacts/artifacts#drivetrain-sensor-data-v1>") AS ?outlier)
+                }
+            }
+        }
+        """
+    )
+    try:
+        ret = sparql.query().convert()
+    except URLError as e:
+        logging.error(e)
+        return
+    if not ret:
+        logging.info("No outliers!")
+    for r in ret["results"]["bindings"]:
+        logging.info(r)
+
+
+if __name__ == "__main__":
+    query_0()
+    query_1()
+    query_2()