Usage

Open an existing ontology

To open an ontology use the open_ontology() function. It guesses the serialization of the ontology by the file extension or the first bytes. Alternatively, specify the serialization format explicitly with the serialization option. See Serializations for a list of supported formats.

import pyhornedowl
rdf_ontology = pyhornedowl.open_ontology("example.owl")
omn_ontology = pyhornedowl.open_ontology("example.omn", serialization='omn')

Save an ontology

Use the PyIndexedOntology.save_to_file function to write the ontology to a file. Again, the serialization is guessed by the file extension and defaults to OWL/XML. Alternatively, specify the serialization format explicitly with the serialization option. See Serializations for a list of supported formats.

import pyhornedowl
ontology = pyhornedowl.open_ontology("example.owl")

ontology.save_to_file("example.owl")
ontology.save_to_file("example.ofn", serialization='ofn')

Serializations

The following serializations are supported:

  • rdf (or owl) for RDF/XML

  • owx for OWL/XML

  • ofn for OWL Functional Syntax

  • omn for OWL 2 Manchester Syntax

  • obo for OBO flat files

  • Other RDF serializations recognised by oxrdfio, such as Turtle and N-Triples, are accepted by their extension. See the supported oxrdfio formats for details.

IRIs and CURIEs

The preferred way to create IRIs is through an ontology instance as it enables Horned-OWLs caching mechanism. Alternatively, they can be created by hand using IRI.parse.

import pyhornedowl
from pyhornedowl.model import IRI

ontology = pyhornedowl.open_ontology("example.owl")

i1 = ontology.iri("https://example.com/test")
i2 = IRI.parse("https://example.com/test")

assert i1 != i2

The PyIndexedOntology.iri function guesses if you passed it an absolute IRI or a CURIE based on the existence of :// in the value. This is also true for all other convenience functions accepting IRIs as an argument. You can explicitly specify if the value is an absolute IRI or a CURIE by using the optional parameter absolute.

An exception to this is the the function PyIndexedOntology.curie which only accepts CURIEs.

Note

To create a curie the prefix must be defined.

Prefixes

By default, no prefixes are defined. The standard prefixes for rdf, rdfs, xsd, and owl can be added via the PrefixMapping.add_default_prefix_names. Other prefixes can be added using the PrefixMapping.add_prefix method.

import pyhornedowl

ontology = pyhornedowl.open_ontology("example.owl")

ontology.prefix_mapping.add_default_prefix_names()
ontology.prefix_mapping.add_prefix("ex", "https://example.com/")

Create entities

Classes, Individuals, Data-, Annotation- and Objectproperties can be created using convenience methods on an ontology.

import pyhornedowl
o = pyhornedowl.open_ontology("example.owl")
o.add_prefix_mapping("", "https://example.com/")

c = o.class_(":A")
op = o.object_property(":op")
dp = o.data_property(":dp")
ap = o.annotation_property(":ap")
i = o.named_individual(":I")
n = o.anonymous_individual("_:n")

Pattern match

All (pyhornedowl.model) classes can be pattern matched using the match statement.

import pyhornedowl
from pyhornedowl.model import *

o = pyhornedowl.open_ontology("example.owl")

for component in o.get_components():
    match component:
        case AnnotatedComponent(OntologyID(id, version), _):
            print(f"Ontology ID: {id}, Version: {version}")
        case AnnotatedComponent(SubClassOf(Class(iri1),Class(iri2)), _):
            print(f"{iri1} is a subclass of {iri2}")
        case AnnotatedComponent(SubClassOf(Class(iri1), ObjectUnionOf([Class(iri2), Class(iri3)])), _):
            print(f"{iri1} is a subclass of {iri2} or {iri3}")
        case _:
            pass

Write class expressions

Instead of writing class expressions as nested constructor calls, some expressions can be expressed using operators.

import pyhornedowl
from pyhornedowl.model import *

o = pyhornedowl.PyIndexedOntology()
o.add_prefix_mapping("", "https://example.com/")

A = o.class_(":A")
B = o.class_(":B")
C = o.class_(":C")
r = o.object_property(":r")

assert A & B == ObjectIntersectionOf([A, B])
assert A | B == ObjectUnionOf([A, B])
assert ~A == ObjectComplementOf(A)
assert ~r == InverseObjectProperty(r)
assert r.some(A) == ObjectSomeValuesFrom(r, A)
assert r.only(A) == ObjectAllValuesFrom(r, A)
assert r.some(A & B | (~r).only(C)) == ObjectSomeValuesFrom(r, ObjectUnionOf([ObjectIntersectionOf([A, B]), ObjectAllValuesFrom(InverseObjectProperty(r), C)]))

Render a single axiom

serialize renders a single axiom, component, or class expression as a string. Every model class has it. It is the per-element counterpart to save_to_string, and for Manchester it is the only option: save_to_string("omn") groups axioms into entity frames, which cannot be sliced back into individual axioms.

import pyhornedowl

ontology = pyhornedowl.open_ontology("example.owl")

for axiom in ontology.get_axioms():
    print(axiom.serialize())               # functional syntax (default)
    print(axiom.serialize("omn"))          # Manchester

Accepted values are ofn (the default) and omn: the serializations for which horned-owl provides a per-element writer. Its OWL/XML, RDF and OBO writers operate on whole ontologies only.

Serializing a single construct to obo is not possible as OBO is stanza-oriented: A component does not render to a string of its own but to a clause line under some other entity’s [Term] stanza, and which stanza that is depends on oboInOwl:id annotations gathered from the whole ontology. There is nothing for a per-element writer to return.

Pass a PrefixMapping to abbreviate IRIs:

print(axiom.serialize("omn", ontology.prefix_mapping))

Note, that ofn renders an AnnotatedComponent including its axiom annotations, while omn renders only the component.

Currently, the following classes do not support Manchester syntax rendering on their own: - Annotation - AnnotationProperty - FacetRestriction - Facet

However, they are rendered if they occur as part of a larger construct (e.g. a class expression).