Skip to content

Commit

Permalink
test: add python variants to variant based tests (#2544)
Browse files Browse the repository at this point in the history
This change adds python based variants to the variant tests. The python
based variants provide a `populate_graph` function that populates a
passed graph with quads or triples. This provides for the ability to do
more nuanced and narrow tests using variants.

Other changes:

- Add some more variants for `diverse_quads` that explicitly sets the
  datatype of strings.
- Removed the hand coded `simple_triple` graph from `test/data.py` as
  this is now subsumed by `test/data/variants/simple_triple.py`.
  • Loading branch information
aucampia authored Aug 26, 2023
1 parent 5b02406 commit e757687
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 33 deletions.
18 changes: 2 additions & 16 deletions test/data.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from pathlib import Path
from test.utils.graph import cached_graph

from rdflib import URIRef
from rdflib.graph import Graph

TEST_DIR = Path(__file__).parent
TEST_DATA_DIR = TEST_DIR / "data"
Expand All @@ -22,18 +22,4 @@
context2 = URIRef("urn:example:context-2")


simple_triple_graph = Graph().add(
(
URIRef("http://example.org/subject"),
URIRef("http://example.org/predicate"),
URIRef("http://example.org/object"),
)
)
"""
A simple graph with a single triple. This is equivalent to the following RDF files:
* ``test/data/variants/simple_triple.nq``
* ``test/data/variants/simple_triple.nt``
* ``test/data/variants/simple_triple.ttl``
* ``test/data/variants/simple_triple.xml``
"""
SIMPLE_TRIPLE_GRAPH = cached_graph((TEST_DATA_DIR / "variants" / "simple_triple.py",))
73 changes: 73 additions & 0 deletions test/data/variants/diverse_quads-variant-typed.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"@graph": [
{
"@graph": [
{
"@id": "egschema:subject",
"egschema:predicate": [
12,
{
"@id": "egschema:object"
}
]
},
{
"@id": "eghttp:subject",
"predicate": {
"@language": "jpx",
"@value": "日本語の表記体系"
}
},
{
"@id": "egurn:subject",
"egschema:predicate": {
"@id": "egschema:subject"
}
}
],
"@id": "egschema:graph"
},
{
"@id": "egschema:subject",
"egschema:predicate": {
"@id": "egschema:object"
}
},
{
"@id": "eghttp:subject",
"predicate": "typeless"
},
{
"@graph": [
{
"@id": "egschema:subject",
"egschema:predicate": {
"@id": "egschema:object"
},
"predicate": [
{"@value": "XSD string", "@type": "xsd:string"},
{
"@id": "eghttp:object"
}
]
}
],
"@id": "egurn:graph"
},
{
"@id": "egurn:subject",
"egurn:predicate": {
"@id": "egurn:object"
}
}
],
"@context": {
"predicate": {
"@id": "http://example.com/predicate"
},
"egurn": "urn:example:",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"egschema": "example:",
"eghttp": "http://example.com/"
}
}
10 changes: 10 additions & 0 deletions test/data/variants/diverse_quads-variant-typed.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<http://example.com/subject> <http://example.com/predicate> "日本語の表記体系"@jpx <example:graph> .
<urn:example:subject> <example:predicate> <example:subject> <example:graph> .
<example:subject> <example:predicate> <example:object> <example:graph> .
<example:subject> <example:predicate> "12"^^<http://www.w3.org/2001/XMLSchema#integer> <example:graph> .
<example:subject> <example:predicate> <example:object> <urn:example:graph> .
<example:subject> <http://example.com/predicate> <http://example.com/object> <urn:example:graph> .
<example:subject> <http://example.com/predicate> "XSD string"^^<http://www.w3.org/2001/XMLSchema#string> <urn:example:graph> .
<example:subject> <example:predicate> <example:object> .
<http://example.com/subject> <http://example.com/predicate> "typeless" .
<urn:example:subject> <urn:example:predicate> <urn:example:object> .
29 changes: 29 additions & 0 deletions test/data/variants/diverse_quads.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from test.utils.namespace import EGDC, EGSCHEME, EGURN

from rdflib.graph import ConjunctiveGraph, Graph
from rdflib.namespace import XSD
from rdflib.term import Literal


def populate_graph(graph: Graph) -> None:
assert isinstance(graph, ConjunctiveGraph)

graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
graph.add((EGDC.subject, EGDC.predicate, Literal("typeless")))
graph.add((EGURN.subject, EGURN.predicate, EGURN.object))

egscheme_graph = graph.get_context(EGSCHEME.graph)
egscheme_graph.add((EGDC.subject, EGDC.predicate, Literal("日本語の表記体系", lang="jpx")))
egscheme_graph.add((EGURN.subject, EGSCHEME.predicate, EGSCHEME.subject))
egscheme_graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
egscheme_graph.add((EGSCHEME.subject, EGSCHEME.predicate, Literal(12)))

egurn_graph = graph.get_context(EGURN.graph)
egurn_graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
egurn_graph.add((EGSCHEME.subject, EGDC.predicate, EGDC.object))
egurn_graph.add(
(EGSCHEME.subject, EGDC.predicate, Literal("XSD string", datatype=XSD.string))
)


__all__ = ["populate_graph"]
18 changes: 18 additions & 0 deletions test/data/variants/diverse_triples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from test.utils.namespace import EGDC, EGSCHEME, EGURN

