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
131 changes: 103 additions & 28 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ This is done via a plugin system for different triplestore `backends`.
See the README file for a [list of currently supported backends].

The API provided by Tripper is modelled after [rdflib], so if you know that library, you will find Tripper rather familiar.
But there are some differences that you should be aware of.
Most recognisable:
But there are some differences to be aware of.
Most important are:

* All IRIs are represented by Python strings.
Example: `"https://w3id.org/emmo#Metre"`
* Blank nodes are strings starting with "_:".
Expand Down Expand Up @@ -51,7 +52,7 @@ For example:

```

New namespaces can be created using the [Namespace] class, but are usually added with the `bind()` method:
New namespaces can be created using the [Namespace] class, but are usually added with the [`bind()`] method:

```python
>>> ONTO = ts.bind("onto", "http://example.com/onto#")
Expand All @@ -61,7 +62,7 @@ New namespaces can be created using the [Namespace] class, but are usually added
```

### Adding triples to the triplestore
We can now start to add triples to the triplestore, using the `add()` and `add_triples()` methods:
Triples can now be added to the triplestore, using the [`add()`] and [`add_triples()`] methods:

```python
>>> from tripper.utils import en
Expand All @@ -72,10 +73,10 @@ We can now start to add triples to the triplestore, using the `add()` and `add_t

```

The function `en(msg)` is just a convenient function for adding english literals.
The function [`en()`] is just a convenient function for adding English literals.
It is equivalent to `tripper.Literal(msg, lang="en")`.

You can also load triples from a source using the `parse()` method.
Triples can also be added from a source using the [`parse()`] method.
For example will

```python
Expand All @@ -84,16 +85,16 @@ ts.parse("onto.ttl", format="turtle")

load all triples in turtle file `onto.ttl` into the triplestore.

Similarly you can serialise the triplestore to a string or a file using the `serialize()` method:
Similarly, the triplestore can be serialised to a string or a file using the [`serialize()`] method:

```python
ts.serialize("onto2.ttl") # serialise to file `onto2.ttl`
s = ts.serialize(format="ntriples") # serialise to string s in ntriples format
```

### Retrieving triples from and querying a triplestore
A set of convenient functions exists for simple queries, including `triples()`, `subjects()`, `predicates()`, `objects()`, `subject_predicates()`, `subject_objects()`, `predicate_objects()` and `value()`.
Except for `value()`, they return the result as generators.
A set of convenient functions exist for simple queries, including [`triples()`], [`subjects()`], [`predicates()`], [`objects()`], [`subject_predicates()`], [`subject_objects()`], [`predicate_objects()`] and [`value()`].
Except for [`value()`], they return iterators.
For example:

```python
Expand All @@ -105,7 +106,7 @@ For example:

```

The `query()` and `update()` methods can be used to query and update the triplestore using SPARQL.
The [`query()`] and [`update()`] methods can be used to query and update the triplestore using SPARQL.
See the next section.


Expand Down Expand Up @@ -142,11 +143,57 @@ Maybe you have to remove the cache file: ...
```

The above example works, since the `namespace="https://w3id.org/emmo#"` is resolvable.
In the case when the IRI in the `namespace` argument is not resolvable, it is possible to supply a resolvable IRI or a reference to a populated Triplestore instance via the `triplestore` keyword argument.
When the IRI in the `namespace` argument is not resolvable, it is possible to supply a resolvable IRI or a reference to a populated [Triplestore] instance via the `triplestore` keyword argument.

Access by label makes it much easier to work with ontologies, like EMMO, that uses non-human readable IDs for the IRIs.
More about this below.

The utility function [`extend_namespace()`] can be used to add additional known labels to a namespace.
For example:

