Skip to content

feat(gen-owl): honor instantiates on emitted schema resources - #31

Open
jdsika wants to merge 1 commit into
mainfrom
feat/owlgen-permissible-value-instantiates
Open

jdsika wants to merge 1 commit into
mainfrom
feat/owlgen-permissible-value-instantiates

Conversation

@jdsika

@jdsika jdsika commented Oct 2, 2026 •

Copy link
Copy Markdown

Mirror of linkml#4171, same head. Review there; this PR tracks the fork stack and keeps the fork review below.

2026-10-23, third push: the instantiated class is now declared as owl:Class (OWL 2 DL §5.8.1); OWLAPI 5.5.0's profile check on the integration branch flagged it as undeclared. test_instantiated_class_is_declared fails without the change. test_owlgen.py: 123 passed.

2026-10-23, second push (adversarial review): a value that is neither a CURIE nor an IRI (a bare element name) is now skipped with a warning instead of becoming a relative IRI, with test_instantiates_ignored_for_a_bare_name; test_instantiates_types_the_emitted_class_resource fixes the behaviour under use_native_uris=False; the design decisions below spell out the specification basis, the punning question and the cross-generator findings. test_owlgen.py: 121 passed, 3 skipped.

2026-10-23: rebased onto main (a1593d16c). The only conflict was in test_owlgen.py, where the --ontology-uri-suffix regression tests (linkml#4139) and this PR's tests were inserted at the same position; both are kept, no code change. test_owlgen.py: 118 passed.

2026-10-14: fixed a defect found when combined with #33: without type objects a type is emitted as its XSD datatype (for example xsd:integer), and asserting its instantiates made that datatype an individual, which OWL 2 DL forbids (OWL 2 Structural Specification §2.4, reserved vocabulary). Such assertions are now skipped with a warning; test_instantiates_ignored_on_reserved_vocabulary fails without the fix. The OWLAPI consumer gate passes on the integration branch with it.

Summary

gen-owl ignored explicit instantiates declarations. This PR translates them to rdf:type on the emitted schema resource using one shared mapping for schemas, classes, slots, locally emitted types, enums, and non-literal permissible values.

For example, an enum value with meaning: ex:approved and instantiates: [vocab:Category] emits ex:approved rdf:type vocab:Category. CURIEs expand using the schema's prefixes; absolute IRIs and minted permissible-value IRIs are supported. An enum represented as named individuals retains its own owl:oneOf; the external class is not closed by that enumeration.

Literal permissible values cannot be RDF subjects, so the generator warns that their instantiates declaration cannot be emitted. Existing implements and permissible-value representation settings retain their roles.

Semantics, generality, and option necessity

  • LinkML instantiates is a multivalued URI-or-CURIE relationship applicable to schema elements and permissible values. The implementation follows those declarations and contains no vocabulary-specific lists.
  • LinkML's instantiation guide defines a relationship at the metamodel level: it types the schema element itself, not its ordinary data instances. This change neither inherits slots nor introduces rdfs:subClassOf to the instantiated class.
  • OWL 2's RDF mapping represents class assertions with rdf:type. Where the same IRI is an OWL class or property and an individual, OWL metamodeling/punning keeps those interpretations separate. The change does not claim that every existing generator representation satisfies the full OWL 2 DL profile.
  • No new flag: the author already chose the relationship in the schema. --metaclasses controls automatically added LinkML metamodel types, not whether explicit instantiates declarations are honored.
  • Specification basis: the specification's validation chapter (05validation.md, "LinkML 1.6 introduces the ability to validate annotation tags and values") defines instantiates as a uriorcurie "that references a class that serves as a metamodel extension class"; the metamodel reads "An element in another schema which this element instantiates". cmungall closed add metaclass_for to capture instances of LinkML classes as OWL classes to the meta model.  linkml/linkml#153 (metaclass_for, "instances of linkml classes to be OWL classes") with "The metamodel now has instantiates", and linkml/valuesets declares instantiates: [valuesets_meta:ValueSetEnumDefinitionWithStewardship] on its enums. A class assertion is the OWL reading of that relationship.
  • Punning under --no-metaclasses: rdf:type on a class, slot or type resource puns it as an individual even when --no-metaclasses (the default) keeps the LinkML metamodel types out. OWL 2 DL permits that punning (Structural Specification, Metamodeling); the option's help text describes it as a consequence of adding LinkML metaclasses. An explicit instantiates is the schema author's own statement, so it is honored regardless. This is the design question an upstream reviewer should confirm.
  • Values that are not CURIEs or IRIs: a bare element name expands to itself and would be emitted as a relative IRI, which a consumer resolves against its base. It is skipped with a warning. A CURIE with an undeclared prefix passes through unexpanded, as it does for every CURIE-valued metaslot in gen-owl.
  • use_native_uris=False: the assertion goes on the resource the element is emitted as, its class_uri, like every other axiom about it. A local class named by its native CURIE in instantiates is not remapped: the value is an IRI, not an element name.

Cross-generator consistency

gen-rdf and gen-jsonld serialize the schema as metamodel data and retain linkml:instantiates, as an xsd:anyURI literal holding the unexpanded CURIE, which is how the metamodel's JSON-LD context renders every uriorcurie metaslot (implements, see_also, the mappings); the term kind of such values is the subject of #32 and #58. gen-owl translates the declaration to an ontology membership assertion. A regression test exercises both RDF and OWL generation. JSON Schema and SHACL describe data instances, so applying a schema element's metaclass to those instances would be incorrect. Elements that the OWL generator does not emit, such as standalone subsets, gain no new representation from this change.

The same mapping applies across emitted schema resources. Tests cover both values of metaclasses and type_objects.

The downstream use in OMB #106 declares domain enum values as members of open vocabulary classes. Each enum closes only its own class; this does not turn those external vocabulary classes into closed enums.

Validation

  • OWL generator suite: 110 passed, 3 skipped.
  • Tests cover multiple memberships, absent declarations, warning behavior for literals, explicit/minted IRIs, class/individual punning, enum closure, every emitted element category, and RDF-versus-OWL representation.
  • Combined OWL/RDF/JSON-LD/OWL-CLI suites: 118 passed, 11 skipped.
  • Lock check, pinned Ruff and pre-commit checks, Sphinx HTML build with warnings as errors, and both packages' wheel/sdist builds passed.
  • Rebased onto main bd102062b (2026-10-14): full compiler suite 12,404 passed. CI: see the checks on the current head.

@jdsika jdsika self-assigned this Oct 2, 2026
@jdsika
jdsika force-pushed the feat/owlgen-permissible-value-instantiates branch from d3b8b2d to 7335442 Compare October 5, 2026 07:37
@jdsika jdsika changed the title feat(gen-owl): type a permissible value by the classes it instantiates feat(gen-owl): honor instantiates on emitted schema resources Oct 5, 2026
@jdsika
jdsika force-pushed the feat/owlgen-permissible-value-instantiates branch 2 times, most recently from fa0010a to bbc8680 Compare October 14, 2026 07:42
jdsika added a commit that referenced this pull request Oct 14, 2026
Review update from #31: without type objects a type is emitted as its XSD
datatype, and asserting its instantiates made xsd:integer an individual,
which OWL 2 DL forbids (found by the OWLAPI consumer gate in this branch).

Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
jdsika added a commit that referenced this pull request Oct 14, 2026
Review update from #31: without type objects a type is emitted as its XSD
datatype, and asserting its instantiates made xsd:integer an individual,
which OWL 2 DL forbids (found by the OWLAPI consumer gate in this branch).

Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
@jdsika
jdsika force-pushed the feat/owlgen-permissible-value-instantiates branch 2 times, most recently from c2af487 to 1aca117 Compare October 23, 2026 09:37
Translate explicit instantiates declarations to rdf:type on the emitted
schema resource through one shared helper. Apply the mapping consistently
to schemas, classes, slots, types, enums, and non-literal permissible values.
Literal permissible values cannot be RDF subjects and produce a warning.

Membership types the schema element itself, not its ordinary data instances,
and does not become subclass inheritance. Existing enum representation and
OWL class/individual punning remain intact. No additional flag is needed
because the schema already declares the relationship.

Cover CURIEs, absolute and minted IRIs, literal values, representation modes,
and the distinction between gen-rdf metamodel serialization and gen-owl
ontology assertions. Document the LinkML and OWL specification references.

A resource in the OWL 2 reserved vocabulary (Structural Specification
section 2.4), such as a type emitted as xsd:integer without type objects,
cannot be an OWL 2 DL individual; its instantiates is not asserted, with
a warning. A value that is neither a CURIE nor an IRI would become a
relative IRI and is skipped with a warning too.

The instantiated class is declared as owl:Class, since OWL 2 DL requires a
declaration for every class a class assertion uses (section 5.8.1).

Signed-off-by: jdsika <carlo.van-driesten@vdl.digital>
@jdsika
jdsika force-pushed the feat/owlgen-permissible-value-instantiates branch from 1aca117 to d612aea Compare October 23, 2026 14:24
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.

add metaclass_for to capture instances of LinkML classes as OWL classes to the meta model.

1 participant