Skip to content

Commit e757687

Browse files
authored
test: add python variants to variant based tests (#2544)
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`.
1 parent 5b02406 commit e757687

File tree

10 files changed

+196
-33
lines changed

10 files changed

+196
-33
lines changed

test/data.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from pathlib import Path
2+
from test.utils.graph import cached_graph
23

34
from rdflib import URIRef
4-
from rdflib.graph import Graph
55

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

2424

25-
simple_triple_graph = Graph().add(
26-
(
27-
URIRef("http://example.org/subject"),
28-
URIRef("http://example.org/predicate"),
29-
URIRef("http://example.org/object"),
30-
)
31-
)
32-
"""
33-
A simple graph with a single triple. This is equivalent to the following RDF files:
34-
35-
* ``test/data/variants/simple_triple.nq``
36-
* ``test/data/variants/simple_triple.nt``
37-
* ``test/data/variants/simple_triple.ttl``
38-
* ``test/data/variants/simple_triple.xml``
39-
"""
25+
SIMPLE_TRIPLE_GRAPH = cached_graph((TEST_DATA_DIR / "variants" / "simple_triple.py",))
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
{
2+
"@graph": [
3+
{
4+
"@graph": [
5+
{
6+
"@id": "egschema:subject",
7+
"egschema:predicate": [
8+
12,
9+
{
10+
"@id": "egschema:object"
11+
}
12+
]
13+
},
14+
{
15+
"@id": "eghttp:subject",
16+
"predicate": {
17+
"@language": "jpx",
18+
"@value": "日本語の表記体系"
19+
}
20+
},
21+
{
22+
"@id": "egurn:subject",
23+
"egschema:predicate": {
24+
"@id": "egschema:subject"
25+
}
26+
}
27+
],
28+
"@id": "egschema:graph"
29+
},
30+
{
31+
"@id": "egschema:subject",
32+
"egschema:predicate": {
33+
"@id": "egschema:object"
34+
}
35+
},
36+
{
37+
"@id": "eghttp:subject",
38+
"predicate": "typeless"
39+
},
40+
{
41+
"@graph": [
42+
{
43+
"@id": "egschema:subject",
44+
"egschema:predicate": {
45+
"@id": "egschema:object"
46+
},
47+
"predicate": [
48+
{"@value": "XSD string", "@type": "xsd:string"},
49+
{
50+
"@id": "eghttp:object"
51+
}
52+
]
53+
}
54+
],
55+
"@id": "egurn:graph"
56+
},
57+
{
58+
"@id": "egurn:subject",
59+
"egurn:predicate": {
60+
"@id": "egurn:object"
61+
}
62+
}
63+
],
64+
"@context": {
65+
"predicate": {
66+
"@id": "http://example.com/predicate"
67+
},
68+
"egurn": "urn:example:",
69+
"xsd": "http://www.w3.org/2001/XMLSchema#",
70+
"egschema": "example:",
71+
"eghttp": "http://example.com/"
72+
}
73+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<http://example.com/subject> <http://example.com/predicate> "日本語の表記体系"@jpx <example:graph> .
2+
<urn:example:subject> <example:predicate> <example:subject> <example:graph> .
3+
<example:subject> <example:predicate> <example:object> <example:graph> .
4+
<example:subject> <example:predicate> "12"^^<http://www.w3.org/2001/XMLSchema#integer> <example:graph> .
5+
<example:subject> <example:predicate> <example:object> <urn:example:graph> .
6+
<example:subject> <http://example.com/predicate> <http://example.com/object> <urn:example:graph> .
7+
<example:subject> <http://example.com/predicate> "XSD string"^^<http://www.w3.org/2001/XMLSchema#string> <urn:example:graph> .
8+
<example:subject> <example:predicate> <example:object> .
9+
<http://example.com/subject> <http://example.com/predicate> "typeless" .
10+
<urn:example:subject> <urn:example:predicate> <urn:example:object> .
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from test.utils.namespace import EGDC, EGSCHEME, EGURN
2+
3+
from rdflib.graph import ConjunctiveGraph, Graph
4+
from rdflib.namespace import XSD
5+
from rdflib.term import Literal
6+
7+
8+
def populate_graph(graph: Graph) -> None:
9+
assert isinstance(graph, ConjunctiveGraph)
10+
11+
graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
12+
graph.add((EGDC.subject, EGDC.predicate, Literal("typeless")))
13+
graph.add((EGURN.subject, EGURN.predicate, EGURN.object))
14+
15+
egscheme_graph = graph.get_context(EGSCHEME.graph)
16+
egscheme_graph.add((EGDC.subject, EGDC.predicate, Literal("日本語の表記体系", lang="jpx")))
17+
egscheme_graph.add((EGURN.subject, EGSCHEME.predicate, EGSCHEME.subject))
18+
egscheme_graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
19+
egscheme_graph.add((EGSCHEME.subject, EGSCHEME.predicate, Literal(12)))
20+
21+
egurn_graph = graph.get_context(EGURN.graph)
22+
egurn_graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
23+
egurn_graph.add((EGSCHEME.subject, EGDC.predicate, EGDC.object))
24+
egurn_graph.add(
25+
(EGSCHEME.subject, EGDC.predicate, Literal("XSD string", datatype=XSD.string))
26+
)
27+
28+
29+
__all__ = ["populate_graph"]
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from test.utils.namespace import EGDC, EGSCHEME, EGURN
2+
3+
from rdflib.graph import Graph
4+
from rdflib.term import Literal
5+
6+
7+
def populate_graph(graph: Graph) -> None:
8+
assert isinstance(graph, Graph)
9+
10+
graph.add((EGDC.subject, EGDC.predicate, Literal("日本語の表記体系", lang="jpx")))
11+
graph.add((EGURN.subject, EGSCHEME.predicate, EGSCHEME.subject))
12+
13+
graph.add((EGSCHEME.object, EGDC.predicate, Literal("XSD string")))
14+
graph.add((EGSCHEME.subject, EGSCHEME.predicate, EGSCHEME.object))
15+
graph.add((EGSCHEME.subject, EGSCHEME.predicate, Literal(12)))
16+
17+
18+
__all__ = ["populate_graph"]

test/data/variants/simple_quad.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from test.utils.namespace import EGDO
2+
3+
from rdflib.graph import ConjunctiveGraph, Graph
4+
5+
6+
def populate_graph(graph: Graph) -> None:
7+
assert isinstance(graph, ConjunctiveGraph)
8+
9+
egdo_graph = graph.get_context(EGDO.graph)
10+
egdo_graph.add((EGDO.subject, EGDO.predicate, EGDO.object))
11+
12+
13+
__all__ = ["populate_graph"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from test.utils.namespace import EGDO
2+
3+
from rdflib.graph import Graph
4+
5+
6+
def populate_graph(graph: Graph) -> None:
7+
graph.add((EGDO.subject, EGDO.predicate, EGDO.object))
8+
9+
10+
__all__ = ["populate_graph"]

test/test_graph/test_graph_redirect.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from test.data import TEST_DATA_DIR, simple_triple_graph
1+
from test.data import SIMPLE_TRIPLE_GRAPH, TEST_DATA_DIR
22
from test.utils import GraphHelper
33
from test.utils.http import MethodName, MockHTTPResponse
44
from test.utils.httpservermock import ServedBaseHTTPServerMock
@@ -38,7 +38,7 @@ def test_graph_redirect_new_host(
3838

3939
graph = Graph()
4040
graph.parse(location=f"{mock_a.url}/a/data.ttl")
41-
GraphHelper.assert_sets_equals(graph, simple_triple_graph)
41+
GraphHelper.assert_sets_equals(graph, SIMPLE_TRIPLE_GRAPH)
4242
for mock in function_httpmocks:
4343
assert 1 == len(mock.requests[MethodName.GET])
4444
for request in mock.requests[MethodName.GET]:

test/test_graph/test_variants.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class GraphVariantsMeta(GraphAsserts):
9494
(format, index)
9595
for index, format in enumerate(
9696
[
97+
"python",
9798
"nquads",
9899
"nt",
99100
"ntriples",
@@ -246,15 +247,19 @@ def for_directory(
246247
""",
247248
raises=AssertionError,
248249
),
249-
("variants/diverse_quads", ".trig"): pytest.mark.xfail(
250+
("variants/diverse_quads", ".nq"): pytest.mark.xfail(
250251
reason="""
251-
TriG parsing gets confused about what graph 'XSD string' appears in:
252-
(rdflib.term.URIRef('example:subject'),
253-
rdflib.term.URIRef('http://example.com/predicate'),
254-
rdflib.term.Literal('XSD string'),
255-
- rdflib.term.URIRef('example:graph')),
256-
+ rdflib.term.URIRef('urn:example:graph')),
257-
? ++++
252+
Problems with default/implicit datatype of strings. It should be
253+
xsd:string, but for some parsers it is not. See
254+
<https://github.com/RDFLib/rdflib/issues/1326> for more info.
255+
""",
256+
raises=AssertionError,
257+
),
258+
("variants/diverse_quads", ".jsonld"): pytest.mark.xfail(
259+
reason="""
260+
Problems with default/implicit datatype of strings. It should be
261+
xsd:string, but for some parsers it is not. See
262+
<https://github.com/RDFLib/rdflib/issues/1326> for more info.
258263
""",
259264
raises=AssertionError,
260265
),
@@ -308,8 +313,8 @@ def test_variant_source(
308313
graph_variants: GraphVariants, variant_key: Optional[str]
309314
) -> None:
310315
"""
311-
All variants of a graph are isomorphic with the first variant, and thus
312-
eachother.
316+
All variants of a graph are isomorphic with the preferred variant,
317+
and thus eachother.
313318
"""
314319
preferred_path = graph_variants.preferred_variant[1].path
315320
preferred_graph: Dataset = load_preferred(graph_variants)

test/utils/graph.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from dataclasses import dataclass
55
from functools import lru_cache
66
from pathlib import Path
7+
from runpy import run_path
78
from typing import Optional, Tuple, Type, Union
89

910
import rdflib.util
@@ -66,11 +67,14 @@ def load(
6667
) -> _GraphT:
6768
if graph is None:
6869
graph = graph_type()
69-
graph.parse(
70-
source=self.path,
71-
format=self.format,
72-
publicID=self.public_id if public_id is None else public_id,
73-
)
70+
if self.format == "python":
71+
load_from_python(self.path, graph, graph_type)
72+
else:
73+
graph.parse(
74+
source=self.path,
75+
format=self.format,
76+
publicID=self.public_id if public_id is None else public_id,
77+
)
7478
return graph
7579

7680

@@ -94,3 +98,18 @@ def cached_graph(
9498
graph_type: Type[_GraphT] = Graph, # type: ignore[assignment]
9599
) -> _GraphT:
96100
return load_sources(*sources, public_id=public_id, graph_type=graph_type)
101+
102+
103+
def load_from_python(
104+
path: Path,
105+
graph: Optional[_GraphT] = None,
106+
graph_type: Type[_GraphT] = Graph, # type: ignore[assignment]
107+
) -> _GraphT:
108+
if graph is None:
109+
graph = graph_type()
110+
111+
mod = run_path(f"{path}")
112+
if "populate_graph" not in mod:
113+
raise ValueError(f"{path} does not contain a `populate_graph` function")
114+
mod["populate_graph"](graph)
115+
return graph

0 commit comments

Comments
 (0)