Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
b98b496
feat(rdf): add opt-in diff-stable blank-node labels
jdsika Sep 8, 2026
a55ba23
fix(rdf): bump diffable-rdf to 0.3.0 and stop diff_stable silently no…
jdsika Sep 11, 2026
a4d5253
build(deps): require diffable-rdf 0.4.0
jdsika Sep 11, 2026
16172e9
test(rdf): mark diff-stable tests for diffable-rdf canary CI
jdsika Sep 14, 2026
20ee81f
Make diff-stable serialization optional and address review feedback
jdsika Sep 16, 2026
4e6a03d
fix(schemaview): get_uri resolves elements of relatively-imported sch…
noelmcloughlin Sep 17, 2026
b39f78f
chore: update packages/linkml_runtime/src/linkml_runtime/utils/schema…
noelmcloughlin Sep 18, 2026
814b74b
Merge branch 'main' into issue_3878
noelmcloughlin Sep 18, 2026
b842129
fix(schemaview): restore .get() lookup in get_uri, reverting b39f78f9
noelmcloughlin Sep 18, 2026
c8ad021
docs(schemaview): say why get_uri uses .get() rather than a subscript
noelmcloughlin Sep 18, 2026
b57dac4
Merge branch 'main' into feat/diff-stable-serialization
jdsika Sep 19, 2026
4f43bd2
build(deps): bump sqlalchemy
dependabot[bot] Sep 24, 2026
69938e5
Merge branch 'main' into issue_3878
kevinschaper Sep 24, 2026
9cf563c
fix(schemaview): keep track of which schema requested each import (#3…
noelmcloughlin Sep 24, 2026
1350e94
Merge branch 'main' into issue_3878
matentzn Sep 25, 2026
d2fb821
Merge pull request #4000 from noelmcloughlin/issue_3878
matentzn Sep 25, 2026
0cb65a8
build(deps): bump platformdirs in the patch-updates group
dependabot[bot] Sep 25, 2026
b07d0a0
fix(jsonschemagen): keep classes closed by default, per the metamodel
amc-corey-cox Sep 25, 2026
3864e08
Update metamodel test fixtures from linkml-model
github-actions[bot] Sep 25, 2026
5ef7622
Warn hybrid schemaloader-schemaview use
Silvanoc Sep 25, 2026
d8035d3
build(deps): bump platformdirs in the patch-updates group
dependabot[bot] Sep 28, 2026
4ca0022
build(deps-dev): bump tox from 4.61.5 to 4.63.0
dependabot[bot] Sep 28, 2026
123bc30
build(deps): bump platformdirs in the patch-updates group
dependabot[bot] Sep 29, 2026
95a39e2
build(deps-dev): bump typedb-driver from 3.12.3 to 3.13.6
dependabot[bot] Sep 29, 2026
fd4ed99
feat(openapigen): prepare support for multiple openapi versions
Silvanoc Sep 29, 2026
30203e5
build(deps-dev): bump tox from 4.63.0 to 4.64.1
dependabot[bot] Oct 1, 2026
62d30bf
build(deps): bump the github-actions group with 5 updates
dependabot[bot] Oct 1, 2026
d6cb3b5
Merge branch 'main' into feat/diff-stable-serialization
jdsika Oct 2, 2026
084aaa9
test(rdf): trim the diff-stable tests and reuse the existing fixture
jdsika Oct 2, 2026
2208d4f
test(rdf): record the canonicalizer gaps against the extracted library
jdsika Sep 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/scripts/check_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@
"snomed.info",
# LinkML metamodel - w3id redirects to linkml.io/linkml-model which may have issues
"w3id.org",
# Certificate expired Sep/24/2026
"datashapes.org",
}


Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check-external-links.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
python-version: "3.12"

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}

Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/dependency-audit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:

# Pin uv to a known-good, recent release.
- name: Install uv and setup uv caching
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand All @@ -56,7 +56,10 @@ jobs:
#
# So gate the audit on whether the change actually altered dependencies,
# relative to each event's natural base:
# * pull_request -> the PR base
# * pull_request -> the base the checked-out merge commit was built on
# (HEAD^1). Not github.event.pull_request.base.sha: that can be an
# older main commit, so the diff would include main's own uv.lock
# bumps and audit a PR that changed no dependencies.
# * push (main) -> the commit before the push (github.event.before)
# * merge_group -> the queue base
# * otherwise (workflow_dispatch, first/force push) -> audit
Expand All @@ -78,7 +81,7 @@ jobs:
run: |
set -euo pipefail
case "${{ github.event_name }}" in
pull_request) base="${{ github.event.pull_request.base.sha }}" ;;
pull_request) base="$(git rev-parse HEAD^1)" ;;
merge_group) base="${{ github.event.merge_group.base_sha }}" ;;
push) base="${{ github.event.before }}" ;;
*) base="" ;;
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/doc-pages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
git fetch upstream --tags

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/docker-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ jobs:
echo "Ref: ${{ github.ref }}"

- name: Set up QEMU
uses: docker/setup-qemu-action@v4.2.0
uses: docker/setup-qemu-action@v4.4.0

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4.3.0
uses: docker/setup-buildx-action@v4.4.1