from rdflib.graph import Graph
from rdflib.term import Literal


def populate_graph(graph: Graph) -> None:
assert isinstance(graph, Graph)

graph.add((EGDC.subject, EGDC.predicate, Literal("日本語の表記体系", lang="jpx")))
graph.add((EGURN.subject, EGSCHEME.predicate, EGSCHEME.subject))

graph.add((EGSCHEME.object, EGDC.predicate, Literal("XSD string")))
graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
graph.add((EGSCHEME.subject, EGSCHEME.predicate, Literal(12)))


__all__ = ["populate_graph"]
13 changes: 13 additions & 0 deletions test/data/variants/simple_quad.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from test.utils.namespace import EGDO

from rdflib.graph import ConjunctiveGraph, Graph


def populate_graph(graph: Graph) -> None:
assert isinstance(graph, ConjunctiveGraph)

egdo_graph = graph.get_context(EGDO.graph)
egdo_graph.add((EGDO.subject, EGDO.predicate, EGDO.object))


__all__ = ["populate_graph"]
10 changes: 10 additions & 0 deletions test/data/variants/simple_triple.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from test.utils.namespace import EGDO

from rdflib.graph import Graph


def populate_graph(graph: Graph) -> None:
graph.add((EGDO.subject, EGDO.predicate, EGDO.object))


__all__ = ["populate_graph"]
4 changes: 2 additions & 2 deletions test/test_graph/test_graph_redirect.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from test.data import TEST_DATA_DIR, simple_triple_graph
from test.data import SIMPLE_TRIPLE_GRAPH, TEST_DATA_DIR
from test.utils import GraphHelper
from test.utils.http import MethodName, MockHTTPResponse
from test.utils.httpservermock import ServedBaseHTTPServerMock
Expand Down Expand Up @@ -38,7 +38,7 @@ def test_graph_redirect_new_host(

graph = Graph()
graph.parse(location=f"{mock_a.url}/a/data.ttl")
GraphHelper.assert_sets_equals(graph, simple_triple_graph)
GraphHelper.assert_sets_equals(graph, SIMPLE_TRIPLE_GRAPH)
for mock in function_httpmocks:
assert 1 == len(mock.requests[MethodName.GET])
for request in mock.requests[MethodName.GET]:
Expand Down
25 changes: 15 additions & 10 deletions test/test_graph/test_variants.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class GraphVariantsMeta(GraphAsserts):
(format, index)
for index, format in enumerate(
[
"python",
"nquads",
"nt",
"ntriples",
Expand Down Expand Up @@ -246,15 +247,19 @@ def for_directory(
""",
raises=AssertionError,
),
("variants/diverse_quads", ".trig"): pytest.mark.xfail(
("variants/diverse_quads", ".nq"): pytest.mark.xfail(
reason="""
TriG parsing gets confused about what graph 'XSD string' appears in:
(rdflib.term.URIRef('example:subject'),
rdflib.term.URIRef('http://example.com/predicate'),
rdflib.term.Literal('XSD string'),
- rdflib.term.URIRef('example:graph')),
+ rdflib.term.URIRef('urn:example:graph')),
? ++++
Problems with default/implicit datatype of strings. It should be
xsd:string, but for some parsers it is not. See
<https://github.com/RDFLib/rdflib/issues/1326> for more info.
""",
raises=AssertionError,
),
("variants/diverse_quads", ".jsonld"): pytest.mark.xfail(
reason="""
Problems with default/implicit datatype of strings. It should be
xsd:string, but for some parsers it is not. See
<https://github.com/RDFLib/rdflib/issues/1326> for more info.
""",
raises=AssertionError,
),
Expand Down Expand Up @@ -308,8 +313,8 @@ def test_variant_source(
graph_variants: GraphVariants, variant_key: Optional[str]
) -> None:
"""
All variants of a graph are isomorphic with the first variant, and thus
eachother.
All variants of a graph are isomorphic with the preferred variant,
and thus eachother.
"""
preferred_path = graph_variants.preferred_variant[1].path
preferred_graph: Dataset = load_preferred(graph_variants)
Expand Down
29 changes: 24 additions & 5 deletions test/utils/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
from runpy import run_path
from typing import Optional, Tuple, Type, Union

import rdflib.util
Expand Down Expand Up @@ -66,11 +67,14 @@ def load(
) -> _GraphT:
if graph is None:
graph = graph_type()
graph.parse(
source=self.path,
format=self.format,
publicID=self.public_id if public_id is None else public_id,
)
if self.format == "python":
load_from_python(self.path, graph, graph_type)
else:
graph.parse(
source=self.path,
format=self.format,
publicID=self.public_id if public_id is None else public_id,
)
return graph


Expand All @@ -94,3 +98,18 @@ def cached_graph(
graph_type: Type[_GraphT] = Graph, # type: ignore[assignment]
) -> _GraphT:
return load_sources(*sources, public_id=public_id, graph_type=graph_type)


def load_from_python(
path: Path,
graph: Optional[_GraphT] = None,
graph_type: Type[_GraphT] = Graph, # type: ignore[assignment]
) -> _GraphT:
if graph is None:
graph = graph_type()

mod = run_path(f"{path}")
if "populate_graph" not in mod:
raise ValueError(f"{path} does not contain a `populate_graph` function")
mod["populate_graph"](graph)
return graph

0 comments on commit e757687

Please sign in to comment.