KCNG-Explorer / src /structure.py
khairi's picture
Claude Sonnet 5
Remove dangling streamlit imports, add precomputed matrix data
9775cc8
Raw History Blame Contribute Delete
3.01 kB
"""Fetching 3D protein structures: experimental structures UniProt
cross-references (RCSB PDB) when available, otherwise the public AlphaFold
DB's predicted model."""
from __future__ import annotations
from dataclasses import dataclass
import requests
UNIPROT_ENTRY_URL = "https://rest.uniprot.org/uniprotkb/{accession}.json"
ALPHAFOLD_PREDICTION_URL = "https://alphafold.ebi.ac.uk/api/prediction/{accession}"
RCSB_PDB_URL = "https://files.rcsb.org/download/{pdb_id}.pdb"
@dataclass
class PdbCrossReference:
pdb_id: str
method: str | None
resolution: str | None
chains: str | None
@dataclass
class AlphaFoldPrediction:
pdb_url: str
mean_plddt: float | None
model_created_date: str | None
def fetch_pdb_cross_references(accession: str, timeout: float = 10.0) -> list[PdbCrossReference]:
"""Experimental structures UniProt cross-references to RCSB PDB for
`accession` (often empty — most proteins have no solved structure)."""
url = UNIPROT_ENTRY_URL.format(accession=accession.strip())
response = requests.get(url, timeout=timeout)
response.raise_for_status()
entry = response.json()
references = []
for xref in entry.get("uniProtKBCrossReferences", []):
if xref.get("database") != "PDB":
continue
properties = {p["key"]: p["value"] for p in xref.get("properties", [])}
references.append(
PdbCrossReference(
pdb_id=xref.get("id"),
method=properties.get("Method"),
resolution=properties.get("Resolution"),
chains=properties.get("Chains"),
)
)
return references
def fetch_alphafold_prediction(accession: str, timeout: float = 10.0) -> AlphaFoldPrediction | None:
"""Metadata for `accession`'s AlphaFold DB prediction (including the
*current* model file URLs — AlphaFold DB periodically republishes
models under a new version number, so this is fetched from the API
rather than guessed/hardcoded), or None if it has no model."""
url = ALPHAFOLD_PREDICTION_URL.format(accession=accession.strip())
response = requests.get(url, timeout=timeout)
if response.status_code == 404:
return None
response.raise_for_status()
entries = response.json()
if not entries:
return None
entry = entries[0]
return AlphaFoldPrediction(
pdb_url=entry["pdbUrl"],
mean_plddt=entry.get("globalMetricValue"),
model_created_date=entry.get("modelCreatedDate"),
)
def fetch_structure_text(url: str, timeout: float = 20.0) -> str:
"""Raw PDB-format text from any public URL (AlphaFold DB or RCSB)."""
response = requests.get(url, timeout=timeout)
response.raise_for_status()
return response.text
def fetch_pdb_structure(pdb_id: str, timeout: float = 20.0) -> str:
"""An experimental structure from RCSB PDB, as PDB text."""
return fetch_structure_text(RCSB_PDB_URL.format(pdb_id=pdb_id.strip()), timeout=timeout)