- name: Login to DockerHub
if: startsWith(github.ref, 'refs/tags/v')
Expand All @@ -61,7 +61,7 @@ jobs:
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}

- name: Build and push
uses: docker/build-push-action@v7.3.0
uses: docker/build-push-action@v7.4.0
with:
context: .
platforms: linux/amd64,linux/arm64/v8
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
git fetch upstream --tags

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
steps:
- uses: actions/checkout@v7
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}

Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:
git fetch upstream --tags

- name: Install uv and setup uv caching
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down Expand Up @@ -105,7 +105,7 @@ jobs:
shell: bash
- name: Upload linkml coverage report
if: github.repository == 'linkml/linkml' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v7.0.0
uses: codecov/codecov-action@v7.1.1
with:
name: codecov-linkml-${{ matrix.os }}-${{ matrix.python-version }}
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -114,7 +114,7 @@ jobs:
fail_ci_if_error: true
- name: Upload runtime coverage report
if: github.repository == 'linkml/linkml' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v7.0.0
uses: codecov/codecov-action@v7.1.1
with:
name: codecov-runtime-${{ matrix.os }}-${{ matrix.python-version }}
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -139,7 +139,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v7
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand All @@ -160,7 +160,7 @@ jobs:
uv run coverage report -m
- name: Upload linkml slow test coverage
if: github.repository == 'linkml/linkml' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v7.0.0
uses: codecov/codecov-action@v7.1.1
with:
name: codecov-linkml-slow-${{ matrix.os }}-${{ matrix.python-version }}
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down Expand Up @@ -189,7 +189,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v7
- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand All @@ -207,7 +207,7 @@ jobs:
uv run pytest tests/linkml/test_notebooks/ -m "not kroki" --cov --cov-report xml:coverage-notebooks.xml --cov-report term-missing
- name: Upload notebook coverage
if: github.repository == 'linkml/linkml' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v7.0.0
uses: codecov/codecov-action@v7.1.1
with:
name: codecov-notebooks-${{ matrix.os }}-${{ matrix.python-version }}
token: ${{ secrets.CODECOV_TOKEN }}
Expand All @@ -232,7 +232,7 @@ jobs:
python-version: 3.13

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
- name: Build source and wheel archives
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/metamodel-compat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@v7

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pypi-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
python-version: 3.13

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/rustgen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
git fetch upstream --tags

- name: Install uv and setup uv caching
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:

- name: Upload coverage report
if: github.repository == 'linkml/linkml' && github.actor != 'dependabot[bot]'
uses: codecov/codecov-action@v7.0.0
uses: codecov/codecov-action@v7.1.1
with:
name: codecov-results-rustgen
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/typedb-integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
--health-start-period 30s
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.0.1
- uses: astral-sh/setup-uv@v10.2.0
- uses: actions/setup-python@v7.0.0
with:
python-version: "3.12"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-feature-dashboard.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
git fetch upstream --tags

- name: Install uv
uses: astral-sh/setup-uv@v10.0.1
uses: astral-sh/setup-uv@v10.2.0
with:
version: ${{ env.UV_VERSION }}
enable-cache: true
Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ All commands use `uv run` prefix (e.g., `uv run pytest`).
* Do not "fix" issues by changing or weakening test conditions. Try harder, or ask questions if a test fails.
* Avoid try/except blocks, these can mask bugs
* Failing fast is a good principle
* Optional dependencies are the documented exception to the two rules above. Guard the import, not the spec: `try: import x` / `except ImportError as exc: raise ImportError("x is required. Install with: pip install 'linkml[extra]'") from exc` - see `generators/bigquerygen.py`. `importlib.util.find_spec` raises under the test fixture below, which hides your message.
* Testing that an optional dependency is absent is not a mock test: use the `mock_missing_import` fixture in `tests/conftest.py`. Do not build isolated environments in CI for this.
* Follow the DRY principle
* Avoid repeating chunks of code, but also avoid premature over-abstraction
* Declarative principles are favored
Expand Down
25 changes: 12 additions & 13 deletions docs/generators/openapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ OpenAPI
=======

`OpenAPI <https://www.openapis.org/>`_ is a specification for describing
RESTful HTTP APIs. The OpenAPI generator produces an OpenAPI v3.0.3
specification in YAML from a LinkML schema.
RESTful HTTP APIs. The OpenAPI generator produces an OpenAPI
specification in YAML from a LinkML schema. As of now it supports OpenAPI
specification versions v3.0.3 and v3.1.0.

