"""Utilities for downloading biomodel models."""
import shutil
import tempfile
from pathlib import Path
from typing import List
import requests
from pymetadata.omex import EntryFormat, ManifestEntry, Omex
from requests.exceptions import HTTPError
from sbmlutils import log
from sbmlutils.console import console
from sbmlutils.resources import BIOMODELS_CURATED_PATH
[docs]logger = log.get_logger(__name__)
[docs]def download_file(url: str, path: Path) -> Path:
"""Download file from url to path.
Raises :class:`HTTPError`, if one occurred.
"""
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(path, "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
# If you have chunk encoded response uncomment if
# and set chunk_size parameter to None.
# if chunk:
f.write(chunk)
return path
[docs]def download_biomodel_omex(biomodel_id: str, omex_path: Path) -> Path:
"""Download omex for biomodel id.
This downloads the latest version of the OMEX from biomodels
via the rest service.
:returns: path to omex
Raises :class:`HTTPError`, if one occurred, i.e. if the model does not exist.
"""
url = f"https://www.ebi.ac.uk/biomodels/model/download/{biomodel_id}"
logger.info(f"Download '{url}' -> '{omex_path}'")
download_file(url, omex_path)
return omex_path
[docs]def download_biomodel_sbml(
biomodel_id: str, output_dir: Path, output_format: str = "sbml"
) -> List[str]:
"""Download SBML file for biomodel.
Retrieves the archive from biomodels and gets the SBML files from it.
Stores the raw SBML files for output_format='sbml' or creates an OMEX archive
in case of output_format='omex'.
:param output_format: 'sbml' or 'omex'
:return: list of location strings
Raises :class:`HTTPError`, if one occurred, i.e. if the model does not exist.
Raises :class:`ValueError`, if invalid format string is provided.
"""
with tempfile.TemporaryDirectory() as f_tmp:
tmp_path = Path(f_tmp)
omex_path = tmp_path / f"{biomodel_id}.omex"
download_biomodel_omex(biomodel_id=biomodel_id, omex_path=omex_path)
omex = Omex.from_omex(omex_path)
# get SBML models in archive
sbml_entries = omex.entries_by_format(format_key="sbml")
if not sbml_entries:
msg = f"No SBML entries found in archive '{omex_path}'."
logger.error(msg)
raise ValueError(msg)
if output_format == "omex":
omex_out_path = output_dir / f"{biomodel_id}.omex"
omex_out = Omex()
for sbml_entry in sbml_entries:
entry_path = omex.get_path(sbml_entry.location)
omex_out.add_entry(
entry_path=entry_path,
entry=ManifestEntry(
location=f"./{entry_path.name}",
format=EntryFormat.SBML,
),
)
omex_out.to_omex(omex_out_path)
logger.info(f"Save '{omex_path}'")
elif output_format == "sbml":
for sbml_entry in sbml_entries:
entry_path = omex.get_path(sbml_entry.location)
sbml_path = Path(output_dir) / sbml_entry.location
shutil.copyfile(src=entry_path, dst=sbml_path)
logger.info(f"Save '{sbml_path}'")
else:
raise ValueError(f"Unsupported format: '{output_format}'.")
return [e.location for e in sbml_entries]
[docs]def query_curated_biomodels() -> List[str]:
"""Query the curated biomodels.
:return List of biomodel identifiers
"""
url = "https://www.ebi.ac.uk/biomodels/search?query=curationstatus%3A%22Manually%20curated%22&numResults=1&format=json"
response = requests.get(url)
response.raise_for_status()
json = response.json()
matches: int = json["matches"]
offset = 0
biomodel_ids = []
while offset < matches:
url = f"https://www.ebi.ac.uk/biomodels/search?query=curationstatus%3A%22Manually%20curated%22&numResults=100&offset={offset}&format=json"
logger.info(url)
response = requests.get(url)
response.raise_for_status()
json = response.json()
ids = [model["id"] for model in json["models"]]
biomodel_ids.extend(ids)
offset += 100
logger.info(f"Retrieved '{len(biomodel_ids)}' identifiers")
return sorted(biomodel_ids)
[docs]def _create_biomodels_testfiles(output_dir: Path) -> None:
"""Download all curated biomodels and create omex files."""
# query the
biomodel_ids = query_curated_biomodels()
console.print(biomodel_ids)
for biomodel_id in biomodel_ids:
# download SBML model as omex
try:
download_biomodel_sbml(biomodel_id, output_dir, output_format="omex")
except HTTPError as err:
logger.error(f"Could not retrieve OMEX for biomodel: '{biomodel_id}'")
logger.error(err)
if __name__ == "__main__":
"""Download curated biomodels
This script provides support for downloading models from biomodels.
"""
with tempfile.TemporaryDirectory() as f_tmp:
[docs] output_dir = Path(f_tmp)
# output_dir = Path(__name__).parent / "tmp"
download_biomodel_omex(
biomodel_id="BIOMD0000000001",
omex_path=output_dir / "BIOMD0000000001_1.omex",
)
download_biomodel_sbml(
biomodel_id="BIOMD0000000001",
output_dir=output_dir,
output_format="sbml",
)
download_biomodel_sbml(
biomodel_id="BIOMD0000000001",
output_dir=Path(output_dir),
output_format="omex",
)
omex_path = output_dir / "BIOMD0000000001.omex"
omex = Omex.from_omex(omex_path)
console.log(omex)
_create_biomodels_testfiles(output_dir=BIOMODELS_CURATED_PATH)