Skip to content
Open
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
15 changes: 15 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: SHACL validation of manifests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
validate_manifest:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5
- uses: astral-sh/setup-uv@v7
- run: uv run shapes/validate_manifest.py
8 changes: 4 additions & 4 deletions rdf/rdf11/rdf-mt/manifest-az.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<#ill-formed-string> a mf:PositiveEntailmentTest;
mf:name "ill-formed-string";
rdfs:comment """
XSD Strings do not allow the null code point \0000.
XSD Strings do not allow the null code point \\0000.
""";
mf:entailmentRegime "Simple" ;
mf:recognizedDatatypes ( xsd:string ) ;
Expand All @@ -50,7 +50,7 @@
<#well-formed-html> a mf:NegativeEntailmentTest;
mf:name "well-formed-html";
rdfs:comment """
rdf:HTML does allow the null code point \0000.
rdf:HTML does allow the null code point \\0000.
""";
mf:entailmentRegime "Simple" ;
mf:recognizedDatatypes ( rdf:HTML ) ;
Expand Down Expand Up @@ -87,7 +87,7 @@
""";
mf:entailmentRegime "RDFS" ;
mf:recognizedDatatypes ( xsd:integer ) ;
mf:unrecognizedDatatypes ( ex:dt ) ;
mf:unrecognizedDatatypes ( <http://example.org/dt> ) ;
mf:action <az-tests/unrecognized-datatype001.ttl>;
mf:result false .

Expand All @@ -100,7 +100,7 @@
""";
mf:entailmentRegime "RDFS" ;
mf:recognizedDatatypes ( ) ;
mf:unrecognizedDatatypes ( ex:dt ) ;
mf:unrecognizedDatatypes ( <http://example.org/dt> ) ;
mf:action <az-tests/unrecognized-datatype002.ttl>;
mf:result <az-tests/unrecognized-datatype003.ttl> .

Expand Down
2 changes: 1 addition & 1 deletion rdf/rdf12/rdf-semantics/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ <h2>
<dt>type</dt>
<dd>mf:PositiveEntailmentTest</dd>
<dt>approval</dt>
<dd property='mf:approval' resource=''>none</dd>
<dd property='mf:approval' resource='rdft:NotClassified'>rdft:NotClassified</dd>
<dt>entailmentRegime</dt>
<dd property='mf:entailmentRegime'></dd>
<dt>recognizedDatatypes</dt>
Expand Down
2 changes: 1 addition & 1 deletion rdf/rdf12/rdf-semantics/manifest.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ trs:literal-type a mf:PositiveEntailmentTest;
mf:recognizedDatatypes (xsd:integer);
mf:result <literal-type.ttl>;
mf:unrecognizedDatatypes ();
test:approval test:NotClassified .
rdft:approval rdft:NotClassified .

trs:malformed-literal a mf:PositiveEntailmentTest;
rdfs:comment "Malformed literals are allowed in triple terms, but cause inconsistency.";
Expand Down
40 changes: 40 additions & 0 deletions shapes/manifest.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# SHACL shapes for tests

PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdft: <http://www.w3.org/ns/rdftest#>
PREFIX sh: <http://www.w3.org/ns/shacl#>

[
a sh:NodeShape ;
sh:targetClass mf:Manifest ;
sh:property [
sh:path mf:include ;
sh:maxCount 1
] ;
sh:property [
sh:path mf:entries ;
sh:maxCount 1
]
] .

[
a sh:NodeShape ;
sh:targetClass rdft:Test ;
sh:property [
sh:path mf:action ;
sh:nodeKind sh:IRI ;
sh:maxCount 1
] ;
sh:property [
sh:path mf:result ;
sh:or ( [ sh:nodeKind sh:IRI ] [ sh:hasValue false ] ) ;
sh:maxCount 1
] ;
sh:property [
sh:path rdft:approval ;
sh:nodeKind sh:IRI ;
sh:in (rdft:Approved rdft:Proposed rdft:Rejected rdft:NotClassified) ; # TODO: rdft:NotClassified is not in the vocabulary but used
sh:maxCount 1
]
] .
56 changes: 56 additions & 0 deletions shapes/validate_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# /// script
# dependencies = [
# "pyshacl~=0.30.0",
# ]
# ///
"""
Small Python script to validate manifest files
"""

import os
from pathlib import Path
from pyshacl import validate

repository_root = Path(__file__).parent.parent
shape_path = repository_root / "shapes" / "manifest.ttl"
vocab_path = repository_root / "ns" / "rdftest.ttl"


def log_line(message: str, level: str, file: Path | None = None) -> None:
if "GITHUB_ACTIONS" in os.environ:
print(
f"::{level}{f' file={file.relative_to(repository_root)}' if file else ''}::{message}"
)
else:
print(message)


failure_counter = 0
total_counter = 0
for manifest_path in repository_root.rglob("manifest*.ttl"):
try:
(conforms, _, results_text) = validate(
str(manifest_path),
shacl_graph=str(shape_path),
ont_graph=str(vocab_path),
inference="rdfs",
)
except SyntaxError as e:
conforms = False
results_text = str(e)
if not conforms:
log_line(
f"Error in {manifest_path.relative_to(repository_root)}: {results_text}",
"error",
manifest_path,
)
failure_counter += 1
total_counter += 1

log_line(
f"Found {failure_counter} files with error"
if failure_counter > 0
else f"Validated {total_counter} files without errors",
"notice",
)
exit(int(failure_counter > 0))
Loading