{"id":49643423,"url":"https://github.com/tacular-omics/psimodpy","last_synced_at":"2026-05-05T21:39:20.858Z","repository":{"id":353646173,"uuid":"1194002496","full_name":"tacular-omics/psimodpy","owner":"tacular-omics","description":"Python library for parsing and querying the PSIMOD post-translational modification (PTM) controlled vocabulary.","archived":false,"fork":false,"pushed_at":"2026-04-28T21:18:21.000Z","size":343,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-05T21:39:16.310Z","etag":null,"topics":["omics","ontology","peptide","protein","proteomics","psi","ptm"],"latest_commit_sha":null,"homepage":"https://tacular-omics.github.io/psimodpy/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tacular-omics.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-27T20:11:22.000Z","updated_at":"2026-04-27T19:48:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tacular-omics/psimodpy","commit_stats":null,"previous_names":["tacular-omics/psimodpy"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/tacular-omics/psimodpy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tacular-omics%2Fpsimodpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tacular-omics%2Fpsimodpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tacular-omics%2Fpsimodpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tacular-omics%2Fpsimodpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tacular-omics","download_url":"https://codeload.github.com/tacular-omics/psimodpy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tacular-omics%2Fpsimodpy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32669433,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-05T11:29:49.557Z","status":"ssl_error","status_checked_at":"2026-05-05T11:29:48.587Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["omics","ontology","peptide","protein","proteomics","psi","ptm"],"created_at":"2026-05-05T21:39:19.855Z","updated_at":"2026-05-05T21:39:20.845Z","avatar_url":"https://github.com/tacular-omics.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# psimodpy\n\n[![CI](https://github.com/tacular-omics/psimodpy/actions/workflows/ci.yml/badge.svg)](https://github.com/tacular-omics/psimodpy/actions/workflows/ci.yml)\n[![PyPI version](https://img.shields.io/pypi/v/psimodpy)](https://pypi.org/project/psimodpy/)\n[![Python](https://img.shields.io/pypi/pyversions/psimodpy)](https://pypi.org/project/psimodpy/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n\nPython library for parsing and querying the [PSI-MOD](https://github.com/HUPO-PSI/psi-mod-CV) protein modification ontology.\n\n- Zero core dependencies\n- Bundled PSI-MOD data (2,116 entries) — works offline out of the box\n- Typed, immutable data models (`py.typed` / PEP 561)\n- TSV/CSV export and round-trip OBO writer\n- Optional FastAPI / [Model Context Protocol](https://modelcontextprotocol.io) server (`pip install psimodpy[server]`)\n\n## Online Viewer\n#### [Click Me!](https://tacular-omics.github.io/psimodpy/)\n\nThe same database is also reachable as a hosted REST + MCP service — see\n[HTTP API and MCP Server](#http-api-and-mcp-server) below.\n\n## Installation\n\n```bash\npip install psimodpy\n```\n\nOr with [uv](https://docs.astral.sh/uv/):\n\n```bash\nuv add psimodpy\n```\n\nRequires Python 3.12+. No third-party dependencies.\n\n## Quick Start\n\n```python\nimport psimodpy\n\n# Load the bundled PSI-MOD database\ndb = psimodpy.load()\n\n# Lookup by ID\nentry = db[46]  # O-phospho-L-serine\nprint(entry.name)       # \"O-phospho-L-serine\"\nprint(entry.diff_mono)  # 79.966331\nprint(entry.origin)     # AminoAcid.SER\n\n# Lookup by name (case-insensitive)\nentry = db.get_by_name(\"O-phospho-L-serine\")\n\n# Also accepts MOD:NNNNN format\nentry = db.get_by_id(\"MOD:00046\")\n\n# Search across names, definitions, and synonyms\nresults = db.search(\"phospho\")\n\n# Find all modifications for an amino acid\nser_mods = db.get_by_origin(\"S\")\n\n# Filter entries\nslim = db.filter(slim_only=True, include_obsolete=False)\n\n# Formula parsing\nprint(entry.dict_diff_formula)      # {'C': 0, 'H': 0, 'N': 0, 'O': 3, 'P': 1}\nprint(entry.proforma_diff_formula)  # 'O3P'\n```\n\n## Exporting to TSV/CSV\n\n```python\n# Write all entries to a tab-separated file\ndb.write_tsv(\"psimod.tsv\")\n\n# Or CSV\ndb.write_tsv(\"psimod.csv\", delimiter=\",\")\n\n# Standalone function\nfrom psimodpy import write_tsv\nwrite_tsv(db, \"psimod.tsv\")\n```\n\nThe TSV includes one row per entry. Dynamic synonym columns (e.g. `synonym_psi_mod_label`,\n`synonym_omssa_label`) are added for each `SynonymType` found in the data.\n\n## Writing back to OBO format\n\n```python\n# Round-trip: write entries back to PSI-MOD OBO format\ndb.write_obo(\"out/psi-mod.obo\")\n\n# Re-parse — identical entry count and field values\ndb2 = psimodpy.parse_obo(\"out/psi-mod.obo\")\n\n# Standalone function; pass original header lines for a faithful round-trip\nfrom psimodpy import write_obo\nwrite_obo(db, \"out/psi-mod.obo\", header_lines=db.header_lines)\n```\n\n## HTTP API and MCP Server\n\nThe optional `[server]` extra ships a FastAPI app that exposes the same\ndatabase over a JSON REST API *and* over the\n[Model Context Protocol](https://modelcontextprotocol.io) so language-model\ntools can query PSI-MOD directly.\n\n```bash\npip install psimodpy[server]\nuvicorn psimodpy.server.app:app --reload\n```\n\n### REST endpoints\n\n| Method \u0026 path | Returns |\n|---------------|---------|\n| `GET /api/health` | Service metadata and entry count. |\n| `GET /api/entries?limit=\u0026offset=\u0026include_obsolete=` | Paginated full entries. |\n| `GET /api/entries/{id}` | One full entry by ID (`46` or `MOD:00046`). |\n| `GET /api/entries/by-name/{name}` | One full entry by exact name. |\n| `GET /api/entries/{id}/parents` | Direct `is_a` parents. |\n| `GET /api/entries/{id}/children` | Direct `is_a` children. |\n| `GET /api/by-origin/{aa}` | Entries with the given amino-acid origin. |\n| `GET /api/search?q=\u0026limit=` | Search hits as lightweight summaries. |\n\nFull entry payloads include `references` parsed from `definition_ref` into\n`{type, accession, value}` objects and a typed `origin` object (either\n`{type: \"amino_acid\", code}` or `{type: \"crosslink\", sites}`). Search\nresponses contain just `{id, accession, name, mass_mono, is_obsolete}` to\nkeep token cost low; call `/api/entries/{id}` on any hit for the full\nrecord.\n\n### MCP server\n\nThe same FastAPI app mounts an MCP endpoint at `POST /mcp` with these tools:\n\n| Tool | Purpose |\n|------|---------|\n| `get_by_id(id)` | Look up a single entry. |\n| `get_by_name(name)` | Exact name lookup. |\n| `search(query, limit=25)` | Full-text search returning summaries. |\n| `get_parents(id)` | Direct `is_a` parents of an entry. |\n| `get_children(id)` | Direct `is_a` children of an entry. |\n| `get_by_origin(aa)` | Entries with the given amino-acid origin. |\n\nTool responses use MCP's structured-output mechanism: the server emits an\n`outputSchema` per tool in `tools/list` and returns both `structuredContent`\n(typed Pydantic instance) and `content` (text fallback) on `tools/call`, so\nLLM clients can parse the response without re-reading the JSON string.\n\nConfigure your MCP-aware client to point at `http://localhost:8000/mcp`\n(or wherever you deploy the app). Example with the Anthropic CLI:\n\n```bash\nclaude mcp add psi-mod http://localhost:8000/mcp --transport http\n```\n\n## API Overview\n\n### Loading\n\n| Function | Description |\n|----------|-------------|\n| `psimodpy.load()` | Load the bundled PSI-MOD database. |\n| `psimodpy.load_from(path)` | Load from a custom OBO file. |\n| `psimodpy.parse_obo(path)` | Parse an OBO file into a database. |\n| `psimodpy.download_obo()` | Download the latest OBO file from GitHub. |\n| `psimodpy.write_tsv(entries, path, *, delimiter)` | Write entries to a TSV (or CSV) file. |\n| `psimodpy.write_obo(entries, path, *, header_lines)` | Write entries back to PSI-MOD OBO format. |\n\n### PsiModDatabase\n\n| Method | Description |\n|--------|-------------|\n| `db[id]` | Lookup by ID (int or `\"MOD:00046\"`), raises `KeyError`. |\n| `db.get_by_id(id)` | Lookup by ID, returns `None` if missing. |\n| `db.get_by_name(name)` | Case-insensitive name lookup. |\n| `db.search(query)` | Full-text search in names, definitions, synonyms. |\n| `db.get_by_origin(aa)` | Find entries by amino acid origin. |\n| `db.get_parents(entry)` | Direct parent entries (is_a hierarchy). |\n| `db.get_children(entry)` | Direct child entries. |\n| `db.get_related(entry, type)` | Follow relationship edges (derives_from, contains, etc.). |\n| `db.filter(...)` | Filter by obsolete/slim status. |\n| `db.write_tsv(path, *, delimiter)` | Write all entries to a TSV (or CSV) file. |\n| `db.write_obo(path)` | Write all entries back to OBO format. |\n| `db.header_lines` | Original header lines from the parsed OBO file. |\n\n### PsiModEntry\n\nEach entry provides: `id`, `name`, `definition`, `definition_ref`, `synonyms`, `is_a`, `relationships`,\n`origin`, `diff_mono`, `diff_avg`, `diff_formula`, `mass_mono`, `mass_avg`, `formula`,\n`term_spec`, `source`, `formal_charge`, `xref_unimod`, `xref_uniprot_ptm`, `xref_gnome`,\n`xref_remap`, `in_slim_subset`, `is_obsolete`.\n\nComputed properties: `dict_diff_formula`, `dict_formula`, `proforma_diff_formula`.\n\nEach `Synonym` has: `value`, `type` (`SynonymType`), `scope` (e.g. `\"EXACT\"`, `\"RELATED\"`).\n\n### Data Types\n\n- `AminoAcid` — single-letter amino acid codes\n- `Crosslink` — multi-residue or MOD-referenced origins\n- `Synonym` / `SynonymType` — typed synonyms\n- `Relationship` / `RelationshipType` — directed relationships\n- `TermSpec` — positional specificity\n- `Source` — modification origin\n\n## Development\n\n```bash\njust install   # install dependencies with uv\njust lint      # ruff check\njust format    # ruff format\njust ty        # ty type check\njust test      # pytest\njust check     # lint + type check + test\n```\n\n## Related Projects\n\n| Package | Description |\n|---------|-------------|\n| [unimodpy](https://github.com/tacular-omics/unimodpy) | Parse and query the UNIMOD mass spectrometry modifications database |\n| [uniprotptmpy](https://github.com/tacular-omics/uniprotptmpy) | Parse and query the UniProt PTM controlled vocabulary |\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftacular-omics%2Fpsimodpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftacular-omics%2Fpsimodpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftacular-omics%2Fpsimodpy/lists"}