diff --git a/lodkit/__init__.py b/lodkit/__init__.py index e1e7946..dcfeaa5 100644 --- a/lodkit/__init__.py +++ b/lodkit/__init__.py @@ -25,7 +25,7 @@ ) from lodkit.rdf_importer import RDFImporter from lodkit.testing_tools.strategies import TripleStrategies, tst, tst_xml -from lodkit.triple_tools.ttl_constructor import ttl +from lodkit.triple_tools.ttl_constructor import TripleChain, ttl from lodkit.uri_tools.uribase import uribase from lodkit.uri_tools.uriclass import make_uriclass, uriclass from lodkit.uri_tools.utils import ( diff --git a/lodkit/triple_tools/ttl_constructor.py b/lodkit/triple_tools/ttl_constructor.py index 5ac3908..634db41 100644 --- a/lodkit/triple_tools/ttl_constructor.py +++ b/lodkit/triple_tools/ttl_constructor.py @@ -1,7 +1,10 @@ """LODKit Triple utilities.""" from collections.abc import Iterable, Iterator +import functools from itertools import repeat +import itertools +from typing import Self from lodkit.lod_types import _Triple, _TripleObject, _TripleSubject from rdflib import BNode, Graph, Literal, URIRef @@ -19,38 +22,31 @@ type _TPredicateObjectPair = tuple[URIRef, _TPredicateObjectPairObject] -class ttl(Iterable[_Triple]): - """Triple generation facility that implements a Turtle-like interface. +class _ToGraphMixin: + def to_graph(self: Iterable[_Triple], graph: Graph | None = None) -> Graph: + """Generate a graph instance from a ttl Iterator.""" + _graph = Graph() if graph is None else graph - The generator takes a triple subject and an aribitrary number of predicate/object pairs - and produces an Iterator of RDFLib object 3-tuples. + for triple in self: + _graph.add(triple) + return _graph - Triple objects passed to the constructor can be - - URIRefs, BNodes, Literals - - Python lists of predicate/object tuples (resolved as blank nodes), - - tuples (resolved as Turtle object lists) - - ttl constructors (resolved recursively) - Args: - uri (_TripleSubject): The subject of a triple - *predicate_object_pairs (tuple[ URIRef, _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...]]): Predicate-object pairs +class TripleChain(Iterator[_Triple], _ToGraphMixin): + def __init__(self, *triples: Iterable[_Triple]) -> None: + self._triples = itertools.chain.from_iterable(triples) - Returns: - None + def __iter__(self) -> Self: + return self - Examples: + def __next__(self) -> _Triple: + return next(self._triples) - triples: Iterator[lodkit._Triple] = ttl( - URIRef('https://subject'), - (RDF.type, URIRef('https://some_type')), - (RDFS.label, Literal('label 1'), 'label 2'), - (RDFS.seeAlso, [(RDFS.label, 'label 3')]), - (RDFS.isDefinedBy, ttl(URIRef('https://subject_2'), (RDF.type, URI('https://another_type')))) - ) + def __or__(self, other: Iterable[_Triple]) -> Self: + return self.__class__(self, other) - graph: Graph = triples.to_graph() - """ +class ttl(Iterable[_Triple], _ToGraphMixin): def __init__( self, uri: _TripleSubject, @@ -84,10 +80,5 @@ def __iter__(self) -> Iterator[_Triple]: "See the ttl docs and type annotation for applicable object types." ) - def to_graph(self, graph: Graph | None = None) -> Graph: - """Generate a graph instance from a ttl Iterator.""" - _graph = Graph() if graph is None else graph - - for triple in self: - _graph.add(triple) - return _graph + def __or__(self, other: Iterable[_Triple]) -> TripleChain: + return TripleChain(self, other)