From b3263f9c475c0ec62edd24c5866a110e2634ac03 Mon Sep 17 00:00:00 2001 From: Edmond Chuc Date: Mon, 20 Oct 2025 09:40:12 +1000 Subject: [PATCH 1/3] fix: the return type of Dataset.parse --- rdflib/graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rdflib/graph.py b/rdflib/graph.py index 5d739a957..7b7256d04 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -2623,7 +2623,7 @@ def parse( file: Optional[Union[BinaryIO, TextIO]] = None, data: Optional[Union[str, bytes]] = None, **args: Any, - ) -> Graph: + ) -> Dataset: """ Parse an RDF source adding the resulting triples to the Graph. From 414fbdc325ad3d7a0a913d130f0910a4de48ff70 Mon Sep 17 00:00:00 2001 From: Edmond Chuc Date: Mon, 20 Oct 2025 09:42:33 +1000 Subject: [PATCH 2/3] fix: SPARQL Update inserts into the default graph does not create a new graph with a blank node label as the graph name --- rdflib/plugins/sparql/update.py | 2 +- test/test_sparql/test_update.py | 90 ++++++++++++++++++++++++++++++++- 2 files changed, 89 insertions(+), 3 deletions(-) diff --git a/rdflib/plugins/sparql/update.py b/rdflib/plugins/sparql/update.py index a69083935..9d59c8eef 100644 --- a/rdflib/plugins/sparql/update.py +++ b/rdflib/plugins/sparql/update.py @@ -182,7 +182,7 @@ def evalModify(ctx: QueryContext, u: CompValue) -> None: ctx = ctx.pushGraph(g) for c in list(res): - dg = ctx.graph + dg = ctx.graph if type(ctx.graph) is Graph else ctx.dataset.default_context if u.delete: # type error: Unsupported left operand type for - ("None") # type error: Unsupported operand types for - ("Graph" and "Generator[Tuple[Identifier, Identifier, Identifier], None, None]") diff --git a/test/test_sparql/test_update.py b/test/test_sparql/test_update.py index ba1ddb306..4b16aa7de 100644 --- a/test/test_sparql/test_update.py +++ b/test/test_sparql/test_update.py @@ -4,8 +4,9 @@ import pytest -from rdflib import Literal, Namespace, Variable -from rdflib.graph import ConjunctiveGraph, Dataset, Graph +from rdflib import Literal, Namespace, URIRef, Variable +from rdflib.compare import isomorphic +from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, ConjunctiveGraph, Dataset, Graph from test.data import TEST_DATA_DIR from test.utils import GraphHelper from test.utils.graph import GraphSource @@ -164,3 +165,88 @@ def test_reevaluation_between_updates_insert() -> None: result = g.query("SELECT ?x WHERE { ex:bar ex:value ?x }") values = {b.get(Variable("x")) for b in result} # type: ignore assert values == {Literal(3), Literal(4), Literal(14)} + + +def test_inserts_in_named_graph(): + trig_data = """ + @prefix ex: . + @prefix rdf: . + + # Named graph 1 + ex:graph1 { + ex:person1 ex:name "Alice" ; + ex:age 30 . + } + + # Named graph 2 + ex:graph2 { + ex:person1 ex:worksFor ex:company1 . + ex:company1 ex:industry "Technology" . + } + """ + ds = Dataset().parse(data=trig_data, format="trig") + ds.update( + """ + INSERT { + GRAPH { + ?s ?p ?o + } + + ?s ?p ?o + } + WHERE { + GRAPH ?g { + ?s ?p ?o + } + } + """ + ) + + expected_trig = """ + @prefix ex: . + @prefix xsd: . + + { + ex:person1 ex:age 30 ; + ex:name "Alice" ; + ex:worksFor ex:company1 . + + ex:company1 ex:industry "Technology" . + } + + { + ex:person1 ex:age 30 ; + ex:name "Alice" ; + ex:worksFor ex:company1 . + + ex:company1 ex:industry "Technology" . + } + + ex:graph1 { + ex:person1 ex:age 30 ; + ex:name "Alice" . + } + + ex:graph2 { + ex:person1 ex:worksFor ex:company1 . + + ex:company1 ex:industry "Technology" . + } + """ + expected_ds = Dataset().parse(data=expected_trig, format="trig") + + # There should be exactly 4 graphs, including the default graph. + # SPARQL Update inserts into the default graph should go into the default graph, + # not to a new graph with a blank node label. + # See https://github.com/RDFLib/rdflib/issues/3080 + expected_graph_names = [ + DATASET_DEFAULT_GRAPH_ID, + URIRef("urn:graph"), + URIRef("http://example.org/graph1"), + URIRef("http://example.org/graph2"), + ] + assert set(expected_graph_names) == set(graph.identifier for graph in ds.graphs()) + + for graph in ds.graphs(): + expected_graph = expected_ds.graph(graph.identifier) + assert isomorphic(graph, expected_graph) From 6c2e17afd0775c72878da91c339eb8687dca5f3c Mon Sep 17 00:00:00 2001 From: Edmond Chuc Date: Mon, 20 Oct 2025 23:06:16 +1000 Subject: [PATCH 3/3] chore: add todo comment --- rdflib/plugins/sparql/update.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rdflib/plugins/sparql/update.py b/rdflib/plugins/sparql/update.py index 9d59c8eef..c9d36564c 100644 --- a/rdflib/plugins/sparql/update.py +++ b/rdflib/plugins/sparql/update.py @@ -182,6 +182,9 @@ def evalModify(ctx: QueryContext, u: CompValue) -> None: ctx = ctx.pushGraph(g) for c in list(res): + # TODO: Make this more intentional and without the weird type checking logic + # once ConjunctiveGraph is removed and Dataset no longer inherits from + # Graph. dg = ctx.graph if type(ctx.graph) is Graph else ctx.dataset.default_context if u.delete: # type error: Unsupported left operand type for - ("None")