Coverage for src / bioimageio / spec / _description.py: 92%

52 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-31 13:09 +0000

1from types import MappingProxyType 

2from typing import Any, Literal, Optional, TypeVar, Union, overload 

3 

4from pydantic import Discriminator 

5from typing_extensions import Annotated 

6 

7from ._description_impl import DISCOVER, build_description_impl, get_rd_class_impl 

8from ._internal.common_nodes import InvalidDescr 

9from ._internal.io import BioimageioYamlContent, BioimageioYamlContentView 

10from ._internal.types import FormatVersionPlaceholder 

11from ._internal.validation_context import ValidationContext, get_validation_context 

12from .application import ( 

13 AnyApplicationDescr, 

14 ApplicationDescr, 

15 ApplicationDescr_v0_2, 

16 ApplicationDescr_v0_3, 

17) 

18from .dataset import AnyDatasetDescr, DatasetDescr, DatasetDescr_v0_2, DatasetDescr_v0_3 

19from .generic import AnyGenericDescr, GenericDescr, GenericDescr_v0_2, GenericDescr_v0_3 

20from .model import AnyModelDescr, ModelDescr, ModelDescr_v0_4, ModelDescr_v0_5 

21from .notebook import ( 

22 AnyNotebookDescr, 

23 NotebookDescr, 

24 NotebookDescr_v0_2, 

25 NotebookDescr_v0_3, 

26) 

27from .summary import ValidationSummary 

28 

29LATEST: Literal["latest"] = "latest" 

30"""placeholder for the latest available format version""" 

31 

32 

33LatestResourceDescr = Union[ 

34 Annotated[ 

35 Union[ 

36 ApplicationDescr, 

37 DatasetDescr, 

38 ModelDescr, 

39 NotebookDescr, 

40 ], 

41 Discriminator("type"), 

42 ], 

43 GenericDescr, 

44] 

45"""A resource description following the latest specification format""" 

46 

47 

48SpecificResourceDescr = Annotated[ 

49 Union[ 

50 AnyApplicationDescr, 

51 AnyDatasetDescr, 

52 AnyModelDescr, 

53 AnyNotebookDescr, 

54 ], 

55 Discriminator("type"), 

56] 

57"""Any of the implemented, non-generic resource descriptions""" 

58 

59ResourceDescr = Union[SpecificResourceDescr, AnyGenericDescr] 

60"""Any of the implemented resource descriptions""" 

61 

62 

63def dump_description( 

64 rd: Union[ResourceDescr, InvalidDescr], 

65 /, 

66 *, 

67 exclude_unset: bool = True, 

68 exclude_defaults: bool = False, 

69) -> BioimageioYamlContent: 

70 """Converts a resource to a dictionary containing only simple types that can directly be serialzed to YAML. 

71 

72 Args: 

73 rd: bioimageio resource description 

74 exclude_unset: Exclude fields that have not explicitly be set. 

75 exclude_defaults: Exclude fields that have the default value (even if set explicitly). 

76 """ 

77 return rd.model_dump( 

78 mode="json", exclude_unset=exclude_unset, exclude_defaults=exclude_defaults 

79 ) 

80 

81 

82RD = TypeVar("RD", bound=ResourceDescr) 

83 

84 

85LATEST_DESCRIPTIONS_MAP = MappingProxyType( 

86 { 

87 None: GenericDescr, 

88 "generic": GenericDescr, 

89 "application": ApplicationDescr, 

90 "dataset": DatasetDescr, 

91 "notebook": NotebookDescr, 

92 "model": ModelDescr, 

93 } 

94) 

95DESCRIPTIONS_MAP = MappingProxyType( 

96 { 

97 None: MappingProxyType( 

98 { 

99 "0.2": GenericDescr_v0_2, 

100 "0.3": GenericDescr_v0_3, 

101 "latest": GenericDescr, 

102 } 

103 ), 

104 "generic": MappingProxyType( 

105 { 

106 "0.2": GenericDescr_v0_2, 

107 "0.3": GenericDescr_v0_3, 

108 "latest": GenericDescr, 

109 } 

110 ), 

111 "application": MappingProxyType( 

112 { 

113 "0.2": ApplicationDescr_v0_2, 

114 "0.3": ApplicationDescr_v0_3, 

115 "latest": ApplicationDescr, 

116 } 

117 ), 

118 "dataset": MappingProxyType( 

119 { 

120 "0.2": DatasetDescr_v0_2, 

121 "0.3": DatasetDescr_v0_3, 

122 "latest": DatasetDescr, 

123 } 

124 ), 

125 "notebook": MappingProxyType( 

126 { 

127 "0.2": NotebookDescr_v0_2, 

128 "0.3": NotebookDescr_v0_3, 

129 "latest": NotebookDescr, 

130 } 

131 ), 

132 "model": MappingProxyType( 

133 { 

134 "0.3": ModelDescr_v0_4, 

135 "0.4": ModelDescr_v0_4, 

136 "0.5": ModelDescr_v0_5, 

137 "latest": ModelDescr, 

138 } 

139 ), 

140 } 

141) 

