Skip to content

Commit

Permalink
Merge pull request #274 from RDFLib/owl_named_graph
Browse files Browse the repository at this point in the history
Merge named-graph-expansion feature
  • Loading branch information
ashleysommer authored Nov 1, 2024
2 parents c992727 + c5af68c commit baf0e65
Show file tree
Hide file tree
Showing 20 changed files with 475 additions and 379 deletions.
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ jobs:
strategy:
matrix:
python-version:
- '3.8'
- '3.9'
- '3.10'
- '3.11'
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,8 @@ celerybeat-schedule
# Environments
.env
.venv/
.venv38/
.venv39/
.venv311/
env/
venv/
ENV/
Expand Down
56 changes: 0 additions & 56 deletions .travis.yml

This file was deleted.

21 changes: 20 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ and this project adheres to [Python PEP 440 Versioning](https://www.python.org/d
## [Unreleased]
- Nothing yet

## [0.29.0] - 2024-11-01

### Added
- When validating a Dataset instead of a bare Graph, PySHACL will now expand RDFS and OWL-RL inferences into
a separate named graph, to avoid polluting the datagraph.
- When using SHACL Triple Rules from SHACL-AF spec, PySHACL will now add the expressed triples into
a separate named graph. This allows you to more easily get the expanded triples back out again afterward.

### Changed
- PySHACL no longer supports older RDFLib versions
- PySHACL relies on the latest OWL-RL version, that in-turn relies on the latest RDFLib version
- Therefore PySHACL now requires RDFLib v7.1.1 or newer
- Dropped Python 3.8 support.
- Python developers discontinued Python 3.8 last month
- The next version of RDFLib and OWL-RL will not support Python 3.8
- Removed Python 3.8 from the RDFLib test suite
- Python 3.9-specific typing changes will be incrementally introduced

## [0.28.1] - 2024-10-25

### Fixed
Expand Down Expand Up @@ -1182,7 +1200,8 @@ just leaves the files open. Now it is up to the command-line client to close the

- Initial version, limited functionality

[Unreleased]: https://github.com/RDFLib/pySHACL/compare/v0.28.1...HEAD
[Unreleased]: https://github.com/RDFLib/pySHACL/compare/v0.29.0...HEAD
[0.29.0]: https://github.com/RDFLib/pySHACL/compare/v0.28.1...v0.29.0
[0.28.1]: https://github.com/RDFLib/pySHACL/compare/v0.28.0...v0.28.1
[0.28.0]: https://github.com/RDFLib/pySHACL/compare/v0.27.0...v0.28.0
[0.27.0]: https://github.com/RDFLib/pySHACL/compare/v0.26.0...v0.27.0
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ endif
.PHONY: type-check
type-check: venvcheck ## Validate with MyPy in check-only mode
ifeq ("$(FilePath)", "")
poetry run python3 -m mypy --ignore-missing-imports pyshacl
poetry run python3 -m mypy --python-version 3.9 --ignore-missing-imports pyshacl
else
poetry run python3 -m mypy --ignore-missing-imports "$(FilePath)"
poetry run python3 -m mypy --python-version 3.9 --ignore-missing-imports "$(FilePath)"
endif

.PHONY: upgrade
Expand Down
224 changes: 67 additions & 157 deletions poetry.lock

Large diffs are not rendered by default.

26 changes: 9 additions & 17 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
[project]
name = "pyshacl"
# Black and Ruff both now read target-version from [project.requires-python]
requires-python = ">=3.8.1"
requires-python = ">=3.9"

[tool.poetry]
name = "pyshacl"
Expand Down Expand Up @@ -60,11 +60,10 @@ include = [
]

[tool.poetry.dependencies]
python = "^3.8.1" # Poetry doesn't read from [project.requires-python]
# Note, 3.8.0 is not supported, only 3.8.1 or above. See:
# https://github.com/RDFLib/rdflib/blob/3bee979cd0e5b6efc57296b4fc43dd8ede8cf375/CHANGELOG.md?plain=1#L53
rdflib = {version=">=6.3.2,<8.0", python = ">=3.8.1", extras=["html"]}
owlrl = ">=6.0.2,<7"
# The <4 is reauired for compatiblity with OWL-RL that requdires Python <4
python = ">=3.9,<4" # Poetry doesn't read from [project.requires-python]
rdflib = {version=">=7.1.1,<8.0", extras=["html"]}
owlrl = ">=7.1.2,<8"
prettytable = [
{version=">=3.5.0", python = ">=3.8,<3.12"},
{version=">=3.7.0", python = ">=3.12"}
Expand All @@ -77,10 +76,7 @@ sanic-ext = {version=">=23.3, <23.6", optional=true} #For the HTTP service
sanic-cors = {version="2.2.0", optional=true} #For the HTTP service
ruff = {version="^0.1.5", optional=true}
black = {version="24.3.0", optional=true}
mypy = [
{version=">=0.812,<0.900", optional=true, python = "<3.10"},
{version=">=0.900,<0.1000", optional=true, python = ">=3.10"}
]
mypy = {version=">=1.13.0", optional=true}
types-setuptools = {version="*", optional=true}
platformdirs = {version="*", optional=true}
coverage = {version=">6,<7,!=6.0.*,!=6.1,!=6.1.1", optional=true}
Expand All @@ -92,10 +88,7 @@ coverage = {version=">6,<7,!=6.0.*,!=6.1,!=6.1.1", optional=true}
pytest-cov = {version="^2.8.1", optional=true}
ruff = {version="^0.1.5", optional=true}
black = {version="24.3.0", optional=true}
mypy = [
{version=">=0.812,<0.900", optional=true, python = "<3.10"},
{version=">=0.900,<0.1000", optional=true, python = ">=3.10"}
]
mypy = {version=">=1.13.0", optional=true}
types-setuptools = {version="*", optional=true}
platformdirs = {version="*", optional=true}

Expand Down Expand Up @@ -206,7 +199,7 @@ testpaths = [
legacy_tox_ini = """
[tox]
skipsdist = true
envlist = py38, py39, py310, py311, py312, lint, type-checking
envlist = py39, py310, py311, py312, lint, type-checking
toxworkdir={env:TOX_WORK_DIR:.tox}
[testenv]
Expand Down Expand Up @@ -250,7 +243,7 @@ commands_pre =
poetry run pip3 install "mypy>=0.812" "types-setuptools"
commands =
- poetry show
poetry run python3 -m mypy --ignore-missing-imports pyshacl
poetry run python3 -m mypy --python-version 3.9 --ignore-missing-imports pyshacl
[gh]
# Don't include lint or type-checking in gh-actions matrix
Expand All @@ -259,6 +252,5 @@ python =
3.11 = py311
3.10 = py310
3.9 = py39
3.8 = py38
"""
25 changes: 18 additions & 7 deletions pyshacl/extras/js/rules.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#
#
import typing
from typing import List, Sequence, Union
from typing import TYPE_CHECKING, List, Optional, Sequence, Union

import rdflib

Expand All @@ -11,14 +10,18 @@

from .js_executable import JSExecutable

if typing.TYPE_CHECKING:
if TYPE_CHECKING:

from rdflib.term import URIRef

from pyshacl.pytypes import GraphLike, RDFNode, SHACLExecutor
from pyshacl.shape import Shape
from pyshacl.shapes_graph import ShapesGraph

SH_JSRule = SH.JSRule

JS_RULE_ITERATE_LIMIT = 100


class JSRule(SHACLRule):
__slots__ = ('js_exe',)
Expand All @@ -32,6 +35,7 @@ def apply(
self,
data_graph: 'GraphLike',
focus_nodes: Union[Sequence['RDFNode'], None] = None,
target_graph_identifier: Optional['URIRef'] = None,
) -> int:
focus_list: Sequence['RDFNode']
if focus_nodes is not None:
Expand All @@ -48,10 +52,10 @@ def apply(
return 0
focus_list = filtered_focus_nodes
all_added = 0
iterate_limit = 100
iterate_limit = int(JS_RULE_ITERATE_LIMIT)
while True:
if iterate_limit < 1:
raise ReportableRuntimeError("Local rule iteration exceeded iteration limit of 100.")
raise ReportableRuntimeError(f"JS rule iteration exceeded iteration limit of {JS_RULE_ITERATE_LIMIT}.")
iterate_limit -= 1
added = 0
applicable_nodes = self.filter_conditions(focus_list, data_graph)
Expand All @@ -72,10 +76,17 @@ def apply(
if this_added:
added += 1
if added > 0:
all_added += added
if isinstance(data_graph, (rdflib.Dataset, rdflib.ConjunctiveGraph)):
if target_graph_identifier is not None:
target_graph = data_graph.get_context(target_graph_identifier)
else:
target_graph = data_graph.default_context
else:
target_graph = data_graph
for s in sets_to_add:
for t in s:
data_graph.add(t)
target_graph.add(t)
all_added += added
if self.iterate:
continue # Jump up to iterate
else:
Expand Down
12 changes: 9 additions & 3 deletions pyshacl/inference/custom_rdfs_closure.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
from typing import TYPE_CHECKING, Optional

try:
from owlrl import OWL

Expand All @@ -25,6 +27,9 @@
from owlrl.OWLRL import OWLRL_Semantics
from owlrl.RDFSClosure import RDFS_Semantics as OrigRDFSSemantics

if TYPE_CHECKING:
from rdflib.graph import Graph


class CustomRDFSSemantics(OrigRDFSSemantics):
def one_time_rules(self):
Expand All @@ -49,9 +54,10 @@ class CustomRDFSOWLRLSemantics(CustomRDFSSemantics, OWLRL_Semantics):
(OWL.DataRange, OWL.equivalentClass, RDFS.Datatype),
]

def __init__(self, graph, axioms, daxioms, rdfs=True):
OWLRL_Semantics.__init__(self, graph, axioms, daxioms, rdfs)
CustomRDFSSemantics.__init__(self, graph, axioms, daxioms, rdfs)
def __init__(self, graph, axioms, daxioms, rdfs: bool = True, destination: Optional['Graph'] = None):
# MyPy thinks this is object.__init__ and says the kwargs are incorrect for __init__
OWLRL_Semantics.__init__(self, graph, axioms, daxioms, rdfs=rdfs, destination=destination) # type: ignore[arg-type, call-arg]
CustomRDFSSemantics.__init__(self, graph, axioms, daxioms, rdfs=rdfs, destination=destination) # type: ignore[arg-type, call-arg]
self.rdfs = True

# noinspection PyMethodMayBeStatic
Expand Down
Loading

0 comments on commit baf0e65

Please sign in to comment.