Skip to content

Commit c37d399

Browse files
build(deps-dev): bump mypy from 1.13.0 to 1.14.1 (#3023)
* build(deps-dev): bump mypy from 1.13.0 to 1.14.1 Bumps [mypy](https://github.com/python/mypy) from 1.13.0 to 1.14.1. - [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md) - [Commits](python/mypy@v1.13.0...v1.14.1) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> * fix slice typing * fix slice typing #2 * Graph().__getitem_ returns via yield from generators * tests for ypdated Graph().__getitems * allow Path as type of 'p' in Graph slice * modernise old test; add two new tests * moving slice tests to test_slice.py * blacked & ruff --fix --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nicholas Car <[email protected]> Co-authored-by: Nicholas Car <[email protected]>
1 parent 97ff668 commit c37d399

File tree

4 files changed

+133
-67
lines changed

4 files changed

+133
-67
lines changed

poetry.lock

Lines changed: 41 additions & 35 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rdflib/graph.py

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -661,10 +661,11 @@ def triples(
661661

662662
def __getitem__(self, item):
663663
"""
664-
A graph can be "sliced" as a shortcut for the triples method
665-
The python slice syntax is (ab)used for specifying triples.
666-
A generator over matches is returned,
667-
the returned tuples include only the parts not given
664+
A graph can be "sliced" as a shortcut for the triples method.
665+
The Python slice syntax is (ab)used for specifying triples.
666+
667+
A generator over matches is returned, the returned tuples include only the
668+
parts not given.
668669
669670
>>> import rdflib
670671
>>> g = rdflib.Graph()
@@ -701,30 +702,37 @@ def __getitem__(self, item):
701702
702703
"""
703704

704-
if isinstance(item, slice):
705+
if isinstance(item, IdentifiedNode):
706+
yield from self.predicate_objects(item)
707+
elif isinstance(item, slice):
705708
s, p, o = item.start, item.stop, item.step
709+
# type narrowing since we cannot use typing within a slice()
710+
assert isinstance(s, IdentifiedNode) or isinstance(s, Variable) or s is None
711+
assert (
712+
isinstance(p, IdentifiedNode)
713+
or isinstance(p, Path)
714+
or isinstance(p, Variable)
715+
or p is None
716+
)
717+
assert isinstance(o, Node) or isinstance(o, Variable) or o is None
718+
706719
if s is None and p is None and o is None:
707-
return self.triples((s, p, o))
720+
yield from self.triples((s, p, o))
708721
elif s is None and p is None:
709-
return self.subject_predicates(o)
722+
yield from self.subject_predicates(o) # type: ignore[arg-type]
710723
elif s is None and o is None:
711-
return self.subject_objects(p)
724+
yield from self.subject_objects(p)
712725
elif p is None and o is None:
713-
return self.predicate_objects(s)
726+
yield from self.predicate_objects(s)
714727
elif s is None:
715-
return self.subjects(p, o)
728+
yield from self.subjects(p, o) # type: ignore[arg-type]
716729
elif p is None:
717-
return self.predicates(s, o)
730+
yield from self.predicates(s, o) # type: ignore[arg-type]
718731
elif o is None:
719-
return self.objects(s, p)
732+
yield from self.objects(s, p)
720733
else:
721734
# all given
722-
return (s, p, o) in self
723-
724-
elif isinstance(item, (Path, Node)):
725-
# type error: Argument 1 to "predicate_objects" of "Graph" has incompatible type "Union[Path, Node]"; expected "Optional[Node]"
726-
return self.predicate_objects(item) # type: ignore[arg-type]
727-
735+
yield s, p, o
728736
else:
729737
raise TypeError(
730738
"You can only index a graph by a single rdflib term or path, or a slice of rdflib terms."

test/test_graph/test_graph_items.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from rdflib import RDF, Graph, Namespace
1+
from rdflib import Graph, Namespace
2+
from rdflib.namespace import RDF
23

34
EX = Namespace("http://example.org/")
45

test/test_graph/test_slice.py

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
from rdflib import Graph
1+
from rdflib import Graph, Literal, Namespace, URIRef
2+
from rdflib.namespace import RDFS
23
from test.data import BOB, CHEESE, HATES, LIKES, MICHEL, PIZZA, TAREK
34

5+
EX = Namespace("http://example.org/")
6+
47

58
class TestGraphSlice:
69
def test_slice(self):
710
"""
8-
We pervert the slice object,
9-
and use start, stop, step as subject, predicate, object
11+
We pervert the slice object, and use start, stop, step as subject, predicate,
12+
object
1013
11-
all operations return generators over full triples
14+
All operations return generators over full triples
1215
"""
1316

14-
def sl(x, y):
15-
return len(list(x)) == y
17+
def sl(x):
18+
return len(list(x))
1619

1720
def soe(x, y):
1821
return set([a[2] for a in x]) == set(y) # equals objects
@@ -30,25 +33,73 @@ def soe(x, y):
3033

3134
# single index slices by subject, i.e. return triples((x,None,None))
3235
# tell me everything about "TAREK"
33-
sl(g[TAREK], 2)
36+
assert sl(g[TAREK]) == 2
3437

3538
# single slice slices by s,p,o, with : used to split
3639
# tell me everything about "TAREK" (same as above)
37-
sl(g[TAREK::], 2)
40+
assert sl(g[TAREK::]) == 2
3841

3942
# give me every "LIKES" relationship
40-
sl(g[:LIKES:], 5)
43+
assert sl(g[:LIKES:]) == 5
4144

4245
# give me every relationship to PIZZA
43-
sl(g[::PIZZA], 3)
46+
assert sl(g[::PIZZA]) == 3
4447

4548
# give me everyone who LIKES PIZZA
46-
sl(g[:LIKES:PIZZA], 2)
49+
assert sl(g[:LIKES:PIZZA]) == 2
4750

4851
# does TAREK like PIZZA?
49-
assert g[TAREK:LIKES:PIZZA] is True
52+
assert sorted(next(g[TAREK:LIKES:PIZZA])) == sorted(
53+
(
54+
URIRef("urn:example:tarek"),
55+
URIRef("urn:example:likes"),
56+
URIRef("urn:example:pizza"),
57+
)
58+
)
5059

5160
# More intesting is using paths
5261

5362
# everything hated or liked
54-
sl(g[: HATES | LIKES], 7)
63+
assert sl(g[: HATES | LIKES]) == 7
64+
65+
66+
def test_graph_slice_eg():
67+
g = Graph()
68+
g.add((URIRef("urn:bob"), RDFS.label, Literal("Bob")))
69+
assert sorted(list(g[URIRef("urn:bob")])) == sorted(
70+
[(URIRef("http://www.w3.org/2000/01/rdf-schema#label"), Literal("Bob"))]
71+
)
72+
73+
assert sorted(list(g[: RDFS.label])) == sorted(
74+
[(URIRef("urn:bob"), Literal("Bob"))]
75+
)
76+
77+
assert sorted(list(g[:: Literal("Bob")])) == sorted(
78+
[(URIRef("urn:bob"), URIRef("http://www.w3.org/2000/01/rdf-schema#label"))]
79+
)
80+
81+
82+
def test_graph_slice_all():
83+
g = Graph()
84+
g.parse(
85+
data="""
86+
PREFIX ex: <http://example.org/>
87+
88+
ex:a ex:b ex:c .
89+
ex:a ex:d ex:e .
90+
ex:f ex:b ex:c .
91+
ex:g ex:b ex:h .
92+
"""
93+
)
94+
95+
assert len(list(g[EX.a])) == 2
96+
97+
assert len(list(g[EX.f])) == 1
98+
99+
assert len(list(g[: EX.b])) == 3
100+
101+
assert len(list(g[:: EX.c])) == 2
102+
103+
assert len(list(g[EX.a : EX.b : EX.c])) == 1
104+
105+
assert sorted(list(g[EX.a])) == sorted(list(g.predicate_objects(EX.a)))

0 commit comments

Comments
 (0)