Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for --allow-levels #127

Merged
merged 2 commits into from
Mar 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pyshacl/shape.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,12 +477,16 @@ def validate(
focus_value_nodes = self.value_nodes(target_graph, focus)
filter_reports: bool = False
allow_conform: bool = False
allowed_severities: Set[URIRef] = set()
if allow_infos:
allowed_severities.add(SH_Info)
if self.severity == SH_Info:
allow_conform = True
else:
filter_reports = True
if allow_warnings:
allowed_severities.add(SH_Info)
allowed_severities.add(SH_Warning)
if self.severity in (SH_Warning, SH_Info):
allow_conform = True
else:
Expand Down Expand Up @@ -516,7 +520,7 @@ def validate(
v_str, v_node, v_parts = _r_inner
severity_bits = list(filter(lambda p: p[0] == v_node and p[1] == SH_resultSeverity, v_parts))
if severity_bits:
all_warn = all_warn and severity_bits[0][2] in (SH_Warning, SH_Info)
all_warn = all_warn and severity_bits[0][2] in allowed_severities
non_conformant = not all_warn
else:
non_conformant = non_conformant or (not _is_conform)
Expand Down
114 changes: 114 additions & 0 deletions test/issues/test_126.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
#

# This software was developed at the National Institute of Standards
# and Technology by employees of the Federal Government in the course
# of their official duties. Pursuant to title 17 Section 105 of the
# United States Code this software is not subject to copyright
# protection and is in the public domain. NIST assumes no
# responsibility whatsoever for its use by other parties, and makes
# no guarantees, expressed or implied, about its quality,
# reliability, or any other characteristic.
#
# We would appreciate acknowledgement if the software is used.

"""
https://github.com/RDFLib/pySHACL/issues/126
"""

from typing import Optional

from pyshacl import validate
from rdflib import Namespace, SH, URIRef

NS_EX = Namespace("http://example.org/ns#")

mixed_file_text = """
@prefix ex: <http://example.org/ns#> .
@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:myProperty-datatype
a sh:PropertyShape ;
rdfs:comment "Violations of sh:datatype are produced as warnings"@en ;
sh:datatype xsd:string ;
sh:path ex:myProperty ;
sh:severity sh:Warning ;
.

ex:myProperty-maxLength
a sh:PropertyShape ;
rdfs:comment "The default severity here is sh:Info"@en ;
sh:maxLength 10 ;
sh:message "Too many characters"@en ;
sh:path ex:myProperty ;
sh:severity sh:Info ;
.

ex:MyShape
a sh:NodeShape ;
rdfs:comment "This example was adapted from the example shapes and validation graph in the Severity section of the SHACL specification."@en ;
rdfs:seeAlso "https://www.w3.org/TR/shacl/#severity" ;
sh:property
ex:myProperty-datatype ,
ex:myProperty-maxLength
;
sh:targetNode ex:MyInstance ;
.

ex:MyInstance
rdfs:comment "This instance triggers one Info-level and one Warning-level violation."@en ;
ex:myProperty "http://toomanycharacters"^^xsd:anyURI ;
.
"""


def _test_126_template(expected_conformance: bool, allow_level: Optional[URIRef] = None) -> None:
validate_kwargs: Dict[Any] = {"data_graph_format": "turtle", "shacl_graph_format": "turtle", "debug": True}
if allow_level is None:
pass
elif allow_level == SH.Info:
validate_kwargs["allow_infos"] = True
elif allow_level == SH.Warning:
validate_kwargs["allow_warnings"] = True
else:
raise NotImplementedError("allow_level=%r" % allow_level)

res1 = validate(mixed_file_text, **validate_kwargs)
conforms, graph, string = res1
assert conforms == expected_conformance

datatype_shape_reported = False
maxlength_shape_reported = False

# Confirm the report graph emits ValidationResults pertaining to each expected triggering property shape.
for triple in graph.triples((None, SH.sourceShape, NS_EX["myProperty-datatype"])):
datatype_shape_reported = True
for triple in graph.triples((None, SH.sourceShape, NS_EX["myProperty-maxLength"])):
maxlength_shape_reported = True

assert datatype_shape_reported
assert maxlength_shape_reported


def test_126_1() -> None:
"""
With no severities allowed, expect non-conformance.
"""
_test_126_template(False)


def test_126_2() -> None:
"""
With Infos allowed, expect non-conformance.
"""
_test_126_template(False, SH.Info)


def test_126_3() -> None:
"""
With Warnings allowed, expect conformance.
"""
_test_126_template(True, SH.Warning)