bioimageio.spec.common

 1from pydantic import ValidationError
 2
 3from ._internal.common_nodes import InvalidDescr
 4from ._internal.io import (
 5    BioimageioYamlContent,
 6    BioimageioYamlSource,
 7    FileDescr,
 8    YamlValue,
 9)
10from ._internal.io_basics import (
11    AbsoluteDirectory,
12    AbsoluteFilePath,
13    FileName,
14    Sha256,
15    ZipPath,
16)
17from ._internal.root_url import RootHttpUrl
18from ._internal.types import (
19    FilePath,
20    FileSource,
21    PermissiveFileSource,
22    RelativeFilePath,
23)
24from ._internal.url import HttpUrl
25
26__all__ = [
27    "AbsoluteDirectory",
28    "AbsoluteFilePath",
29    "BioimageioYamlContent",
30    "BioimageioYamlSource",
31    "FileDescr",
32    "FileName",
33    "FilePath",
34    "FileSource",
35    "HttpUrl",
36    "InvalidDescr",
37    "PermissiveFileSource",
38    "RelativeFilePath",
39    "RootHttpUrl",
40    "Sha256",
41    "ValidationError",
42    "YamlValue",
43    "ZipPath",
44]
AbsoluteDirectory = typing.Annotated[pathlib.Path, PathType(path_type='dir'), Predicate(is_absolute), FieldInfo(annotation=NoneType, required=True, title='AbsoluteDirectory')]
AbsoluteFilePath = typing.Annotated[pathlib.Path, PathType(path_type='file'), Predicate(is_absolute), FieldInfo(annotation=NoneType, required=True, title='AbsoluteFilePath')]
BioimageioYamlContent = typing.Dict[str, YamlValue]
BioimageioYamlSource = typing.Union[typing.Annotated[typing.Union[HttpUrl, RelativeFilePath, typing.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, typing.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)], zipfile.ZipFile, typing.Dict[str, YamlValue]]
class FileDescr(bioimageio.spec._internal.node.Node):
787class FileDescr(Node):
788    source: ImportantFileSource
789    """∈📦 file source"""
790
791    sha256: Optional[Sha256] = None
792    """SHA256 checksum of the source file"""
793
794    @model_validator(mode="after")
795    def _validate_sha256(self) -> Self:
796        if get_validation_context().perform_io_checks:
797            self.validate_sha256()
798
799        return self
800
801    def validate_sha256(self):
802        context = get_validation_context()
803        if (src_str := str(self.source)) in context.known_files:
804            actual_sha = context.known_files[src_str]
805        else:
806            local_source = download(self.source, sha256=self.sha256).path
807            actual_sha = get_sha256(local_source)
808            context.known_files[str(self.source)] = actual_sha
809
810        if self.sha256 == actual_sha:
811            pass
812        elif self.sha256 is None or context.update_hashes:
813            self.sha256 = actual_sha
814        elif self.sha256 != actual_sha:
815            raise ValueError(
816                f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got "
817                + f"{actual_sha}. Update expected `sha256` or point to the matching "
818                + "file."
819            )
820
821        return
822
823    def download(self):
824
825        return download(self.source, sha256=self.sha256)
source: Annotated[Union[HttpUrl, 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')]), AfterValidator(func=<function wo_special_file_name at 0x7f2602536ca0>), PlainSerializer(func=<function _package at 0x7f2602535e40>, return_type=PydanticUndefined, when_used='unless-none')]

∈📦 file source

sha256: Optional[Sha256]

SHA256 checksum of the source file

def validate_sha256(self):
801    def validate_sha256(self):
802        context = get_validation_context()
803        if (src_str := str(self.source)) in context.known_files:
804            actual_sha = context.known_files[src_str]
805        else:
806            local_source = download(self.source, sha256=self.sha256).path
807            actual_sha = get_sha256(local_source)
808            context.known_files[str(self.source)] = actual_sha
809
810        if self.sha256 == actual_sha:
811            pass
812        elif self.sha256 is None or context.update_hashes:
813            self.sha256 = actual_sha
814        elif self.sha256 != actual_sha:
815            raise ValueError(
816                f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got "
817                + f"{actual_sha}. Update expected `sha256` or point to the matching "
818                + "file."
819            )
820
821        return
def download(self):
823    def download(self):
824
825        return download(self.source, sha256=self.sha256)
FileName = <class 'str'>
FilePath = typing.Annotated[pathlib.Path, PathType(path_type='file'), FieldInfo(annotation=NoneType, required=True, title='FilePath')]
FileSource = typing.Annotated[typing.Union[HttpUrl, RelativeFilePath, typing.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')])]
class HttpUrl(bioimageio.spec.common.RootHttpUrl):
123class HttpUrl(RootHttpUrl):
124    """A URL with the HTTP or HTTPS scheme."""
125
126    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[pydantic.HttpUrl]
127    _exists: Optional[bool] = None
128
129    def _after_validator(self):
130        self = super()._after_validator()
131        context = get_validation_context()
132        if (
133            context.perform_io_checks
134            and str(self._validated) not in context.known_files
135        ):
136            self._validated = _validate_url(self._validated)
137            self._exists = True
138
139        return self
140
141    def exists(self):
142        """True if URL is available"""
143        if self._exists is None:
144            try:
145                self._validated = _validate_url(self._validated)
146            except Exception as e:
147                logger.info(e)
148                self._exists = False
149            else:
150                self._exists = True
151
152        return self._exists

A URL with the HTTP or HTTPS scheme.

root_model: ClassVar[Type[pydantic.root_model.RootModel[Any]]] = <class 'pydantic.root_model.RootModel[Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]]'>

the pydantic root model to validate the string

def exists(self):
141    def exists(self):
142        """True if URL is available"""
143        if self._exists is None:
144            try:
145                self._validated = _validate_url(self._validated)
146            except Exception as e:
147                logger.info(e)
148                self._exists = False
149            else:
150                self._exists = True
151
152        return self._exists

True if URL is available

class InvalidDescr(bioimageio.spec._internal.common_nodes.ResourceDescrBase):
356class InvalidDescr(
357    ResourceDescrBase,
358    extra="allow",
359    title="An invalid resource description",
360):
361    """A representation of an invalid resource description"""
362
363    implemented_type: ClassVar[Literal["unknown"]] = "unknown"
364    if TYPE_CHECKING:  # see NodeWithExplicitlySetFields
365        type: Any = "unknown"
366    else:
367        type: Any
368
369    implemented_format_version: ClassVar[Literal["unknown"]] = "unknown"
370    if TYPE_CHECKING:  # see NodeWithExplicitlySetFields
371        format_version: Any = "unknown"
372    else:
373        format_version: Any

A representation of an invalid resource description

implemented_type: ClassVar[Literal['unknown']] = 'unknown'
implemented_format_version: ClassVar[Literal['unknown']] = 'unknown'
implemented_format_version_tuple: ClassVar[Tuple[int, int, int]] = (0, 0, 0)
def model_post_init(self: pydantic.main.BaseModel, context: Any, /) -> None:
124                    def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
125                        """We need to both initialize private attributes and call the user-defined model_post_init
126                        method.
127                        """
128                        init_private_attributes(self, context)
129                        original_model_post_init(self, context)

We need to both initialize private attributes and call the user-defined model_post_init method.

PermissiveFileSource = typing.Union[typing.Annotated[typing.Union[HttpUrl, RelativeFilePath, typing.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, typing.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)]]
class RelativeFilePath(pydantic.root_model.RootModel[PurePath], typing.Generic[~AbsolutePathT]):
184class RelativeFilePath(
185    RelativePathBase[Union[AbsoluteFilePath, HttpUrl, ZipPath]], frozen=True
186):
187    """A path relative to the `rdf.yaml` file (also if the RDF source is a URL)."""
188
189    def model_post_init(self, __context: Any) -> None:
190        """add validation @private"""
191        if not self.root.parts:  # an empty path can only be a directory
192            raise ValueError(f"{self.root} is not a valid file path.")
193
194        super().model_post_init(__context)
195
196    def get_absolute(
197        self, root: "RootHttpUrl | Path | AnyUrl | ZipFile"
198    ) -> "AbsoluteFilePath | HttpUrl | ZipPath":
199        absolute = self._get_absolute_impl(root)
200        if (
201            isinstance(absolute, Path)
202            and (context := get_validation_context()).perform_io_checks
203            and str(self.root) not in context.known_files
204            and not absolute.is_file()
205        ):
206            raise ValueError(f"{absolute} does not point to an existing file")
207
208        return absolute

A path relative to the rdf.yaml file (also if the RDF source is a URL).

def model_post_init(self: pydantic.main.BaseModel, context: Any, /) -> None:
124                    def wrapped_model_post_init(self: BaseModel, context: Any, /) -> None:
125                        """We need to both initialize private attributes and call the user-defined model_post_init
126                        method.
127                        """
128                        init_private_attributes(self, context)
129                        original_model_post_init(self, context)

We need to both initialize private attributes and call the user-defined model_post_init method.

def get_absolute( self, root: RootHttpUrl | pathlib.Path | pydantic_core._pydantic_core.Url | zipfile.ZipFile) -> Union[Annotated[pathlib.Path, PathType(path_type='file'), Predicate(is_absolute), FieldInfo(annotation=NoneType, required=True, title='AbsoluteFilePath')], HttpUrl, zipp.Path]:
196    def get_absolute(
197        self, root: "RootHttpUrl | Path | AnyUrl | ZipFile"
198    ) -> "AbsoluteFilePath | HttpUrl | ZipPath":
199        absolute = self._get_absolute_impl(root)
200        if (
201            isinstance(absolute, Path)
202            and (context := get_validation_context()).perform_io_checks
203            and str(self.root) not in context.known_files
204            and not absolute.is_file()
205        ):
206            raise ValueError(f"{absolute} does not point to an existing file")
207
208        return absolute
class RootHttpUrl(bioimageio.spec._internal.validated_string.ValidatedString):
13class RootHttpUrl(ValidatedString):
14    """A 'URL folder', possibly an invalid HTTP URL"""
15
16    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[pydantic.HttpUrl]
17    _validated: pydantic.HttpUrl
18
19    def absolute(self):
20        """analog to `absolute` method of pathlib."""
21        return self
22
23    @property
24    def scheme(self) -> str:
25        return self._validated.scheme
26
27    @property
28    def host(self) -> Optional[str]:
29        return self._validated.host
30
31    @property
32    def path(self) -> Optional[str]:
33        return self._validated.path
34
35    @property
36    def parent(self) -> RootHttpUrl:
37        parsed = urlsplit(str(self))
38        path = list(parsed.path.split("/"))
39        if (
40            parsed.netloc == "zenodo.org"
41            and parsed.path.startswith("/api/records/")
42            and parsed.path.endswith("/content")
43        ):
44            path[-2:-1] = []
45        else:
46            path = path[:-1]
47
48        return RootHttpUrl(
49            urlunsplit(
50                (
51                    parsed.scheme,
52                    parsed.netloc,
53                    "/".join(path),
54                    parsed.query,
55                    parsed.fragment,
56                )
57            )
58        )
59
60    @property
61    def parents(self) -> Iterable[RootHttpUrl]:
62        """iterate over all URL parents (max 100)"""
63        current = self
64        for _ in range(100):
65            current = current.parent
66            yield current

A 'URL folder', possibly an invalid HTTP URL

root_model: ClassVar[Type[pydantic.root_model.RootModel[Any]]] = <class 'pydantic.root_model.RootModel[Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]]'>

the pydantic root model to validate the string

def absolute(self):
19    def absolute(self):
20        """analog to `absolute` method of pathlib."""
21        return self

analog to absolute method of pathlib.

scheme: str
23    @property
24    def scheme(self) -> str:
25        return self._validated.scheme
host: Optional[str]
27    @property
28    def host(self) -> Optional[str]:
29        return self._validated.host
path: Optional[str]
31    @property
32    def path(self) -> Optional[str]:
33        return self._validated.path
parent: RootHttpUrl
35    @property
36    def parent(self) -> RootHttpUrl:
37        parsed = urlsplit(str(self))
38        path = list(parsed.path.split("/"))
39        if (
40            parsed.netloc == "zenodo.org"
41            and parsed.path.startswith("/api/records/")
42            and parsed.path.endswith("/content")
43        ):
44            path[-2:-1] = []
45        else:
46            path = path[:-1]
47
48        return RootHttpUrl(
49            urlunsplit(
50                (
51                    parsed.scheme,
52                    parsed.netloc,
53                    "/".join(path),
54                    parsed.query,
55                    parsed.fragment,
56                )
57            )
58        )
parents: Iterable[RootHttpUrl]
60    @property
61    def parents(self) -> Iterable[RootHttpUrl]:
62        """iterate over all URL parents (max 100)"""
63        current = self
64        for _ in range(100):
65            current = current.parent
66            yield current

iterate over all URL parents (max 100)

class Sha256(bioimageio.spec._internal.validated_string.ValidatedString):
33class Sha256(ValidatedString):
34    """A SHA-256 hash value"""
35
36    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[
37        Annotated[
38            str,
39            StringConstraints(
40                strip_whitespace=True, to_lower=True, min_length=64, max_length=64
41            ),
42        ]
43    ]

A SHA-256 hash value

root_model: ClassVar[Type[pydantic.root_model.RootModel[Any]]] = <class 'pydantic.root_model.RootModel[Annotated[str, StringConstraints]]'>

the pydantic root model to validate the string

class ValidationError(builtins.ValueError):

Inappropriate argument value (of correct type).

def from_exception_data(title, line_errors, input_type='python', hide_input=False):
def error_count(self, /):
def errors( self, /, *, include_url=True, include_context=True, include_input=True):
def json( self, /, *, indent=None, include_url=True, include_context=True, include_input=True):
title
YamlValue = YamlValue
ZipPath = <class 'zipp.Path'>