You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Ontology: add Uberon, NCIT, EDAM, IAO, STATO and SchemaOrg providers #98
Part of #90 (PR #61 catch-up). Small, self-contained, no dependencies on the other items.
Current state
src/ndi/ontology/providers.py on main implements 14 providers: OLSProvider and its subclasses CL, OM, CHEBI, SNOMED, EFO, PATO, plus standalone NDIC, NCIm, NCBITaxon, WBStrain, RRID, PubChem, EMPTY.
Most of these are OLS-backed, so they are OLSProvider subclasses in the same shape as the existing CL/PATO/EFO entries — a few lines each. The work is:
Add the provider classes to src/ndi/ontology/providers.py.
Extend src/ndi/ndi_common/ontology/ontology_list.json with the corresponding registry entries.
Tests per provider — lookup by id, lookup by name, and the not-found path.
Reference: PR #61 commit 31cf026 (59 lines in providers.py, 82 in ontology_list.json, 74 of test).
Two related items from the same line
Alphanumeric OLS ids + synonyms. PR NDI-python 2026-08 catch-up — hardening bundle + MATLAB parity + CI safety #61 commit d6bb534 fixed OLS id resolution for alphanumeric ids and made providers return synonyms. Worth checking whether main's OLSProvider handles both before adding six more subclasses on top of it.
Single-source the prefix map. Commit 11d1d0b derived the prefix map from ontology_list.json rather than maintaining a second copy in code. Doing that first makes step 2 above the only place a new ontology needs registering, which is the point.
Suggested order: prefix-map single-sourcing → OLS id/synonym fix → the six new providers.
Done, and closing. The work landed in ndi-ontology-python rather than here, so GitHub never linked it — closing keywords don't cross repositories.
Where it went
The ontology namespace was split out into Waltham-Data-Science/ndi-ontology-python, the companion to ndi-ontology-matlab (which is the source of truth — NDI-matlab has no +ndi/ontology.m). NDI-python re-exports it at src/ndi/ontology.py, so every call site here still reads from ndi.ontology import lookup and nothing downstream changed shape.
The distribution is top-level ndi_ontology rather than ndi.ontology, because a second distribution cannot add a subpackage to a regular package — MATLAB merges the ndi namespace across path entries for free and Python does not. That divergence is recorded in the bridge contract's decision_log.
The three items, in the order this issue suggested
1. Single-source the prefix map — the 14-entry literal _PREFIX_MAP is gone; _load_prefix_map() reads ontology_list.json alone (22 prefixes) and raises on an empty registry. Registering an ontology is now one edit, which was the point.
2. Alphanumeric OLS ids + synonyms — worth checking, as you suspected, and it was broken. OLSProvider was calling term.zfill(7), so CHEBI:15377 went out as CHEBI:0015377 and every CHEBI lookup-by-id returned empty. MATLAB's preprocessLookupInput (ontology.m:395) pads nothing. The id is now sent verbatim, which is also what makes alphanumeric ids work — OM:Temperature and OM:Acidity resolve live. Synonyms are carried through: OntologyResult.__slots__ is ("id", "name", "prefix", "definition", "synonyms", "short_name"), matching MATLAB's declaration order at ontology.m:125, and unpacking derives from __slots__ so the order cannot drift.
3. The six providers — Uberon, NCIT, EDAM, IAO, STATO, SchemaOrg. Only three turned out to be OLS-backed; EDAM and IAO download and parse OWL, and SchemaOrg walks a JSON-LD @graph. PROVIDER_REGISTRY now has 19.
Verification
Rather than per-provider unit tests, parity is checked against ndi-ontology-matlab's own fixture — ontology_lookup_tests.json, 66 cases across 15 ontologies, each naming the exact expected_id and expected_name. The file is read directly, never vendored, so it cannot drift the way ontology_list.json had (17 registered prefixes against 22). CI checks out ndi-ontology-matlab and points NDI_ONTOLOGY_MATLAB_DIR at it.
Latest run on main: 84 passed in 95.54s, zero skipped — including the new providers live (EDAM:1929, format:FASTA, IAO:document, schema:Person, STATO:p-value, UBERON:heart) and every should_succeed: false case.
The fixture earned its keep. It caught six port defects, four of which had been invisible because an empty result was indistinguishable from a real answer:
NDIC / NCIm / PubChem
returned prefixed ids where MATLAB returns bare
CHEBI
the zfill above
EMPTY
a 404'd data source, whose three failure cases were passing vacuously
the lookup cache
a transient failure cached as though it were a fact
lookup() now raises NDIOntologyLookupError instead of returning an empty result, matching MATLAB, which errors on every failure and whose own test asserts verifyError(funcToTest, ?MException). Every call site here already sat inside except Exception, and this repo's suite was unchanged across that switch.
One thing this issue asked for that is shipped but unverified
NCIT has no test case. It is implemented and registered, but ontology_lookup_tests.json has no NCIT entry, so it has never been checked against a real lookup in either language. The same is true of SNOMED, EFO and WBStrain, which predate this work. Filed upstream as Waltham-Data-Science/ndi-ontology-matlab#8; until cases exist there, test_case_table_covers_every_ported_provider carries them in a known_gaps set so the omission stays visible rather than silent.
Everything else this issue named is covered by live parity cases that pass.
Activity
Run ndi-ontology-matlab's own case table against the port
Return bare ids from NDIC, NCIm and PubChem, as MATLAB does
Fix CHEBI id lookups and the EMPTY ontology URL
Stop caching empty lookups, and retry them in the shared case table
Fail the shared-case job when the live cases could not run
Raise NDIOntologyLookupError instead of returning an empty result
stevevanhooser commentedon Sep 3, 2026
Done, and closing. The work landed in ndi-ontology-python rather than here, so GitHub never linked it — closing keywords don't cross repositories.
Where it went
The ontology namespace was split out into
Waltham-Data-Science/ndi-ontology-python, the companion tondi-ontology-matlab(which is the source of truth — NDI-matlab has no+ndi/ontology.m). NDI-python re-exports it atsrc/ndi/ontology.py, so every call site here still readsfrom ndi.ontology import lookupand nothing downstream changed shape.The distribution is top-level
ndi_ontologyrather thanndi.ontology, because a second distribution cannot add a subpackage to a regular package — MATLAB merges thendinamespace across path entries for free and Python does not. That divergence is recorded in the bridge contract'sdecision_log.The three items, in the order this issue suggested
1. Single-source the prefix map — the 14-entry literal
_PREFIX_MAPis gone;_load_prefix_map()readsontology_list.jsonalone (22 prefixes) and raises on an empty registry. Registering an ontology is now one edit, which was the point.2. Alphanumeric OLS ids + synonyms — worth checking, as you suspected, and it was broken.
OLSProviderwas callingterm.zfill(7), soCHEBI:15377went out asCHEBI:0015377and every CHEBI lookup-by-id returned empty. MATLAB'spreprocessLookupInput(ontology.m:395) pads nothing. The id is now sent verbatim, which is also what makes alphanumeric ids work —OM:TemperatureandOM:Acidityresolve live. Synonyms are carried through:OntologyResult.__slots__is("id", "name", "prefix", "definition", "synonyms", "short_name"), matching MATLAB's declaration order atontology.m:125, and unpacking derives from__slots__so the order cannot drift.3. The six providers — Uberon, NCIT, EDAM, IAO, STATO, SchemaOrg. Only three turned out to be OLS-backed; EDAM and IAO download and parse OWL, and SchemaOrg walks a JSON-LD
@graph.PROVIDER_REGISTRYnow has 19.Verification
Rather than per-provider unit tests, parity is checked against ndi-ontology-matlab's own fixture —
ontology_lookup_tests.json, 66 cases across 15 ontologies, each naming the exactexpected_idandexpected_name. The file is read directly, never vendored, so it cannot drift the wayontology_list.jsonhad (17 registered prefixes against 22). CI checks out ndi-ontology-matlab and pointsNDI_ONTOLOGY_MATLAB_DIRat it.Latest run on
main: 84 passed in 95.54s, zero skipped — including the new providers live (EDAM:1929,format:FASTA,IAO:document,schema:Person,STATO:p-value,UBERON:heart) and everyshould_succeed: falsecase.The fixture earned its keep. It caught six port defects, four of which had been invisible because an empty result was indistinguishable from a real answer:
zfillabovelookup()now raisesNDIOntologyLookupErrorinstead of returning an empty result, matching MATLAB, which errors on every failure and whose own test assertsverifyError(funcToTest, ?MException). Every call site here already sat insideexcept Exception, and this repo's suite was unchanged across that switch.One thing this issue asked for that is shipped but unverified
NCIT has no test case. It is implemented and registered, but
ontology_lookup_tests.jsonhas no NCIT entry, so it has never been checked against a real lookup in either language. The same is true of SNOMED, EFO and WBStrain, which predate this work. Filed upstream as Waltham-Data-Science/ndi-ontology-matlab#8; until cases exist there,test_case_table_covers_every_ported_providercarries them in aknown_gapsset so the omission stays visible rather than silent.Everything else this issue named is covered by live parity cases that pass.
Merged in ndi-ontology-python: #3 (providers + prefix registry), #4 (
lookup()raises), #5 (live-test gate).Generated by Claude Code