Source code for tooluniverse.tumorhope2_tool

"""TumorHoPe 2 tumor-homing peptide tool (live REST, keyless).

TumorHoPe 2 / TumorHope2 (Raghava lab, IIITD) is a database of tumor-homing
peptides used for drug-delivery targeting. This tool provides a non-immune
targeting-peptide capability absent from ToolUniverse: given a source (peptide
source label), target tumor, source name, or conjugate it returns the peptide
sequence, target tumor / cell, receptor / biomarker, terminal modifications,
phage-display origin, and in-vitro / in-vivo evidence.

The public API is keyless. Unlike the other IIITD peptide APIs it does NOT use
``dataType``/``dataValue`` and does NOT support sequence queries; it accepts
one or more of these query parameters directly::

    api.php?source=A33H
    api.php?target_tumor=Brain%20tumor
    api.php?name_source=...
    api.php?conjugate=...

A successful response is a JSON object ``{"status": "success",
"message": ..., "count": int, "results": [ ... ]}``. A no-match query returns
``{"status": "success", "message": "No results found", "count": 0,
"results": []}``.
"""

from typing import Any, Dict

import requests

from .base_tool import BaseTool
from .tool_registry import register_tool

_BASE_URL = "https://webs.iiitd.edu.in/raghava/tumorhope2/restapi/api.php"
_TIMEOUT = 30
_HEADERS = {"Accept": "application/json"}

# user-arg -> TumorHope2 query parameter (all map 1:1 here).
_PARAM_KEYS = ("source", "target_tumor", "name_source", "conjugate")


def _err(message: str, **extra: Any) -> Dict[str, Any]:
    out: Dict[str, Any] = {"status": "error", "error": message}
    out.update(extra)
    return out


[docs] @register_tool( "TumorHope2SearchPeptidesTool", config={ "name": "TumorHope2_search_peptides", "type": "TumorHope2SearchPeptidesTool", "description": ( "Search TumorHoPe 2 (Raghava lab, IIITD) for TUMOR-HOMING peptide " "records used in drug delivery. Filter by 'source' (peptide source " "label, e.g. A33H), 'target_tumor' (e.g. 'Brain tumor'), " "'name_source', or 'conjugate'. Each record returns the peptide " "sequence, target tumor / cell, receptor / biomarker, N/C-terminus " "modifications, sequence motif, phage-display origin, in-vitro and " "in-vivo evidence, conjugate, PubMed ID, year, and title. Note: " "this API does not support sequence search. Keyless public API." ), "parameter": { "type": "object", "properties": { "source": { "type": "string", "description": ( "Peptide source label. Example: 'A33H' -> 1 record " "(SIWV, a brain-tumor-homing tetrapeptide)." ), }, "target_tumor": { "type": "string", "description": ( "Target tumor type. Example: 'Brain tumor' -> ~39 records." ), }, "name_source": { "type": "string", "description": "Source name to match.", }, "conjugate": { "type": "string", "description": ( "Conjugate / payload label (e.g. a fluorophore or " "nanoparticle)." ), }, }, "required": [], }, "return_schema": { "oneOf": [ { "type": "object", "properties": { "status": {"const": "success"}, "data": { "type": "array", "items": {"type": "object"}, "description": ( "Matching tumor-homing peptide records. Each " "has id, title, pmid, year, source, " "name_source, sequence, n_term, c_term, motif, " "target_tumor, target_cell, " "receptors_biomarker, phage_display, invitro, " "invivo." ), }, "metadata": {"type": "object"}, }, "required": ["status", "data", "metadata"], }, { "type": "object", "properties": { "status": {"const": "error"}, "error": {"type": "string"}, }, "required": ["status", "error"], }, ] }, "test_examples": [ {"source": "A33H"}, {"target_tumor": "Brain tumor"}, ], }, ) class TumorHope2SearchPeptidesTool(BaseTool): """Search TumorHoPe 2 tumor-homing peptide records."""
[docs] def run(self, arguments: Dict[str, Any]) -> Dict[str, Any]: arguments = arguments or {} params: Dict[str, Any] = {} for key in _PARAM_KEYS: val = arguments.get(key) if val is not None and str(val).strip() != "": params[key] = str(val) if not params: return _err( "At least one search filter is required: source, " "target_tumor, name_source, or conjugate." ) try: resp = requests.get( _BASE_URL, params=params, headers=_HEADERS, timeout=_TIMEOUT ) except requests.exceptions.RequestException as exc: return _err(f"Request to TumorHoPe 2 failed: {exc}") if resp.status_code != 200: return _err( f"TumorHoPe 2 returned HTTP {resp.status_code}", url=resp.url, response_snippet=(resp.text or "")[:200], ) try: payload = resp.json() except ValueError: return _err( "TumorHoPe 2 returned a non-JSON response", url=resp.url, response_snippet=(resp.text or "")[:200], ) if not isinstance(payload, dict): return _err("Unexpected TumorHoPe 2 response shape", url=resp.url) # The API signals a malformed query with status="error". if payload.get("status") == "error": return _err( payload.get("message") or "TumorHoPe 2 rejected the query", url=resp.url, ) records = payload.get("results") if not isinstance(records, list): return _err("Unexpected TumorHoPe 2 data shape", url=resp.url) return { "status": "success", "data": records, "metadata": { "source": "TumorHoPe 2 (Raghava lab, IIITD)", "url": resp.url, "query": params, "total_count": payload.get("count", len(records)), "returned_count": len(records), "message": payload.get("message"), }, }