RDFLib / pySHACL

A Python validator for SHACL
Apache License 2.0
241 stars 63 forks source link

Multiple sh:nots causing strange validation results #219

Closed ajnelson-nist closed 3 months ago

ajnelson-nist commented 7 months ago

The resolution of Issue #217 enabled attaching multiple sh:nots to a sh:Shape, bumping up from a restriction on only-one-sh:not.

I think there is some leftover logic that was assuming singleton occurrences of sh:not on shapes. This comes to light with an exercise of a 3-way disjointedness in OWL 2 DL.

owl:ObjectProperty, owl:DatatypeProperty, and owl:AnnotationProperty are all disjoint with one another. So, if I have some owl:ObjectProperty, it should be neither a owl:DatatypeProperty nor an owl:AnnotationProperty. This constraint is realizable with these shapes:

@prefix ex: <http://example.org/ontology/example/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

ex:AnnotationProperty-shape
    a sh:NodeShape ;
    sh:not
        [
            a sh:NodeShape ;
            sh:class owl:DatatypeProperty ;
        ] ,
        [
            a sh:NodeShape ;
            sh:class owl:ObjectProperty ;
        ]
        ;
    sh:targetClass owl:AnnotationProperty ;
    .

ex:DatatypeProperty-shape
    a sh:NodeShape ;
    sh:not
        [
            a sh:NodeShape ;
            sh:class owl:AnnotationProperty ;
        ] ,
        [
            a sh:NodeShape ;
            sh:class owl:ObjectProperty ;
        ]
        ;
    sh:targetClass owl:DatatypeProperty ;
    .

ex:ObjectProperty-shape
    a sh:NodeShape ;
    sh:not
        [
            a sh:NodeShape ;
            sh:class owl:AnnotationProperty ;
        ] ,
        [
            a sh:NodeShape ;
            sh:class owl:DatatypeProperty ;
        ]
        ;
    sh:targetClass owl:ObjectProperty ;
    .

(As an aside, I tried the form ex:AnnotationProperty-shape sh:not ex:DatatypeProperty-shape ., etc., but was quickly informed by pyshacl that that forms an infinite loop of the shapes loading one another. Yup. I'm just leaving that here in case someone else is about to stub their toe trying that.)

I got a curious result trying the above graph on this test ontology:

@prefix ex: <http://example.org/ontology/example/> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# For symmetry, all AP, DP, OP combinations are provided, but to focus
# discussion, all but one XFAIL case is commented out.

ex:PASS-AP
    a owl:AnnotationProperty ;
    .

#ex:PASS-DP
#   a owl:DatatypeProperty ;
#   .

#ex:PASS-OP
#   a owl:ObjectProperty ;
#   .

#ex:XFAIL-AP-DP
#   a owl:AnnotationProperty ;
#   a owl:DatatypeProperty ;
#   .

ex:XFAIL-AP-OP
    a owl:AnnotationProperty ;
    a owl:ObjectProperty ;
    .

#ex:XFAIL-DP-OP
#   a owl:DatatypeProperty ;
#   a owl:ObjectProperty ;
#   .

#ex:XFAIL-AP-DP-OP
#   a owl:AnnotationProperty ;
#   a owl:DatatypeProperty ;
#   a owl:ObjectProperty ;
#   .

Shell transcript:

pyshacl \
        --shacl try_shapes.ttl \
        try_owl.ttl
Validation Report
Conforms: False
Results (2):
Constraint Violation in NotConstraintComponent (http://www.w3.org/ns/shacl#NotConstraintComponent):
    Severity: sh:Violation
    Source Shape: ex:ObjectProperty-shape
    Focus Node: ex:XFAIL-AP-OP
    Value Node: ex:XFAIL-AP-OP
    Message: Node ex:XFAIL-AP-OP conforms to shape [ rdf:type sh:NodeShape ; sh:class owl:AnnotationProperty ]
Constraint Violation in NotConstraintComponent (http://www.w3.org/ns/shacl#NotConstraintComponent):
    Severity: sh:Violation
    Source Shape: ex:AnnotationProperty-shape
    Focus Node: ex:XFAIL-AP-OP
    Value Node: ex:XFAIL-AP-OP
    Message: Node ex:XFAIL-AP-OP conforms to shape [ rdf:type sh:NodeShape ; sh:class owl:DatatypeProperty ]

First, the node ex:PASS-AP doesn't show up in among the sh:Violations. Great!

That first sh:Violation looks fine - the focus node matches the object property targeter, and has the class annotation property, conforming to the disallowed node shape.

The second one, though, matches the annotation property targeter (fine), but uses the datatype property shape. That node in the OWL file does not tie in owl:DatatypeProperty.

Is this an issue in the report displaying, or in the constraint evaluation?

ashleysommer commented 7 months ago

Hi @ajnelson-nist Thanks for reporting this.

As you suspected, this is some left over logic from when pyshacl assumed only a single value for sh:not on the Shape.

It is a problem in the reporting, not in the evaluation. The violation result generated is correct, but it is displaying the incorrect sh:not constraint in the message.

This is likely an easy fix.

ashleysommer commented 3 months ago

Fix for this was created back in January, but only just pushed into the codebase now. It will be in the next release.