Use the Python resolver API
Use the Python API when a local program needs structured DICOM Standard facts without launching a subprocess or MCP server.
Prerequisites
Section titled “Prerequisites”dicom-standard-kbinstalled in the Python environment;- a local SQLite knowledge base;
- the matching concrete edition.
Resolver functions live in:
dicom_kb.query.resolverComplete lookup example
Section titled “Complete lookup example”from __future__ import annotations
import jsonimport sqlite3from pathlib import Path
from dicom_kb.query.resolver import lookup_data_element
def connect_read_only(path: Path) -> sqlite3.Connection: connection = sqlite3.connect(f"file:{path}?mode=ro", uri=True) connection.row_factory = sqlite3.Row return connection
database = Path("/tmp/dicom-kb-fixture.sqlite")edition = "2026b"
with connect_read_only(database) as connection: response = lookup_data_element( connection, tag_or_keyword="(0008,0060)", edition=edition, )
print(json.dumps(response.model_dump(mode="json"), indent=2, sort_keys=True))Run it from the source environment:
uv run python lookup_modality.pyReuse one connection for related queries
Section titled “Reuse one connection for related queries”from __future__ import annotations
import sqlite3from pathlib import Path
from dicom_kb.query.resolver import ( list_modules_for_iod, lookup_data_element, resolve_attribute_context,)
def connect_read_only(path: Path) -> sqlite3.Connection: connection = sqlite3.connect(f"file:{path}?mode=ro", uri=True) connection.row_factory = sqlite3.Row return connection
database = Path("/path/to/edition.sqlite")edition = "2025e" # Replace with the database's concrete edition.
with connect_read_only(database) as connection: element = lookup_data_element( connection, tag_or_keyword="Modality", edition=edition, ) modules = list_modules_for_iod( connection, iod_name="CT Image", edition=edition, ) context = resolve_attribute_context( connection, attribute="Modality", iod_name="CT Image", edition=edition, )
for response in (element, modules, context): print(response.status, response.tool, response.warnings)The caller owns the connection lifecycle. A read-only URI protects the database from accidental writes during queries.
Handle structured outcomes
Section titled “Handle structured outcomes”Resolver input problems and absent matches are normally represented in the response:
if response.status == "ok": use_result(response.result)elif response.status == "not_found": report_absence(response.result, response.refs, response.warnings)else: report_invalid_input(response.result)Do not assume that a returned ToolResponse is an ok result. Database-open
errors and lower-level SQLite failures can still raise normal Python
exceptions.
Preserve Pydantic types or serialize explicitly
Section titled “Preserve Pydantic types or serialize explicitly”Keep the ToolResponse object when another Python component can use typed
fields. Serialize for logs or process boundaries with:
payload = response.model_dump(mode="json", exclude_none=True)This is the same public JSON shape emitted by the CLI and MCP adapter.
Choose a resolver
Section titled “Choose a resolver”The direct API includes functions for:
- data elements and UIDs;
- IODs, SOP Classes, modules, and attribute rows;
- contextual attribute use;
- enumerated values and defined terms;
- VRs, transfer syntaxes, and encoding explanations;
- DICOMweb transactions and media types;
- SR templates, context groups, and code meanings;
- cited text search and retrieval.
Use Python resolver API for exact function names and arguments.
Avoid coupling to database tables
Section titled “Avoid coupling to database tables”Prefer resolver functions over direct SQL for application behavior. The resolver layer supplies:
- identifier normalization and validation;
- deterministic ambiguity handling;
- source references;
- response classification;
- parse confidence;
- trace metadata.
Direct SQL is appropriate for contributor diagnostics, migrations, and parser development, but it bypasses the public answer contract.