fix(shaclgen): emit sh:maxCount 0 for zero maximum_cardinality#12
Open
fix(shaclgen): emit sh:maxCount 0 for zero maximum_cardinality#12
Conversation
jdsika
added a commit
that referenced
this pull request
May 2, 2026
Apply same fix as fix/shaclgen-maxcount-zero branch to develop. Change truthiness checks to explicit `is not None` comparisons for minimum_cardinality and maximum_cardinality in SHACL generator. See: #12
jdsika
added a commit
that referenced
this pull request
May 2, 2026
Restore shaclgen.py (accidentally emptied) and apply the is-not-None fix for minimum/maximum_cardinality checks. See: #12
abe3f1c to
4f0020c
Compare
7 tasks
Co-authored-by: Patrick Kalita <pkalita@lbl.gov>
…rrides Co-authored-by: Kevin Schaper <kevinschaper@gmail.com>
fix(excelgen): move workbook.save outside loop
The error is explained in the comment - its spurious and annoying to wait rely on the PURL system being updated.
6a5873d to
af15819
Compare
Co-authored-by: Kevin Schaper <kevinschaper@gmail.com> Co-authored-by: Corey Cox <69321580+amc-corey-cox@users.noreply.github.com>
ccaf0d7 to
3ec940e
Compare
The SHACL generator used Python truthiness checks for
minimum_cardinality and maximum_cardinality:
if s.minimum_cardinality: # 0 is falsy!
if s.maximum_cardinality: # 0 is falsy!
Since int(0) evaluates as False in Python, setting
maximum_cardinality: 0 (which should produce sh:maxCount 0,
meaning the property MUST NOT appear) silently emitted nothing.
This patch changes both checks to explicit `is not None`
comparisons, matching the pattern already used in the OWL
generator (owlgen.py lines 627-640) for the same attributes.
sh:maxCount 0 is valid per the W3C SHACL specification and means
"this property must not exist on any conforming node". This is
the standard mechanism for suppressing inherited properties on
subclasses via slot_usage with maximum_cardinality: 0.
Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de>
3ec940e to
4bc7b3d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix a Python truthiness bug in the SHACL generator that prevents
sh:maxCount 0andsh:minCount 0from being emitted whenmaximum_cardinality: 0orminimum_cardinality: 0is set in a LinkML schema.Problem
In
shaclgen.py, the cardinality checks use Python truthiness:Since
0evaluates asFalsein Python, settingmaximum_cardinality: 0(which should emitsh:maxCount 0meaning "this property MUST NOT appear") produces no output at all.Root Cause
The condition
if s.maximum_cardinality:fails when the value is0because Python treats0as falsy. The correct check isif s.maximum_cardinality is not None:which distinguishes "not set" from "explicitly set to zero".Fix
Changed both checks to use explicit
is not Nonecomparisons:This matches the pattern already used in the OWL generator (
owlgen.pylines 627-640) for the same attributes.Verification
sh:maxCount 0(means "property must not exist on any conforming node")is not Noneand emitsowl:maxCardinality 0is not Nonefor the same field (line 693)sh:maxCount 0appears in generated outputUse Case
This is needed for modeling class hierarchies where subclasses restrict inherited properties. For example,
slot_usagewithmaximum_cardinality: 0is the idiomatic way in LinkML to express "this inherited slot is not applicable on this subclass" --- but without this fix, the SHACL output silently omits the constraint.Testing
ChildWithZeroMaxCardclass totests/linkml/test_generators/input/shaclgen/cardinality.yamltest_zero_maximum_cardinality_emits_maxcountregression test totest_shaclgen.pyis not Nonecheck)Note on
exact_cardinalityThe
elif s.exact_cardinality:branches (lines 174, 184) have the same truthiness issue for the value0. However,exact_cardinality: 0is semantically degenerate (a list with exactly zero items is the same as a forbidden property) and extremely unlikely in practice. This fix focuses on the common and semantically meaningful case. A follow-up can addressexact_cardinalityif needed.