Skip to content

Reference

This part of the project documentation provides information about the technical implementation of the LODKit project.

lodkit.triple_tools.ttl_constructor

LODKit Triple utilities.

plist

Bases: ttl

Deprecated alias to ttl.

This is for backwards api compatibility only. Since ttl also implements Turtle object lists now, refering to the class as "plist" is inaccurate/misleading.

Source code in lodkit/triple_tools/ttl_constructor.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
class plist(ttl):
    """Deprecated alias to ttl.

    This is for backwards api compatibility only.
    Since ttl also implements Turtle object lists now,
    refering to the class as "plist" is inaccurate/misleading.
    """

    def __init__(self, *args, **kwargs):
        logger.warning("Class 'plist' is a deprecated alias. Use 'ttl' instead.")
        super().__init__(*args, **kwargs)

ttl

Triple constructor implementing a Turtle-like interface.

Source code in lodkit/triple_tools/ttl_constructor.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
class ttl:
    """Triple constructor implementing a Turtle-like interface."""

    @typechecked
    def __init__(
        self,
        uri: _TripleSubject,
        *predicate_object_pairs: tuple[
            URIRef,
            _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...],
        ],
        graph: Graph | None = None,
    ) -> None:
        """Initialize a ttl triple constructor.

        The callable interface aims to provide a Python representation
        fo Turtle predicate and object list syntax.

        Args:
            uri (_TripleSubject): The subject of a triple
            *predicate_object_pairs (tuple[ URIRef, _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...]]): Predicate-object pairs
            graph (Graph | None): An optional rdflib.Graph instance

        Returns:
            None

        Examples:

            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'))))
            )

            graph: Graph = triples.to_graph()
        """
        self.uri = uri
        self.predicate_object_pairs = predicate_object_pairs
        self.graph = Graph() if graph is None else deepcopy(graph)
        self._iter = iter(self)

    def __iter__(self) -> Iterator[_Triple]:
        """Generate an iterator of tuple-based triple representations."""
        for pred, obj in self.predicate_object_pairs:
            match obj:
                case ttl():
                    yield (self.uri, pred, obj.uri)
                    yield from obj
                case list() | Iterator():
                    _b = BNode()
                    yield (self.uri, pred, _b)
                    yield from ttl(_b, *obj)
                case tuple():
                    _object_list = zip(repeat(pred), obj)
                    yield from ttl(self.uri, *_object_list)
                case str():
                    yield (self.uri, pred, Literal(obj))
                case _:
                    yield (self.uri, pred, obj)

    def __next__(self) -> _Triple:
        """Return the next triple from the iterator."""
        return next(self._iter)

    def to_graph(self, graph: Graph | None = None) -> Graph:
        """Generate a graph instance from a ttl Iterator."""
        if graph is not None:
            graph_copy = deepcopy(graph)
            self.graph = graph_copy

        for triple in self:
            self.graph.add(triple)
        return self.graph

__init__(uri, *predicate_object_pairs, graph=None)

Initialize a ttl triple constructor.

The callable interface aims to provide a Python representation fo Turtle predicate and object list syntax.

Parameters:

Name Type Description Default
uri _TripleSubject

The subject of a triple

required
*predicate_object_pairs tuple[URIRef, _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...]]

Predicate-object pairs

()
graph Graph | None

An optional rdflib.Graph instance

None

Returns:

Type Description
None

None

Examples:

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'))))
)

graph: Graph = triples.to_graph()
Source code in lodkit/triple_tools/ttl_constructor.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
@typechecked
def __init__(
    self,
    uri: _TripleSubject,
    *predicate_object_pairs: tuple[
        URIRef,
        _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...],
    ],
    graph: Graph | None = None,
) -> None:
    """Initialize a ttl triple constructor.

    The callable interface aims to provide a Python representation
    fo Turtle predicate and object list syntax.

    Args:
        uri (_TripleSubject): The subject of a triple
        *predicate_object_pairs (tuple[ URIRef, _TripleObject | list | Iterator | Self | str | tuple[_TripleObject, ...]]): Predicate-object pairs
        graph (Graph | None): An optional rdflib.Graph instance

    Returns:
        None

    Examples:

        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'))))
        )

        graph: Graph = triples.to_graph()
    """
    self.uri = uri
    self.predicate_object_pairs = predicate_object_pairs
    self.graph = Graph() if graph is None else deepcopy(graph)
    self._iter = iter(self)

__iter__()

Generate an iterator of tuple-based triple representations.

