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)
def get_spdx_licenses() -> SpdxLicenses:
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:
419def is_valid_bioimageio_yaml_name(file_name: FileName) -> bool:
420    for bioimageio_name in ALL_BIOIMAGEIO_YAML_NAMES:
421        if file_name == bioimageio_name or file_name.endswith("." + bioimageio_name):
422            return True
423
424    return False
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]]:
284def load_array(source: Union[FileSource, FileDescr, ZipPath]) -> NDArray[Any]:
285    path = resolve(source).path
286    with path.open(mode="rb") as f:
287        assert not isinstance(f, io.TextIOWrapper)
288        return numpy.load(f, allow_pickle=False)
def save_array( path: Union[pathlib.Path, zipp.Path], array: numpy.ndarray[typing.Any, numpy.dtype[typing.Any]]) -> None:
291def save_array(path: Union[Path, ZipPath], array: NDArray[Any]) -> None:
292    with path.open(mode="wb") as f:
293        assert not isinstance(f, io.TextIOWrapper)
294        return numpy.save(f, array, allow_pickle=False)
class SpdxLicenseEntry(typing.TypedDict):
33class SpdxLicenseEntry(TypedDict):
34    isDeprecatedLicenseId: bool
35    isKnownByZenodo: bool
36    isOsiApproved: bool
37    licenseId: str
38    name: str
39    reference: str
isDeprecatedLicenseId: bool
isKnownByZenodo: bool
isOsiApproved: bool
licenseId: str
name: str
reference: str
class SpdxLicenses(typing.TypedDict):
42class SpdxLicenses(TypedDict):
43    licenseListVersion: str
44    licenses: List[SpdxLicenseEntry]
45    releaseDate: str
licenseListVersion: str
licenses: List[SpdxLicenseEntry]
releaseDate: str
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)