Skip to content

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.

  • dicom-standard-kb installed in the Python environment;
  • a local SQLite knowledge base;
  • the matching concrete edition.

Resolver functions live in:

dicom_kb.query.resolver
lookup_modality.py
from __future__ import annotations
import json
import sqlite3
from 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:

Terminal window
uv run python lookup_modality.py
inspect_ct.py
from __future__ import annotations
import sqlite3
from 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.

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.

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.

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.