fix(schemaview): resolve default_curi_maps and builtin linkml: import prefixes - #106
Conversation
… prefixes
converter_from_schemas (identifier.rs) only ever registered prefixes
declared inline under a schema's `prefixes:`, plus a hardcoded 3-entry
fallback (rdfs/rdf/dcterms). It never read `default_curi_maps` (parsed
correctly onto SchemaDefinition, but otherwise unused), and prefixes from
builtin `linkml:` imports (linkml:types, linkml:mappings, linkml:extensions,
linkml:annotations, linkml:units — the schemas bundled with the LinkML
language itself) were only reachable via the network-only `resolve`
feature, which never runs automatically during add_schema's own indexing
step. A schema relying on either mechanism to resolve a prefix like
`schema:`/`owl:` without declaring it inline (a common pattern — LinkML's
own metamodel does this) failed `add_schema` outright with
CurieError(NotFound(..)) the moment it indexed a class/slot using that
prefix.
linkml_runtime.SchemaView/SchemaLoader resolve both: default_curi_maps via
Namespaces.add_prefixmap (looked up against the prefixcommons/prefixmaps
registries), and imported schemas' prefixes via recursively loading each
import and merging its `prefixes:` in — both with "explicit always wins"
precedence (`k not in self`).
Added builtin_prefix_contributions, merging in:
- default_curi_maps entries resolved against a small bundled registry
(semweb_context today; trivially extensible — an unrecognised name is
left unresolved exactly as before)
- prefixes of the 5 builtin linkml: schemas (matching both the CURIE and
fully-expanded URI import forms), transcribed verbatim from
linkml_model's actual schema files (same identity list resolve.rs
already uses for full-content network resolution — this only ever
contributes prefixes, never duplicating or conflicting with that
mechanism)
without overriding anything already registered, mirroring
Namespaces.add_prefixmap's precedence exactly. Fixed synchronously, no
network access, no dependency on imports having already been loaded as
separate schemas.
Building the merged prefix table required grouping same-URI prefixes as
Converter::Record synonyms (as the existing explicit-prefix path already
did) rather than adding them independently: semweb_context has both `dc`
and `dcterms` mapping to the same URI, and Converter::add_record rejects a
second record for an already-claimed URI, silently dropping the second
prefix if added as an independent record (caught by the existing
`io::tests::test_resolve_schemas` unit test, which loads the real LinkML
metamodel schema and started failing with
CurieError(NotFound("dcterms")) until this was fixed).
Added src/schemaview/tests/default_curi_maps.rs: a schema resolving
`schema:` via `imports: [linkml:types]` alone (the reported bug's exact
shape), a schema resolving `owl:` via `default_curi_maps: [semweb_context]`
alone, an explicit-prefix-wins precedence test, an expanded-URI-form import
test, and a control test proving a plain schema with neither mechanism is
unaffected.
Verified: cargo test --workspace, 0 failures.
|
hey sorry for late reply, i was offline. looking at it now |
|
Thanks for this — the direction is right, and the research behind the bundled tables is careful. I checked all six transcribed tables against The tables are fine; it's the merge logic that needs another look. Three things I'd want fixed before this goes in. 1. Two prefixes point at the same URI, and only one of them survives as the name we write
Example, on The Turtle writer builds its 2. Two prefixes point at the same URI again, this time from two different tables — so which one wins is random
Example, same two schemas, only the visit order differs: So identical input can serialize differently on consecutive runs. Sorting the contributions before merging, and only adding a builtin prefix as an alias when the URI already has an owner, makes it deterministic. 3. The builtin schemas import each other, and we're only reading one level deepThe five builtins aren't independent — Here we only take each entry's own The new tests pass because Smaller things
|
|
AI assisted comment above. i think the main things is duplicate prefixes (do we need them ?) and lack of recursion in resolving |
Fixes #105.
What
converter_from_schemas(identifier.rs) previously only registered prefixes declared inline under a schema'sprefixes:, plus a hardcoded 3-entry fallback (rdfs/rdf/dcterms). It never readdefault_curi_maps, and prefixes from builtinlinkml:imports (linkml:types,linkml:mappings,linkml:extensions,linkml:annotations,linkml:units) were only reachable via the network-onlyresolvefeature — which never runs automatically duringadd_schema's own indexing step, the exact point whereCurieErrorgets raised. A schema relying on either mechanism to resolve a prefix likeschema:/owl:without declaring it inline (a common pattern — LinkML's own metamodel does this) failedadd_schemaoutright.linkml_runtime.SchemaView/SchemaLoaderresolve both, with "explicit always wins" precedence (Namespaces.add_prefixmap'sk not in selfrule).The fix
Added
builtin_prefix_contributions, merging in — synchronously, no network access, no dependency on imports already being loaded as separate schemas:default_curi_mapsentries resolved against a small bundled registry (semweb_contexttoday; trivially extensible via one match arm — an unrecognised name is left unresolved exactly as before, so this is purely additive)linkml:schemas (matching both the CURIE and fully-expanded-URI import forms), transcribed verbatim fromlinkml_model's actual schema files. Uses the same identity listresolve::get_uri_for_idalready has for full-content network resolution — this PR only ever contributes prefixes, so it doesn't duplicate or conflict with that mechanism, which still owns resolving imported classes/slots.Merge precedence matches
Namespaces.add_prefixmapexactly: explicitprefixes:always win.A bug this surfaced along the way
Building the merged table required grouping same-URI prefixes as
Converter::Recordsynonyms (the way the pre-existing explicit-prefix path already does), rather than adding each builtin prefix independently viaadd_prefix.semweb_contexthas bothdcanddctermsmapping to the same URI (http://purl.org/dc/terms/), andConverter::add_recordrejects a second record for an already-claimed URI — so a flat per-prefix merge silently drops the second prefix. This was caught by the existingio::tests::test_resolve_schemasunit test (loads the real LinkML metamodel schema), which started failing withCurieError(NotFound("dcterms"))during development until the merge was restructured to group by URI first.Tests
Added
src/schemaview/tests/default_curi_maps.rs:schema:viaimports: [linkml:types]alone (the reported bug's exact shape)owl:viadefault_curi_maps: [semweb_context]alonehttps://w3id.org/linkml/typesvs.linkml:types)Verification
cargo test --workspace: all passing, 0 failurescargo clippy -p schemaview --all-targets: clean (no new warnings; pre-existing warnings are all in the generatedlinkml_metacrate, untouched by this change)linkml-runtime==1.11.1/linkml==1.11.1install that the bundled prefix tables matchlinkml_model's actual schema files andprefixcommons'semweb_context.jsonldbyte-for-byte