Skip to main content

UMLS Python Client

Production-ready Python SDK for the National Library of Medicine UMLS Terminology Services APIs.

umls-python-client keeps the original UMLSClient interface for existing users and adds typed sync, async, export, release, and workflow helpers for new applications. It is designed for developers and researchers who need a practical one-stop Python client for UMLS search, concepts, source vocabularies, semantic types, crosswalks, metadata, and UTS release downloads.

Why This Client

  • Current NLM REST coverage, including the May 4, 2026 search filters semanticTypes and semanticGroups.
  • Typed sync and async clients built on httpx.
  • Backward-compatible legacy client with the original camelCase namespaces.
  • Structured exceptions for modern clients and legacy error payloads for older code.
  • JSON, JSONL, CSV, and RDF/Turtle exports.
  • Practical helpers for bulk search, bulk crosswalk, concept profiles, source lookup, UMLS URL following, API-key validation, and release downloads.
  • CI across Python 3.9 through 3.14.

Installation

pip install umls-python-client

For local development:

pip install ".[dev,docs]"

Authentication

Most UMLS requests require an API key from your UTS profile: https://documentation.uts.nlm.nih.gov/rest/authentication.html

import os

api_key = os.environ["UMLS_API_KEY"]

The metadata sources endpoint is public and does not require authentication, but the client still uses one consistent client configuration.

Typed Sync Quickstart

from umls_python_client import TypedUMLSClient

with TypedUMLSClient(api_key="YOUR_UMLS_API_KEY") as client:
    response = client.search_api.search(
        "diabetes",
        semantic_groups="Disorders",
        page_size=25,
    )

    for result in response.result:
        print(result.ui, result.name)

Typed methods return UMLSResponse[T]. Use response.result for parsed models, response.raw or response.to_dict() for the original UMLS envelope, and response.to_rdf() for Turtle RDF.

Async Quickstart

from umls_python_client import AsyncUMLSClient


async def main() -> None:
    async with AsyncUMLSClient(api_key="YOUR_UMLS_API_KEY") as client:
        response = await client.crosswalk_api.get_crosswalk(
            source="HPO",
            id="HP:0001947",
            target_source="SNOMEDCT_US",
        )
        print(response.result)

Legacy Compatible Usage

UMLSClient keeps existing imports, JSON string defaults, and camelCase namespaces:

from umls_python_client import UMLSClient

client = UMLSClient(api_key="YOUR_UMLS_API_KEY")

pretty_json = client.searchAPI.search("diabetes")
raw_dict = client.search_api.search("diabetes", return_indented=False)
rdf = client.cui_api.get_cui_info("C0011849", format="rdf")

Existing namespaces are preserved:

  • client.searchAPI
  • client.sourceAPI
  • client.cuiAPI
  • client.semanticNetworkAPI
  • client.crosswalkAPI
  • client.metadataAPI
  • client.atomAPI
  • client.authAPI
  • client.releaseAPI

Modern namespaces are also available:

  • search_api
  • source_api
  • cui_api
  • semantic_network_api
  • crosswalk_api
  • metadata_api
  • atom_api
  • auth_api
  • release_api

Common Recipes

response = client.search_api.search(
    "depression",
    semantic_types="T047|T046",
    semantic_groups="Disorders",
)

semantic_types supports semantic type TUIs, semantic type names, and semantic tree number prefixes. Use pipes for multiple values, matching NLM's search documentation.

Source Code To CUI

response = client.search_api.search(
    "9468002",
    input_type="sourceUi",
    search_type="exact",
    sabs="SNOMEDCT_US",
)

HPO To SNOMED CT Crosswalk

response = client.crosswalk_api.get_crosswalk(
    source="HPO",
    id="HP:0001947",
    target_source="SNOMEDCT_US",
)

UMLS CUI crosswalks are useful starting points for mapping work. Review results before using them in clinical or research pipelines.

Concept Profile

profile = client.cui_api.get_concept_profile(
    "C0011849",
    include_atoms=False,
).result

print(profile.concept.name)
print([definition.value for definition in profile.definitions])

Metadata Lookup

sources = client.metadata_api.find_source(abbreviation="SNOMEDCT_US").result

Bulk Workflows

searches = client.search_api.bulk_search(["diabetes", "asthma"])
crosswalks = client.crosswalk_api.bulk_crosswalk(
    ["HP:0001947", "HP:0001250"],
    source="HPO",
    target_source="SNOMEDCT_US",
)

Follow UMLS URLs

Many UMLS payload fields contain URLs to related resources. Follow those URLs with the same authenticated client:

