Skip to content

feat(jsonschemagen): add --include-null/--no-include-null CLI option - #15

Open
jdsika wants to merge 126 commits into
mainfrom
feat/jsonschemagen-include-null-cli
Open

feat(jsonschemagen): add --include-null/--no-include-null CLI option#15
jdsika wants to merge 126 commits into
mainfrom
feat/jsonschemagen-include-null-cli

Conversation

@jdsika

@jdsika jdsika commented Jun 18, 2026

Copy link
Copy Markdown

Summary

Expose the existing JsonSchemaGenerator.include_null field (default True) on the
gen-json-schema CLI as --include-null/--no-include-null. No generator logic
changes — the option is forwarded to the existing field.

Motivation (standards)

include_null decides whether an optional slot is rendered as ["<type>", "null"]
(accepts an explicit JSON null) or as the bare "<type>".

  • JSON Schema Validation, draft 2019-09, §6.1.1 (type) — the allowed type
    tokens are the six primitive types (null, boolean, object, array, number,
    string). null is a value type, so a type array is the standard mechanism for
    declaring whether an explicit null is an acceptable value.
  • JSON Schema Validation, draft 2019-09, §6.5.3 (required) — presence/absence
    of a property is a separate concern from type.
  • RFC 8259, §3 (Values)null is a literal JSON value, distinct from an absent
    member (null ≠ absent).

Because required (§6.5.3) already expresses optionality, adding "null" to type
to model "optional" overloads the value-type keyword. --no-include-null yields the
idiomatic rendering of a non-nullable optional ({"type": "string"} + omission from
required), required for strict structural parity with normative reference schemas
that declare a bare type and forbid null.

Changes

  • One click option on gen-json-schema, forwarded to the existing include_null
    generator field.

Backward compatibility

Default remains include_null=True; output is byte-identical unless
--no-include-null is passed.

How was this tested?

test_include_null_cli_option (parametrized over no flag, --include-null, and
--no-include-null): an optional scalar slot is ["string", "null"] by default and
"string" under --no-include-null; an optional multivalued slot is
["array", "null"] vs "array"; a required slot is unaffected in all cases.

Areas of uncertainty

  • The default (--include-null) preserves current upstream behaviour; whether upstream would prefer flipping the default (a breaking change for consumers relying on explicit null) is a maintainer decision.

Checklist

  • My code follows the contributor guidelines
  • I have added tests that prove my fix/feature works
  • Existing tests pass locally with my changes

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.

@jdsika
jdsika force-pushed the feat/jsonschemagen-include-null-cli branch 2 times, most recently from 6180ba8 to cbf901d Compare June 18, 2026 13:31
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
jdsika force-pushed the feat/jsonschemagen-include-null-cli branch from 5e4ece3 to 1072190 Compare July 3, 2026 12:45
@rmessaou
rmessaou force-pushed the feat/jsonschemagen-include-null-cli branch from 1072190 to 0e58ff2 Compare July 8, 2026 08:22
Expose the existing JsonSchemaGenerator.include_null field on the gen-json-schema
CLI. --no-include-null forbids explicit JSON null in optional slots so optionality
is expressed only via absence from required (JSON Schema Validation 6.5.3), keeping
the bare value type (6.1.1) -- needed for strict parity with reference schemas that
forbid null. Default unchanged (include_null=True).

Tested at the CLI surface via CliRunner over scalar, multivalued, and required
slots; the standards rationale lives in the include_null field docstring.

Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de>
@rmessaou
rmessaou force-pushed the feat/jsonschemagen-include-null-cli branch from 0e58ff2 to 845cb31 Compare July 8, 2026 08:49
Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
sagehrke and others added 16 commits July 14, 2026 16:17
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.
Bumps [sphinxcontrib-mermaid](https://github.com/mgaitan/sphinxcontrib-mermaid) from 1.0.0 to 2.0.3.
- [Changelog](https://github.com/mgaitan/sphinxcontrib-mermaid/blob/master/CHANGELOG.md)
- [Commits](mgaitan/sphinxcontrib-mermaid@1.0.0...v2.0.3)

---
updated-dependencies:
- dependency-name: sphinxcontrib-mermaid
  dependency-version: 2.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…chema1 brittleness

Two bugs in test_output_prefixes:

1. No fixture dependency on issue_429_graph: the test read OUT_429 from disk,
   which only exists if a prior test had already run the fixture. Running the
   test in isolation (or after a clean checkout) would fail or read a stale
   file. Fixed by adding issue_429_graph as a parameter and reading the turtle
   from the graph directly via g.serialize().

2. Assertions for 'prefix sdo:' and 'sdo:Person' were brittle: the semweb_context
   prefix map binds http://schema.org/ as schema1: rather than sdo:, so these
   always failed on a freshly generated graph. Replaced with a namespace-manager
   URI check and a graph-level triple assertion, which are independent of the
   prefix label chosen by the serialiser.
…ons with graph-level checks

Replace the four residual turtle string assertions ('prefix ORCID:',
'prefix personinfo:', 'personinfo:age', 'ORCID:1234') with graph-level
assertions using the namespace manager and triple membership, consistent
with how test_rdf_output already works.

Also extend coverage to ORCID:4567 (Lois Lane), which was not asserted at
all in test_output_prefixes.
…d sub-schema prefixes

Add assertions to test_phenopackets that all predicate and rdf:type object
URIs in the dumped graph are fully expanded (contain '://').

Before this fix, sub-schema prefixes (e.g. 'base:' declared in
phenopackets/base) were absent from the namespace cache when namespaces()
was first called, so slot URIs like 'base:label' and class URIs like
'base:OntologyClass' were emitted as raw unexpanded CURIEs into the RDF
graph instead of being expanded to their full https:// equivalents.

This test fails on the unfixed code and will pass once imports_closure()
is called before the namespace cache is populated.
…d all sub-schema prefixes

SchemaView.namespaces() is lru_cache'd. When as_rdf_graph() called
namespaces() before walking the import closure, imported sub-schemas
(e.g. phenopackets/base with its 'base:' prefix) were absent from
schema_map, so the cached Namespaces object was incomplete.

Subsequent calls to get_uri(expand=True) inside inject_triples() then
failed to expand CURIEs like 'base:label' and 'base:OntologyClass',
silently emitting malformed URIRef('base:label') triples into the graph.

Fix: call imports_closure() first so schema_map is fully populated
before the namespace cache is seeded.
dependabot Bot and others added 30 commits August 13, 2026 17:46
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Corey Cox <69321580+amc-corey-cox@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…ml#3894)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…nkml#3451)

Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de>
linkml#3473)

Signed-off-by: Carlo van Driesten <carlo.van-driesten@bmw.de>
Co-authored-by: Mark Andrew Miller <MAM@lbl.gov>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: amc-corey-cox <69321580+amc-corey-cox@users.noreply.github.com>
… URI expansion

Signed-off-by: Silvano Cirujano Cuesta <silvano.cirujano-cuesta@siemens.com>
Co-authored-by: amc-corey-cox <69321580+amc-corey-cox@users.noreply.github.com>
…l#3898)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
As mentioned [here](linkml#3664 (comment)), we are no longer using or developing this generator, or the Python implementation of LinkML in general. We are focusing our efforts on [LinkML-Scala](https://github.com/NeverBlink-OSS/linkml-scala) instead.
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.