Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 8 additions & 15 deletions rdflib/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,11 @@
_TripleOrQuadSelectorType = Union["_TripleSelectorType", "_QuadSelectorType"]
_TriplePathType = Tuple["_SubjectType", Path, "_ObjectType"]
_TripleOrTriplePathType = Union["_TripleType", "_TriplePathType"]
_TripleChoiceType = Union[
Tuple[List[_SubjectType], Optional[_PredicateType], Optional[_ObjectType]],
Tuple[Optional[_SubjectType], List[_PredicateType], Optional[_ObjectType]],
Tuple[Optional[_SubjectType], Optional[_PredicateType], List[_ObjectType]],
]

_GraphT = TypeVar("_GraphT", bound="Graph")
_ConjunctiveGraphT = TypeVar("_ConjunctiveGraphT", bound="ConjunctiveGraph")
Expand Down Expand Up @@ -994,11 +999,7 @@ def predicate_objects(

def triples_choices(
self,
triple: Union[
Tuple[List[_SubjectType], _PredicateType, _ObjectType],
Tuple[_SubjectType, List[_PredicateType], _ObjectType],
Tuple[_SubjectType, _PredicateType, List[_ObjectType]],
],
triple: _TripleChoiceType,
context: Optional[_ContextType] = None,
) -> Generator[_TripleType, None, None]:
subject, predicate, object_ = triple
Expand Down Expand Up @@ -2196,11 +2197,7 @@ def quads(

def triples_choices(
self,
triple: Union[
Tuple[List[_SubjectType], _PredicateType, _ObjectType],
Tuple[_SubjectType, List[_PredicateType], _ObjectType],
Tuple[_SubjectType, _PredicateType, List[_ObjectType]],
],
triple: _TripleChoiceType,
context: Optional[_ContextType] = None,
) -> Generator[_TripleType, None, None]:
"""Iterate over all the triples in the entire conjunctive graph"""
Expand Down Expand Up @@ -2946,11 +2943,7 @@ def __isub__(self: _GraphT, other: Iterable[_TripleType]) -> NoReturn:

def triples_choices(
self,
triple: Union[
Tuple[List[_SubjectType], _PredicateType, _ObjectType],
Tuple[_SubjectType, List[_PredicateType], _ObjectType],
Tuple[_SubjectType, _PredicateType, List[_ObjectType]],
],
triple: _TripleChoiceType,
context: Optional[_ContextType] = None,
) -> Generator[_TripleType, None, None]:
subject, predicate, object_ = triple
Expand Down
9 changes: 6 additions & 3 deletions rdflib/plugins/parsers/rdfxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ def document_element_start(
self, name: Tuple[str, str], qname, attrs: AttributesImpl
) -> None:
if name[0] and URIRef("".join(name)) == RDFVOC.RDF:
next = self.next
# Cheap hack so 2to3 doesn't turn it into __next__
next = getattr(self, "next")
next.start = self.node_element_start
next.end = self.node_element_end
else:
Expand All @@ -315,7 +316,8 @@ def node_element_start(
current = self.current
absolutize = self.absolutize

next = self.next
# Cheap hack so 2to3 doesn't turn it into __next__
next = getattr(self, "next")
next.start = self.property_element_start
next.end = self.property_element_end

Expand Down Expand Up @@ -408,7 +410,8 @@ def property_element_start(
current = self.current
absolutize = self.absolutize

next = self.next
# Cheap hack so 2to3 doesn't turn it into __next__
next = getattr(self, "next")
object: Optional[_ObjectType] = None
current.data = None
current.list = None
Expand Down
43 changes: 33 additions & 10 deletions rdflib/plugins/serializers/longturtle.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,20 @@


class LongTurtleSerializer(RecursiveSerializer):
"""LongTurtle, a Turtle serialization format.

When the optional parameter ``canon`` is set to :py:obj:`True`, the graph is canonicalized
before serialization. This normalizes blank node identifiers and allows for
deterministic serialization of the graph. Useful when consistent outputs are required.
"""

short_name = "longturtle"
indentString = " "

def __init__(self, store):
self._ns_rewrite = {}
store = to_canonical_graph(store)
content = store.serialize(format="application/n-triples")
lines = content.split("\n")
lines.sort()
graph = Graph()
graph.parse(
data="\n".join(lines), format="application/n-triples", skolemize=True
)
graph = graph.de_skolemize()
super(LongTurtleSerializer, self).__init__(graph)
self._canon = False
super(LongTurtleSerializer, self).__init__(store)
self.keywords = {RDF.type: "a"}
self.reset()
self.stream = None
Expand Down Expand Up @@ -83,11 +82,34 @@ def addNamespace(self, prefix, namespace):
super(LongTurtleSerializer, self).addNamespace(prefix, namespace)
return prefix

def canonize(self):
"""Apply canonicalization to the store.

This normalizes blank node identifiers and allows for deterministic
serialization of the graph.
"""
if not self._canon:
return

namespace_manager = self.store.namespace_manager
store = to_canonical_graph(self.store)
content = store.serialize(format="application/n-triples")
lines = content.split("\n")
lines.sort()
graph = Graph()
graph.parse(
data="\n".join(lines), format="application/n-triples", skolemize=True
)
graph = graph.de_skolemize()
graph.namespace_manager = namespace_manager
self.store = graph

def reset(self):
super(LongTurtleSerializer, self).reset()
self._shortNames = {}
self._started = False
self._ns_rewrite = {}
self.canonize()

def serialize(
self,
Expand All @@ -97,6 +119,7 @@ def serialize(
spacious: Optional[bool] = None,
**kwargs: Any,
) -> None:
self._canon = kwargs.get("canon", False)
self.reset()
self.stream = stream
# if base is given here, use, if not and a base is set for the graph use that
Expand Down
15 changes: 10 additions & 5 deletions rdflib/plugins/stores/berkeleydb.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,8 @@ def remove( # type: ignore[override]
cursor = index.cursor(txn=txn)
try:
cursor.set_range(key)
current = cursor.next
# Hack to stop 2to3 converting this to next(cursor)
current = getattr(cursor, "next")()
except db.DBNotFoundError:
current = None
cursor.close()
Expand Down Expand Up @@ -505,7 +506,8 @@ def triples(
cursor = index.cursor(txn=txn)
try:
cursor.set_range(key)
current = cursor.next
# Cheap hack so 2to3 doesn't convert to next(cursor)
current = getattr(cursor, "next")()
except db.DBNotFoundError:
current = None
cursor.close()
Expand Down Expand Up @@ -537,7 +539,8 @@ def __len__(self, context: Optional[_ContextType] = None) -> int:
key, value = current
if key.startswith(prefix):
count += 1
current = cursor.next
# Hack to stop 2to3 converting this to next(cursor)
current = getattr(cursor, "next")()
else:
break
cursor.close()
Expand Down Expand Up @@ -590,7 +593,8 @@ def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]:
while current:
prefix, namespace = current
results.append((prefix.decode("utf-8"), namespace.decode("utf-8")))
current = cursor.next
# Hack to stop 2to3 converting this to next(cursor)
current = getattr(cursor, "next")()
cursor.close()
for prefix, namespace in results:
yield prefix, URIRef(namespace)
Expand Down Expand Up @@ -633,7 +637,8 @@ def contexts(
cursor = index.cursor()
try:
cursor.set_range(key)
current = cursor.next
# Hack to stop 2to3 converting this to next(cursor)
current = getattr(cursor, "next")()
except db.DBNotFoundError:
current = None
cursor.close()
Expand Down
7 changes: 2 additions & 5 deletions rdflib/plugins/stores/sparqlstore.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
_TripleType,
_ContextType,
_QuadType,
_TripleChoiceType,
_TriplePatternType,
_SubjectType,
_PredicateType,
Expand Down Expand Up @@ -367,11 +368,7 @@ def triples( # type: ignore[override]

def triples_choices(
self,
_: Tuple[
Union[_SubjectType, List[_SubjectType]],
Union[_PredicateType, List[_PredicateType]],
Union[_ObjectType, List[_ObjectType]],
],
_: _TripleChoiceType,
context: Optional[_ContextType] = None,
) -> Generator[
Tuple[
Expand Down
11 changes: 2 additions & 9 deletions rdflib/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
Generator,
Iterable,
Iterator,
List,
Mapping,
Optional,
Tuple,
Expand All @@ -49,10 +48,8 @@
from rdflib.graph import (
Graph,
_ContextType,
_ObjectType,
_PredicateType,
_QuadType,
_SubjectType,
_TripleChoiceType,
_TriplePatternType,
_TripleType,
)
Expand Down Expand Up @@ -281,11 +278,7 @@ def remove(

def triples_choices(
self,
triple: Union[
Tuple[List[_SubjectType], _PredicateType, _ObjectType],
Tuple[_SubjectType, List[_PredicateType], _ObjectType],
Tuple[_SubjectType, _PredicateType, List[_ObjectType]],
],
triple: _TripleChoiceType,
context: Optional[_ContextType] = None,
) -> Generator[
Tuple[
Expand Down
64 changes: 33 additions & 31 deletions test/data/longturtle/longturtle-target.ttl
Original file line number Diff line number Diff line change
@@ -1,72 +1,74 @@
PREFIX cn: <https://linked.data.gov.au/def/cn/>
PREFIX ex: <http://example.com/>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX schema: <https://schema.org/>
PREFIX sdo: <https://schema.org/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

<http://example.com/nicholas>
a schema:Person ;
schema:age 41 ;
schema:alternateName
ex:nicholas
a sdo:Person ;
sdo:age 41 ;
sdo:alternateName
[
schema:name "Dr N.J. Car" ;
sdo:name "Dr N.J. Car" ;
] ,
"N.J. Car" ,
"Nick Car" ;
schema:name
sdo:name
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
schema:hasPart
a cn:CompoundName ;
sdo:hasPart
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
schema:hasPart
a cn:CompoundName ;
sdo:hasPart
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
a cn:CompoundName ;
rdf:value "Car" ;
] ,
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
a cn:CompoundName ;
rdf:value "Maxov" ;
] ;
] ,
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
a cn:CompoundName ;
rdf:value "Nicholas" ;
] ,
[
a <https://linked.data.gov.au/def/cn/CompoundName> ;
a cn:CompoundName ;
rdf:value "John" ;
] ;
] ;
schema:worksFor <https://kurrawong.ai> ;
sdo:worksFor <https://kurrawong.ai> ;
.

<https://kurrawong.ai>
a schema:Organization ;
schema:location <https://kurrawong.ai/hq> ;
a sdo:Organization ;
sdo:location <https://kurrawong.ai/hq> ;
.

<https://kurrawong.ai/hq>
a schema:Place ;
schema:address
a sdo:Place ;
sdo:address
[
a schema:PostalAddress ;
schema:addressCountry
a sdo:PostalAddress ;
sdo:addressCountry
[
schema:identifier "au" ;
schema:name "Australia" ;
sdo:identifier "au" ;
sdo:name "Australia" ;
] ;
schema:addressLocality "Shorncliffe" ;
schema:addressRegion "QLD" ;
schema:postalCode 4017 ;
schema:streetAddress (
sdo:addressLocality "Shorncliffe" ;
sdo:addressRegion "QLD" ;
sdo:postalCode 4017 ;
sdo:streetAddress (
72
"Yundah"
"Street"
) ;
] ;
schema:geo
sdo:geo
[
schema:polygon "POLYGON((153.082403 -27.325801, 153.08241 -27.32582, 153.082943 -27.325612, 153.083010 -27.325742, 153.083543 -27.325521, 153.083456 -27.325365, 153.082403 -27.325801))"^^geo:wktLiteral ;
sdo:polygon "POLYGON((153.082403 -27.325801, 153.08241 -27.32582, 153.082943 -27.325612, 153.083010 -27.325742, 153.083543 -27.325521, 153.083456 -27.325365, 153.082403 -27.325801))"^^geo:wktLiteral ;
] ;
schema:name "KurrawongAI HQ" ;
sdo:name "KurrawongAI HQ" ;
.
2 changes: 1 addition & 1 deletion test/test_graph/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ def test_guess_format_for_parse_http_text_plain():
assert len(graph) > 0

# A url that returns content-type text/html.
url = "https://github.com/RDFLib/rdflib/issues/2734"
url = "https://www.w3.org/TR/REC-rdf-syntax/"
with pytest.raises(PluginException):
graph = Graph().parse(url)

Expand Down
2 changes: 1 addition & 1 deletion test/test_serializers/test_serializer_longturtle.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def test_longturtle():
g.bind("sdo", SDO)

# run the long turtle serializer
output = g.serialize(format="longturtle")
output = g.serialize(format="longturtle", canon=True)

# fix the target
current_dir = Path.cwd() # Get the current directory
Expand Down
Loading
Loading