Handle validation results in code

Use validate_algebra() to handle failures as Python objects. For a W3C report graph, use validate() as shown in Validating a model.

Read individual failures

Using the shapes and failing data from the validation tutorial:

from pathlib import Path

import shifty


example_dir = Path(__file__).parent / "quick-start"
result = shifty.validate_algebra(
    example_dir / "data.ttl",
    example_dir / "shapes.ttl",
)

print("conforms:", result.conforms)
print("violations:", len(result.violations))
for violation in result.violations:
    print(violation.focus_node, violation.severity)
    for reason in violation.reasons:
        print("  ", reason.constraint_kind, reason.path, reason.value)
        print("  ", reason.message)
conforms: False
violations: 1
<http://example.org/bob> Violation
   ConstraintKind.Cardinality ex:email <http://example.org/bob>
   at least 1 value(s) required along ex:email, found 0
   ConstraintKind.ValueType ex:name "123"^^<http://www.w3.org/2001/XMLSchema#integer>
   test(datatype(xsd:string)) not satisfied

A violation is one failing focus node under one statement. Its reasons describe the individual failures. Bob has one violation with two reasons.

Branch on reason.constraint_kind when handling a failure in code. reason.message is display text and may change:

import shifty

result = shifty.validate_algebra("data.ttl", "shapes.ttl")
for violation in result.violations:
    for reason in violation.reasons:
        if reason.constraint_kind == shifty.ConstraintKind.Cardinality:
            print("missing or excess values:", reason.path)
        elif reason.constraint_kind == shifty.ConstraintKind.ValueType:
            print("wrong type:", reason.value, "at", reason.path)

reason.value identifies an offending value when available; for a missing value, it falls back to the focus node. Prefer reason.author_message or reason.message to display an authored sh:message when present.

Apply a severity threshold

To retain warnings in the results while only violations make the graph fail:

result = shifty.validate_algebra(
    "data.ttl", "shapes.ttl", minimum_severity="violation"
)
print(result.conforms)
for violation in result.violations:
    for reason in violation.reasons:
        print(reason.severity, reason.message)

conforms applies the threshold. violations still includes findings below it. Severity belongs to each reason; violation.severity is the most severe reason for that focus node and statement.

Inspect the compiled constraint

Each reason identifies the compiled constraint that produced it:

for violation in result.violations:
    for reason in violation.reasons:
        print(reason.constraint_id, reason.constraint.render)
        print(reason.constraint.definition)

violation.constraint_id identifies the top-level constraint; reason.constraint_id identifies the nested constraint that failed. Compare these with Investigate unexpected results to trace a result through the compiled schema.

See Python API reference for exact result fields and Explain why a node passed or failed for supporting values and evidence trees.