concept = client.cui_api.get_cui_info("C0011849").result
atoms = client.follow_url(concept.raw["atoms"])

Release Downloads

releases = client.release_api.list_releases(
    release_type="umls-full-release",
    current=True,
)

client.release_api.download_file(
    url=releases.result[0].url,
    path="downloads",
)

Call list_releases() without a release_type to inspect NLM's release catalog, or pass a release type such as umls-full-release to discover current download URLs.

Exports

Typed responses can save themselves:

response = client.search_api.search("fracture", page_size=25)

response.save("exports/search", format="jsonl")
response.save("exports/search.csv", format="csv")
response.save("exports/search.ttl", format="rdf")

Clients can export any response or raw payload:

client.export(response, "exports/search.json", format="json", overwrite=True)

Supported formats:

Format Output
json Full UMLS response envelope
jsonl One result record per line
csv Flattened scalar result fields
rdf Turtle RDF

If the path has a file suffix, the client writes exactly there. If the path is a directory or suffixless path, parent directories are created and a safe filename is generated.

Legacy save_to_file=True still works and now delegates to the same export implementation.

Endpoint Coverage

Namespace Coverage Pagination behavior
search_api /search/{version} with semantic filters Sends pageSize; no obsolete pageNumber
metadata_api /metadata/{version}/sources No auth required
cui_api CUI detail, atoms, preferred atom, definitions, relations Pagination where NLM documents it
atom_api AUI detail, parents, children, ancestors, descendants Sends pageSize; no pageNumber
source_api Source detail, atoms, preferred atom, hierarchy, attributes, relations Pagination where NLM documents it
crosswalk_api Source identifier crosswalk Supports documented pagination
semantic_network_api Semantic type lookup Single resource
auth_api UMLS license/API-key validation UTS validation endpoint
release_api Release listing and authenticated downloads UTS release/download endpoints

Error Handling

Typed clients raise structured exceptions:

  • UMLSRequestError
  • UMLSHTTPError
  • UMLSDecodeError

Legacy UMLSClient methods keep returning error payload dictionaries instead of raising for UMLS request failures.

Configure timeouts and retries at client construction:

client = TypedUMLSClient(
    api_key="YOUR_UMLS_API_KEY",
    timeout=20.0,
    retries=3,
)

Testing

ruff check .
ruff format --check .
mypy src
pytest
mkdocs build --strict
python -m build

Live integration tests are optional and require UMLS_API_KEY. Tests that would validate user keys or download release files remain opt-in and do not run in default CI.

Migration Notes

From 1.0.x and 1.1.0:

  • Existing imports and UMLSClient behavior remain supported.
  • Prefer TypedUMLSClient for new sync code.
  • Prefer AsyncUMLSClient for async applications.
  • Prefer response.save(...) or client.export(...) over new uses of save_to_file=True.
  • Use snake_case namespaces in new code. CamelCase namespaces remain available for compatibility.

Documentation

Releases

This repository uses Release Please and PyPI trusted publishing. Merged commits should use Conventional Commit prefixes:

  • fix: for patch releases
  • feat: for minor releases
  • feat!: or fix!: for major releases

Release Please opens a release PR. Merging that release PR creates the GitHub Release, builds distributions, attaches artifacts, and publishes to PyPI.

GitHub Actions must be allowed to create release PRs, or the repository must provide a RELEASE_PLEASE_TOKEN secret with PR permissions.

License

Apache-2.0. See LICENSE.

Metadata

Release files for umls-python-client 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for umls-python-client 1.2.0
File Size Uploaded
umls_python_client-1.2.0.tar.gz 39.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for umls-python-client 1.2.0
File Interpreter ABI Platform
umls_python_client-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 77.5 kB

Release files / umls_python_client-1.2.0.tar.gz

Download URL umls_python_client-1.2.0.tar.gz
Size 39.8 kB
Tags Source
SHA-256 checksum
How to use checksums
ba86fbb2ba3f70931cfc62295805839a2b2d3771c3c0941c1f38183856587daf
BLAKE2b-256 checksum
How to use checksums
48fca024ee2932322a72664b676ec5557edf1fbf3506db6b4908c06dc16c88ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 27, 2026.

Transparency log

Release files / umls_python_client-1.2.0-py3-none-any.whl

Download URL umls_python_client-1.2.0-py3-none-any.whl
Size 37.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c782eff4311d7b96c4df51977eff17fa65da81a3bb331c521d50679cacf7dca7
BLAKE2b-256 checksum
How to use checksums
f6fd003bebfb60a9b2166e2bc14b316eb6337425bef42ea71105888aa7c1b06e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.2.0 This release

2 release files

1.1.0

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page