-
Notifications
You must be signed in to change notification settings - Fork 218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add embl gems repository #1282
base: devel
Are you sure you want to change the base?
Changes from all commits
dbdec10
bb2372d
f7bfa8c
b298b23
6ecf224
5b2258f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,98 @@ | ||||||
""" | ||||||
Provide a concrete implementation of the carveme repository interface. | ||||||
""" | ||||||
|
||||||
|
||||||
from io import BytesIO | ||||||
|
||||||
import httpx | ||||||
|
||||||
from .abstract_model_repository import AbstractModelRepository | ||||||
|
||||||
|
||||||
def _decode_model_path(model_path): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make this a class method. |
||||||
"""Decode the model path to EMBL GEMs.""" | ||||||
tokens = model_path.split("_") | ||||||
genus = tokens[0] | ||||||
|
||||||
directory = genus.lower() | ||||||
alphabet = directory[0] | ||||||
|
||||||
return f"{alphabet}/{directory}/{model_path}" | ||||||
|
||||||
|
||||||
class EMBLGems(AbstractModelRepository): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||||||
""" | ||||||
Define a concrete implementation of the EMBL GEMs repository. | ||||||
|
||||||
Attributes | ||||||
---------- | ||||||
name : str | ||||||
The name of the EMBL GEMs repository. | ||||||
|
||||||
""" | ||||||
|
||||||
name: str = "EMBL GEMs" | ||||||
|
||||||
def __init__( | ||||||
self, | ||||||
**kwargs, | ||||||
) -> None: | ||||||
""" | ||||||
Initialize a EMBL GEMs repository interface. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Other Parameters | ||||||
---------------- | ||||||
kwargs | ||||||
Passed to the parent constructor in order to enable multiple inheritance. | ||||||
|
||||||
""" | ||||||
super().__init__( | ||||||
url="https://github.com/cdanielmachado/embl_gems/blob/master/models/", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Access the raw content directly:
Suggested change
|
||||||
**kwargs, | ||||||
) | ||||||
|
||||||
def get_sbml(self, model_id: str) -> bytes: | ||||||
""" | ||||||
Attempt to download an SBML document from the repository. | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
model_id : str | ||||||
The identifier of the desired metabolic model. This is typically repository | ||||||
specific. | ||||||
|
||||||
Returns | ||||||
------- | ||||||
bytes | ||||||
A gzip-compressed, UTF-8 encoded SBML document. | ||||||
|
||||||
Raises | ||||||
------ | ||||||
httpx.HTTPError | ||||||
In case there are any connection problems. | ||||||
|
||||||
""" | ||||||
compressed = BytesIO() | ||||||
|
||||||
decoded_path = _decode_model_path(model_id) | ||||||
|
||||||
filename = f"{model_id}.xml.gz" | ||||||
print(self._url.join(decoded_path).join(filename)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove the print or use logging instead. |
||||||
with self._progress, httpx.stream( | ||||||
method="GET", | ||||||
url=self._url.join(decoded_path).join(filename), | ||||||
params={"raw": "true"}, | ||||||
follow_redirects=True, | ||||||
) as response: | ||||||
response.raise_for_status() | ||||||
task_id = self._progress.add_task( | ||||||
description="download", | ||||||
total=int(response.headers["Content-Length"]), | ||||||
model_id=model_id, | ||||||
) | ||||||
for chunk in response.iter_bytes(): | ||||||
compressed.write(chunk) | ||||||
self._progress.update(task_id=task_id, advance=len(chunk)) | ||||||
compressed.seek(0) | ||||||
return compressed.read() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -8,7 +8,7 @@ | |||||
import pytest | ||||||
|
||||||
from cobra import Configuration | ||||||
from cobra.io import BiGGModels, BioModels, load_model | ||||||
from cobra.io import BiGGModels, BioModels, EMLBGems, load_model | ||||||
|
||||||
|
||||||
if TYPE_CHECKING: | ||||||
|
@@ -39,6 +39,12 @@ def biomodels(mini_sbml: bytes, mocker: "MockerFixture") -> Mock: | |||||
result.get_sbml.return_value = mini_sbml | ||||||
return result | ||||||
|
||||||
@pytest.fixture | ||||||
def embl_gems(mini_sbml: bytes, mocker: "MockerFixture") -> Mock: | ||||||
"""Provide a mocked EMBL Gems repository interface.""" | ||||||
result = mocker.Mock(spec_set=EMLBGems) | ||||||
result.get_sbml.return_value = mini_sbml | ||||||
return result | ||||||
|
||||||
def test_bigg_access(bigg_models: Mock) -> None: | ||||||
"""Test that SBML would be retrieved from the BiGG Models repository. | ||||||
|
@@ -66,6 +72,30 @@ def test_biomodels_access(biomodels: Mock) -> None: | |||||
biomodels.get_sbml.assert_called_once_with(model_id="BIOMD0000000633") | ||||||
|
||||||
|
||||||
def test_biomodels_access(biomodels: Mock) -> None: | ||||||
"""Test that SBML would be retrieved from the BioModels repository. | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
biomodels : unittest.mock.Mock | ||||||
The mocked object for BioModels model respository. | ||||||
|
||||||
""" | ||||||
load_model("BIOMD0000000633", cache=False, repositories=[biomodels]) | ||||||
biomodels.get_sbml.assert_called_once_with(model_id="BIOMD0000000633") | ||||||
|
||||||
def test_biomodels_access(embl_gems: Mock) -> None: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need a different name here:
Suggested change
|
||||||
"""Test that SBML would be retrieved from the EMBL Gems repository. | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
embl_gems : unittest.mock.Mock | ||||||
The mocked object for BioModels model respository. | ||||||
|
||||||
""" | ||||||
load_model("Abiotrophia_defectiva_ATCC_49176", cache=False, repositories=[embl_gems]) | ||||||
biomodels.get_sbml.assert_called_once_with(model_id="Abiotrophia_defectiva_ATCC_49176") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
def test_unknown_model() -> None: | ||||||
"""Expect that a not found error is raised (e2e).""" | ||||||
with pytest.raises(RuntimeError): | ||||||
|
@@ -75,6 +105,7 @@ def test_unknown_model() -> None: | |||||
@pytest.mark.parametrize( | ||||||
"model_id, num_metabolites, num_reactions", | ||||||
[("e_coli_core", 72, 95), ("BIOMD0000000633", 50, 35)], | ||||||
[("Abiotrophia_defectiva_ATCC_49176", 1070, 826)] | ||||||
) | ||||||
def test_remote_load(model_id: str, num_metabolites: int, num_reactions: int) -> None: | ||||||
"""Test that sample models can be loaded from remote repositories (e2e). | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks 😊