Source code in lodkit/triple_tools/ttl_constructor.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def __iter__(self) -> Iterator[_Triple]:
    """Generate an iterator of tuple-based triple representations."""
    for pred, obj in self.predicate_object_pairs:
        match obj:
            case ttl():
                yield (self.uri, pred, obj.uri)
                yield from obj
            case list() | Iterator():
                _b = BNode()
                yield (self.uri, pred, _b)
                yield from ttl(_b, *obj)
            case tuple():
                _object_list = zip(repeat(pred), obj)
                yield from ttl(self.uri, *_object_list)
            case str():
                yield (self.uri, pred, Literal(obj))
            case _:
                yield (self.uri, pred, obj)

__next__()

Return the next triple from the iterator.

Source code in lodkit/triple_tools/ttl_constructor.py
77
78
79
def __next__(self) -> _Triple:
    """Return the next triple from the iterator."""
    return next(self._iter)

to_graph(graph=None)

Generate a graph instance from a ttl Iterator.

Source code in lodkit/triple_tools/ttl_constructor.py
81
82
83
84
85
86
87
88
89
def to_graph(self, graph: Graph | None = None) -> Graph:
    """Generate a graph instance from a ttl Iterator."""
    if graph is not None:
        graph_copy = deepcopy(graph)
        self.graph = graph_copy

    for triple in self:
        self.graph.add(triple)
    return self.graph

lodkit.uri_tools.uriclass

LODKit uriclass: A dataclass inspired URI constructor mechanism.

uriclass

Dataclass-inspired URI constructor.

Class-level attributes are converted to URIs according to uri_constructor. For class attributes with just type information, URIs are constructed using UUIDs, for class attributes with string values, URIs are constructed using hashing based on that string.

Examples:

@uriclass(Namespace("https://test.org/test/"))
class uris:
    x1: str

    y1 = "hash value 1"
    y2 = "hash value 1"


print(uris.x1)             # Namespace("https://test.org/test/<UUID>")
print(uris.y1 == uris.y2)  # True
Source code in lodkit/uri_tools/uriclass.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class uriclass:
    """Dataclass-inspired URI constructor.

    Class-level attributes are converted to URIs according to uri_constructor.
    For class attributes with just type information, URIs are constructed using UUIDs,
    for class attributes with string values, URIs are constructed using hashing based on that string.

    Examples:

        @uriclass(Namespace("https://test.org/test/"))
        class uris:
            x1: str

            y1 = "hash value 1"
            y2 = "hash value 1"


        print(uris.x1)             # Namespace("https://test.org/test/<UUID>")
        print(uris.y1 == uris.y2)  # True
    """

    def __init__(
        self,
        namespace: str,
        uri_constructor: _TURIConstructorFactory = mkuri_factory,
    ) -> None:

        self._mkuri = uri_constructor(namespace)

    def __call__[T](self, cls: T) -> T:
        # note: order matters, the second loop sets attributes in cls!
        for key, value in cls.__dict__.items():
            if not key.startswith("_"):
                setattr(cls, key, self._mkuri(value))

        for var, _ in cls.__annotations__.items():
            setattr(cls, var, self._mkuri())

        return cls

make_uriclass(cls_name, namespace, fields, uri_constructor=mkuri_factory)

Constructor for dynamic URI class creation.

make_uriclass provides functionality structurally equivalent to @uriclass, but fields are read from an Iterable[str | tuple[str, str]].

Examples:

uris = make_uriclass(
    cls_name="TestURIFun",
    namespace="https://test.org/test/",
    fields=("x", ("y1", "hash value 1"), ("y2", "hash value 1")),
)


print(uris.x1)             # Namespace("https://test.org/test/<UUID>")
print(uris.y1 == uris.y2)  # True
Source code in lodkit/uri_tools/uriclass.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def make_uriclass(
    cls_name: str,
    namespace: str,
    fields: Iterable[str | tuple[str, str]],
    uri_constructor: _TURIConstructorFactory = mkuri_factory,
) -> type[uriclass]:
    """Constructor for dynamic URI class creation.

    make_uriclass provides functionality structurally equivalent to @uriclass,
    but fields are read from an Iterable[str | tuple[str, str]].

    Examples:

        uris = make_uriclass(
            cls_name="TestURIFun",
            namespace="https://test.org/test/",
            fields=("x", ("y1", "hash value 1"), ("y2", "hash value 1")),
        )


        print(uris.x1)             # Namespace("https://test.org/test/<UUID>")
        print(uris.y1 == uris.y2)  # True
    """
    _mkuri = uri_constructor(namespace)

    def _generate_pairs() -> Iterator[tuple[str, str]]:
        for field in fields:
            match field:
                case str():
                    yield (field, _mkuri())
                case (str(), str()):
                    name, value = field
                    yield (name, _mkuri(value))
                case _:
                    raise Exception(
                        "Fields must be of type Iterable[str | tuple[str, str]]."
                    )

    _cls = new_class(
        name=cls_name, exec_body=lambda ns: ns.update(dict(_generate_pairs()))
    )
    return _cls