Coverage for bioimageio/spec/_description.py: 74%

61 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-02 14:21 +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 bioimageio.spec._internal.validation_context import ValidationContext 

8 

9from ._description_impl import DISCOVER, build_description_impl, get_rd_class_impl 

10from ._internal.common_nodes import InvalidDescr 

11from ._internal.io import BioimageioYamlContent 

12from ._internal.types import FormatVersionPlaceholder 

13from ._internal.validation_context import get_validation_context 

14from .application import ( 

15 AnyApplicationDescr, 

16 ApplicationDescr, 

17 ApplicationDescr_v0_2, 

18 ApplicationDescr_v0_3, 

19) 

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

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

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

23from .notebook import ( 

24 AnyNotebookDescr, 

25 NotebookDescr, 

26 NotebookDescr_v0_2, 

27 NotebookDescr_v0_3, 

28) 

29from .summary import ValidationSummary 

30 

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

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

33 

34 

35LatestResourceDescr = Union[ 

36 Annotated[ 

37 Union[ 

38 ApplicationDescr, 

39 DatasetDescr, 

40 ModelDescr, 

41 NotebookDescr, 

42 ], 

43 Discriminator("type"), 

44 ], 

45 GenericDescr, 

46] 

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

48 

49 

50SpecificResourceDescr = Annotated[ 

51 Union[ 

52 AnyApplicationDescr, 

53 AnyDatasetDescr, 

54 AnyModelDescr, 

55 AnyNotebookDescr, 

56 ], 

57 Discriminator("type"), 

58] 

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

60 

61ResourceDescr = Union[SpecificResourceDescr, AnyGenericDescr] 

62"""Any of the implemented resource descriptions""" 

63 

64 

65def dump_description( 

66 rd: Union[ResourceDescr, InvalidDescr], 

67 /, 

68 *, 

69 exclude_unset: bool = True, 

70 exclude_defaults: bool = False, 

71) -> BioimageioYamlContent: 

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

73 

74 Args: 

75 rd: bioimageio resource description 

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

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

78 """ 

79 return rd.model_dump( 

80 mode="json", exclude_unset=exclude_unset, exclude_defaults=exclude_defaults 

81 ) 

82 

83 

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

85 

86 

87LATEST_DESCRIPTIONS_MAP = MappingProxyType( 

88 { 

89 None: GenericDescr, 

90 "generic": GenericDescr, 

91 "application": ApplicationDescr, 

92 "dataset": DatasetDescr, 

93 "notebook": NotebookDescr, 

94 "model": ModelDescr, 

95 } 

96) 

97DESCRIPTIONS_MAP = MappingProxyType( 

98 { 

99 None: MappingProxyType( 

100 { 

101 "0.2": GenericDescr_v0_2, 

102 "0.3": GenericDescr_v0_3, 

103 None: GenericDescr, 

104 } 

105 ), 

106 "generic": MappingProxyType( 

107 { 

108 "0.2": GenericDescr_v0_2, 

109 "0.3": GenericDescr_v0_3, 

110 None: GenericDescr, 

111 } 

112 ), 

113 "application": MappingProxyType( 

114 { 

115 "0.2": ApplicationDescr_v0_2, 

116 "0.3": ApplicationDescr_v0_3, 

117 None: ApplicationDescr, 

118 } 

119 ), 

120 "dataset": MappingProxyType( 

121 { 

122 "0.2": DatasetDescr_v0_2, 

123 "0.3": DatasetDescr_v0_3, 

124 None: DatasetDescr, 

125 } 

126 ), 

127 "notebook": MappingProxyType( 

128 { 

129 "0.2": NotebookDescr_v0_2, 

130 "0.3": NotebookDescr_v0_3, 

131 None: NotebookDescr, 

132 } 

133 ), 

134 "model": MappingProxyType( 

135 { 

136 "0.3": ModelDescr_v0_4, 

137 "0.4": ModelDescr_v0_4, 

138 "0.5": ModelDescr_v0_5, 

139 None: ModelDescr, 

140 } 

141 ), 

142 } 

143) 

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

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

146 

147 

148def _get_rd_class(typ: Any, format_version: Any): 

149 return get_rd_class_impl(typ, format_version, DESCRIPTIONS_MAP) 

150 

151 

152@overload 

153def build_description( 

154 content: BioimageioYamlContent, 

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: BioimageioYamlContent, 

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: BioimageioYamlContent, 

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: (optional) use this argument to load the resource and 

188 convert its metadata to a higher format_version 

189 

190 Returns: 

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

192 

193 """ 

194 

195 return build_description_impl( 

196 content, 

197 context=context, 

198 format_version=format_version, 

199 get_rd_class=_get_rd_class, 

200 ) 

201 

202 

203def validate_format( 

204 data: BioimageioYamlContent, 

205 /, 

206 *, 

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

208 context: Optional[ValidationContext] = None, 

209) -> ValidationSummary: 

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

211 See `bioimagieo.spec.load_description_and_validate_format_only` 

212 to validate a file source. 

213 

214 Args: 

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

216 format_version: Format version to (update to and) use for validation. 

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

218 

219 Note: 

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

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

222 `ValidationContext`. 

223 

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

225 `validation_summary` attribute of the returned object. 

226 """ 

227 with context or get_validation_context(): 

228 rd = build_description(data, format_version=format_version) 

229 

230 assert rd.validation_summary is not None 

231 return rd.validation_summary 

232 

233 

234def ensure_description_is_model( 

235 rd: Union[InvalidDescr, ResourceDescr], 

236) -> AnyModelDescr: 

237 """ 

238 Raises: 

239 ValueError: for invalid or non-model resources 

240 """ 

241 if isinstance(rd, InvalidDescr): 

242 rd.validation_summary.display() 

243 raise ValueError(f"Invalid {rd.type} description") 

244 

245 if rd.type != "model": 

246 rd.validation_summary.display() 

247 raise ValueError( 

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

249 ) 

250 

251 assert not isinstance( 

252 rd, 

253 ( 

254 GenericDescr_v0_2, 

255 GenericDescr_v0_3, 

256 ), 

257 ) 

258 

259 return rd 

260 

261 

262def ensure_description_is_dataset( 

263 rd: Union[InvalidDescr, ResourceDescr], 

264) -> AnyDatasetDescr: 

265 if isinstance(rd, InvalidDescr): 

266 rd.validation_summary.display() 

267 raise ValueError(f"Invalid {rd.type} description.") 

268 

269 if rd.type != "dataset": 

270 rd.validation_summary.display() 

271 raise ValueError( 

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

273 ) 

274 

275 assert not isinstance( 

276 rd, 

277 ( 

278 GenericDescr_v0_2, 

279 GenericDescr_v0_3, 

280 ), 

281 ) 

282 

283 return rd