diff --git a/CHANGELOG.md b/CHANGELOG.md index 2dc8ec2..ecdf57c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,15 @@ and this project adheres to [Python PEP 440 Versioning](https://www.python.org/d ## [Unreleased] - Nothing yet... +## [0.24.1] - 2023-11-23 +## Note - The 0.24.x series is the last to support Python 3.7 +### RDFLib v7.0.0 and some other dependencies already don't support 3.7, so PySHACL will drop it from 0.25+ +### Fixed +- Shape can have multiple values for `sh:not`. Fixes #217 ## [0.24.0] - 2023-11-08 -## Note - This is the last version to support Python 3.7 -### RDFLib v7.0.0 and some other dependencies already don't support 3.7, so PySHACL will drop it after this release. +## Note - The 0.24.x series is the last to support Python 3.7 +### RDFLib v7.0.0 and some other dependencies already don't support 3.7, so PySHACL will drop it from 0.25+ ### Added - Compatibility with RDFLib v7.0.0 - Closes #197 ### Fixed @@ -1073,7 +1078,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.24.0...HEAD +[Unreleased]: https://github.com/RDFLib/pySHACL/compare/v0.24.1...HEAD +[0.24.1]: https://github.com/RDFLib/pySHACL/compare/v0.24.0...v0.24.1 [0.24.0]: https://github.com/RDFLib/pySHACL/compare/v0.23.0...v0.24.0 [0.23.0]: https://github.com/RDFLib/pySHACL/compare/v0.22.2...v0.23.0 [0.22.2]: https://github.com/RDFLib/pySHACL/compare/v0.22.1...v0.22.2 diff --git a/CITATION.cff b/CITATION.cff index 429023c..51068b3 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -8,7 +8,7 @@ authors: given-names: "Nicholas" orcid: "http://orcid.org/0000-0002-8742-7730" title: "pySHACL" -version: 0.24.0 +version: 0.24.1 doi: 10.5281/zenodo.4750840 license: Apache-2.0 date-released: 2022-01-13 diff --git a/Dockerfile b/Dockerfile index aca70ea..a6bdcf7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ WORKDIR /home/pyshacl RUN addgroup -g 1000 -S pyshacl &&\ adduser --disabled-password --gecos "" --home "$(pwd)" --ingroup "pyshacl" --no-create-home --uid 1000 pyshacl WORKDIR /app -LABEL org.opencontainers.image.version="0.24.0" +LABEL org.opencontainers.image.version="0.24.1" COPY . . RUN chown -R pyshacl:pyshacl /home/pyshacl /app && chmod -R 775 /home/pyshacl /app USER pyshacl diff --git a/README.md b/README.md index e957714..529c009 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ usage: pyshacl [-h] [-s [SHACL]] [-e [ONT]] [-i {none,rdfs,owlrl,both}] [-m] [-ef {auto,turtle,xml,json-ld,nt,n3}] [-V] [-o [OUTPUT]] DataGraph -PySHACL 0.24.0 command line tool. +PySHACL 0.24.1 command line tool. positional arguments: DataGraph The file containing the Target Data Graph. diff --git a/poetry.lock b/poetry.lock index be49699..068dfd7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -151,13 +151,13 @@ toml = ["tomli"] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -507,13 +507,13 @@ files = [ [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = true python-versions = ">=3.7" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.dependencies] @@ -1031,13 +1031,13 @@ files = [ [[package]] name = "types-setuptools" -version = "68.2.0.0" +version = "68.2.0.1" description = "Typing stubs for setuptools" optional = true -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "types-setuptools-68.2.0.0.tar.gz", hash = "sha256:a4216f1e2ef29d089877b3af3ab2acf489eb869ccaf905125c69d2dc3932fd85"}, - {file = "types_setuptools-68.2.0.0-py3-none-any.whl", hash = "sha256:77edcc843e53f8fc83bb1a840684841f3dc804ec94562623bfa2ea70d5a2ba1b"}, + {file = "types-setuptools-68.2.0.1.tar.gz", hash = "sha256:8f31e8201e7969789e0eb23463b53ebe5f67d92417df4b648a6ea3c357ca4f51"}, + {file = "types_setuptools-68.2.0.1-py3-none-any.whl", hash = "sha256:e9c649559743e9f98c924bec91eae97f3ba208a70686182c3658fd7e81778d37"}, ] [[package]] @@ -1176,13 +1176,13 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" [[package]] name = "wcwidth" -version = "0.2.9" +version = "0.2.12" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.9-py2.py3-none-any.whl", hash = "sha256:9a929bd8380f6cd9571a968a9c8f4353ca58d7cd812a4822bba831f8d685b223"}, - {file = "wcwidth-0.2.9.tar.gz", hash = "sha256:a675d1a4a2d24ef67096a04b85b02deeecd8e226f57b5e3a72dbb9ed99d27da8"}, + {file = "wcwidth-0.2.12-py2.py3-none-any.whl", hash = "sha256:f26ec43d96c8cbfed76a5075dac87680124fa84e0855195a6184da9c187f133c"}, + {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index a9a2e8a..c0b75e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "pyshacl" -version = "0.24.0" +version = "0.24.1" # Don't forget to change the version number in __init__.py, Dockerfile, and CITATION.cff along with this one description = "Python SHACL Validator" license = "Apache-2.0" diff --git a/pyshacl/__init__.py b/pyshacl/__init__.py index a91d4a2..ce2f030 100644 --- a/pyshacl/__init__.py +++ b/pyshacl/__init__.py @@ -5,7 +5,7 @@ from .validate import Validator, validate # version compliant with https://www.python.org/dev/peps/pep-0440/ -__version__ = '0.24.0' +__version__ = '0.24.1' # Don't forget to change the version number in pyproject.toml, Dockerfile, and CITATION.cff along with this one __all__ = ['validate', 'Validator', '__version__', 'Shape', 'ShapesGraph'] diff --git a/pyshacl/constraints/core/logical_constraints.py b/pyshacl/constraints/core/logical_constraints.py index 0df5c6b..a2cb3b1 100644 --- a/pyshacl/constraints/core/logical_constraints.py +++ b/pyshacl/constraints/core/logical_constraints.py @@ -45,11 +45,6 @@ def __init__(self, shape): "NotConstraintComponent must have at least one sh:not predicate.", "https://www.w3.org/TR/shacl/#NotConstraintComponent", ) - if len(not_list) > 1: - raise ConstraintLoadError( - "NotConstraintComponent must have at most one sh:not predicate.", - "https://www.w3.org/TR/shacl/#NotConstraintComponent", - ) self.not_list = not_list @classmethod diff --git a/test/issues/test_217.py b/test/issues/test_217.py new file mode 100644 index 0000000..b9319ef --- /dev/null +++ b/test/issues/test_217.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# +""" +https://github.com/RDFLib/pySHACL/issues/217 +""" +import rdflib +import pyshacl +import sys + +shapes_data = '''\ +@prefix ex: . +@prefix sh-ex: . +@prefix sh: . + +sh-ex:ClassC-shape + a sh:NodeShape ; + sh:not + [ + a sh:NodeShape ; + sh:class ex:ClassA ; + ] , + [ + a sh:NodeShape ; + sh:class ex:ClassB ; + ] + ; + sh:targetClass ex:ClassC ; + . +''' + +data_g_text = '''\ +@prefix ex: . +@prefix kb: . +@prefix rdfs: . + +kb:Thing-1 + a + ex:ClassA , + ex:ClassB + ; + rdfs:comment "This individual is consistent per OWL and should validate with SHACL."@en ; + . + +kb:Thing-2 + a + ex:ClassA , + ex:ClassC + ; + rdfs:comment "This individual is inconsistent per OWL and should not validate with SHACL."@en ; + . + +kb:Thing-3 + a + ex:ClassB , + ex:ClassC + ; + rdfs:comment "This individual is inconsistent per OWL and should not validate with SHACL."@en ; + . +''' + + +def test_217(): + shape_g = rdflib.Graph().parse(data=shapes_data, format='turtle') + data_g = rdflib.Graph().parse(data=data_g_text, format="turtle") + conforms, results_graph, results_text = pyshacl.validate( + data_g, shacl_graph=shape_g, debug=True, meta_shacl=False, + ) + assert not conforms + assert "Node kb:Thing-2 conforms to shape" in results_text and "Node kb:Thing-3 conforms to shape" in results_text + + +if __name__ == "__main__": + sys.exit(test_217())