Tutorial 02: Ontology Interface

This tutorial introduces the interface to the installed ontologies. The code presented is based on this example. If you want to create your own ontology please refer to this guide.

Background

In the previous tutorial we have discussed the CUDS API. CUDS objects correspond to ontology individuals. In this tutorial we present the API of all other entities: ontology classes, relationships and attributes. These are defined in an ontology file in YAML format. With the presented API you can access the entities and navigate within an ontology.

Preliminaries

[ ]:
# If you did not install the CITY ontology
# you have to execute these commands first:
from osp.core import Parser
p = Parser()
p.parse("city")

Accessing entities

First, we want to acces the entities in the ontology. For that, we need to know the installed ontology namespaces. The namespace is stated at the top of the ontology YAML files:

---
version: "0.0.3"

namespace: "CITY"

ontology:
   ...

Knowing the name of the namespace, we can import it in python. With the namespace python object we can access the entities within the namespace:

[1]:
from osp.core import city, CITY  # This imports the namespace city

print("\nYou can use UPPERCASE and lowercase to access a namespace")
print(city is CITY)

print("\nYou can use the namespace to access its entities")
print(city.living_being)

print("\nYou can use UPPERCASE, lowercase or CamelCase to access entities")
print(city.living_being is city.LIVING_BEING is city.LivingBeing)

print("\nYou can also use index notation")
print(city.living_being is city["living_being"])

print("\nYou can access the namespace of an entity")
print(city is city.LivingBeing.namespace)

You can use UPPERCASE and lowercase to access a namespace
True

You can use the namespace to access its entities
CITY.LIVING_BEING

You can use UPPERCASE, lowercase or CamelCase to access entities
True

You can also use index notation
True

You can access the namespace of an entity
True

Accessing super- and subclasses

Using the properties superclasses and subclasses it is easy to navigate the ontology. Direct superclasses and subclasses can also be accessed:

[2]:
print("\nYou can access the superclasses and the subclasses")
print(city.LivingBeing.superclasses)
print(city.LivingBeing.subclasses)

print("\nYou can access the direct superclasses and subclasses")
print(city.LivingBeing.direct_superclasses)
print(city.LivingBeing.direct_subclasses)

print("\nYou can access a description of the entities")
print(city.LivingBeing.description)

print("\nYou can test if one entity is a subclass / superclass of another")
print(city.Person.is_subclass_of(city.LivingBeing))
print(city.LivingBeing.is_superclass_of(city.Person))

You can access the superclasses and the subclasses
[<OntologyClass CITY.LIVING_BEING>, <OntologyClass CUBA.ENTITY>]
[<OntologyClass CITY.LIVING_BEING>, <OntologyClass CITY.PERSON>, <OntologyClass CITY.CITIZEN>]

You can access the direct superclasses and subclasses
[<OntologyClass CUBA.ENTITY>]
[<OntologyClass CITY.PERSON>]

You can access a description of the entities
A being that lives

You can test if one entity is a subclass / superclass of another
True
True

Access entities using a string

Sometimes you only have a string refering to an entity. Using the get_entity function you can get the corresponding python object easily:

[3]:
from osp.core import get_entity  # noqa: E402

print("\nYou can get an entity from a string")
print(get_entity("city.LivingBeing"))
print(get_entity("city.LivingBeing") is city.LivingBeing)

You can get an entity from a string
CITY.LIVING_BEING
True

Testing the type of the entities

In the OSP-core YAML ontology files three types of entities can be defined: classes, relationships and attributes. Relationships are subclasses of CUBA.RELATIONSHIP and attributes are subclasses of CUBA.ATTRIBUTE. There are different Python objects for the different entity types. You can use both to check which type of entity you are dealing with:

[4]:
# CUBA namespace
# This is the main namespace that is always available
from osp.core import cuba  # noqa: E402

# These are the classes for the ontology entities
from osp.core.ontology import (  # noqa: F401, E402
      OntologyEntity,
      OntologyClass,
      OntologyRelationship,
      OntologyAttribute
)

print("\nYou can test if an entity is a class")
print(isinstance(city.LivingBeing, OntologyClass))
print(not city.LivingBeing.is_subclass_of(cuba.Relationship)
      and not city.LivingBeing.is_subclass_of(cuba.Attribute))

print("\nYou can test if an entity is a relationship")
print(isinstance(city.HasInhabitant, OntologyRelationship))
print(city.HasInhabitant.is_subclass_of(cuba.Relationship))

