Tutorial 01: CUDS API¶
This tutorial introduces the CUDS API. The code given here is based on this example.
CUDS stands for Common Universal Data Structure, and it is used to uniformly represent an ontological individual. In the python implementation of OSP-core, it means that every ontological individual is an instance of the
Conceptually, we consider CUDS objects as containers. The content of a CUDS object consists of other CUDS objects. This means that a CUDS is a recursive data structure. There are various types of relationships between a container and its contained objects. We will see this later on.
As a data structure, CUDS exposes an API that provides the functionalities Create, Read, Update and Delete (or simply CRUD). Except Create, all the other functionalities are supported by the methods
iter, that are defined in the class
Cuds. Here, we cover all of the methods except
update since it is used to synchronize between two or more data sources, and in
this tutorial we will only use one, that is the data we will create through our python code on the fly. Check out the wrapper tutorial to see the
update method in action.
Every CUDS object is related to an ontological concept via the ontological
is a relation. In the python implementation of OSP-core, all ontological concepts are instances of the
OntologyEntity class. The ontological concept that can be used to Create CUDS objects are instances of
OntologyClass, a subclass of
OntologyEntity. The ontological concepts are organized in namespaces.
Let’s get hands on¶
We start by importing the example namespace from osp-core. It consists of concepts that were automatically generated from the dummy city ontology. There is another tutorial on the ontology YAML file. However, it is not important for the purposes of this tutorial.
# If you did not install the CITY ontology (pico install city), you have to execute these commands first: # from osp.core import Parser # p = Parser() # p.parse("city") from osp.core import CITY
Let’s create a CUDS object that represents the city of Freiburg:
c = CITY.CITY(name="Freiburg", coordinates=[47, 7])
c is assigned with a newly created CUDS object. This object was initialized with a name (Freiburg) and coordinates ([47, 7]). To understand why these two arguments were necessary, we’ll have to take a look at the ontology. This will be explained in another tutorial.
Each CUDS object has a unique identifier (UID) which can be accessed:
print("uid of c: " + str(c.uid))
The type of an object can be queried as well:
print("type of c: " + str(c.oclass))
type of c: CITY.CITY
Let’s add two citizens to our city object:
p1 = CITY.CITIZEN(name="Peter") p2 = CITY.CITIZEN(name="Anne") c.add(p1, rel=CITY.HAS_INHABITANT) c.add(p2, rel=CITY.HAS_INHABITANT)
<CITY.CITIZEN: 192b50d6-9235-4214-91a8-f0669ac7ac18, CoreSession: @0x7f4cd6f5e610>
Note that the relationship type between the city and its two citizens in this case is ‘HAS_INHABITANT’. In our context, this means that Anne and Peter are Freiburg inhabitants.
Next, we would like to iterate over the objects contained in the city object. We do so by using the
for el in c.iter(): print("uid: " + str(el.uid))
uid: f34cb649-d25a-46fe-8e43-c35e2746f8cf uid: 192b50d6-9235-4214-91a8-f0669ac7ac18
get() an object from a container if we have a UID of one of its immediate contained objects:
We can also filter the contained objects by type:
[<CITY.CITIZEN: f34cb649-d25a-46fe-8e43-c35e2746f8cf, CoreSession: @0x7f4cd6f5e610>, <CITY.CITIZEN: 192b50d6-9235-4214-91a8-f0669ac7ac18, CoreSession: @0x7f4cd6f5e610>]
We remove objects using the
c.remove(p1) # c.remove(p1.uid) also works!
Let’s close this tutorial by adding some neighbourhoods in a loop:
for i in range(6): c.add(CITY.NEIGHBOURHOOD(name="neighbourhood %s" % i))