BrickSchema / py-brickschema

Python package for working with Brick (brickschema.org/)
Other
55 stars 15 forks source link

Property shape performs differently when using blank nodes vs. explicit nodes #39

Closed corymosiman12 closed 3 years ago

corymosiman12 commented 3 years ago

Hey Gabe - let me know if I'm doing anything obviously incorrect. I'm running v0.2.0.

I define the expected data graph:

@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix ex: <https://example.com#> .

# Should validate
ex:vav-01 a brick:Variable_Air_Volume_Box ;
    brick:hasPoint ex:p1,
        ex:p2 .
ex:p1 a brick:Discharge_Air_Temperature_Sensor .
ex:p2 a brick:Damper_Position_Sensor .

# Should NOT validate
ex:vav-02 a brick:Variable_Air_Volume_Box ;
    brick:hasPoint ex:p1 .

I then define to shapes graphs that I believe should resolve to identical shapes graphs. The first way with blank nodes works as expected:

@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix bsh: <https://brickschema.org/schema/1.1/BrickShape#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <https://example.com#> .

bsh:VAVShape1 a sh:NodeShape ;
    sh:targetNode ex:vav-01, ex:vav-02 ;
    sh:property [ 
        sh:path brick:hasPoint ;
        sh:qualifiedValueShape [
            sh:class brick:Discharge_Air_Temperature_Sensor ;
        ] ;
        sh:qualifiedMinCount 1 ;
        sh:qualifiedMaxCount 1 ;
    ] ;
    sh:property [ 
        sh:path brick:hasPoint ;
        sh:qualifiedValueShape [
            sh:class brick:Damper_Position_Sensor ;
        ] ;
        sh:qualifiedMinCount 1 ;
        sh:qualifiedMaxCount 1 ;
    ] .

I get the following validation errors (expected):

Validation Report
Conforms: False
Results (1):
Constraint Violation in QualifiedValueShapeConstraintComponent (http://www.w3.org/ns/shacl#QualifiedMinCountConstraintComponent):
    Severity: sh:Violation
    Source Shape: [ rdf:type rdfs:Resource ; sh:path brick:hasPoint ; sh:qualifiedMaxCount Literal("1", datatype=xsd:integer) ; sh:qualifiedMinCount Literal("1", datatype=xsd:integer) ; sh:qualifiedValueShape [ rdf:type rdfs:Resource ; sh:class brick:Damper_Position_Sensor ] ]
    Focus Node: ex:vav-02
    Result Path: brick:hasPoint

Additional info (1 constraint violations with offender hint):

Constraint violation:
[] a sh:ValidationResult ;
    sh:focusNode ex:vav-02 ;
    sh:resultPath brick:hasPoint ;
    sh:resultSeverity sh:Violation ;
    sh:sourceConstraintComponent sh:QualifiedMinCountConstraintComponent ;
    sh:sourceShape [ a rdfs:Resource ;
            sh:path brick:hasPoint ;
            sh:qualifiedMaxCount 1 ;
            sh:qualifiedMinCount 1 ;
            sh:qualifiedValueShape [ a rdfs:Resource ;
                    sh:class brick:Damper_Position_Sensor ] ] .
Violation hint (subject predicate cause):
ex:vav-02 brick:hasPoint "sh:qualifiedMinCount <1>" .

Second way with explicitly defined property shapes:

@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix bsh: <https://brickschema.org/schema/1.1/BrickShape#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <https://example.com#> .

bsh:VAVShape1 a sh:NodeShape ;
    sh:targetNode ex:vav-01, ex:vav-02 ;
    sh:property ex:hasDischargeAirTemperatureSensor ;
    sh:property ex:hasDamperPositionSensor .

ex:hasDischargeAirTemperatureSensor a sh:PropertyShape ;
    sh:path brick:hasPoint ;
    sh:qualifiedValueShape [
        sh:class brick:Discharge_Air_Temperature_Sensor ;
    ] ;
    sh:qualifiedMinCount 1 ;
    sh:qualifiedMaxCount 1 .

ex:hasDamperPositionSensor a sh:PropertyShape ;
    sh:path brick:hasPoint ;
    sh:qualifiedValueShape [
        sh:class brick:Damper_Position_Sensor ;
    ] ;
    sh:qualifiedMinCount 1 ;
    sh:qualifiedMaxCount 1 .

I get the following error:

Traceback (most recent call last):
  File "br-test1.py", line 14, in <module>
    result = v.validate(dataG, shacl_graphs=[shapeG])
  File "/Users/cmosiman/.pyenv/versions/validation/lib/python3.7/site-packages/brickschema/validate.py", line 129, in validate
    self.violationList = self.__attachOffendingTriples()
  File "/Users/cmosiman/.pyenv/versions/validation/lib/python3.7/site-packages/brickschema/validate.py", line 172, in __attachOffendingTriples
    self.__triplesForOneViolation(violation)
  File "/Users/cmosiman/.pyenv/versions/validation/lib/python3.7/site-packages/brickschema/validate.py", line 246, in __triplesForOneViolation
    cObj = f"<{self.__violationPredicateObj(violation, cPred)}>"
  File "/Users/cmosiman/.pyenv/versions/validation/lib/python3.7/site-packages/brickschema/validate.py", line 210, in __violationPredicateObj
    assert len(res) == 1, f"Must have predicate '{predicate}'"
AssertionError: Must have predicate 'sh:qualifiedMinCount'

Thoughts?

gtfierro commented 3 years ago

Strange! I put the files into a gist and tested with the latest version of brickschema. It works fine for me in both cases; can you try brickschema==0.2.2 and see if that changes? You may have an outdated version of pySHACL as well

gtfierro commented 3 years ago

@corymosiman12 any updates on this issue? We are now on 0.3.0 so I am closing this for now, but we can reopen if you can reproduce the issue on the newer versions