More advanced example

More advanced example#

Let’s say that you have the following Python class:

class Person:
    """A person.

    Arguments:
        name: Full name.
        age: Age of person.
        skills: List of skills.

    """

    def __init__(self, name: str, age: float, skills: list[str]) -> None:
        self.name = name
        self.age = age
        self.skills = skills

You want to describe this class semantically. This is done by defining the following metadata (using JSON) identifying the Python attributes with DLite properties. Here we define name to be a string, age to be a float and skills to be an array of N strings, where N is a name of a dimension. The metadata uniquely identifies itself with the “name”, “version” and “namespace” fields and “meta” refers to the metadata schema (meta-metadata) that this metadata is described by. Finally, human descriptions of the metadata itself, its dimensions and its properties are provided in the “description” fields.

{
  "name": "Person",
  "version": "0.1",
  "namespace": "http://onto-ns.com/meta",
  "meta": "http://onto-ns.com/meta/0.3/EntitySchema",
  "description": "A person.",
  "dimensions": [
    {
      "name": "N",
      "description": "Number of skills."
    }
  ],
  "properties": [
    {
      "name": "name",
      "type": "string",
      "description": "Full name."
    },
    {
      "name": "age",
      "type": "float",
      "unit": "year",
      "description": "Age of person."
    },
    {
      "name": "skills",
      "type": "string",
      "shape": ["N"],
      "description": "List of skills."
    }
  ]
}

The metadata can be saved in file Person.json. In Python we can now make a DLite-aware subclass of Person, instantiate it, and serialise it to a storage:

import dlite

# Create a DLite-aware subclass of Person
DLitePerson = dlite.classfactory("Person", url="json://Person.json")

# Instantiate
person = DLitePerson(
    "Sherlock Holmes",
    34.,
    ["observing", "chemistry", "violin", "boxing"],
)

# Write to storage (here a JSON file)
person.dlite_inst.save('json://homes.json?mode=w')

To access this new instance from C, you can first generate a header file from the meta data

dlite-codegen -f c-header -o person.h Person.json

and then include it in your C program:

// homes.c -- sample program that loads instance from homes.json and prints it
#include <stdio.h>
#include <dlite.h>
#include "person.h"  // header generated with dlite-codegen

int main()
{
  /* URL of instance to load using the json driver.  The storage is
     here the file 'homes.json' and the instance we want to load in
     this file is identified with the UUID following the hash (#)
     sign. */
  char *url = "json://homes.json#315088f2-6ebd-4c53-b825-7a6ae5c9659b";

  Person *person = (Person *)dlite_instance_load_url(url);

  int i;
  printf("name:  %s\n", person->name);
  printf("age:   %g\n", person->age);
  printf("skills:\n");
  for (i=0; i<person->N; i++)
    printf("  - %s\n", person->skills[i]);

  return 0;
}

Now run the Python file and it will create a homes.json file, which contains a serialized DLite entity. Use the UUID of the entity from the homes.json file and update the url variable in the homes.c file.

Since we are using dlite_instance_load_url() to load the instance, you must link to DLite when compiling this program. Assuming you are using Linux and DLite is installed in $HOME/.local, compiling with gcc would look like:

gcc homes.c -o homes -I$HOME/.local/include/dlite -L$HOME/.local/lib -ldlite -ldlite-utils

Or if you are using the development environment, you can compile using:

gcc -I/tmp/dlite-install/include/dlite -L/tmp/dlite-install/lib -o homes homes.c -ldlite -ldlite-utils

Finally, you can run the program with

$ DLITE_STORAGES=*.json ./homes
name:  Sherlock Holmes
age:   34
skills:
  - observing
  - chemistry
  - violin
  - boxing

Note that in this case it is necessary to define the environment variable DLITE_STORAGES in order to let DLite find the metadata stored in Person.json. There are ways to avoid this, e.g., by hardcoding the metadata in C using dlite-codegen -f c-source or in the C program explicitely load Person.json before homes.json.