How to validate data files with linkml model

57 Views Asked by At

I wrote a linkml model as follows: #PersonMode.yaml:
id: person name: Person slots: - id: name name: name
required: true type: string

  - id: gender
    name: gender
    required: true
    type: string

  - id: weight
    name: weight
    required: true
    type: decimal

  - id: height
    name: height
    required: true
    type: decimal

  - id: bmi
    name: BMI
    type: decimal
    formula: "weight / (height * height)"

Now there is an instance file Bob.yaml( gender value is missing):

- id: bob
  type: Person
  name: Bob
  weight: 67
  height: 1.7

How should I verify the compliance of instance.yaml and calculate the value of bob.BMI?

from linkml_runtime.loaders import yaml_loader
from linkml_runtime.linkml_model import SchemaDefinition

model_path = "PersonModel.yaml"
instance_path = "Bob.yaml"

model = yaml_loader.load(model_path, SchemaDefinition)
instances = yaml_loader.load(instance_path, SchemaDefinition)

person_class = model.get_class("Person")
instance = instances[0]
if not person_class.validate(instance):
    print("data file is invalid !")
    exit()

weight = instance["weight"]
height = instance["height"]
bmi_formula = person_class.get_slot("bmi").formula
bmi = eval(bmi_formula)
print("Bob.BMI=:", bmi)

I tried writing a python program, but it doesn't seem to work properly,I'm still not very familiar with linkml, and I didn't find detailed usage instructions for linkml_runtime.loaders. How should I modify this code?

1

There are 1 best solutions below

0
Chris Mungall On

It looks like your schema is not conformant to the LinkML spec.

I think this does what you want it to:

id: https://stackoverflow.com/questions/77122653/
name: how-to-validate-data-files-with-linkml-model
prefixes:
  linkml: https://w3id.org/linkml/
  ex: https://example.org/
default_prefix: ex
imports:
  - linkml:types
classes:
  Person:
    attributes:
      name:
        required: true
    
      gender:
        required: true
        range: string
    
      weight:
        required: true
        range: decimal
    
      height:
        required: true
        range: decimal
    
      bmi:
        range: decimal
        equals_expression: "weight / (height * height)"

This should compile to Python classes

Note you can bypass Python classes altogether and validate json directly:

bob_dict = {
    "name": "Bob",
    "weight": 67,
    "height": 1.7
}
from linkml.validator import validate

report = validate(bob_dict, "tmp/person.yaml")
for r in report.results:
    print(r.message)

This returns:

'gender' is a required property in /

Note that if you do try and instantiate a python object like this:

bob = Person(name="Bob", weight=67, height= 1.7)

You will get:

ValueError: gender must be supplied

Note though that python validation will be less complete than using the LinkML validator

Since you asked your question, the LinkML validation documentation has been improved: https://linkml.io/linkml/data/validating-data.html