Skip to main content

semanticlint

semanticlint

Extensible linter and quality pipeline for RDF, SKOS, OWL and RDFS vocabularies.

PyPI version CI Coverage Ruff License


Features

  • Stage 1 — Lint: syntax validation for Turtle, RDF/XML, N-Triples, JSON-LD
  • Stage 2 — Integrity: SKOS integrity conditions (W3C), OWL consistency, RDFS checks
  • Stage 3 — Quality: label, definition and language coverage
  • Auto-detection: identifies SKOS / OWL / RDFS / RDF vocabulary types automatically
  • Extensible: add custom checks with a single class and @CheckRegistry.register
  • Configurable: onto-ci.yml alongside your vocabulary files controls which stages run

Why semanticlint, and how it relates to SHACL / pySHACL

Decision: semanticlint is the aggregation layer; pySHACL is the SHACL engine underneath it. Shape-based, per-node constraints (a class must have an rdfs:label, a property must declare rdfs:domain/rdfs:range, SKOS label disjointness, …) are expressed as SHACL shapes and validated through pySHACL — the W3C-standard, reusable way to do it. semanticlint does not reimplement what SHACL already does well.

Objective: aggregate, under one tool and one report, the validations and metrics that SHACL cannot express on its own. SHACL validates one node against a shape and answers pass / fail per node. It is not designed for statistical, graph-wide quality — questions like:

  • What fraction of classes carry a label? (coverage metrics, not per-node constraints)
  • Rolling many heterogeneous signals — SHACL shape results, aggregate metrics, and imperative Python checks — into a single severity-graded report with fail-on gating for CI.

This limitation of SHACL for aggregate data-quality assessment is documented in the literature — see “Is SHACL Suitable for Data Quality Assessment?” (arXiv, 2025): https://arxiv.org/html/2507.22305v2. semanticlint exists to cover precisely that gap: it runs SHACL where SHACL fits, and adds coverage metrics, auto vocabulary detection, curated rule sets, and unified reporting on top.

Scope of the two tools

Capability pySHACL (SHACL engine) semanticlint (aggregation layer)
Per-node shape constraints (sh:minCount, domain/range, datatypes, disjointness) (via pySHACL)
Severity per result (sh:Violation/Warning/Info)
Aggregate coverage metrics (e.g. % of classes labelled)
Imperative / custom Python checks alongside shapes
Auto-detect SKOS / OWL / RDFS / RDF and select applicable checks
Curated, ready-made OWL / SKOS / RDFS / URI rule sets (you author every shape)
Unified report + fail-on gating for CI across all of the above

Rule of thumb: if a rule is a per-node constraint, write it as a SHACL shape (pySHACL runs it). If it is an aggregate, or needs to sit in one graded report with everything else, that is what semanticlint adds.

Installation

pip install semanticlint

Quick start

semanticlint check my-taxonomy.ttl
semanticlint check vocabularies/ --select SKO --ignore SKO003

Project-specific rules (*.shapes.ttl)

Rules that are specific to your ontology — business constraints the built-in checks can't know about — live in a plain SHACL file committed next to the vocabulary it constrains. semanticlint auto-discovers any *.shapes.ttl file (a sibling when you check a single file, the whole tree when you check a directory), unions it with the built-in shapes, and enforces it. No configuration, no registration.

Say zoo.ttl defines a zoo ontology. Drop a zoo.shapes.ttl beside it:

# zoo.shapes.ttl — versioned in git next to zoo.ttl
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ex: <http://example.org/zoo#> .

ex:PersonEmploymentShape a sh:NodeShape ;
    sh:targetClass ex:Person ;
    sh:property [ sh:path ex:work_for ;
                  sh:class ex:Department ;
                  sh:maxCount 1 ;
                  sh:message "A Person may work_for at most one Department" ] .
semanticlint check zoo/
#   ERROR   [PersonEmploymentShape] alice: A Person may work_for at most one Department
# 1 violation: 1 error  (fail-on: error)   → exit code 1, CI fails

Notes:

  • No annotations needed. The violation's id defaults to the shape's name (PersonEmploymentShape); set a custom one with slint:checkId "ZOO001" if you want it stable for --select/--ignore.
  • Severity & CI gating. A plain shape reports at SHACL's default sh:Violationerror, so it fails CI under the default --fail-on error. Use sh:severity sh:Warning/sh:Info to soften it.
  • Shapes files are never linted as data — a *.shapes.ttl is treated as rules, not as a vocabulary to check.
  • Targets do the gating, so a local shape only fires on the nodes it targets — it's safe to keep shared shapes for several vocabularies in one directory.

Writing a custom check

from semanticlint import Check, CheckRegistry, VocabType, Severity, Violation
from rdflib import RDF
from rdflib.namespace import SKOS

@CheckRegistry.register
class CamelCaseConceptCheck(Check):
    id          = "CUS001"
    description = "Concept local names should be CamelCase"
    severity    = Severity.WARNING
    applies_to  = VocabType.SKOS

    def run(self, graph, config):
        violations = []
        for concept in graph.subjects(RDF.type, SKOS.Concept):
            local = str(concept).split("#")[-1].split("/")[-1]
            if not local[0].isupper():
                violations.append(Violation(self.id, f"{local} is not CamelCase", self.severity, concept))
        return violations

Configuration (onto-ci.yml)

version: 1
sources: ["*.ttl", "vocabularies/**/*.ttl"]

select: ["RDF", "SKO", "QUA"]
ignore: []

quality:
  min_label_coverage: 1.0
  min_definition_coverage: 0.5
  languages: ["en"]

plugins:
  - my_project.custom_checks

License

MIT — logo is public domain (W3C RDF logo via Wikimedia Commons).

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

semanticlint-0.6.0.tar.gz (99.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

semanticlint-0.6.0-py3-none-any.whl (31.7 kB view details)

Uploaded Python 3

File details

Details for the file semanticlint-0.6.0.tar.gz.

File metadata

  • Download URL: semanticlint-0.6.0.tar.gz
  • Upload date:
  • Size: 99.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for semanticlint-0.6.0.tar.gz
Algorithm Hash digest
SHA256 9b466687f7772d1175458c643bdc17342f4611df57c1595261748752019adc6d
MD5 8013ec51886e366876e5d4868fc49c1b
BLAKE2b-256 94cb704a8edd9348fda72e046a6aafd2c487567684205c7447fc21fe71d59659

See more details on using hashes here.

Provenance

The following attestation bundles were made for semanticlint-0.6.0.tar.gz:

Publisher: publish.yml on gbelbe/semanticlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file semanticlint-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: semanticlint-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 31.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for semanticlint-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 594ea7a445223953f7b57db6809475119d32e06fc14d33796eb68fc1ed606822
MD5 ab8be240ffea762fb667bdb5e49ba90d
BLAKE2b-256 146425fb72bb7142e4134b493925778136a4b69f72abdd5198a612bc65d2bc99

See more details on using hashes here.

Provenance

The following attestation bundles were made for semanticlint-0.6.0-py3-none-any.whl:

Publisher: publish.yml on gbelbe/semanticlint

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

0.5.0

2 files

0.4.2

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page