```python
>>> from tripper import Namespace
>>> from tripper.utils import extend_namespace
>>> FOOD = Namespace(
... "http://onto-ns.com/ontologies/examples/food#",
... label_annotations=True,
... check=True,
... reload=True,
... triplestore="https://raw.githubusercontent.com/EMMC-ASBL/tripper/master/tests/ontologies/food.ttl",
... format="turtle",
... )

# Hamburger is not a known label
>>> FOOD.Hamburger # doctest: +ELLIPSIS
Traceback (most recent call last):
...
tripper.errors.NoSuchIRIError: http://onto-ns.com/ontologies/examples/food#Hamburger
...

# Add Hamburger to known labels
>>> extend_namespace(FOOD, {"Hamburger": FOOD + "Hamburger"})
>>> FOOD.Hamburger == FOOD + "Hamburger"
True

# Fish is not a known label
>>> FOOD.Fish # doctest: +ELLIPSIS
Traceback (most recent call last):
...
tripper.errors.NoSuchIRIError: http://onto-ns.com/ontologies/examples/food#Fish
...

# Extend FOOD from an online turtle file
>>> extend_namespace(
... FOOD,
... "https://raw.githubusercontent.com/EMMC-ASBL/tripper/master/tests/ontologies/food-more.ttl",
... format="turtle",
... )

# Now Fish is in the namespace
>>> FOOD.Fish
'http://onto-ns.com/ontologies/examples/food#FOOD_90f5dd54_9e5c_46c9_824f_e10625a90c26'

```


### Writing SPARQL queries using Tripper
Expand Down Expand Up @@ -192,7 +239,8 @@ The Triplestore class has two convenient methods for this, that do not require k
Only support basic restrictions, without any nested logical constructs, are supoprted.
For more advanced restrictions, we recommend to use [EMMOntoPy] or [Owlready2].

A [restriction] is described by the following set of parameters.
A [restriction] restricts a class to only those individuals that satisfy the restriction.
It is described by the following set of parameters.

* **cls**: IRI of class to which the restriction applies.
* **property**: IRI of restriction property.
Expand Down Expand Up @@ -223,8 +271,7 @@ With Tripper this can be stated as:
```
The returned `iri` is the blank node IRI of the new restriction.


To find the above restriction, the `restrictions()` method can be used.
To find the above restriction, the [`restrictions()`] method can be used.
It returns an iterator over all restrictions that matches the provided criteria.
For example:

Expand All @@ -235,7 +282,7 @@ For example:

```

With the `return_dicts` argument set to false, an iterator over the IRIs of all matching restrictions is returned:
With the `asdict` argument set to false, an iterator over the IRIs of all matching restrictions is returned:

