In Owlready2, annotations are accessed as attributes. For Classes, notice that annotations are not inherited.

Adding an annotation

For a given entity (a Class, a Property or an Individual), the following syntax can be used to add annotations:

>>> from owlready2 import *

>>> onto = get_ontology("")

>>> with onto:
...     class Drug(Thing):
...         pass

>>> Drug.comment = ["A first comment on the Drug class", "A second comment"]

>>> Drug.comment.append("A third comment")

The following annotations are available by default: comment, isDefinedBy, label, seeAlso, backwardCompatibleWith, deprecated, incompatibleWith, priorVersion, versionInfo.

Owlready2 also supports annotations on relation triples, using the AnnotationProperty (here comment) as a pseudo-dictionary:

>>> with onto:
...     class HealthProblem(Thing):
...         pass

...     class is_prescribed_for(Drug >> HealthProblem):
...         pass

>>> acetaminophen = Drug("acetaminophen")
>>> pain = HealthProblem("pain")
>>> acetaminophen.is_prescribed_for.append(pain)

>>> comment[acetaminophen, is_prescribed_for, pain] = "A comment on the acetaminophen-pain relation"

Special pseudo-properties are provided for annotating is-a relations (owl_subclassof and rdf_type), domains (rdf_domain) and ranges (rdf_range).

>>> comment[Drug, owl_subclassof, Thing] = "A comment on an is-a relation"

Annotation values are usually lists of values. However, in many cases, a single value is used. Owlready2 accepts to set an annotation property to a single value, for example:

>>> acetaminophen.comment = "This comment replaces all existing comments on acetaminophen"

Querying annotations

Annotation values can be obtained using the dot notation, as if they were attributes of the entity:

>>> print(Drug.comment)
['A first comment on the Drug class', 'A second comment', 'A third comment']

>>> print(comment[acetaminophen, is_prescribed_for, pain])
['A comment on the acetaminophen-pain relation']

>>> print(comment[Drug, owl_subclassof, Thing])
['A comment on an is-a relation']

If you expect a single value, the .first() method of the list can be used. It returns the first value of the list, or None if the list is empty.

>>> acetaminophen.comment.first()
'This comment replaces all existing comments on acetaminophen'

Deleting annotations

To delete an annotation, simply remove it from the list.

>>> Drug.comment.remove("A second comment")

For removing all annotations of a given type:

>>> Drug.comment = []

Custom rendering of entities

The set_render_func() global function can be used to specify how Owlready2 renders entities, i.e. how they are converted to text when printing them. set_render_func() accepts a single param, a function which takes one entity and return a string.

The ‘label’ annotation is commonly used for rendering entities. The following example renders entities using their ‘label’ annotation, defaulting to their name:

>>> def render_using_label(entity):
...     return entity.label.first() or

>>> set_render_func(render_using_label)

>>> Drug    # No label defined yet => use

>>> Drug.label = "The drug class"

>>> Drug
The drug class

The following example renders entities using their IRI:

>>> def render_using_iri(entity):
...     return entity.iri

>>> set_render_func(render_using_iri)

>>> Drug

Language-specific annotations

To specify the language of textual annotations, the ‘locstr’ (localized string) type can be used:

>>> Drug.comment = [ locstr("Un commentaire en Français", lang = "fr"),
...                  locstr("A comment in English", lang = "en") ]
>>> Drug.comment[0]
'Un commentaire en Français'
>>> Drug.comment[0].lang

In addition, the list of values support language-specific sublists, available as ‘.<language code>’ (e.g. .fr, .en, .es, .de,…). These sublists contain normal string (not locstr), and they can be modified.

['Un commentaire en Français']

>>> Drug.comment.en
['A comment in English']

>>> Drug.comment.en.first()
'A comment in English'

>>> Drug.comment.en.append("A second English comment")


Modifying the language-specific sublist will automatically update the list of values (and the quad store). However, the contrary is not true: modifying the list of values does not update language-specific sublists.

Creating new classes of annotation

The AnnotationProperty class can be subclasses to create a new class of annotation:

>>> with onto:
...     class my_annotation(AnnotationProperty):
...         pass

You can also create a subclass of an existing annotation class:

>>> with onto:
...     class pharmaceutical_comment(comment):
...         pass

>>> acetaminophen.pharmaceutical_comment = "A comment related to pharmacology of acetaminophen"