add test of ConjunctiveGraph operators · Pull Request #1647 · RDFLib/rdflib (original) (raw)

“Currently all operations are done on the default graph, i.e. if you add another graph, even if it's a conjunctive graph, all triples are added to the default graph.

The tests introduced in this PR include an example of the above, adding a ConjunctiveGraph to a ConjunctiveGraph but it's not a sufficiently thorough test to reveal what gromgull was concerned about:

def test_operators_with_two_conjunctivegraphs(): cg1 = ConjunctiveGraph() cg1.add([tarek, likes, pizza]) cg1.add([tarek, likes, michel]) cg2 = ConjunctiveGraph() cg2.add([tarek, likes, pizza]) cg2.add([tarek, likes, cheese]) assert len(cg1 + cg2) == 3 # adds cheese as liking assert len(cg1 - cg2) == 1 # removes pizza from cg1 assert len(cg1 * cg2) == 1 # only pizza assert len(cg1 + cg2) == 3 # adds cheese as liking assert len(cg1 ^ cg2) == 2 # removes pizza, adds cheese

In the course of neatening the Dataset tests I've just realised an implication from the above that sheds more light on the difference between ConjunctiveGraph and Dataset. It's true that for ConjunctiveGraph all operations are done on the default graph and “all triples are added to the default graph”

def test_cg_with_contexts_add_to_cg(): cg1 = Dataset() assert len(list(cg1.contexts())) == 1 assert len(list(cg1)) == 0 cg2 = ConjunctiveGraph() cg2.parse( data="urn:x-rdflib:tarek urn:x-rdflib:likes urn:x-rdflib:pizza .", publicID="urn:x-rdflib:context-a", format="ttl", ) cg2.parse( data="urn:x-rdflib:michel urn:x-rdflib:likes urn:x-rdflib:cheese .", publicID="urn:x-rdflib:context-b", format="ttl", ) assert len(list(cg2.contexts())) == 2 cg1 += cg2 assert len(list(cg1.contexts())) == 1 # publicID contexts lost assert len(list(cg1)) == 2 # Two triples added to default graph

Now, according to the Dataset docstring, you get your working Graphs from a Dataset:

    >>> # Create a graph in the dataset, if the graph name has already been
    >>> # used, the corresponding graph will be returned
    >>> # (ie, the Dataset keeps track of the constituent graphs)
    >>> g = ds.graph(URIRef("http://www.example.com/gr"))

graph (synonym add_graph) returns a Graph object, nominally precluding the use of a ConjunctiveGraph object as a Dataset context. However, gromgull does describe the situation as "chaos" and I guess this is what he meant:

def test_cg_with_contexts_add_to_ds(): ds = Dataset() assert len(list(ds.contexts())) == 1 assert len(list(ds)) == 0 cg = ConjunctiveGraph() cg.parse( data="urn:x-rdflib:tarek urn:x-rdflib:likes urn:x-rdflib:pizza .", publicID="urn:x-rdflib:context-a", format="ttl", ) cg.parse( data="urn:x-rdflib:michel urn:x-rdflib:likes urn:x-rdflib:cheese .", publicID="urn:x-rdflib:context-b", format="ttl", ) assert len(list(cg.contexts())) == 2 ds += cg # !! assert len(list(ds.contexts())) == 1 # publicID contexts lost assert len(list(ds)) == 2 # Two triples added to default graph

It's difficult to see this as desirable for Dataset (or ConjunctiveGraph for that matter) but any coherent implementation will need to resolve the set-theoretic aspects of Dataset (and ConjunctiveGraph) operators, in-place or otherwise.