bioimageio.spec.utils
1import json 2from typing import List, TypedDict 3 4from ._description import ensure_description_is_dataset, ensure_description_is_model 5from ._internal.io import ( 6 download, 7 extract_file_name, 8 get_sha256, 9 identify_bioimageio_yaml_file_name, 10 is_valid_bioimageio_yaml_name, 11) 12from ._internal.io_utils import load_array, save_array, write_yaml 13from ._internal.utils import files 14 15__all__ = [ 16 "download", 17 "ensure_description_is_dataset", 18 "ensure_description_is_model", 19 "extract_file_name", 20 "get_sha256", 21 "get_spdx_licenses", 22 "identify_bioimageio_yaml_file_name", 23 "is_valid_bioimageio_yaml_name", 24 "load_array", 25 "save_array", 26 "SpdxLicenseEntry", 27 "SpdxLicenses", 28 "write_yaml", 29] 30 31 32class SpdxLicenseEntry(TypedDict): 33 isDeprecatedLicenseId: bool 34 isKnownByZenodo: bool 35 isOsiApproved: bool 36 licenseId: str 37 name: str 38 reference: str 39 40 41class SpdxLicenses(TypedDict): 42 licenseListVersion: str 43 licenses: List[SpdxLicenseEntry] 44 releaseDate: str 45 46 47def get_spdx_licenses() -> SpdxLicenses: 48 """get details of the SPDX licenses known to bioimageio.spec""" 49 with files("bioimageio.spec").joinpath("static/spdx_licenses.json").open( 50 "r", encoding="utf-8" 51 ) as f: 52 return json.load(f)
def
download( source: Union[Annotated[Union[bioimageio.spec._internal.url.HttpUrl, bioimageio.spec._internal.io.RelativeFilePath, Annotated[pathlib.Path, PathType(path_type='file'), FieldInfo(annotation=NoneType, required=True, title='FilePath')]], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], str, Annotated[pydantic_core._pydantic_core.Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)], bioimageio.spec._internal.io.FileDescr, zipp.Path], /, progressbar: Union[bioimageio.spec._internal.io.Progressbar, bool, NoneType] = None, **kwargs: Unpack[bioimageio.spec._internal.io.HashKwargs]) -> Union[bioimageio.spec._internal.io.LocalFile, bioimageio.spec._internal.io.FileInZip]:
668def resolve( 669 source: Union[PermissiveFileSource, FileDescr, ZipPath], 670 /, 671 progressbar: Union[Progressbar, bool, None] = None, 672 **kwargs: Unpack[HashKwargs], 673) -> Union[LocalFile, FileInZip]: 674 """Resolve file `source` (download if needed)""" 675 676 if isinstance(source, str): 677 source = interprete_file_source(source) 678 679 if isinstance(source, RelativeFilePath): 680 source = source.absolute() 681 if isinstance(source, ZipPath): 682 return FileInZip(source, source.root, extract_file_name(source)) 683 684 if isinstance(source, pydantic.AnyUrl): 685 with get_validation_context().replace(perform_io_checks=False): 686 source = HttpUrl(source) 687 688 if isinstance(source, FileDescr): 689 return source.download() 690 elif isinstance(source, ZipPath): 691 zip_root = source.root 692 assert isinstance(zip_root, ZipFile) 693 return FileInZip( 694 source, 695 zip_root, 696 extract_file_name(source), 697 ) 698 elif isinstance(source, Path): 699 if source.is_dir(): 700 raise FileNotFoundError(f"{source} is a directory, not a file") 701 702 if not source.exists(): 703 raise FileNotFoundError(source) 704 local_source = source 705 root: Union[RootHttpUrl, DirectoryPath] = source.parent 706 elif isinstance(source, HttpUrl): 707 if source.scheme not in ("http", "https"): 708 raise NotImplementedError(source.scheme) 709 710 if settings.CI: 711 headers = {"User-Agent": "ci"} 712 if progressbar is None: 713 progressbar = False 714 else: 715 headers = {} 716 if progressbar is None: 717 progressbar = True 718 719 if settings.user_agent is not None: 720 headers["User-Agent"] = settings.user_agent 721 722 downloader = pooch.HTTPDownloader( 723 headers=headers, 724 progressbar=progressbar, # pyright: ignore[reportArgumentType] 725 ) 726 fname = _get_unique_file_name(source) 727 _ls: Any = pooch.retrieve( 728 url=str(source), 729 known_hash=_get_known_hash(kwargs), 730 downloader=downloader, 731 fname=fname, 732 path=settings.cache_path, 733 ) 734 local_source = Path(_ls).absolute() 735 root = source.parent 736 else: 737 assert_never(source) 738 739 return LocalFile( 740 local_source, 741 root, 742 extract_file_name(source), 743 )
Resolve file source
(download if needed)
def
ensure_description_is_dataset( rd: Union[bioimageio.spec.InvalidDescr, Annotated[Union[Annotated[Union[Annotated[bioimageio.spec.application.v0_2.ApplicationDescr, FieldInfo(annotation=NoneType, required=True, title='application 0.2')], Annotated[bioimageio.spec.ApplicationDescr, FieldInfo(annotation=NoneType, required=True, title='application 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='application')], Annotated[Union[Annotated[bioimageio.spec.dataset.v0_2.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.2')], Annotated[bioimageio.spec.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='dataset')], Annotated[Union[Annotated[bioimageio.spec.model.v0_4.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.4')], Annotated[bioimageio.spec.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.5')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='model')], Annotated[Union[Annotated[bioimageio.spec.NotebookDescr, FieldInfo(annotation=NoneType, required=True, title='notebook 0.2')], Annotated[bioimageio.spec.NotebookDescr, FieldInfo(annotation=NoneType, required=True, title='notebook 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='notebook')]], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[Annotated[bioimageio.spec.generic.v0_2.GenericDescr, FieldInfo(annotation=NoneType, required=True, title='generic 0.2')], Annotated[bioimageio.spec.GenericDescr, FieldInfo(annotation=NoneType, required=True, title='generic 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='generic')]]) -> Annotated[Union[Annotated[bioimageio.spec.dataset.v0_2.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.2')], Annotated[bioimageio.spec.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='dataset')]:
263def ensure_description_is_dataset( 264 rd: Union[InvalidDescr, ResourceDescr], 265) -> AnyDatasetDescr: 266 if isinstance(rd, InvalidDescr): 267 rd.validation_summary.display() 268 raise ValueError(f"Invalid {rd.type} description.") 269 270 if rd.type != "dataset": 271 rd.validation_summary.display() 272 raise ValueError( 273 f"Expected a dataset resource, but got resource type '{rd.type}'" 274 ) 275 276 assert not isinstance( 277 rd, 278 ( 279 GenericDescr_v0_2, 280 GenericDescr_v0_3, 281 ), 282 ) 283 284 return rd
def
ensure_description_is_model( rd: Union[bioimageio.spec.InvalidDescr, Annotated[Union[Annotated[Union[Annotated[bioimageio.spec.application.v0_2.ApplicationDescr, FieldInfo(annotation=NoneType, required=True, title='application 0.2')], Annotated[bioimageio.spec.ApplicationDescr, FieldInfo(annotation=NoneType, required=True, title='application 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='application')], Annotated[Union[Annotated[bioimageio.spec.dataset.v0_2.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.2')], Annotated[bioimageio.spec.DatasetDescr, FieldInfo(annotation=NoneType, required=True, title='dataset 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='dataset')], Annotated[Union[Annotated[bioimageio.spec.model.v0_4.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.4')], Annotated[bioimageio.spec.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.5')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='model')], Annotated[Union[Annotated[bioimageio.spec.NotebookDescr, FieldInfo(annotation=NoneType, required=True, title='notebook 0.2')], Annotated[bioimageio.spec.NotebookDescr, FieldInfo(annotation=NoneType, required=True, title='notebook 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='notebook')]], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[Annotated[bioimageio.spec.generic.v0_2.GenericDescr, FieldInfo(annotation=NoneType, required=True, title='generic 0.2')], Annotated[bioimageio.spec.GenericDescr, FieldInfo(annotation=NoneType, required=True, title='generic 0.3')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='generic')]]) -> Annotated[Union[Annotated[bioimageio.spec.model.v0_4.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.4')], Annotated[bioimageio.spec.ModelDescr, FieldInfo(annotation=NoneType, required=True, title='model 0.5')]], Discriminator(discriminator='format_version', custom_error_type=None, custom_error_message=None, custom_error_context=None), FieldInfo(annotation=NoneType, required=True, title='model')]:
235def ensure_description_is_model( 236 rd: Union[InvalidDescr, ResourceDescr], 237) -> AnyModelDescr: 238 """ 239 Raises: 240 ValueError: for invalid or non-model resources 241 """ 242 if isinstance(rd, InvalidDescr): 243 rd.validation_summary.display() 244 raise ValueError(f"Invalid {rd.type} description") 245 246 if rd.type != "model": 247 rd.validation_summary.display() 248 raise ValueError( 249 f"Expected a model resource, but got resource type '{rd.type}'" 250 ) 251 252 assert not isinstance( 253 rd, 254 ( 255 GenericDescr_v0_2, 256 GenericDescr_v0_3, 257 ), 258 ) 259 260 return rd
Raises:
- ValueError: for invalid or non-model resources
def
extract_file_name( src: Union[Annotated[pydantic_core._pydantic_core.Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)], bioimageio.spec._internal.url.HttpUrl, pathlib.PurePath, bioimageio.spec._internal.io.RelativeFilePath, zipp.Path]) -> str:
828def extract_file_name( 829 src: Union[pydantic.HttpUrl, HttpUrl, PurePath, RelativeFilePath, ZipPath], 830) -> FileName: 831 if isinstance(src, ZipPath): 832 return src.name or src.root.filename or "bioimageio.zip" 833 elif isinstance(src, RelativeFilePath): 834 return src.path.name 835 elif isinstance(src, PurePath): 836 return src.name 837 else: 838 url = urlparse(str(src)) 839 if ( 840 url.scheme == "https" 841 and url.hostname == "zenodo.org" 842 and url.path.startswith("/api/records/") 843 and url.path.endswith("/content") 844 ): 845 return url.path.split("/")[-2] 846 else: 847 return url.path.split("/")[-1]
def
get_sha256( path: Union[pathlib.Path, zipp.Path]) -> bioimageio.spec._internal.io_basics.Sha256:
850def get_sha256(path: Union[Path, ZipPath]) -> Sha256: 851 """from https://stackoverflow.com/a/44873382""" 852 if isinstance(path, ZipPath): 853 # no buffered reading available 854 zf = path.root 855 assert isinstance(zf, ZipFile) 856 data = path.read_bytes() 857 assert isinstance(data, bytes) 858 h = hashlib.sha256(data) 859 else: 860 h = hashlib.sha256() 861 chunksize = 128 * 1024 862 b = bytearray(chunksize) 863 mv = memoryview(b) 864 with open(path, "rb", buffering=0) as f: 865 for n in iter(lambda: f.readinto(mv), 0): 866 h.update(mv[:n]) 867 868 sha = h.hexdigest() 869 assert len(sha) == 64 870 return Sha256(sha)
48def get_spdx_licenses() -> SpdxLicenses: 49 """get details of the SPDX licenses known to bioimageio.spec""" 50 with files("bioimageio.spec").joinpath("static/spdx_licenses.json").open( 51 "r", encoding="utf-8" 52 ) as f: 53 return json.load(f)
get details of the SPDX licenses known to bioimageio.spec
def
identify_bioimageio_yaml_file_name(file_names: Iterable[str]) -> str:
427def identify_bioimageio_yaml_file_name(file_names: Iterable[FileName]) -> FileName: 428 file_names = sorted(file_names) 429 for bioimageio_name in ALL_BIOIMAGEIO_YAML_NAMES: 430 for file_name in file_names: 431 if file_name == bioimageio_name or file_name.endswith( 432 "." + bioimageio_name 433 ): 434 return file_name 435 436 raise ValueError( 437 f"No {BIOIMAGEIO_YAML} found in {file_names}. (Looking for '{BIOIMAGEIO_YAML}'" 438 + " or or any of the alterntive file names:" 439 + f" {ALTERNATIVE_BIOIMAGEIO_YAML_NAMES}, or any file with an extension of" 440 + f" those, e.g. 'anything.{BIOIMAGEIO_YAML}')." 441 )
def
is_valid_bioimageio_yaml_name(file_name: str) -> bool:
def
load_array( source: Union[Annotated[Union[bioimageio.spec._internal.url.HttpUrl, bioimageio.spec._internal.io.RelativeFilePath, Annotated[pathlib.Path, PathType(path_type='file'), FieldInfo(annotation=NoneType, required=True, title='FilePath')]], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])], bioimageio.spec._internal.io.FileDescr, zipp.Path]) -> numpy.ndarray[typing.Any, numpy.dtype[typing.Any]]:
def
save_array( path: Union[pathlib.Path, zipp.Path], array: numpy.ndarray[typing.Any, numpy.dtype[typing.Any]]) -> None:
class
SpdxLicenseEntry(typing.TypedDict):
class
SpdxLicenses(typing.TypedDict):
42class SpdxLicenses(TypedDict): 43 licenseListVersion: str 44 licenses: List[SpdxLicenseEntry] 45 releaseDate: str
licenses: List[SpdxLicenseEntry]
def
write_yaml( content: Union[YamlValue, Dict[str, YamlValue]], /, file: Union[Annotated[pathlib.Path, PathType(path_type='new')], Annotated[pathlib.Path, PathType(path_type='file')], IO[str], IO[bytes], zipp.Path]):
65def write_yaml( 66 content: Union[YamlValue, BioimageioYamlContent], 67 /, 68 file: Union[NewPath, FilePath, IO[str], IO[bytes], ZipPath], 69): 70 if isinstance(file, Path): 71 cm = file.open("w", encoding="utf-8") 72 else: 73 cm = nullcontext(file) 74 75 with cm as f: 76 _yaml_dump.dump(content, f)