```python
>>> g = ts.restrictions(cls=ONTO.Bacteria, property=EMMO.hasPart, asdict=False)
Expand All @@ -261,10 +308,10 @@ To provide a shared semantic meaning of a data model and its *properties* (struc

Mappings can also be used to semantically document the arguments and return values of a function.

The [Triplestore] class has two specialised methods for adding mappings, `map()` and `add_function()`.
The purpose of the `map()` method, is to map a data models and its properties to ontological concepts, while `add_function()` maps the arguments and return value of a function to ontological concepts.
The [Triplestore] class has two specialised methods for adding mappings, [`map()`] and [`add_function()`].
The purpose of the [`map()`] method, is to map a data models and its properties to ontological concepts, while [`add_function()`] maps the arguments and return value of a function to ontological concepts.

**Note**, the name of the `map()` and `add_function()` methods are not very intuitive and may be changed in the future.
**Note**, the name of the [`map()`] and [`add_function()`] methods are not very intuitive and may be changed in the future.


### Adding mappings
Expand Down Expand Up @@ -315,22 +362,50 @@ ts.add_function(



### Representing pydantic data models as RDF
*Todo: Describe the `tripper.convert` subpackage...*


[rdflib]: https://rdflib.readthedocs.io/
[EMMO]: https://emmc.eu/emmo/
[OTEIO]: https://github.com/emmo-repo/domain-oteio/
[Function Ontology (FnO)]: https://fno.io/
[EMMOntoPy]: https://emmo-repo.github.io/EMMOntoPy/
[Owlready2]: https://pypi.org/project/owlready2/
[restriction]: https://www.w3.org/TR/owl-ref/#Restriction
[JSON-LD]: https://json-ld.org/

[Creating a triplestore interface]: #creating-a-triplestore-interface
[list of currently supported backends]: https://github.com/EMMC-ASBL/tripper?tab=readme-ov-file#available-backends

[tripper.convert]: https://emmc-asbl.github.io/tripper/latest/api_reference/convert/convert/

[rdflib]: https://rdflib.readthedocs.io/
[Triplestore]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore
[Namespace]:
https://emmc-asbl.github.io/tripper/latest/api_reference/namespace/#tripper.namespace.Namespace
[Literal]:
https://emmc-asbl.github.io/tripper/latest/api_reference/literal/#tripper.literal.Literal
[Creating a triplestore interface]: #creating-a-triplestore-interface
[EMMO]: https://emmc.eu/emmo/
[Function Ontology (FnO)]: https://fno.io/
[list of currently supported backends]: https://github.com/EMMC-ASBL/tripper?tab=readme-ov-file#available-backends
[EMMOntoPy]: https://emmo-repo.github.io/EMMOntoPy/
[Owlready2]: https://pypi.org/project/owlready2/
[restriction]: https://www.w3.org/TR/owl-ref/#Restriction

[`en()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.utils.en
[`extend_namespace()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.utils.extend_namespace

[`load_container()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/convert/convert/#tripper.convert.convert.load_container
[`save_container()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/convert/convert/#tripper.convert.convert.save_container

[`add()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.add
[`add_function()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.add_function
[`add_restriction()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.add_restriction
[`add_triples()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.add_triples
[`bind()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.bind
[`map()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.map
[`objects()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.objects
[`parse()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.parse
[`predicates()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.predicates
[`predicate_objects()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.predicate_objects
[`query()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.query
[`restrictions()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.restrictions
[`serialize()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.serialize
[`subject_objects()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.subject_objects
[`subject_predicates()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.subject_predicates
[`subjects()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.subjects
[`triples()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.triples
[`update()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.update
[`value()`]: https://emmc-asbl.github.io/tripper/latest/api_reference/triplestore/#tripper.triplestore.Triplestore.value
1 change: 1 addition & 0 deletions tests/test_triplestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ def test_restriction() -> None: # pylint: disable=too-many-statements
)

# Test find restriction

assert set(ts.restrictions(asdict=False)) == {iri, iri2, iri3}
assert set(ts.restrictions(cls=EX.Kerberos, asdict=False)) == {iri2, iri3}
assert set(ts.restrictions(cls=EX.Animal, asdict=False)) == {iri}
Expand Down
6 changes: 4 additions & 2 deletions tripper/triplestore.py
Original file line number Diff line number Diff line change
Expand Up @@ -573,10 +573,12 @@ def value( # pylint: disable=redefined-builtin
"""Return the value for a pair of two criteria.

Useful if one knows that there may only be one value.
Two of `subject`, `predicate` or `object` must be provided.

Parameters:
subject, predicate, object: Criteria to match. Two of these must
be provided.
subject: Possible criteria to match.
predicate: Possible criteria to match.
object: Possible criteria to match.
default: Value to return if no matches are found.
any: If true, return any matching value, otherwise raise
UniquenessError.
Expand Down
14 changes: 12 additions & 2 deletions tripper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,15 @@


def infer_iri(obj):
"""Return IRI of the individual that stands for object `obj`."""
"""Return IRI of the individual that stands for Python object `obj`.

Valid Python objects are [DLite] and [Pydantic] instances.

References:

[DLite]: https://github.com/SINTEF/dlite
[Pydantic]: https://docs.pydantic.dev/
"""

# Please note that tripper does not depend on neither DLite nor Pydantic.
# Hence neither of these packages are imported. However, due to duck-
Expand Down Expand Up @@ -380,6 +388,7 @@ def random_string(length=8):
def extend_namespace(
namespace: Namespace,
triplestore: "Union[Triplestore, str, Path, dict]",
format: "Optional[str]" = None,
):
"""Extend a namespace with additional known names.

Expand All @@ -395,6 +404,7 @@ def extend_namespace(
path to a local file to read from
- Path: path to a local file to read from
- dict: dict mapping new IRI names to their corresponding IRIs
format: Format to use when loading from a triplestore.
"""
if namespace._iris is None: # pylint: disable=protected-access
raise TypeError(
Expand All @@ -405,5 +415,5 @@ def extend_namespace(
namespace._iris.update(triplestore) # pylint: disable=protected-access
else:
namespace._update_iris( # pylint: disable=protected-access
triplestore, reload=True
triplestore, reload=True, format=format
)