Metadata-Version: 2.4
Name: sparql-validator
Version: 0.1.0
Summary: Pre-execution SPARQL query validator (SQV): syntactic and semantic validation against OWL ontologies and SHACL shapes.
Project-URL: Homepage, https://github.com/dacamposol/sparql-validator
Project-URL: Repository, https://github.com/dacamposol/sparql-validator
Project-URL: Issues, https://github.com/dacamposol/sparql-validator/issues
Project-URL: Changelog, https://github.com/dacamposol/sparql-validator/blob/main/CHANGELOG.md
Author-email: Daniel Campos Olivares <dacamposol@gmail.com>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: ontology,owl,rdf,semantic-web,shacl,sparql,validation
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: pyshacl>=0.30.0
Requires-Dist: rdflib>=7.1.0
Description-Content-Type: text/markdown

# sparql-validator

[![PyPI](https://img.shields.io/pypi/v/sparql-validator.svg)](https://pypi.org/project/sparql-validator/)
[![Python versions](https://img.shields.io/pypi/pyversions/sparql-validator.svg)](https://pypi.org/project/sparql-validator/)
[![License](https://img.shields.io/pypi/l/sparql-validator.svg)](https://github.com/dacamposol/sparql-validator/blob/main/LICENSE)
[![Build Pipeline](https://github.com/dacamposol/sparql-validator/actions/workflows/ci.yml/badge.svg)](https://github.com/dacamposol/sparql-validator/actions/workflows/ci.yml)

**Pre-execution SPARQL query validation** - a Python implementation of the
SQV (SPARQL Query Validation) algorithm.

SQV catches typing errors, ontology-range mismatches, constraining-facet
violations, and object-property-axiom breaches **before** a SPARQL query hits
your triplestore - so you spend milliseconds on validation instead of seconds
on an execution that was going to fail (or worse, silently return nothing).

## Install

```bash
uv add sparql-validator
# or
pip install sparql-validator
```

## 30-second example

```python
from sparql_validator import SPARQLValidator

validator = SPARQLValidator.from_files(
    ontology="tests/fixtures/film.ttl",
    shapes="tests/fixtures/film.shacl.ttl",   # optional - see below
)

query = """
    PREFIX dbo: <http://dbpedia.org/ontology/>
    PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
    SELECT ?x WHERE {
      ?x dbo:birthDate "1974-11-11"^^xsd:char .   # xsd:char is not W3C
    }
"""

report = validator.validate(query)

if report:                       # ValidationReport is truthy iff ok
    print("Query is valid.")
else:
    for err in report:           # iterable of ValidationError
        print(err)
    #  [datatype] Datatype 'xsd:char' is not recommended by the W3C.
    #             - hint: Use one of xsd:string, xsd:integer, xsd:date, ...
```

## SHACL shapes are optional

The `shapes` argument to `SPARQLValidator.from_files` (and the `--shapes`
CLI flag) is optional. What that means for validation:

|                             | `shapes` provided | `shapes` omitted |
|---|---|---|
| Query decomposition         | run               | run              |
| Datatype / range / lexical form / facet checks (syntactic) | run | run |
| RDF data-graph generation   | run               | run              |
| SHACL conformance (semantic axioms: functional, inverse-functional, symmetric, asymmetric, ...) | run | **skipped** |

When no shapes graph is supplied the validator behaves as a **purely
syntactic** validator: every `ErrorKind` in the table below is still detected
*except* `OBJECT_AXIOM`, which can only surface via SHACL.

Skip `shapes` when you don't yet have a shapes graph (they have to be
authored separately from the ontology), when you only care about the
syntactic checks, or when the semantic rules for your ontology are not
expressible as SHACL constraints.

```python
# Purely syntactic validator - no SHACL shapes.
validator = SPARQLValidator.from_files(ontology="film.ttl")
```

```bash
# CLI equivalent: leave --shapes off.
sparql-validator --ontology film.ttl --query @path/to/query.rq
```

## Command line

```bash
sparql-validator \
    --ontology tests/fixtures/film.ttl \
    --shapes   tests/fixtures/film.shacl.ttl \
    --query @path/to/query.rq \
    --json
```

Exit code: `0` valid, `1` invalid, `2` I/O or malformed-query error.

## What SQV checks for you

| Category | Example defect | Kind |
|---|---|---|
| Datatype not in the W3C-recommended set | `"…"^^xsd:char` | `ErrorKind.DATATYPE` |
| Datatype ≠ ontology `rdfs:range` | `"…"^^xsd:dateTime` on a `dbo:birthDate` whose range is `xsd:date` | `ErrorKind.RANGE` |
| Lexical form outside the Lexical Space | `"11-11-1974"^^xsd:date` (needs `CCYY-MM-DD`) | `ErrorKind.LEXICAL_FORM` |
| Value outside a constraining facet (`min/max/length`) | `"1800-01-01"^^xsd:date` when the ontology requires `≥ 1900-01-01` | `ErrorKind.FACET` |
| Typed literal on an ObjectProperty | `?m dbo:director "…"^^xsd:string` | `ErrorKind.STRUCTURAL` |
| Functional / inverse-functional / symmetric / asymmetric axiom breach *(requires SHACL shapes)* | via a supplied SHACL shapes graph | `ErrorKind.OBJECT_AXIOM` |

FILTER expressions with `<`, `>`, `<=`, `>=`, `=` are also facet-checked. On
strict comparisons the boundary constant is adjusted by `+/-1` before the
membership test (`>` moves to `c+1`, `<` to `c-1`) so the value actually
subject to the filter, not the boundary itself, is what gets checked.

## Extensibility

Every phase is an ABC - swap any implementation without touching the façade:

```python
from sparql_validator import SPARQLValidator
from sparql_validator.interfaces import IQueryDecomposer
from sparql_validator.phases import (
    DefaultLiteralValidator, RdflibTripleGenerator, PySHACLGraphValidator,
)

class MyRdflibParserDecomposer(IQueryDecomposer):
    def decompose(self, query): ...

validator = SPARQLValidator(
    ontology=my_onto, shapes=my_shapes,
    decomposer=MyRdflibParserDecomposer(),
    literal_validator=DefaultLiteralValidator(),
    triple_generator=RdflibTripleGenerator(),
    graph_validator=PySHACLGraphValidator(),
)
```

## Development

```bash
uv sync --group dev
uv run ruff check
uv run mypy src
uv run pytest -q
```

## References

The initial implementation of the SQV algorithm is inspired by:

> J. Collio, A. Aguilera and I. Dongo, "Efficient Method for Validating SPARQL Queries Using Semantic Web Ontologies," 2025 LI Latin American Computer Conference (CLEI), Valparaíso, Chile, 2025, pp. 1-10, doi: [10.1109/CLEI67442.2025.11420331](https://ieeexplore.ieee.org/abstract/document/11420331)

