Skip to content

Commit 35a3537

Browse files
authored
fix: validation issues with examples (#2269)
I want to add examples for securing RDFLib network access using `sys.addaudithook` and `urllib.request.install_opener`, but I want to also validate the examples in our CI pipeline, so we can demonstrate they work to our users. This change adds validation for all examples, and the addition of the security examples in a seperate PR will then also get validated.
1 parent 7a7cc1f commit 35a3537

17 files changed

+147
-61
lines changed

examples/berkeleydb_example.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
* does not delete the DB at the end so you can see it on disk
1717
"""
1818
import os
19-
from rdflib import ConjunctiveGraph, Namespace, Literal
20-
from rdflib.store import NO_STORE, VALID_STORE
2119
import tempfile
2220

21+
from rdflib import ConjunctiveGraph, Literal, Namespace
22+
from rdflib.plugins.stores.berkeleydb import has_bsddb
23+
from rdflib.store import NO_STORE, VALID_STORE
24+
2325

2426
def example_1():
2527
"""Creates a ConjunctiveGraph and performs some BerkeleyDB tasks with it"""
@@ -98,10 +100,10 @@ def example_2():
98100
9719
99101
...
100102
"""
101-
from urllib.request import urlopen, Request
102-
from urllib.error import HTTPError
103-
import json
104103
import base64
104+
import json
105+
from urllib.error import HTTPError
106+
from urllib.request import Request, urlopen
105107

106108
g = ConjunctiveGraph("BerkeleyDB")
107109
g.open("gsg_vocabs", create=True)
@@ -129,5 +131,7 @@ def example_2():
129131

130132

131133
if __name__ == "__main__":
132-
example_1()
133-
example_2()
134+
if has_bsddb:
135+
# Only run the examples if BerkeleyDB is available
136+
example_1()
137+
example_2()

examples/conjunctive_graphs.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
conjunction (union) of all the graphs.
99
"""
1010

11-
from rdflib import Namespace, Literal, URIRef
12-
from rdflib.graph import Graph, ConjunctiveGraph
11+
from rdflib import Literal, Namespace, URIRef
12+
from rdflib.graph import ConjunctiveGraph, Graph
1313
from rdflib.plugins.stores.memory import Memory
1414

1515
if __name__ == "__main__":
16-
1716
LOVE = Namespace("http://love.com#")
1817
LOVERS = Namespace("http://love.com/lovers/")
1918

@@ -59,7 +58,7 @@
5958

6059
print("Query the conjunction of all graphs:")
6160
xx = None
62-
for x in g[mary : LOVE.loves / LOVE.hasCuteName]:
61+
for x in g[mary : LOVE.loves / LOVE.hasCuteName]: # type: ignore[misc]
6362
xx = x
6463
print("Q: Who does Mary love?")
6564
print("A: Mary loves {}".format(xx))

examples/custom_datatype.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99
"""
1010

1111

12-
from rdflib import Graph, Literal, Namespace, XSD
13-
from rdflib import term
12+
from rdflib import XSD, Graph, Literal, Namespace, term
1413

1514
if __name__ == "__main__":
16-
1715
# Complex numbers are not registered by default
1816
# No custom constructor/serializer needed since
1917
# complex('(2+3j)') works fine
@@ -46,4 +44,5 @@
4644

4745
# Compare with the original python complex object (should be True)
4846
# l2[2] is the object of the triple
47+
assert isinstance(l2[2], Literal)
4948
print(l2[2].value == c)

examples/custom_eval.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,19 @@
1616
}
1717
"""
1818

19-
import rdflib
2019

21-
from rdflib.plugins.sparql.evaluate import evalBGP
20+
from pathlib import Path
21+
22+
import rdflib
2223
from rdflib.namespace import FOAF, RDF, RDFS
24+
from rdflib.plugins.sparql.evaluate import evalBGP
2325

24-
inferredSubClass = RDFS.subClassOf * "*" # any number of rdfs.subClassOf
26+
EXAMPLES_DIR = Path(__file__).parent
27+
28+
29+
inferred_sub_class = (
30+
RDFS.subClassOf * "*" # type: ignore[operator]
31+
) # any number of rdfs.subClassOf
2532

2633

2734
def customEval(ctx, part):
@@ -36,7 +43,7 @@ def customEval(ctx, part):
3643
if t[1] == RDF.type:
3744
bnode = rdflib.BNode()
3845
triples.append((t[0], t[1], bnode))
39-
triples.append((bnode, inferredSubClass, t[2]))
46+
triples.append((bnode, inferred_sub_class, t[2]))
4047
else:
4148
triples.append(t)
4249

@@ -47,24 +54,23 @@ def customEval(ctx, part):
4754

4855

4956
if __name__ == "__main__":
50-
5157
# add function directly, normally we would use setuptools and entry_points
5258
rdflib.plugins.sparql.CUSTOM_EVALS["exampleEval"] = customEval
5359

5460
g = rdflib.Graph()
55-
g.parse("foaf.n3")
61+
g.parse(f"{EXAMPLES_DIR / 'foaf.n3'}")
5662

5763
# Add the subClassStmt so that we can query for it!
5864
g.add((FOAF.Person, RDFS.subClassOf, FOAF.Agent))
5965

6066
# Find all FOAF Agents
6167
for x in g.query(
6268
f"""
63-
PREFIX foaf: <{FOAF}>
64-
65-
SELECT *
69+
PREFIX foaf: <{FOAF}>
70+
71+
SELECT *
6672
WHERE {{
67-
?s a foaf:Agent .
73+
?s a foaf:Agent .
6874
}}
6975
"""
7076
):

examples/datasets.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@
77
and remove things from it.
88
"""
99

