mgbam commited on
Commit
e5ff04a
Β·
verified Β·
1 Parent(s): b305748

Update mcp/cbio.py

Browse files
Files changed (1) hide show
  1. mcp/cbio.py +54 -36
mcp/cbio.py CHANGED
@@ -1,45 +1,63 @@
 
 
1
  """
2
- MedGenesis v2 – core modules synchronised with the new helper API clients.
3
- Contains three top‑level files:
4
- β€’ mcp/cbio.py – cancer cohort variants via cBioPortal REST v3
5
- β€’ mcp/orchestrator.py – async pipeline coordinator
6
- β€’ app.py – Streamlit UI (CPU‑only)
7
-
8
- All modules assume the new helper files (mygene.py, ensembl.py, opentargets.py,
9
- drugcentral_ext.py, pubchem_ext.py, gene_hub.py, clinicaltrials.py, etc.) are
10
- present in the mcp package as created earlier in the conversation.
11
- """
12
 
13
- # ───────────────────────── mcp/cbio.py ────────────────────────────────
14
- """cBioPortal REST helper – returns detailed mutation calls for a gene.
15
- The public instance does **not** require an API‑key; however, if you have a
16
- personal or GENIE instance token set as CBIO_KEY, it will be used.
 
 
17
  """
18
- import os, httpx
 
 
 
 
19
  from functools import lru_cache
20
  from typing import List, Dict
21
 
22
- _CBIO_BASE = os.getenv("CBIO_BASE_URL", "https://www.cbioportal.org/api")
23
- _CBIO_TOKEN = os.getenv("CBIO_KEY")
24
- _HEADERS = {"accept": "application/json"}
25
- if _CBIO_TOKEN:
26
- _HEADERS["Authorization"] = f"Bearer {_CBIO_TOKEN}"
 
 
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  @lru_cache(maxsize=256)
29
- async def fetch_cbio_variants(
30
- gene_symbol: str,
31
- study: str = "brca_tcga_pan_can_atlas_2018",
32
- *,
33
- timeout: float = 15.0,
34
  ) -> List[Dict]:
35
- """Return list of variant dicts (DETAILED projection)."""
36
- profile = f"{study}_mutations"
37
- url = (
38
- f"{_CBIO_BASE}/molecular-profiles/{profile}/genes/{gene_symbol}/"
39
- "mutations"
40
- )
41
- params = {"projection": "DETAILED"}
42
- async with httpx.AsyncClient(timeout=timeout, headers=_HEADERS, follow_redirects=True) as client:
43
- r = await client.get(url, params=params)
44
- r.raise_for_status()
45
- return r.json()
 
 
 
 
 
 
1
+ # mcp/cbio.py – lightweight async wrapper for cBioPortal REST v3
2
+
3
  """
4
+ Fetch mutation summaries for a gene from a chosen study / molecular profile
5
+ using the public cBioPortal instance (or a private instance via token).
 
 
 
 
 
 
 
 
6
 
7
+ * Default public base URL: https://www.cbioportal.org/api
8
+ * Optionally read `CBIO_BASE` and `CBIO_KEY` from environment variables to
9
+ switch instance and/or add an `Authorization: Bearer <TOKEN>` header.
10
+ * Returns the JSON response directly (empty list on any 4xx/5xx).
11
+ * Response caching: `@lru_cache` to avoid repeated round‑trips for the same
12
+ (gene, profile) pair during a session.
13
  """
14
+
15
+ from __future__ import annotations
16
+
17
+ import os
18
+ import httpx
19
  from functools import lru_cache
20
  from typing import List, Dict
21
 
22
+ __all__ = ["fetch_cbio"]
23
+
24
+ # ---------------------------------------------------------------------------
25
+ # Configuration – overridable via env‑vars to support private portals
26
+ # ---------------------------------------------------------------------------
27
+ _BASE = os.getenv("CBIO_BASE", "https://www.cbioportal.org/api")
28
+ _TOKEN = os.getenv("CBIO_KEY")
29
 
30
+ _HEADERS: Dict[str, str] = {
31
+ "Accept": "application/json",
32
+ }
33
+ if _TOKEN:
34
+ _HEADERS["Authorization"] = f"Bearer {_TOKEN}"
35
+
36
+ _URL_TEMPLATE = (
37
+ "{base}/molecular-profiles/{profile}/genes/{gene}/mutations?projection=SUMMARY"
38
+ )
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # Public helper
42
+ # ---------------------------------------------------------------------------
43
  @lru_cache(maxsize=256)
44
+ async def fetch_cbio(
45
+ gene: str,
46
+ profile: str = "brca_tcga_pan_can_atlas_2018_mutations",
 
 
47
  ) -> List[Dict]:
48
+ """Return mutation summary list or an empty list on error/empty response."""
49
+
50
+ url = _URL_TEMPLATE.format(base=_BASE.rstrip("/"), profile=profile, gene=gene)
51
+
52
+ async with httpx.AsyncClient(timeout=15, headers=_HEADERS) as client:
53
+ try:
54
+ resp = await client.get(url)
55
+ # Treat 404/403 as empty but propagate other errors for logging
56
+ if resp.status_code == 200:
57
+ return resp.json() # type: ignore[return-value]
58
+ elif resp.status_code in (404, 403):
59
+ return []
60
+ resp.raise_for_status()
61
+ except Exception:
62
+ # network issue, invalid JSON, etc. – keep UX smooth
63
+ return []