Skip to content

Commit

Permalink
Merge pull request #656 from bioimage-io/improve_get_conda_envs
Browse files Browse the repository at this point in the history
Improve conda env handling
  • Loading branch information
FynnBe authored Nov 14, 2024
2 parents 33c3673 + ae6480d commit 09f42d0
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 17 deletions.
4 changes: 4 additions & 0 deletions bioimageio/spec/_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ def update_format(
def ensure_description_is_model(
rd: Union[InvalidDescr, ResourceDescr],
) -> AnyModelDescr:
"""
Raises:
ValueError: for invalid or non-model resources
"""
if isinstance(rd, InvalidDescr):
rd.validation_summary.display()
raise ValueError("resource description is invalid")
Expand Down
2 changes: 2 additions & 0 deletions bioimageio/spec/_internal/common_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,8 @@ class InvalidDescr(
extra="allow",
title="An invalid resource description",
):
"""A representation of an invalid resource description"""

type: Any = "unknown"
format_version: Any = "unknown"
fields_to_set_explicitly: ClassVar[FrozenSet[LiteralString]] = frozenset()
Expand Down
3 changes: 3 additions & 0 deletions bioimageio/spec/_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ def load_model_description(
) -> AnyModelDescr:
"""same as `load_description`, but addtionally ensures that the loaded
description is valid and of type 'model'.
Raises:
ValueError: for invalid or non-model resources
"""
rd = load_description(
source,
Expand Down
6 changes: 6 additions & 0 deletions bioimageio/spec/conda_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ def __lt__(self, other: Any):
else:
return False

def __gt__(self, other: Any):
if isinstance(other, PipDeps):
return len(self.pip) > len(other.pip)
else:
return False


class CondaEnv(BaseModel):
"""Represenation of the content of a conda environment.yaml file"""
Expand Down
46 changes: 29 additions & 17 deletions bioimageio/spec/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from io import StringIO
from itertools import chain
from pathlib import Path
from tempfile import NamedTemporaryFile
from tempfile import TemporaryDirectory
from types import MappingProxyType
from typing import (
Any,
Expand Down Expand Up @@ -152,19 +152,30 @@ class ValidationDetail(BaseModel, extra="allow"):
def model_post_init(self, __context: Any):
"""create `conda_compare` default value if needed"""
super().model_post_init(__context)
if self.recommended_env is not None and self.conda_compare is None:
dumped_env = self.recommended_env.model_dump(mode="json")
if is_yaml_value(dumped_env):
with NamedTemporaryFile(mode="w", encoding="utf-8") as f:
write_yaml(dumped_env, f)
self.conda_compare = subprocess.run(
["conda", "compare", f.name],
capture_output=True,
shell=True,
text=True,
).stdout
else:
self.conda_compare = "Failed to dump recommended env to valid yaml"
if self.recommended_env is None or self.conda_compare is not None:
return

dumped_env = self.recommended_env.model_dump(mode="json")
if not is_yaml_value(dumped_env):
self.conda_compare = "Failed to dump recommended env to valid yaml"
return

with TemporaryDirectory() as d:
path = Path(d) / "env.yaml"
with path.open("w", encoding="utf-8") as f:
write_yaml(dumped_env, f)

compare_proc = subprocess.run(
["conda", "compare", str(path)],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
shell=True,
text=True,
)
self.conda_compare = (
compare_proc.stdout
or f"conda compare exited with {compare_proc.returncode}"
)

def __str__(self):
return f"{self.__class__.__name__}:\n" + self.format()
Expand Down Expand Up @@ -330,17 +341,18 @@ def format_loc(loc: Loc):
json_env = d.recommended_env.model_dump(mode="json")
assert is_yaml_value(json_env)
write_yaml(json_env, rec_env)
rec_env_code = rec_env.getvalue().replace("\n", "</code><br><code>")
details.append(
[
"🐍",
"recommended conda env",
f"```yaml\n{rec_env.read()}\n```".replace("\n", "<br>"),
f"<pre><code>{rec_env_code}</code></pre>",
]
)

if d.conda_compare is not None:
if d.conda_compare:
details.append(
["🐍", "actual conda env", d.conda_compare.replace("\n", "<br>")]
["🐍", "conda compare", d.conda_compare.replace("\n", "<br>")]
)

for entry in d.errors:
Expand Down
1 change: 1 addition & 0 deletions tests/test_model/test_v0_5.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@ def test_model(model_data: Dict[str, Any], update: Dict[str, Any]):
summary = validate_format(
model_data, context=ValidationContext(perform_io_checks=False)
)
summary.display()
assert summary.status == "passed", summary.format()


Expand Down

0 comments on commit 09f42d0

Please sign in to comment.