10-
from rdflib import Dataset, URIRef, Literal, Namespace
10+
from rdflib import Dataset, Literal, Namespace, URIRef
11+
12+
# Note regarding `mypy: ignore_errors=true`:
13+
#
14+
# This example is using URIRef values as context identifiers. This is contrary
15+
# to the type hints, but it does work. Most likely the type hints are wrong.
16+
# Ideally we should just use `# type: ignore` comments for the lines that are
17+
# causing problems, but for some reason the error occurs on different lines with
18+
# different python versions, so the only option is to ignore errors for the
19+
# whole file.
20+
21+
# mypy: ignore_errors=true
1122

1223
#
1324
# Create & Add
@@ -99,7 +110,7 @@
99110
"""
100111
print("Printing all triple from one Graph in the Dataset:")
101112
print("---")
102-
for triple in d.triples((None, None, None, graph_1)):
113+
for triple in d.triples((None, None, None, graph_1)): # type: ignore[arg-type]
103114
print(triple)
104115
print("---")
105116
print()

examples/foafpaths.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
This example shows how to get the name of friends (i.e values two steps away x knows y, y name z) with a single query.
2727
"""
2828

29-
from rdflib import URIRef, Graph
29+
from pathlib import Path
30+
31+
from rdflib import Graph, URIRef
3032
from rdflib.namespace import FOAF
3133

32-
if __name__ == "__main__":
34+
EXAMPLES_DIR = Path(__file__).parent
3335

36+
if __name__ == "__main__":
3437
g = Graph()
35-
g.parse("foaf.n3")
38+
g.parse(f"{EXAMPLES_DIR / 'foaf.n3'}")
3639

3740
tim = URIRef("http://www.w3.org/People/Berners-Lee/card#i")
3841

examples/prepared_query.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@
88
``initBindings`` keyword parameter.
99
"""
1010

11+
from pathlib import Path
12+
1113
import rdflib
12-
from rdflib.plugins.sparql import prepareQuery
1314
from rdflib.namespace import FOAF
15+
from rdflib.plugins.sparql import prepareQuery
1416

17+
EXAMPLES_DIR = Path(__file__).parent
1518

1619
if __name__ == "__main__":
17-
1820
q = prepareQuery(
1921
"SELECT ?name WHERE { ?person foaf:knows/foaf:name ?name . }",
2022
initNs={"foaf": FOAF},
2123
)
2224

2325
g = rdflib.Graph()
24-
g.parse("foaf.n3")
26+
g.parse(f"{EXAMPLES_DIR / 'foaf.n3'}")
2527

2628
tim = rdflib.URIRef("http://www.w3.org/People/Berners-Lee/card#i")
2729

2830
for row in g.query(q, initBindings={"person": tim}):
31+
# For select queries, the Result object is an iterable of ResultRow
32+
# objects.
33+
assert isinstance(row, rdflib.query.ResultRow)
2934
print(row.name)

examples/resource_example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
This example shows g.resource() in action.
88
"""
99

10-
from rdflib import Graph, RDF, RDFS, Literal
10+
from rdflib import RDF, RDFS, Graph, Literal
1111
from rdflib.namespace import FOAF
1212

1313
if __name__ == "__main__":

examples/simple_example.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
from rdflib import Graph, Literal, BNode, RDF
2-
from rdflib.namespace import FOAF, DC
1+
import os.path
2+
from tempfile import TemporaryDirectory
33

4-
if __name__ == "__main__":
4+
from rdflib import RDF, BNode, Graph, Literal
5+
from rdflib.namespace import DC, FOAF
56

7+
if __name__ == "__main__":
68
store = Graph()
79

810
# Bind a few prefix, namespace pairs for pretty output
@@ -29,9 +31,11 @@
2931
for mbox in store.objects(person, FOAF["mbox"]):
3032
print(mbox)
3133

32-
print("--- saving RDF to a file (donna_foaf.rdf) ---")
34+
tmp_dir = TemporaryDirectory()
35+
output_file = os.path.join(tmp_dir.name, "donna_foaf.rdf")
36+
print(f"--- saving RDF to a file ({output_file}) ---")
3337
# Serialize the store as RDF/XML to the file donna_foaf.rdf.
34-
store.serialize("donna_foaf.rdf", format="pretty-xml", max_depth=3)
38+
store.serialize(f"{output_file}", format="pretty-xml", max_depth=3)
3539

3640
# Let's show off the serializers
3741
print()

examples/slice.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@
99
See :meth:`rdflib.graph.Graph.__getitem__` for details
1010
"""
1111

12-
from rdflib import Graph, RDF
12+
from pathlib import Path
13+
14+
from rdflib import RDF, Graph
1315
from rdflib.namespace import FOAF
1416

15-
if __name__ == "__main__":
17+
EXAMPLES_DIR = Path(__file__).parent
1618

19+
20+
if __name__ == "__main__":
1721
graph = Graph()
18-
graph.parse("foaf.n3", format="n3")
22+
graph.parse(f"{EXAMPLES_DIR / 'foaf.n3'}", format="n3")
1923

20-
for person in graph[: RDF.type : FOAF.Person]:
21-
friends = list(graph[person : FOAF.knows * "+" / FOAF.name])
24+
for person in graph[: RDF.type : FOAF.Person]: # type: ignore[misc]
25+
friends = list(graph[person : FOAF.knows * "+" / FOAF.name]) # type: ignore[operator]
2226
if friends:
2327
print(f"{graph.value(person, FOAF.name)}'s circle of friends:")
2428
for name in friends:

0 commit comments

Comments
 (0)