Coverage for src / bioimageio / spec / _io.py: 72%
60 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-15 08:44 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-15 08:44 +0000
1import collections.abc
2from pathlib import Path
3from typing import Dict, Literal, Optional, TextIO, Union, cast, overload
4from zipfile import ZipFile
6from loguru import logger
7from pydantic import FilePath, NewPath
9from ._description import (
10 DISCOVER,
11 LATEST,
12 InvalidDescr,
13 LatestResourceDescr,
14 ResourceDescr,
15 build_description,
16 dump_description,
17 ensure_description_is_dataset,
18 ensure_description_is_model,
19)
20from ._internal.common_nodes import ResourceDescrBase
21from ._internal.io import BioimageioYamlContent, YamlValue
22from ._internal.io_basics import Sha256
23from ._internal.io_utils import open_bioimageio_yaml, write_yaml
24from ._internal.types import FormatVersionPlaceholder, PermissiveFileSource
25from ._internal.validation_context import get_validation_context
26from .dataset import AnyDatasetDescr, DatasetDescr
27from .model import AnyModelDescr, ModelDescr
28from .summary import ValidationSummary
31@overload
32def load_description(
33 source: Union[PermissiveFileSource, ZipFile],
34 /,
35 *,
36 format_version: Literal["latest"],
37 perform_io_checks: Optional[bool] = None,
38 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
39 sha256: Optional[Sha256] = None,
40) -> Union[LatestResourceDescr, InvalidDescr]: ...
43@overload
44def load_description(
45 source: Union[PermissiveFileSource, ZipFile],
46 /,
47 *,
48 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
49 perform_io_checks: Optional[bool] = None,
50 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
51 sha256: Optional[Sha256] = None,
52) -> Union[ResourceDescr, InvalidDescr]: ...
55def load_description(
56 source: Union[PermissiveFileSource, ZipFile],
57 /,
58 *,
59 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
60 perform_io_checks: Optional[bool] = None,
61 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
62 sha256: Optional[Sha256] = None,
63) -> Union[ResourceDescr, InvalidDescr]:
64 """load a bioimage.io resource description
66 Args:
67 source:
68 Path or URL to an rdf.yaml or a bioimage.io package
69 (zip-file with rdf.yaml in it).
70 format_version:
71 (optional) Use this argument to load the resource and
72 convert its metadata to a higher format_version.
73 Note:
74 - Use "latest" to convert to the latest available format version.
75 - Use "discover" to use the format version specified in the RDF.
76 - Only considers major.minor format version, ignores patch version.
77 - Conversion to lower format versions is not supported.
78 perform_io_checks:
79 Wether or not to perform validation that requires file io,
80 e.g. downloading a remote files. The existence of local
81 absolute file paths is still being checked.
82 known_files:
83 Allows to bypass download and hashing of referenced files
84 (even if perform_io_checks is True).
86 Keys should be file paths or URL strings as they appear in the
87 bioimageio.yaml file.
89 Values are Sha256 values compared to hash values in the description.
90 For `None` values no hash value comparison is performed.
92 If `perfrom_io_checks` is True, checked files will be added to
93 this dictionary with their SHA-256 value.
95 If `perform_io_checks` is False and `known_files` is not empty,
96 missing, 'unknown' file references are considered invalid.
97 sha256:
98 Optional SHA-256 value of **source**
100 Returns:
101 An object holding all metadata of the bioimage.io resource
103 """
104 if isinstance(source, ResourceDescrBase):
105 name = getattr(source, "name", f"{str(source)[:10]}...")
106 logger.warning("returning already loaded description '{}' as is", name)
107 return source # pyright: ignore[reportReturnType]
109 opened = open_bioimageio_yaml(source, sha256=sha256)
111 context = get_validation_context().replace(
112 root=opened.original_root,
113 file_name=opened.original_file_name,
114 original_source_name=opened.original_source_name,
115 perform_io_checks=perform_io_checks,
116 known_files=known_files,
117 )
119 return build_description(
120 opened.content,
121 context=context,
122 format_version=format_version,
123 )
126@overload
127def load_model_description(
128 source: Union[PermissiveFileSource, ZipFile],
129 /,
130 *,
131 format_version: Literal["latest"],
132 perform_io_checks: Optional[bool] = None,
133 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
134 sha256: Optional[Sha256] = None,
135) -> ModelDescr: ...
138@overload
139def load_model_description(
140 source: Union[PermissiveFileSource, ZipFile],
141 /,
142 *,
143 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
144 perform_io_checks: Optional[bool] = None,
145 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
146 sha256: Optional[Sha256] = None,
147) -> AnyModelDescr: ...
150def load_model_description(
151 source: Union[PermissiveFileSource, ZipFile],
152 /,
153 *,
154 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
155 perform_io_checks: Optional[bool] = None,
156 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
157 sha256: Optional[Sha256] = None,
158) -> AnyModelDescr:
159 """same as `load_description`, but addtionally ensures that the loaded
160 description is valid and of type 'model'.
162 Raises:
163 ValueError: for invalid or non-model resources
164 """
165 rd = load_description(
166 source,
167 format_version=format_version,
168 perform_io_checks=perform_io_checks,
169 known_files=known_files,
170 sha256=sha256,
171 )
172 return ensure_description_is_model(rd)
175@overload
176def load_dataset_description(
177 source: Union[PermissiveFileSource, ZipFile],
178 /,
179 *,
180 format_version: Literal["latest"],
181 perform_io_checks: Optional[bool] = None,
182 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
183 sha256: Optional[Sha256] = None,
184) -> DatasetDescr: ...
187@overload
188def load_dataset_description(
189 source: Union[PermissiveFileSource, ZipFile],
190 /,
191 *,
192 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
193 perform_io_checks: Optional[bool] = None,
194 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
195 sha256: Optional[Sha256] = None,
196) -> AnyDatasetDescr: ...
199def load_dataset_description(
200 source: Union[PermissiveFileSource, ZipFile],
201 /,
202 *,
203 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
204 perform_io_checks: Optional[bool] = None,
205 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
206 sha256: Optional[Sha256] = None,
207) -> AnyDatasetDescr:
208 """same as `load_description`, but addtionally ensures that the loaded
209 description is valid and of type 'dataset'.
210 """
211 rd = load_description(
212 source,
213 format_version=format_version,
214 perform_io_checks=perform_io_checks,
215 known_files=known_files,
216 sha256=sha256,
217 )
218 return ensure_description_is_dataset(rd)
221def save_bioimageio_yaml_only(
222 rd: Union[ResourceDescr, BioimageioYamlContent, InvalidDescr],
223 /,
224 file: Union[NewPath, FilePath, TextIO],
225 *,
226 exclude_unset: bool = True,
227 exclude_defaults: bool = False,
228):
229 """write the metadata of a resource description (`rd`) to `file`
230 without writing any of the referenced files in it.
232 Args:
233 rd: bioimageio resource description
234 file: file or stream to save to
235 exclude_unset: Exclude fields that have not explicitly be set.
236 exclude_defaults: Exclude fields that have the default value (even if set explicitly).
238 Note: To save a resource description with its associated files as a package,
239 use `save_bioimageio_package` or `save_bioimageio_package_as_folder`.
240 """
241 if isinstance(rd, ResourceDescrBase):
242 content = dump_description(
243 rd, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults
244 )
245 else:
246 content = rd
248 write_yaml(cast(YamlValue, content), file)
251def load_description_and_validate_format_only(
252 source: Union[PermissiveFileSource, ZipFile],
253 /,
254 *,
255 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
256 perform_io_checks: Optional[bool] = None,
257 known_files: Optional[Dict[str, Optional[Sha256]]] = None,
258 sha256: Optional[Sha256] = None,
259) -> ValidationSummary:
260 """same as `load_description`, but only return the validation summary.
262 Returns:
263 Validation summary of the bioimage.io resource found at `source`.
265 """
266 rd = load_description(
267 source,
268 format_version=format_version,
269 perform_io_checks=perform_io_checks,
270 known_files=known_files,
271 sha256=sha256,
272 )
273 assert rd.validation_summary is not None
274 return rd.validation_summary
277def update_format(
278 source: Union[
279 ResourceDescr,
280 PermissiveFileSource,
281 ZipFile,
282 BioimageioYamlContent,
283 InvalidDescr,
284 ],
285 /,
286 *,
287 output: Union[Path, TextIO, None] = None,
288 exclude_defaults: bool = True,
289 perform_io_checks: Optional[bool] = None,
290) -> Union[LatestResourceDescr, InvalidDescr]:
291 """Update a resource description.
293 Notes:
294 - Invalid **source** descriptions may fail to update.
295 - The updated description might be invalid (even if the **source** was valid).
296 """
298 if isinstance(source, ResourceDescrBase):
299 root = source.root
300 source = dump_description(source)
301 else:
302 root = None
304 if isinstance(source, collections.abc.Mapping):
305 descr = build_description(
306 source,
307 context=get_validation_context().replace(
308 root=root, perform_io_checks=perform_io_checks
309 ),
310 format_version=LATEST,
311 )
313 else:
314 descr = load_description(
315 source,
316 perform_io_checks=perform_io_checks,
317 format_version=LATEST,
318 )
320 if output is not None:
321 save_bioimageio_yaml_only(descr, file=output, exclude_defaults=exclude_defaults)
323 return descr
326def update_hashes(
327 source: Union[PermissiveFileSource, ZipFile, ResourceDescr, BioimageioYamlContent],
328 /,
329) -> Union[ResourceDescr, InvalidDescr]:
330 """Update hash values of the files referenced in **source**."""
331 if isinstance(source, ResourceDescrBase):
332 root = source.root
333 source = dump_description(source)
334 else:
335 root = None
337 context = get_validation_context().replace(
338 update_hashes=True, root=root, perform_io_checks=True
339 )
340 with context:
341 if isinstance(source, collections.abc.Mapping):
342 return build_description(source)
343 else:
344 return load_description(source, perform_io_checks=True)