Source code for tooluniverse.mpd_tool

import requests
from typing import Any, Dict
from urllib.parse import quote
from .base_tool import BaseTool
from .tool_registry import register_tool


[docs] @register_tool("MPDRESTTool") class MPDRESTTool(BaseTool):
[docs] def __init__(self, tool_config: Dict): super().__init__(tool_config) self.session = requests.Session() self.session.headers.update({"Accept": "application/json"}) self.timeout = 30
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: try: # Use ENCODE as alternative data source for biological samples. # MPD's own REST API (phenome.jax.org/api) has no endpoint that # takes a strain name + phenotype category directly -- confirmed # live, its phenotype endpoints require a measure ID or project # symbol the caller doesn't supply here. strain = arguments.get("strain", "C57BL/6J") limit = arguments.get("limit", 10) # searchTerm is a free-text match, unlike biosample_ontology.term_name # (a tissue/cell-type ontology field, not a strain field) -- confirmed # live the latter always returns zero results for real strain names, # while searchTerm correctly surfaces strain-mentioning experiments # (e.g. 292 hits for "C57BL/6J") and zero for strains ENCODE has no # data on (e.g. "DBA/2J"). url = ( "https://www.encodeproject.org/search/?type=Experiment" f"&searchTerm={quote(str(strain))}&format=json&limit={limit}" ) response = self.session.get(url, timeout=self.timeout) # ENCODE answers a search with no hits with 404, not an empty # result set. DBA/2J has no ENCODE data -- the comment above says # so, having checked it -- so Ex 3 of this tool's own examples # turned "nothing matched" into "MPD API error: 404 Client Error". # A search that found nothing is a successful search. if response.status_code == 404: # The 404 body is a complete ENCODE search response -- # @context "/terms/", @graph [], total 0, notification # "No results found" -- so it is handed back as-is rather than # synthesised, which also keeps it inside the declared schema. try: empty = response.json() except ValueError: empty = {"@context": "/terms/", "@graph": [], "total": 0} return { "status": "success", "data": empty, "url": url, "query_info": { "strain": strain, "limit": limit, "data_source": "ENCODE (MPD alternative)", "note": ( f"ENCODE has no experiment mentioning {strain!r}. " "Its search endpoint reports no hits as HTTP 404, so " "this is an empty result rather than a failure. For " "curated mouse phenotype data, query the Mouse " "Phenome Database directly at " "https://phenome.jax.org/api." ), }, } response.raise_for_status() # Parse JSON response data = response.json() return { "status": "success", "data": data, "url": url, "query_info": { "strain": strain, "limit": limit, "data_source": "ENCODE (MPD alternative)", "note": ( "ENCODE has no mouse-phenotype-by-strain data model, so " "results are general ENCODE experiments whose free text " "mentions this strain, not curated MPD phenotype " "measurements. 'phenotype_category' is not applied -- " "ENCODE has no equivalent concept. For genuine curated " "phenotype data, query the Mouse Phenome Database " "directly at https://phenome.jax.org/api." ), }, } except Exception as e: return {"status": "error", "error": f"MPD API error: {str(e)}"}