142"""A mapping to determine the appropriate Description class 

143 for a given **type** and **format_version**.""" 

144 

145 

146def _get_rd_class(typ: Any, format_version: Any, fallback_to_latest: bool): 

147 return get_rd_class_impl( 

148 typ, format_version, DESCRIPTIONS_MAP, fallback_to_latest=fallback_to_latest 

149 ) 

150 

151 

152@overload 

153def build_description( 

154 content: BioimageioYamlContentView, 

155 /, 

156 *, 

157 context: Optional[ValidationContext] = None, 

158 format_version: Literal["latest"], 

159) -> Union[LatestResourceDescr, InvalidDescr]: ... 

160 

161 

162@overload 

163def build_description( 

164 content: BioimageioYamlContentView, 

165 /, 

166 *, 

167 context: Optional[ValidationContext] = None, 

168 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER, 

169) -> Union[ResourceDescr, InvalidDescr]: ... 

170 

171 

172def build_description( 

173 content: BioimageioYamlContentView, 

174 /, 

175 *, 

176 context: Optional[ValidationContext] = None, 

177 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER, 

178) -> Union[ResourceDescr, InvalidDescr]: 

179 """build a bioimage.io resource description from an RDF's content. 

180 

181 Use `load_description` if you want to build a resource description from an rdf.yaml 

182 or bioimage.io zip-package. 

183 

184 Args: 

185 content: loaded rdf.yaml file (loaded with YAML, not bioimageio.spec) 

186 context: validation context to use during validation 

187 format_version: 

188 (optional) use this argument to load the resource and 

189 convert its metadata to a higher format_version. 

190 Note: 

191 - Use "latest" to convert to the latest available format version. 

192 - Use "discover" to use the format version specified in the RDF. 

193 - Only considers major.minor format version, ignores patch version. 

194 - Conversion to lower format versions is not supported. 

195 

196 Returns: 

197 An object holding all metadata of the bioimage.io resource 

198 

199 """ 

200 

201 return build_description_impl( 

202 content, 

203 context=context, 

204 format_version=format_version, 

205 get_rd_class=_get_rd_class, 

206 ) 

207 

208 

209def validate_format( 

210 data: BioimageioYamlContent, 

211 /, 

212 *, 

213 format_version: Union[Literal["discover", "latest"], str] = DISCOVER, 

214 context: Optional[ValidationContext] = None, 

215) -> ValidationSummary: 

216 """Validate a dictionary holding a bioimageio description. 

217 See `bioimagieo.spec.load_description_and_validate_format_only` 

218 to validate a file source. 

219 

220 Args: 

221 data: Dictionary holding the raw bioimageio.yaml content. 

222 format_version: 

223 Format version to (update to and) use for validation. 

224 Note: 

225 - Use "latest" to convert to the latest available format version. 

226 - Use "discover" to use the format version specified in the RDF. 

227 - Only considers major.minor format version, ignores patch version. 

228 - Conversion to lower format versions is not supported. 

229 context: Validation context, see `bioimagieo.spec.ValidationContext` 

230 

231 Note: 

232 Use `bioimagieo.spec.load_description_and_validate_format_only` to validate a 

233 file source instead of loading the YAML content and creating the appropriate 

234 `ValidationContext`. 

235 

236 Alternatively you can use `bioimagieo.spec.load_description` and access the 

237 `validation_summary` attribute of the returned object. 

238 """ 

239 with context or get_validation_context(): 

240 rd = build_description(data, format_version=format_version) 

241 

242 assert rd.validation_summary is not None 

243 return rd.validation_summary 

244 

245 

246def ensure_description_is_model( 

247 rd: Union[InvalidDescr, ResourceDescr], 

248) -> AnyModelDescr: 

249 """ 

250 Raises: 

251 ValueError: for invalid or non-model resources 

252 """ 

253 if isinstance(rd, InvalidDescr): 

254 raise ValueError(f"Invalid {rd.type} description:\n{rd.get_reason()}") 

255 

256 if rd.type != "model": 

257 raise ValueError( 

258 f"Expected a model resource, but got resource type '{rd.type}'" 

259 ) 

260 

261 assert not isinstance( 

262 rd, 

263 ( 

264 GenericDescr_v0_2, 

265 GenericDescr_v0_3, 

266 ), 

267 ) 

268 

269 return rd 

270 

271 

272def ensure_description_is_dataset( 

273 rd: Union[InvalidDescr, ResourceDescr], 

274) -> AnyDatasetDescr: 

275 if isinstance(rd, InvalidDescr): 

276 raise ValueError(f"Invalid {rd.type} description:\n{rd.get_reason()}") 

277 

278 if rd.type != "dataset": 

279 raise ValueError( 

280 f"Expected a dataset resource, but got resource type '{rd.type}'" 

281 ) 

282 

283 assert not isinstance( 

284 rd, 

285 ( 

286 GenericDescr_v0_2, 

287 GenericDescr_v0_3, 

288 ), 

289 ) 

290 

291 return rd