Skip to main content

unimodpy

CI PyPI version Python License: MIT

Python library for parsing and querying the UNIMOD mass spectrometry modifications database.

  • Zero core dependencies
  • Bundled UNIMOD data (1,552 entries) — works offline out of the box
  • Typed, immutable data models (py.typed / PEP 561)
  • TSV/CSV export and round-trip OBO writer
  • Optional FastAPI / Model Context Protocol server (pip install unimodpy[server])

Online Viewer

Click Me!

The same database is also reachable as a hosted REST + MCP service — see HTTP API and MCP Server below.

Installation

pip install unimodpy

Or with uv:

uv add unimodpy

Requires Python 3.12+. No third-party dependencies.

Quick Start

import unimodpy

# Load the bundled UNIMOD database (no file path needed)
db = unimodpy.load()

# Look up by ID
acetyl = db.get_by_id(1)          # integer
acetyl = db.get_by_id("UNIMOD:1") # UNIMOD accession string
acetyl = db["UNIMOD:1"]           # subscript notation

# Look up by name (case-insensitive)
phospho = db.get_by_name("Phospho")

# Full-text search across name, definition, and synonyms
hits = db.search("glycosyl")

print(acetyl)
# UNIMOD:1  Acetyl
#   Acetylation.
#   Formula  : C2H2O
#   Mass     : +42.010565 Da (mono)  +42.0373 Da (avg)
#   Sites (9):
#     1: K @ Anywhere [Post-translational]
#     ...

Refreshing from unimod.org

# Download the latest OBO and use it immediately
db = unimodpy.load(refresh=True)

# Or just download the file
path = unimodpy.download()                        # ~/.cache/unimodpy/UNIMOD.obo
path = unimodpy.download("/my/dir/UNIMOD.obo")    # custom destination

Loading a Custom File

db = unimodpy.load("/path/to/UNIMOD.obo")
# or low-level:
db = unimodpy.parse_obo("/path/to/UNIMOD.obo")

Working with Entries

Each UnimodEntry is a frozen dataclass:

entry = db.get_by_name("Carbamidomethyl")

entry.id                  # int — UNIMOD accession number
entry.name                # str
entry.delta_mono_mass     # float — monoisotopic mass shift in Da
entry.delta_avge_mass     # float — average mass shift in Da
entry.proforma_formula    # str — Hill-notation formula, e.g. "C3H5NO"
entry.dict_composition    # dict[str, int] — {"C": 3, "H": 5, "N": 1, "O": 1}
entry.synonyms            # tuple[str, ...] — alternative names
entry.specificities       # tuple[Specificity, ...] — site/position rules

for spec in entry.specificities:
    print(spec.site)            # Site enum, e.g. Site.C ("C")
    print(spec.position)        # Position enum, e.g. Position.ANYWHERE
    print(spec.classification)  # Classification enum
    for nl in spec.neutral_losses:
        print(nl.mono_mass, nl.proforma_formula)

Enums

Site, position, and classification values are typed StrEnum members:

from unimodpy import Site, Position, Classification

ptm_sites = [
    spec for spec in entry.specificities
    if spec.classification == Classification.POST_TRANSLATIONAL
    and spec.position == Position.ANYWHERE
]

Exporting to TSV/CSV

# Write all entries to a tab-separated file
db.write_tsv("unimod.tsv")

# Or CSV
db.write_tsv("unimod.csv", delimiter=",")

# Standalone function
from unimodpy import write_tsv
write_tsv(db, "unimod.tsv")

The TSV includes one row per entry. Specificities are serialized as a compact site:position:classification summary (e.g. K:Anywhere:Post-translational).

Writing back to OBO format

# Round-trip: write entries back to UNIMOD OBO format
db.write_obo("out/UNIMOD.obo")

# Re-parse — identical entry count and field values (including citations)
db2 = unimodpy.parse_obo("out/UNIMOD.obo")

# Standalone function; pass the original header lines for a faithful round-trip
from unimodpy import write_obo
write_obo(db, "out/UNIMOD.obo", header_lines=db.header_lines)

HTTP API and MCP Server

