fix(shaclgen): emit sh:maxCount 0 for zero maximum_cardinality - #12
Open
jdsika wants to merge 109 commits into
Open
fix(shaclgen): emit sh:maxCount 0 for zero maximum_cardinality#12jdsika wants to merge 109 commits into
jdsika wants to merge 109 commits into
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
jdsika
force-pushed
the
fix/shaclgen-maxcount-zero
branch
3 times, most recently
from
May 3, 2026 08:35
abe3f1c to
4f0020c
Compare
7 tasks
jdsika
force-pushed
the
fix/shaclgen-maxcount-zero
branch
6 times, most recently
from
May 12, 2026 09:39
ae4b34a to
5544abc
Compare
jdsika
force-pushed
the
fix/shaclgen-maxcount-zero
branch
from
June 9, 2026 15:20
5544abc to
69f833a
Compare
When the object code generator produces the OOField object representing a field in a class (where the field is itself the representation of a LinkML slot or a LinkML attribute), it fills the `slot_uri` member by calling the `SchemaView::get_uri` method and passing it the slot/attribute's name (rather than the slot/attribute's definition). This forces the SchemaView to look up for the actual definition from the specified name, which it may fail to do correctly if the name is not the name of a globally defined slot but of a locally defined slot (which is expected; you cannot lookup a locally defined attribute by its name only). The fix is to provide SchemaView directly with the correct SlotDefinition object (which the OOCodeGen already has), dispensing it from having to look it up. closes linkml#3677
jdsika
force-pushed
the
fix/shaclgen-maxcount-zero
branch
from
July 3, 2026 08:10
ce9d0f8 to
5657d56
Compare
rmessaou
force-pushed
the
fix/shaclgen-maxcount-zero
branch
from
July 8, 2026 08:19
5657d56 to
b9760a8
Compare
Python truthiness (`if s.maximum_cardinality:`) treats 0 as falsy, so `maximum_cardinality: 0`, `minimum_cardinality: 0` and `exact_cardinality: 0` emitted no constraint at all. `maximum_cardinality: 0` (SHACL `sh:maxCount 0`, "property must not appear") is the idiomatic way to suppress an inherited slot on a subclass via slot_usage, and owlgen already emits `owl:maxCardinality 0` for it -- so the SHACL and OWL output silently diverged. Use explicit `is not None` checks for minimum_cardinality, maximum_cardinality and exact_cardinality, matching the pattern already used in owlgen.py and docgen.py. Precedence: an explicit minimum_cardinality wins over the `required` fallback in the elif cascade, consistent with owlgen.py (which uses the same `if minimum_cardinality is not None ... elif required` order), so `required: true` + `minimum_cardinality: 0` yields `sh:minCount 0`. That combination is a schema-authoring contradiction (the metamodel documents minimum_cardinality as a multivalued-slot count); the explicit, more specific constraint is emitted. Tests cover maximum_cardinality: 0, exact_cardinality: 0, minimum_cardinality: 0, and the required + minimum_cardinality: 0 precedence case. Signed-off-by: Carlo van Driesten <[email protected]>
rmessaou
force-pushed
the
fix/shaclgen-maxcount-zero
branch
from
July 8, 2026 08:49
b9760a8 to
c40dfa4
Compare
3 tasks
3 tasks
Added the July 2026 presentation title and link to the project.
The "Audit lockfile for CVEs" step reflects the upstream advisory database, not the PR diff. When a new advisory lands for an already-pinned package, every open PR goes red regardless of whether it touches dependencies. Guard the audit step with a base-diff check so it only runs on PRs that change uv.lock or a pyproject.toml. The job still always runs and reports (no stuck-pending required check), and non-PR events keep auditing so trunk's signal is intact. The malware sync gate is unchanged. Closes linkml#3767
Compare the change under test against each event's natural base (PR base, push's before-sha, merge_group base) and only run the CVE audit when dependencies actually changed. A pyproject.toml edit always counts; uv.lock is compared by its resolved (name, version) set via a small tomllib helper, so non-deterministic lockfile churn with an unchanged resolution is skipped. This keeps a newly-published upstream advisory from turning unrelated PRs — and the next innocent merge to main — red. The malware sync gate is unchanged.
The per-change gate deliberately ignores advisories published against dependencies no PR touched. Cover that case without blocking CI: a weekly scheduled job audits main's lockfile and keeps a single labelled tracking issue in sync — opened when vulnerabilities appear, refreshed while they persist, closed automatically once clean. It never assigns or mentions anyone, so it stays quiet and stays under the project's control.
Dependabot alerts are enabled on the repo and already cover CVEs on dependencies no PR touched. A self-hosted rolling-issue audit duplicates that native detection (and running both double-reports each CVE), so it isn't worth the standing complexity. Notification noise is better handled at the Dependabot notification-routing layer than by rebuilding detection. Reverts the audit-issue job; keeps the per-change scoping and malware gate.
more white space...
Co-authored-by: Damien Goutte-Gattat <[email protected]>
fix(openapigen): replace raw schema with schemaview provided one
doc: Update the documentation about the Java generator.
Signed-off-by: Silvano Cirujano Cuesta <[email protected]> Co-authored-by: Corey Cox <[email protected]>
* fix(notebooks): correct the yamlmagic install cell in examples.ipynb
The flags preceded the `install` subcommand, so uv rejected the command
("unexpected argument '--disable-pip-version-check'"), yamlmagic was never
installed, and the following `%reload_ext yamlmagic` raised ModuleNotFoundError.
All notebooks share one venv, so this only surfaced when examples.ipynb
happened to run before a sibling that installs yamlmagic correctly. Ordering
comes from os.listdir, which is filesystem order, so Notebook Tests failed
intermittently on PRs that had nothing to do with notebooks -- and passed the
rest of the time on a dependency it never installed itself.
Verified against a venv with yamlmagic absent: the notebook fails before the
change and passes after, installing yamlmagic itself.
Refs linkml#3879.
* fix(tests): fetch creature schema fixtures from raw.githubusercontent.com
Both remote creature fixtures fetched through github.com/.../raw/..., which
302s to raw.githubusercontent.com. The extra hop through the more aggressively
rate-limited host is where `RemoteDisconnected: Remote end closed connection
without response` kept coming from -- four occurrences today, each taking out
all six parametrisations at once and reddening required test jobs on unrelated
PRs.
Two URLs move: CREATURE_SCHEMA_RAW_URL, used by creature_view_direct_url, and
the mcc prefix in creature_schema_remote.yaml, which is the fetch base for
creature_view_remote's import.
The github.com/.../tree/... URLs elsewhere under mcc/ are deliberately left
alone. Those are schema identifiers and CURIE bases rather than fetch targets,
so rewriting them would change schema identity without fixing anything.
Refs linkml#3421, which stays open: it also covers a biolink.github.io 503 on a
different host that this does not address.
…4.26.0 (linkml#3862) * fix(ci): retry transient network failures in the link checker Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Corey Cox <[email protected]>
* build(deps): cap open dependabot PRs at 3 Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: amc-corey-cox <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Corey Cox <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…pdates Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Corey Cox <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: amc-corey-cox <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Corey Cox <[email protected]>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Update Community-Meetings.md
Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ml#3894) Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…nkml#3451) Signed-off-by: Carlo van Driesten <[email protected]>
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.How was this tested?
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.Areas of uncertainty
exact_cardinality" above — aligningexact_cardinality: 0handling is deliberately out of scope here and may deserve an upstream issue of its own.Checklist
AI Assistance
If you used AI tools while preparing this PR, you are still the author and responsible for understanding, verifying, and defending your submission. Please engage with reviewers personally rather than through your agent during feedback and revisions. See our AI Covenant for details.