print("\nYou can test if an entity is an attribute")
print(isinstance(city.Name, OntologyAttribute))
print(city.Name.is_subclass_of(cuba.Attribute))


You can test if an entity is a class
True
True

You can test if an entity is a relationship
True
True

You can test if an entity is an attribute
True
True

Operations specific to ontology classes

The different types of entities differ in the operations they offer. For classes, you can access the attributes:

[5]:
print("\nYou can get the attributes of an ontology class and their defaults")
print(city.Citizen.attributes)

print("\nYou can get the non-inherited attributes and their defaults")
print(city.LivingBeing.own_attributes)

print("\nFurther interesting properties:")
print("\nSubclass of:",
      list(map(str, city.LivingBeing.subclass_of_expressions)))
print("\nEquivalent to:", city.LivingBeing.equivalent_to_expressions)  # empty
print("\nDisjoint with:", city.LivingBeing.disjoint_with_expressions)  # empty

You can get the attributes of an ontology class and their defaults
{<OntologyAttribute CITY.NAME>: 'John Smith', <OntologyAttribute CITY.AGE>: 25}

You can get the non-inherited attributes and their defaults
{<OntologyAttribute CITY.NAME>: 'John Smith', <OntologyAttribute CITY.AGE>: 25}

Further interesting properties:

Subclass of: ['CUBA.ENTITY', 'CITY.IS_CHILD_OF 0-2 CITY.LIVING_BEING']

Equivalent to: []

Disjoint with: []

Operations specific to ontology relationships

You can access the inverse, the domain and the range of relationships.

[6]:
print("\nYou can get the inverse of a relationship")
print(city.HasInhabitant.inverse)

print("\nYou can get the characteristics of a relationship")
print(city.HasPart.characteristics)

print("\nYou can get the domain and range of a relationship")
print(city.HasPart.domain_expressions)  # empty
print(city.HasPart.range_expressions)  # empty

You can get the inverse of a relationship
CITY.IS_INHABITANT_OF

You can get the characteristics of a relationship
['transitive']

You can get the domain and range of a relationship
[]
[]

Operations specific to attributes

You can acces the datatype and the argument name of attributes.

[7]:
print("\nYou can get the argument name of an attribute. "
      "The argument name is used when instantiating CUDS objects")
print(city.Age.argname)

print("\nYou can get the datatype of attributes")
print(city.Age.datatype)

print("\nYou can use the attribute to convert values "
      "to the datatype of the attribute")
print(city.Age("10"))

You can get the argument name of an attribute. The argument name is used when instantiating CUDS objects
age

You can get the datatype of attributes
INT

You can use the attribute to convert values to the datatype of the attribute
10

CUDS

You can use ontology classes to create CUDS objects.

[8]:
print("\nYou can instantiate CUDS objects using ontology classes")
print(city.Citizen(name="Test Person", age=42))
print("Take a look at api_example.py for a description of the CUDS API")

print("\nYou can check if a CUDS object is an instace of a ontology class")
print(city.Citizen(name="Test Person", age=42).is_a(city.Citizen))
print(city.Citizen(name="Test Person", age=42).is_a(city.LivingBeing))

print("\nYou can get the ontology class of a CUDS object.")
print(city.Citizen(name="Test Person", age=42).oclass)


You can instantiate CUDS objects using ontology classes
CITY.CITIZEN: b42eaaaa-8c05-4769-8362-3494bed82e30
Take a look at api_example.py for a description of the CUDS API

You can check if a CUDS object is an instace of a ontology class
True
True

You can get the ontology class of a CUDS object.
CITY.CITIZEN

Namespace registry

All namespaces are stored in a namespace registry (singleton). With the namespace registry, you can access the individual namespaces, using index or dot notation.

[9]:
# NAMESPACE_REGISTRY
from osp.core import ONTOLOGY_NAMESPACE_REGISTRY as namespace_reg  # noqa: E402

print("\nAll namespaces are stored in the namespace registry")
print(namespace_reg)

print("\nYou can access the namespaces using dot or index notation")
print(namespace_reg.city)
print(namespace_reg["city"])


All namespaces are stored in the namespace registry
<osp.core.ontology.namespace_registry.NamespaceRegistry object at 0x7fafc88b12b0>

You can access the namespaces using dot or index notation
<osp.core.ontology.namespace.OntologyNamespace object at 0x7faf99e3b0d0>
<osp.core.ontology.namespace.OntologyNamespace object at 0x7faf99e3b0d0>
[ ]: