bioimageio.spec.conda_env
1import warnings 2from typing import Any, List, Optional, Union 3 4from pydantic import BaseModel, Field, field_validator, model_validator 5 6 7class PipDeps(BaseModel): 8 """Pip dependencies to include in conda dependecies""" 9 10 pip: List[str] = Field(default_factory=list) 11 12 @field_validator("pip", mode="after") 13 @classmethod 14 def _remove_empty_and_sort(cls, value: List[str]) -> List[str]: 15 return sorted((vs for v in value if (vs := v.strip()))) 16 17 def __lt__(self, other: Any): 18 if isinstance(other, PipDeps): 19 return len(self.pip) < len(other.pip) 20 else: 21 return False 22 23 def __gt__(self, other: Any): 24 if isinstance(other, PipDeps): 25 return len(self.pip) > len(other.pip) 26 else: 27 return False 28 29 30class CondaEnv(BaseModel): 31 """Represenation of the content of a conda environment.yaml file""" 32 33 name: Optional[str] = None 34 channels: List[str] = Field(default_factory=list) 35 dependencies: List[Union[str, PipDeps]] = Field(default_factory=list) 36 37 @field_validator("name", mode="after") 38 def _ensure_valid_conda_env_name(cls, value: Optional[str]) -> Optional[str]: 39 if value is None: 40 return None 41 42 for illegal in ("/", " ", ":", "#"): 43 value = value.replace(illegal, "") 44 45 return value or "empty" 46 47 @property 48 def wo_name(self): 49 return self.model_construct(**{k: v for k, v in self if k != "name"}) 50 51 def _get_version(self, package: str): 52 """Helper to return any verison pin for **package** 53 54 TODO: improve: interprete version pin and return structured information. 55 """ 56 for d in self.dependencies: 57 if isinstance(d, PipDeps): 58 for p in d.pip: 59 if p.startswith(package): 60 return p[len(package) :] 61 elif d.startswith(package): 62 return d[len(package) :] 63 64 65class BioimageioCondaEnv(CondaEnv): 66 """A special `CondaEnv` that 67 - automatically adds bioimageio specific dependencies 68 - sorts dependencies 69 """ 70 71 @model_validator(mode="after") 72 def _normalize_bioimageio_conda_env(self): 73 """update a conda env such that we have bioimageio.core and sorted dependencies""" 74 for req_channel in ("conda-forge", "nodefaults"): 75 if req_channel not in self.channels: 76 self.channels.append(req_channel) 77 78 if "defaults" in self.channels: 79 warnings.warn("removing 'defaults' from conda-channels") 80 self.channels.remove("defaults") 81 82 if "pip" not in self.dependencies: 83 self.dependencies.append("pip") 84 85 for dep in self.dependencies: 86 if isinstance(dep, PipDeps): 87 pip_section = dep 88 pip_section.pip.sort() 89 break 90 else: 91 pip_section = None 92 93 if ( 94 pip_section is None 95 or not any(pd.startswith("bioimageio.core") for pd in pip_section.pip) 96 ) and not any( 97 d.startswith("bioimageio.core") 98 or d.startswith("conda-forge::bioimageio.core") 99 for d in self.dependencies 100 if not isinstance(d, PipDeps) 101 ): 102 self.dependencies.append("conda-forge::bioimageio.core") 103 104 self.dependencies.sort() 105 return self
class
PipDeps(pydantic.main.BaseModel):
8class PipDeps(BaseModel): 9 """Pip dependencies to include in conda dependecies""" 10 11 pip: List[str] = Field(default_factory=list) 12 13 @field_validator("pip", mode="after") 14 @classmethod 15 def _remove_empty_and_sort(cls, value: List[str]) -> List[str]: 16 return sorted((vs for v in value if (vs := v.strip()))) 17 18 def __lt__(self, other: Any): 19 if isinstance(other, PipDeps): 20 return len(self.pip) < len(other.pip) 21 else: 22 return False 23 24 def __gt__(self, other: Any): 25 if isinstance(other, PipDeps): 26 return len(self.pip) > len(other.pip) 27 else: 28 return False
Pip dependencies to include in conda dependecies
class
CondaEnv(pydantic.main.BaseModel):
31class CondaEnv(BaseModel): 32 """Represenation of the content of a conda environment.yaml file""" 33 34 name: Optional[str] = None 35 channels: List[str] = Field(default_factory=list) 36 dependencies: List[Union[str, PipDeps]] = Field(default_factory=list) 37 38 @field_validator("name", mode="after") 39 def _ensure_valid_conda_env_name(cls, value: Optional[str]) -> Optional[str]: 40 if value is None: 41 return None 42 43 for illegal in ("/", " ", ":", "#"): 44 value = value.replace(illegal, "") 45 46 return value or "empty" 47 48 @property 49 def wo_name(self): 50 return self.model_construct(**{k: v for k, v in self if k != "name"}) 51 52 def _get_version(self, package: str): 53 """Helper to return any verison pin for **package** 54 55 TODO: improve: interprete version pin and return structured information. 56 """ 57 for d in self.dependencies: 58 if isinstance(d, PipDeps): 59 for p in d.pip: 60 if p.startswith(package): 61 return p[len(package) :] 62 elif d.startswith(package): 63 return d[len(package) :]
Represenation of the content of a conda environment.yaml file
dependencies: List[Union[str, PipDeps]]
66class BioimageioCondaEnv(CondaEnv): 67 """A special `CondaEnv` that 68 - automatically adds bioimageio specific dependencies 69 - sorts dependencies 70 """ 71 72 @model_validator(mode="after") 73 def _normalize_bioimageio_conda_env(self): 74 """update a conda env such that we have bioimageio.core and sorted dependencies""" 75 for req_channel in ("conda-forge", "nodefaults"): 76 if req_channel not in self.channels: 77 self.channels.append(req_channel) 78 79 if "defaults" in self.channels: 80 warnings.warn("removing 'defaults' from conda-channels") 81 self.channels.remove("defaults") 82 83 if "pip" not in self.dependencies: 84 self.dependencies.append("pip") 85 86 for dep in self.dependencies: 87 if isinstance(dep, PipDeps): 88 pip_section = dep 89 pip_section.pip.sort() 90 break 91 else: 92 pip_section = None 93 94 if ( 95 pip_section is None 96 or not any(pd.startswith("bioimageio.core") for pd in pip_section.pip) 97 ) and not any( 98 d.startswith("bioimageio.core") 99 or d.startswith("conda-forge::bioimageio.core") 100 for d in self.dependencies 101 if not isinstance(d, PipDeps) 102 ): 103 self.dependencies.append("conda-forge::bioimageio.core") 104 105 self.dependencies.sort() 106 return self
A special CondaEnv
that
- automatically adds bioimageio specific dependencies
- sorts dependencies