The optional [server] extra ships a FastAPI app that exposes the same database over a JSON REST API and over the Model Context Protocol so language-model tools can query UNIMOD directly.

pip install unimodpy[server]
uvicorn unimodpy.server.app:app --reload

REST endpoints

Method & path Returns
GET /api/health Service metadata and entry count.
GET /api/entries?limit=&offset=&include_hidden= Paginated full entries.
GET /api/entries/{id} One full entry by ID (1 or UNIMOD:1).
GET /api/entries/by-name/{name} One full entry by exact name.
GET /api/search?q=&limit= Search hits as lightweight summaries.

Hidden specificities (UNIMOD's hidden=true sites) are filtered out by default; pass ?include_hidden=true to keep them.

Full entry payloads include references parsed from definition_ref into {type, accession, value} objects and parent_id (the entry's UNIMOD hierarchy parent). Search responses contain just {id, accession, name, delta_mono_mass, proforma_formula} to keep token cost low; call /api/entries/{id} on any hit for the full record.

MCP server

The same FastAPI app mounts an MCP endpoint at POST /mcp with three tools:

Tool Purpose
get_by_id(id, include_hidden=False) Look up a single entry.
get_by_name(name, include_hidden=False) Exact name lookup.
search(query, limit=25) Full-text search returning summaries.

Tool responses use MCP's structured-output mechanism: the server emits an outputSchema per tool in tools/list and returns both structuredContent (typed Pydantic instance) and content (text fallback) on tools/call, so LLM clients can parse the response without re-reading the JSON string.

Configure your MCP-aware client to point at http://localhost:8000/mcp (or wherever you deploy the app). Example with the Anthropic CLI:

claude mcp add unimod http://localhost:8000/mcp --transport http

API Overview

Symbol Description
load(source=None, *, refresh=False) Load the database. No args -> bundled file. refresh=True -> download first.
download(dest=None) Download latest OBO from unimod.org; returns Path.
parse_obo(path) Low-level: parse any OBO file at path.
write_tsv(entries, path, *, delimiter) Write entries to a TSV (or CSV) file.
write_obo(entries, path, *, header_lines) Write entries back to UNIMOD OBO format.
UnimodDatabase Iterable collection with get_by_id, get_by_name, search, write_tsv(), write_obo(), __getitem__. Also exposes header_lines.
UnimodEntry Frozen dataclass for one modification term. Includes definition_ref.
Specificity Frozen dataclass for one site/position rule.
NeutralLoss Frozen dataclass for one neutral loss.
Site StrEnum of amino acid residues and termini.
Position StrEnum of sequence position constraints.
Classification StrEnum of modification classes.

Development

just install   # install dependencies with uv
just lint      # ruff check
just format    # ruff format
just ty        # ty type check
just test      # pytest
just check     # lint + type check + test
Package Description
uniprotptmpy Parse and query the UniProt PTM controlled vocabulary
psimodpy Parse and query the PSI-MOD protein modification ontology

License

MIT

Release files for unimodpy 0.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 unimodpy 0.2.0
File Size Uploaded
unimodpy-0.2.0.tar.gz 227.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for unimodpy 0.2.0
File Interpreter ABI Platform
unimodpy-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 403.2 kB

Release files / unimodpy-0.2.0.tar.gz

Download URL unimodpy-0.2.0.tar.gz
Size 227.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7a668c65e3df1c4f879d1d583234b03f4cf41e7de8d352d2a6be77e8da5ba2d5
BLAKE2b-256 checksum
How to use checksums
52f4ed8abed256f2dde4129bb82cf5ffde277b8ad75bcce280fe348e44c2859e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 23, 2026.

Transparency log

Release files / unimodpy-0.2.0-py3-none-any.whl

Download URL unimodpy-0.2.0-py3-none-any.whl
Size 175.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ec7a1607cb341a0006668428ca4670f3c19e9e07898e76b7ea0d6f6b6c9a6bb3
BLAKE2b-256 checksum
How to use checksums
7042cba08b3d7869246d8638f74c634d9fa32965ff1c4ec4d5b1dbb64d56e325
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Sep 23, 2026.

Transparency log

Release history Release notifications | RSS feed

1.1.1

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

This release

0.2.0 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.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