.. note:: This generator produces a complete OpenAPI spec by combining a
user-provided *template* (containing the API header, endpoints, and
Expand All @@ -15,15 +16,16 @@ Overview

The generator works in two stages:

1. The user provides an **OpenAPI template** — a valid OpenAPI v3.0.3 YAML
1. The user provides an **OpenAPI template** — a valid OpenAPI YAML
file that defines the API metadata (title, version, servers), paths
(endpoints), and security schemes.
(endpoints), and security schemes. It also specifies the version of
the OpenAPI specification in its top-level attribute `openapi`.
2. The generator fills the ``components/schemas`` section with JSON Schema
definitions generated from the LinkML schema, keeping only those classes
that are transitively reachable from the endpoints.

Both the input template and the final output are automatically validated
against the OpenAPI 3.0.3 specification using
against the corresponding OpenAPI specification version using
`openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`_.

To run:
Expand All @@ -32,6 +34,9 @@ To run:

gen-openapi personinfo.yaml --template api-template.yaml > personinfo.openapi.yaml

The **template's top-level attribute `openapi` MUST specify the supported OpenAPI
version**.

The ``--template`` / ``-t`` option is required when generating a concrete
specification. If omitted, the generator prints a generic template that can
be used as a starting point:
Expand All @@ -47,14 +52,8 @@ The generator validates both the input template and the final output against
the OpenAPI specification using
`openapi-spec-validator <https://github.com/p1c2u/openapi-spec-validator>`_.

The ``openapi`` field in the template is checked against the expected
version for the chosen output format (currently ``openapi303`` →
``3.0.3``). If the versions do not match, the generator raises a
``ValueError``.

Additionally, the template's ``components/schemas`` section must declare each
resource that is referenced by an endpoint, using two custom extension
fields:
The template's ``components/schemas`` section must declare each resource
that is referenced by an endpoint, using two custom extension fields:

``x-linkml-schema``
The ``id`` of the LinkML schema being used. Must match exactly.
Expand Down
30 changes: 30 additions & 0 deletions docs/howtos/collaborative-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,36 @@ Some projects may opt to manage their data alongside the schema in the same repo
for "registry" style projects, but in other cases the data may be best managed separately in a dedicated
store or a repository like Zenodo or Figshare.

(rdf-in-version-control)=
### Keep generated RDF diffs small

When you track generated RDF in Git, adding a class or property can change many
blank-node labels. The default RDFC-1.0 numbering is repeatable for the same graph,
but an insertion can renumber existing nodes and obscure the actual schema edit.

The optional `--diff-stable` flag uses
[diffable-rdf](https://github.com/ASCS-eV/diffable-rdf) to reduce this label churn.
In a uv project containing your schema, install LinkML with the extra and generate
SHACL as follows (using a release that includes this option):

```bash
uv add 'linkml[diff-stable]'
uv run gen-shacl --diff-stable schema.yaml > schema.shacl.ttl
```

The flag also works with `gen-owl`, `gen-rdf`, and `gen-shex --format rdf`.
Python callers of `canonicalize_rdf_graph(..., diff_stable=True)` can install
`linkml-runtime[diff-stable]`. The feature is disabled by default; enabling it
changes existing labels once, so keep that regeneration separate from schema edits.

Labels depend on blank-node neighborhoods. Edits within connected structures or
among symmetric nodes can still affect other labels; minimum diffs are not
guaranteed. Keep tool versions consistent when comparing generated files.
The relabeled output is not the standard RDFC canonical representation.
ShExC, ShEx JSON and instance-data conversion are outside this option's scope.
Non-standard RDF takes the existing fallback path, which warns that it cannot
apply diff-stable labels.

### Permissively License Your Code and Data

(adapted from [O3 guidelines](https://osf.io/vuzt3/))
Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/tutorial01/personinfo.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$defs": {
"Person": {
"additionalProperties": true,
"additionalProperties": false,
"description": "",
"properties": {
"age": {
Expand Down
12 changes: 8 additions & 4 deletions packages/linkml/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,18 @@ dependencies = [ # Specifier syntax: https://peps.python.org/pep-0631/
"pyyaml",
"rdflib>=7.6.0",
"requests >= 2.22",
"sqlalchemy>=2.0.53",
"sqlalchemy>=2.0.54",
"watchdog >= 0.9.0",
"typing-extensions >= 4.6.0; python_version < '3.12'",
"sphinx-click (>=6.0.0)",
"openapi-spec-validator >= 0.8.4",
"pydantic-settings>=2.15.0",
"platformdirs>=4.11.8",
"platformdirs>=4.11.12",
]

[project.optional-dependencies]
diff-stable = ["linkml-runtime[diff-stable]>=1.10.0,<2.0.0"]

[dependency-groups]
lint = [
"black >= 24.0.0",
Expand All @@ -79,6 +82,7 @@ shacl = [
"pyshacl>=0.40.1",
]
tests = [
"linkml-runtime[diff-stable]",
{ include-group = "lint" },
{ include-group = "typing" },
{ include-group = "shacl" },
Expand All @@ -97,7 +101,7 @@ dev = [
"nbconvert",
"nbformat",
"coverage>=7.16.0",
"tox>=4.61.2",
"tox>=4.64.1",
"tox-uv",
"myst-nb>=1.4.0; python_version >= '3.10'",
"sphinx-design >= 0.5.0",
Expand All @@ -114,7 +118,7 @@ tests-rustgen = [
"maturin>=1.15.0"
]
typedb = [
"typedb-driver>=3.12.3,<4.0",
"typedb-driver>=3.13.6,<4.0",
]
bigquery = [
"sqlalchemy-bigquery >= 1.9.0",
Expand Down
Loading
Loading