Make RemoteSparqlBackend actually work and use it in Field/Table tests
This commit is contained in:
parent
fb02fb3841
commit
a4087ac180
|
@ -15,6 +15,7 @@
|
||||||
"""Abstraction over SPARQL backends, primarily meant to be mocked by tests."""
|
"""Abstraction over SPARQL backends, primarily meant to be mocked by tests."""
|
||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
import urllib.parse
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
@ -41,8 +42,14 @@ class RemoteSparqlBackend(SparqlBackend):
|
||||||
self._session.headers["User-Agent"] = agent
|
self._session.headers["User-Agent"] = agent
|
||||||
|
|
||||||
def query(self, query: str) -> Iterable[tuple]:
|
def query(self, query: str) -> Iterable[tuple]:
|
||||||
params = {"format": "json", "query": query}
|
headers = {
|
||||||
resp = self._session.post(self._url, params=params).json()
|
"Content-Type": "application/sparql-query",
|
||||||
|
"Accept": "application/json",
|
||||||
|
}
|
||||||
|
params = {"query": query}
|
||||||
|
resp = self._session.post(
|
||||||
|
self._url, headers=headers, data=urllib.parse.urlencode(params)
|
||||||
|
).json()
|
||||||
variables = resp["head"]["vars"]
|
variables = resp["head"]["vars"]
|
||||||
for result in resp["results"]["bindings"]:
|
for result in resp["results"]["bindings"]:
|
||||||
yield tuple(result.get(variable) for variable in variables)
|
yield tuple(result.get(variable) for variable in variables)
|
||||||
|
|
|
@ -78,6 +78,10 @@ class LiteralField(Field[rdflib.Literal]):
|
||||||
predicate: rdflib.URIRef
|
predicate: rdflib.URIRef
|
||||||
|
|
||||||
default: Optional[rdflib.Literal] = None
|
default: Optional[rdflib.Literal] = None
|
||||||
|
"""If this is not :const:`None`, allows subjects without a statement for this field;
|
||||||
|
and use this value instead when sorting.
|
||||||
|
|
||||||
|
This is only used when sorting, and isn't displayed."""
|
||||||
|
|
||||||
def sort_key(self, value: rdflib.Literal) -> Any:
|
def sort_key(self, value: rdflib.Literal) -> Any:
|
||||||
"""Function suitable as ``key`` argument to :func:`sorted`.
|
"""Function suitable as ``key`` argument to :func:`sorted`.
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
# pylint: disable=redefined-outer-name
|
# pylint: disable=redefined-outer-name
|
||||||
|
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import rdflib
|
import rdflib
|
||||||
|
|
||||||
|
@ -33,11 +35,15 @@ def rdflib_sparql(requests_mock, rdflib_graph: rdflib.Graph) -> RemoteSparqlBack
|
||||||
"""Returns a SPARQL backend instance for ``rdflib_graph``."""
|
"""Returns a SPARQL backend instance for ``rdflib_graph``."""
|
||||||
|
|
||||||
def json_callback(request, context):
|
def json_callback(request, context):
|
||||||
result = rdflib_graph.query(request.json())
|
params = urllib.parse.parse_qs(request.text)
|
||||||
|
(query,) = params["query"]
|
||||||
|
results = rdflib_graph.query(query)
|
||||||
context.status_code = 200
|
context.status_code = 200
|
||||||
return {
|
return {
|
||||||
"head": {"vars": result.vars},
|
"head": {"vars": results.vars},
|
||||||
"results": list(result),
|
"results": {
|
||||||
|
"bindings": [dict(zip(results.vars, result)) for result in results]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
requests_mock.register_uri("POST", "mock://sparql.example.org/", json=json_callback)
|
requests_mock.register_uri("POST", "mock://sparql.example.org/", json=json_callback)
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License along with
|
# You should have received a copy of the GNU Affero General Public License along with
|
||||||
# this program. If not, see <http://www.gnu.org/licenses/>.
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""Tests :mod:`glowtables.table`.
|
||||||
|
|
||||||
|
Test cases use a graph containing a few CPUs, with names and clock frequencies.
|
||||||
|
"""
|
||||||
|
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
@ -20,6 +25,40 @@ import rdflib
|
||||||
from glowtables.sparql import SparqlBackend
|
from glowtables.sparql import SparqlBackend
|
||||||
from glowtables.table import Language, LiteralField, Table
|
from glowtables.table import Language, LiteralField, Table
|
||||||
|
|
||||||
|
CPU1_URI = rdflib.URIRef("http://example.org/grown-1700")
|
||||||
|
CPU2_URI = rdflib.URIRef("http://example.org/grown-3600")
|
||||||
|
CPU3_URI = rdflib.URIRef("http://example.org/secret-project")
|
||||||
|
CG_URI = rdflib.URIRef("http://example.org/likestone-underdog")
|
||||||
|
CPU = rdflib.URIRef("http://example.org/CPU")
|
||||||
|
DISPLAY_NAME = rdflib.URIRef("http://example.org/display-name")
|
||||||
|
FREQUENCY = rdflib.URIRef("http://example.org/clock-frequency")
|
||||||
|
TYPE = rdflib.URIRef("http://example.org/type")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def rdflib_graph() -> rdflib.Graph:
|
||||||
|
graph = rdflib.Graph()
|
||||||
|
|
||||||
|
# A CPU with all the properties
|
||||||
|
graph.add((CPU1_URI, DISPLAY_NAME, rdflib.Literal("Grown 1700")))
|
||||||
|
graph.add((CPU1_URI, TYPE, CPU))
|
||||||
|
graph.add((CPU1_URI, FREQUENCY, rdflib.Literal(3000)))
|
||||||
|
|
||||||
|
# Another CPU, without a frequency
|
||||||
|
graph.add((CPU2_URI, DISPLAY_NAME, rdflib.Literal("Grown 3600")))
|
||||||
|
graph.add((CPU2_URI, TYPE, CPU))
|
||||||
|
|
||||||
|
# Another CPU, without a name
|
||||||
|
graph.add((CPU3_URI, TYPE, CPU))
|
||||||
|
graph.add((CPU3_URI, FREQUENCY, rdflib.Literal(9000)))
|
||||||
|
|
||||||
|
# Add a graphics card; which should be excluded from CPU searches
|
||||||
|
graph.add((CG_URI, DISPLAY_NAME, rdflib.Literal("LikeStone Underdog")))
|
||||||
|
graph.add((CG_URI, FREQUENCY, rdflib.Literal(1626)))
|
||||||
|
graph.add((CG_URI, TYPE, rdflib.URIRef("http://example.org/graphics-card")))
|
||||||
|
|
||||||
|
return graph
|
||||||
|
|
||||||
|
|
||||||
def test_single_literal(rdflib_sparql: SparqlBackend) -> None:
|
def test_single_literal(rdflib_sparql: SparqlBackend) -> None:
|
||||||
name_field = LiteralField(
|
name_field = LiteralField(
|
||||||
|
@ -42,7 +81,10 @@ def test_single_literal(rdflib_sparql: SparqlBackend) -> None:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
rdflib_sparql.query(table.sparql())
|
assert set(rdflib_sparql.query(table.sparql())) == {
|
||||||
|
("Grown 1700",),
|
||||||
|
("Grown 3600",),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_two_literals(rdflib_sparql: SparqlBackend) -> None:
|
def test_two_literals(rdflib_sparql: SparqlBackend) -> None:
|
||||||
|
@ -72,7 +114,9 @@ def test_two_literals(rdflib_sparql: SparqlBackend) -> None:
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
rdflib_sparql.query(table.sparql())
|
assert set(rdflib_sparql.query(table.sparql())) == {
|
||||||
|
("Grown 1700", "3000"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_default_value(rdflib_sparql: SparqlBackend) -> None:
|
def test_default_value(rdflib_sparql: SparqlBackend) -> None:
|
||||||
|
@ -82,22 +126,33 @@ def test_default_value(rdflib_sparql: SparqlBackend) -> None:
|
||||||
rdflib.URIRef("http://example.org/display-name"),
|
rdflib.URIRef("http://example.org/display-name"),
|
||||||
default=rdflib.Literal("Anonymous CPU"),
|
default=rdflib.Literal("Anonymous CPU"),
|
||||||
)
|
)
|
||||||
|
frequency_field = LiteralField(
|
||||||
|
"frequency",
|
||||||
|
{Language("en"): "Clock frequency"},
|
||||||
|
rdflib.URIRef("http://example.org/clock-frequency"),
|
||||||
|
default=rdflib.Literal(0),
|
||||||
|
)
|
||||||
table = Table(
|
table = Table(
|
||||||
fields=[name_field],
|
fields=[name_field, frequency_field],
|
||||||
constraints="?subject <http://example.org/type> <http://example.org/CPU>.",
|
constraints="?subject <http://example.org/type> <http://example.org/CPU>.",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert table.sparql() == textwrap.dedent(
|
assert table.sparql() == textwrap.dedent(
|
||||||
"""
|
"""
|
||||||
SELECT ?display_name
|
SELECT ?display_name ?frequency
|
||||||
WHERE {
|
WHERE {
|
||||||
?subject <http://example.org/type> <http://example.org/CPU>.
|
?subject <http://example.org/type> <http://example.org/CPU>.
|
||||||
OPTIONAL { ?subject <http://example.org/display-name> ?display_name. }.
|
OPTIONAL { ?subject <http://example.org/display-name> ?display_name. }.
|
||||||
|
OPTIONAL { ?subject <http://example.org/clock-frequency> ?frequency. }.
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
rdflib_sparql.query(table.sparql())
|
assert set(rdflib_sparql.query(table.sparql())) == {
|
||||||
|
("Grown 1700", "3000"),
|
||||||
|
("Grown 3600", None),
|
||||||
|
(None, "9000"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_field_id_subject() -> None:
|
def test_field_id_subject() -> None:
|
||||||
|
|
Loading…
Reference in New Issue