bioimageio.spec.generic.v0_3

  1from __future__ import annotations
  2
  3import string
  4from functools import partial
  5from typing import (
  6    TYPE_CHECKING,
  7    Any,
  8    ClassVar,
  9    Dict,
 10    List,
 11    Literal,
 12    Optional,
 13    Sequence,
 14    Type,
 15    TypeVar,
 16    Union,
 17)
 18
 19import annotated_types
 20from annotated_types import Len, LowerCase, MaxLen, MinLen
 21from pydantic import Field, RootModel, ValidationInfo, field_validator, model_validator
 22from typing_extensions import Annotated
 23
 24from bioimageio.spec._internal.type_guards import is_dict
 25
 26from .._internal.common_nodes import Node, ResourceDescrBase
 27from .._internal.constants import TAG_CATEGORIES
 28from .._internal.field_validation import validate_gh_user
 29from .._internal.field_warning import as_warning, warn
 30from .._internal.io import (
 31    BioimageioYamlContent,
 32    FileDescr,
 33    V_suffix,
 34    include_in_package_serializer,
 35    is_yaml_value,
 36    validate_suffix,
 37)
 38from .._internal.io_basics import AbsoluteFilePath, Sha256
 39from .._internal.license_id import DeprecatedLicenseId, LicenseId
 40from .._internal.node_converter import Converter
 41from .._internal.types import ImportantFileSource, NotEmpty, RelativeFilePath
 42from .._internal.url import HttpUrl
 43from .._internal.validated_string import ValidatedString
 44from .._internal.validator_annotations import (
 45    AfterValidator,
 46    Predicate,
 47    RestrictCharacters,
 48)
 49from .._internal.version_type import Version
 50from .._internal.warning_levels import ALERT, INFO
 51from ._v0_3_converter import convert_from_older_format
 52from .v0_2 import Author as _Author_v0_2
 53from .v0_2 import BadgeDescr, CoverImageSource, Doi, OrcidId, Uploader
 54from .v0_2 import Maintainer as _Maintainer_v0_2
 55
 56__all__ = [
 57    "Author",
 58    "BadgeDescr",
 59    "CiteEntry",
 60    "DeprecatedLicenseId",
 61    "Doi",
 62    "FileDescr",
 63    "GenericDescr",
 64    "HttpUrl",
 65    "KNOWN_SPECIFIC_RESOURCE_TYPES",
 66    "LicenseId",
 67    "LinkedResource",
 68    "Maintainer",
 69    "OrcidId",
 70    "RelativeFilePath",
 71    "ResourceId",
 72    "Sha256",
 73    "Uploader",
 74    "VALID_COVER_IMAGE_EXTENSIONS",
 75    "Version",
 76]
 77
 78KNOWN_SPECIFIC_RESOURCE_TYPES = (
 79    "application",
 80    "collection",
 81    "dataset",
 82    "model",
 83    "notebook",
 84)
 85VALID_COVER_IMAGE_EXTENSIONS = (
 86    ".gif",
 87    ".jpeg",
 88    ".jpg",
 89    ".png",
 90    ".svg",
 91)
 92
 93
 94class ResourceId(ValidatedString):
 95    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[
 96        Annotated[
 97            NotEmpty[str],
 98            RestrictCharacters(string.ascii_lowercase + string.digits + "_-/."),
 99            annotated_types.Predicate(
100                lambda s: not (s.startswith("/") or s.endswith("/"))
101            ),
102        ]
103    ]
104
105
106def _validate_md_suffix(value: V_suffix) -> V_suffix:
107    return validate_suffix(value, suffix=".md", case_sensitive=True)
108
109
110DocumentationSource = Annotated[
111    Union[AbsoluteFilePath, RelativeFilePath, HttpUrl],
112    Field(union_mode="left_to_right"),
113    AfterValidator(_validate_md_suffix),
114    include_in_package_serializer,
115]
116
117
118def _has_no_slash(s: str) -> bool:
119    return "/" not in s and "\\" not in s
120
121
122class Author(_Author_v0_2):
123    name: Annotated[str, Predicate(_has_no_slash)]
124    github_user: Optional[str] = None
125
126    @field_validator("github_user", mode="after")
127    def _validate_gh_user(cls, value: Optional[str]):
128        if value is None:
129            return None
130        else:
131            return validate_gh_user(value)
132
133
134class _AuthorConv(Converter[_Author_v0_2, Author]):
135    def _convert(
136        self, src: _Author_v0_2, tgt: "type[Author] | type[dict[str, Any]]"
137    ) -> "Author | dict[str, Any]":
138        return tgt(
139            name=src.name,
140            github_user=src.github_user,
141            affiliation=src.affiliation,
142            email=src.email,
143            orcid=src.orcid,
144        )
145
146
147_author_conv = _AuthorConv(_Author_v0_2, Author)
148
149
150class Maintainer(_Maintainer_v0_2):
151    name: Optional[Annotated[str, Predicate(_has_no_slash)]] = None
152    github_user: str
153
154    @field_validator("github_user", mode="after")
155    def validate_gh_user(cls, value: str):
156        return validate_gh_user(value)
157
158
159class _MaintainerConv(Converter[_Maintainer_v0_2, Maintainer]):
160    def _convert(
161        self, src: _Maintainer_v0_2, tgt: "type[Maintainer | dict[str, Any]]"
162    ) -> "Maintainer | dict[str, Any]":
163        return tgt(
164            name=src.name,
165            github_user=src.github_user,
166            affiliation=src.affiliation,
167            email=src.email,
168            orcid=src.orcid,
169        )
170
171
172_maintainer_conv = _MaintainerConv(_Maintainer_v0_2, Maintainer)
173
174
175class CiteEntry(Node):
176    """A citation that should be referenced in work using this resource."""
177
178    text: str
179    """free text description"""
180
181    doi: Optional[Doi] = None
182    """A digital object identifier (DOI) is the prefered citation reference.
183    See https://www.doi.org/ for details.
184    Note:
185        Either **doi** or **url** have to be specified.
186    """
187
188    url: Optional[HttpUrl] = None
189    """URL to cite (preferably specify a **doi** instead/also).
190    Note:
191        Either **doi** or **url** have to be specified.
192    """
193
194    @model_validator(mode="after")
195    def _check_doi_or_url(self):
196        if not self.doi and not self.url:
197            raise ValueError("Either 'doi' or 'url' is required")
198
199        return self
200
201
202class LinkedResourceBase(Node):
203
204    @model_validator(mode="before")
205    def _remove_version_number(cls, value: Any):
206        if is_dict(value):
207            vn = value.pop("version_number", None)
208            if vn is not None and value.get("version") is None:
209                value["version"] = vn
210
211        return value
212
213    version: Optional[Version] = None
214    """The version of the linked resource following SemVer 2.0."""
215
216
217class LinkedResource(LinkedResourceBase):
218    """Reference to a bioimage.io resource"""
219
220    id: ResourceId
221    """A valid resource `id` from the official bioimage.io collection."""
222
223
224class BioimageioConfig(Node, extra="allow"):
225    """bioimage.io internal metadata."""
226
227
228class Config(Node, extra="allow"):
229    """A place to store additional metadata (often tool specific).
230
231    Such additional metadata is typically set programmatically by the respective tool
232    or by people with specific insights into the tool.
233    If you want to store additional metadata that does not match any of the other
234    fields, think of a key unlikely to collide with anyone elses use-case/tool and save
235    it here.
236
237    Please consider creating [an issue in the bioimageio.spec repository](https://github.com/bioimage-io/spec-bioimage-io/issues/new?template=Blank+issue)
238    if you are not sure if an existing field could cover your use case
239    or if you think such a field should exist.
240    """
241
242    bioimageio: BioimageioConfig = Field(default_factory=BioimageioConfig)
243    """bioimage.io internal metadata."""
244
245    @model_validator(mode="after")
246    def _validate_extra_fields(self):
247        if self.model_extra:
248            for k, v in self.model_extra.items():
249                if not isinstance(v, Node) and not is_yaml_value(v):
250                    raise ValueError(
251                        f"config.{k} is not a valid YAML value or `Node` instance"
252                    )
253
254        return self
255
256
257class GenericModelDescrBase(ResourceDescrBase):
258    """Base for all resource descriptions including of model descriptions"""
259
260    name: Annotated[
261        Annotated[
262            str, RestrictCharacters(string.ascii_letters + string.digits + "_+- ()")
263        ],
264        MinLen(5),
265        MaxLen(128),
266        warn(MaxLen(64), "Name longer than 64 characters.", INFO),
267    ]
268    name: Annotated[NotEmpty[str], MaxLen(128)]
269    """A human-friendly name of the resource description.
270    May only contains letters, digits, underscore, minus, parentheses and spaces."""
271
272    description: Annotated[
273        str, MaxLen(1024), warn(MaxLen(512), "Description longer than 512 characters.")
274    ]
275    """A string containing a brief description."""
276
277    covers: Annotated[
278        List[CoverImageSource],
279        Field(
280            examples=[],
281            description=(
282                "Cover images. Please use an image smaller than 500KB and an aspect"
283                " ratio width to height of 2:1 or 1:1.\nThe supported image formats"
284                f" are: {VALID_COVER_IMAGE_EXTENSIONS}"
285            ),
286        ),
287    ] = Field(default_factory=list)
288    """∈📦 Cover images."""
289
290    id_emoji: Optional[
291        Annotated[str, Len(min_length=1, max_length=2), Field(examples=["🦈", "🦥"])]
292    ] = None
293    """UTF-8 emoji for display alongside the `id`."""
294
295    authors: NotEmpty[List[Author]]
296    """The authors are the creators of this resource description and the primary points of contact."""
297
298    attachments: List[FileDescr] = Field(default_factory=list)
299    """file attachments"""
300
301    cite: NotEmpty[List[CiteEntry]]
302    """citations"""
303
304    license: Annotated[
305        Annotated[
306            Union[LicenseId, DeprecatedLicenseId], Field(union_mode="left_to_right")
307        ],
308        warn(
309            LicenseId,
310            "{value} is deprecated, see https://spdx.org/licenses/{value}.html",
311        ),
312        Field(examples=["CC0-1.0", "MIT", "BSD-2-Clause"]),
313    ]
314    """A [SPDX license identifier](https://spdx.org/licenses/).
315    We do not support custom license beyond the SPDX license list, if you need that please
316    [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose)
317    to discuss your intentions with the community."""
318
319    git_repo: Annotated[
320        Optional[HttpUrl],
321        Field(
322            examples=[
323                "https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad"
324            ],
325        ),
326    ] = None
327    """A URL to the Git repository where the resource is being developed."""
328
329    icon: Union[
330        Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None
331    ] = None
332    """An icon for illustration, e.g. on bioimage.io"""
333
334    links: Annotated[
335        List[str],
336        Field(
337            examples=[
338                (
339                    "ilastik/ilastik",
340                    "deepimagej/deepimagej",
341                    "zero/notebook_u-net_3d_zerocostdl4mic",
342                )
343            ],
344        ),
345    ] = Field(default_factory=list)
346    """IDs of other bioimage.io resources"""
347
348    uploader: Optional[Uploader] = None
349    """The person who uploaded the model (e.g. to bioimage.io)"""
350
351    maintainers: List[Maintainer] = Field(default_factory=list)
352    """Maintainers of this resource.
353    If not specified, `authors` are maintainers and at least some of them has to specify their `github_user` name"""
354
355    @partial(as_warning, severity=ALERT)
356    @field_validator("maintainers", mode="after")
357    @classmethod
358    def check_maintainers_exist(
359        cls, maintainers: List[Maintainer], info: ValidationInfo
360    ) -> List[Maintainer]:
361        if not maintainers and "authors" in info.data:
362            authors: List[Author] = info.data["authors"]
363            if all(a.github_user is None for a in authors):
364                raise ValueError(
365                    "Missing `maintainers` or any author in `authors` with a specified"
366                    + " `github_user` name."
367                )
368
369        return maintainers
370
371    tags: Annotated[
372        List[str],
373        Field(examples=[("unet2d", "pytorch", "nucleus", "segmentation", "dsb2018")]),
374    ] = Field(default_factory=list)
375    """Associated tags"""
376
377    @as_warning
378    @field_validator("tags")
379    @classmethod
380    def warn_about_tag_categories(
381        cls, value: List[str], info: ValidationInfo
382    ) -> List[str]:
383        categories = TAG_CATEGORIES.get(info.data["type"], {})
384        missing_categories: List[Dict[str, Sequence[str]]] = []
385        for cat, entries in categories.items():
386            if not any(e in value for e in entries):
387                missing_categories.append({cat: entries})
388
389        if missing_categories:
390            raise ValueError(
391                f"Missing tags from bioimage.io categories: {missing_categories}"
392            )
393
394        return value
395
396    version: Optional[Version] = None
397    """The version of the resource following SemVer 2.0."""
398
399    @model_validator(mode="before")
400    def _remove_version_number(cls, value: Any):
401        if is_dict(value):
402            vn = value.pop("version_number", None)
403            if vn is not None and value.get("version") is None:
404                value["version"] = vn
405
406        return value
407
408
409class GenericDescrBase(GenericModelDescrBase):
410    """Base for all resource descriptions except for the model descriptions"""
411
412    implemented_format_version: ClassVar[Literal["0.3.0"]] = "0.3.0"
413    if TYPE_CHECKING:
414        format_version: Literal["0.3.0"] = "0.3.0"
415    else:
416        format_version: Literal["0.3.0"]
417        """The **format** version of this resource specification"""
418
419    @model_validator(mode="before")
420    @classmethod
421    def _convert_from_older_format(
422        cls, data: BioimageioYamlContent, /
423    ) -> BioimageioYamlContent:
424        cls.convert_from_old_format_wo_validation(data)
425        return data
426
427    @classmethod
428    def convert_from_old_format_wo_validation(cls, data: BioimageioYamlContent) -> None:
429        """Convert metadata following an older format version to this classes' format
430        without validating the result.
431        """
432        convert_from_older_format(data)
433
434    documentation: Annotated[
435        Optional[DocumentationSource],
436        Field(
437            examples=[
438                "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_descriptions/models/unet2d_nuclei_broad/README.md",
439                "README.md",
440            ],
441        ),
442    ] = None
443    """∈📦 URL or relative path to a markdown file encoded in UTF-8 with additional documentation.
444    The recommended documentation file name is `README.md`. An `.md` suffix is mandatory."""
445
446    badges: List[BadgeDescr] = Field(default_factory=list)
447    """badges associated with this resource"""
448
449    config: Config = Field(default_factory=Config)
450    """A field for custom configuration that can contain any keys not present in the RDF spec.
451    This means you should not store, for example, a GitHub repo URL in `config` since there is a `git_repo` field.
452    Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions,
453    it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name,
454    for example:
455    ```yaml
456    config:
457        giraffe_neckometer:  # here is the domain name
458            length: 3837283
459            address:
460                home: zoo
461        imagej:              # config specific to ImageJ
462            macro_dir: path/to/macro/file
463    ```
464    If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`.
465    You may want to list linked files additionally under `attachments` to include them when packaging a resource.
466    (Packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains
467    an altered rdf.yaml file with local references to the downloaded files.)"""
468
469
470ResourceDescrType = TypeVar("ResourceDescrType", bound=GenericDescrBase)
471
472
473class GenericDescr(GenericDescrBase, extra="ignore"):
474    """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF).
475
476    An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook.
477    Note that those resources are described with a type-specific RDF.
478    Use this generic resource description, if none of the known specific types matches your resource.
479    """
480
481    type: Annotated[str, LowerCase] = Field("generic", frozen=True)
482    """The resource type assigns a broad category to the resource."""
483
484    id: Optional[
485        Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])]
486    ] = None
487    """bioimage.io-wide unique resource identifier
488    assigned by bioimage.io; version **un**specific."""
489
490    parent: Optional[ResourceId] = None
491    """The description from which this one is derived"""
492
493    source: Optional[HttpUrl] = None
494    """The primary source of the resource"""
495
496    @field_validator("type", mode="after")
497    @classmethod
498    def check_specific_types(cls, value: str) -> str:
499        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
500            raise ValueError(
501                f"Use the {value} description instead of this generic description for"
502                + f" your '{value}' resource."
503            )
504
505        return value
class Author(bioimageio.spec.generic.v0_2.Author):
123class Author(_Author_v0_2):
124    name: Annotated[str, Predicate(_has_no_slash)]
125    github_user: Optional[str] = None
126
127    @field_validator("github_user", mode="after")
128    def _validate_gh_user(cls, value: Optional[str]):
129        if value is None:
130            return None
131        else:
132            return validate_gh_user(value)
name: Annotated[str, Predicate(func=<function _has_no_slash at 0x7f56297339c0>)]
github_user: Optional[str]
class BadgeDescr(bioimageio.spec._internal.node.Node):
142class BadgeDescr(Node):
143    """A custom badge"""
144
145    label: Annotated[str, Field(examples=["Open in Colab"])]
146    """badge label to display on hover"""
147
148    icon: Annotated[
149        Optional[InPackageIfLocalFileSource],
150        Field(examples=["https://colab.research.google.com/assets/colab-badge.svg"]),
151    ] = None
152    """badge icon"""
153
154    url: Annotated[
155        HttpUrl,
156        Field(
157            examples=[
158                "https://colab.research.google.com/github/HenriquesLab/ZeroCostDL4Mic/blob/master/Colab_notebooks/U-net_2D_ZeroCostDL4Mic.ipynb"
159            ]
160        ),
161    ]
162    """target URL"""

A custom badge

label: Annotated[str, FieldInfo(annotation=NoneType, required=True, examples=['Open in Colab'])]

badge label to display on hover

icon: Annotated[Union[Annotated[Union[Annotated[pathlib.Path, PathType(path_type='file'), FieldInfo(annotation=NoneType, required=True, title='FilePath')], RelativeFilePath], AfterValidator(func=<function wo_special_file_name at 0x7f5632ea9080>), PlainSerializer(func=<function _package at 0x7f5632ea9800>, return_type=PydanticUndefined, when_used='unless-none')], HttpUrl, 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)], NoneType], FieldInfo(annotation=NoneType, required=True, examples=['https://colab.research.google.com/assets/colab-badge.svg'])]

badge icon

url: Annotated[HttpUrl, FieldInfo(annotation=NoneType, required=True, examples=['https://colab.research.google.com/github/HenriquesLab/ZeroCostDL4Mic/blob/master/Colab_notebooks/U-net_2D_ZeroCostDL4Mic.ipynb'])]

target URL

class CiteEntry(bioimageio.spec._internal.node.Node):
176class CiteEntry(Node):
177    """A citation that should be referenced in work using this resource."""
178
179    text: str
180    """free text description"""
181
182    doi: Optional[Doi] = None
183    """A digital object identifier (DOI) is the prefered citation reference.
184    See https://www.doi.org/ for details.
185    Note:
186        Either **doi** or **url** have to be specified.
187    """
188
189    url: Optional[HttpUrl] = None
190    """URL to cite (preferably specify a **doi** instead/also).
191    Note:
192        Either **doi** or **url** have to be specified.
193    """
194
195    @model_validator(mode="after")
196    def _check_doi_or_url(self):
197        if not self.doi and not self.url:
198            raise ValueError("Either 'doi' or 'url' is required")
199
200        return self

A citation that should be referenced in work using this resource.

text: str

free text description

doi: Optional[Doi]

A digital object identifier (DOI) is the prefered citation reference. See https://www.doi.org/ for details.

Note:

Either doi or url have to be specified.

url: Optional[HttpUrl]

URL to cite (preferably specify a doi instead/also).

Note:

Either doi or url have to be specified.

class DeprecatedLicenseId(bioimageio.spec._internal.validated_string.ValidatedString):
24class DeprecatedLicenseId(ValidatedString):
25    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[DeprecatedLicenseIdLiteral]

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

root_model: ClassVar[Type[pydantic.root_model.RootModel[Any]]] = <class 'pydantic.root_model.RootModel[Literal['AGPL-1.0', 'AGPL-3.0', 'BSD-2-Clause-FreeBSD', 'BSD-2-Clause-NetBSD', 'bzip2-1.0.5', 'eCos-2.0', 'GFDL-1.1', 'GFDL-1.2', 'GFDL-1.3', 'GPL-1.0', 'GPL-1.0+', 'GPL-2.0', 'GPL-2.0+', 'GPL-2.0-with-autoconf-exception', 'GPL-2.0-with-bison-exception', 'GPL-2.0-with-classpath-exception', 'GPL-2.0-with-font-exception', 'GPL-2.0-with-GCC-exception', 'GPL-3.0', 'GPL-3.0+', 'GPL-3.0-with-autoconf-exception', 'GPL-3.0-with-GCC-exception', 'LGPL-2.0', 'LGPL-2.0+', 'LGPL-2.1', 'LGPL-2.1+', 'LGPL-3.0', 'LGPL-3.0+', 'Nunit', 'StandardML-NJ', 'wxWindows']]'>

the pydantic root model to validate the string

115class Doi(ValidatedString):
116    """A digital object identifier, see https://www.doi.org/"""
117
118    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[
119        Annotated[str, StringConstraints(pattern=DOI_REGEX)]
120    ]

A digital object identifier, see https://www.doi.org/

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 FileDescr(bioimageio.spec._internal.node.Node):
850class FileDescr(Node):
851    source: ImportantFileSource
852    """∈📦 file source"""
853
854    sha256: Optional[Sha256] = None
855    """SHA256 checksum of the source file"""
856
857    @model_validator(mode="after")
858    def _validate_sha256(self) -> Self:
859        if get_validation_context().perform_io_checks:
860            self.validate_sha256()
861
862        return self
863
864    def validate_sha256(self):
865        context = get_validation_context()
866        if (src_str := str(self.source)) in context.known_files:
867            actual_sha = context.known_files[src_str]
868        else:
869            local_source = download(self.source, sha256=self.sha256).path
870            actual_sha = get_sha256(local_source)
871            context.known_files[src_str] = actual_sha
872
873        if actual_sha is None:
874            return
875        elif self.sha256 == actual_sha:
876            pass
877        elif self.sha256 is None or context.update_hashes:
878            self.sha256 = actual_sha
879        elif self.sha256 != actual_sha:
880            raise ValueError(
881                f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got "
882                + f"{actual_sha}. Update expected `sha256` or point to the matching "
883                + "file."
884            )
885
886    def download(self):
887
888        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 0x7f5632ea9080>), PlainSerializer(func=<function _package at 0x7f5632ea9800>, return_type=PydanticUndefined, when_used='unless-none')]

∈📦 file source

sha256: Optional[Sha256]

SHA256 checksum of the source file

def validate_sha256(self):
864    def validate_sha256(self):
865        context = get_validation_context()
866        if (src_str := str(self.source)) in context.known_files:
867            actual_sha = context.known_files[src_str]
868        else:
869            local_source = download(self.source, sha256=self.sha256).path
870            actual_sha = get_sha256(local_source)
871            context.known_files[src_str] = actual_sha
872
873        if actual_sha is None:
874            return
875        elif self.sha256 == actual_sha:
876            pass
877        elif self.sha256 is None or context.update_hashes:
878            self.sha256 = actual_sha
879        elif self.sha256 != actual_sha:
880            raise ValueError(
881                f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got "
882                + f"{actual_sha}. Update expected `sha256` or point to the matching "
883                + "file."
884            )
def download(self):
886    def download(self):
887
888        return download(self.source, sha256=self.sha256)
class GenericDescr(GenericDescrBase):
474class GenericDescr(GenericDescrBase, extra="ignore"):
475    """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF).
476
477    An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook.
478    Note that those resources are described with a type-specific RDF.
479    Use this generic resource description, if none of the known specific types matches your resource.
480    """
481
482    type: Annotated[str, LowerCase] = Field("generic", frozen=True)
483    """The resource type assigns a broad category to the resource."""
484
485    id: Optional[
486        Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])]
487    ] = None
488    """bioimage.io-wide unique resource identifier
489    assigned by bioimage.io; version **un**specific."""
490
491    parent: Optional[ResourceId] = None
492    """The description from which this one is derived"""
493
494    source: Optional[HttpUrl] = None
495    """The primary source of the resource"""
496
497    @field_validator("type", mode="after")
498    @classmethod
499    def check_specific_types(cls, value: str) -> str:
500        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
501            raise ValueError(
502                f"Use the {value} description instead of this generic description for"
503                + f" your '{value}' resource."
504            )
505
506        return value

Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF).

An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook. Note that those resources are described with a type-specific RDF. Use this generic resource description, if none of the known specific types matches your resource.

type: Annotated[str, Annotated[~_StrType, Predicate(str.islower)]]

The resource type assigns a broad category to the resource.

id: Optional[Annotated[ResourceId, FieldInfo(annotation=NoneType, required=True, examples=['affable-shark', 'ambitious-sloth'])]]

bioimage.io-wide unique resource identifier assigned by bioimage.io; version unspecific.

parent: Optional[ResourceId]

The description from which this one is derived

source: Optional[HttpUrl]

The primary source of the resource

@field_validator('type', mode='after')
@classmethod
def check_specific_types(cls, value: str) -> str:
497    @field_validator("type", mode="after")
498    @classmethod
499    def check_specific_types(cls, value: str) -> str:
500        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
501            raise ValueError(
502                f"Use the {value} description instead of this generic description for"
503                + f" your '{value}' resource."
504            )
505
506        return value
implemented_format_version_tuple: ClassVar[Tuple[int, int, int]] = (0, 3, 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.

132class HttpUrl(RootHttpUrl):
133    """A URL with the HTTP or HTTPS scheme."""
134
135    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[pydantic.HttpUrl]
136    _exists: Optional[bool] = None
137
138    def _after_validator(self):
139        self = super()._after_validator()
140        context = get_validation_context()
141        if context.perform_io_checks:
142            self._validated = _validate_url(self._validated)
143            self._exists = True
144
145        return self
146
147    def exists(self):
148        """True if URL is available"""
149        if self._exists is None:
150            try:
151                self._validated = _validate_url(self._validated)
152            except Exception as e:
153                logger.info(e)
154                self._exists = False
155            else:
156                self._exists = True
157
158        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):
147    def exists(self):
148        """True if URL is available"""
149        if self._exists is None:
150            try:
151                self._validated = _validate_url(self._validated)
152            except Exception as e:
153                logger.info(e)
154                self._exists = False
155            else:
156                self._exists = True
157
158        return self._exists

True if URL is available

KNOWN_SPECIFIC_RESOURCE_TYPES = ('application', 'collection', 'dataset', 'model', 'notebook')
20class LicenseId(ValidatedString):
21    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[LicenseIdLiteral]

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

root_model: ClassVar[Type[pydantic.root_model.RootModel[Any]]] = <class 'pydantic.root_model.RootModel[Literal['0BSD', 'AAL', 'Abstyles', 'AdaCore-doc', 'Adobe-2006', 'Adobe-Display-PostScript', 'Adobe-Glyph', 'Adobe-Utopia', 'ADSL', 'AFL-1.1', 'AFL-1.2', 'AFL-2.0', 'AFL-2.1', 'AFL-3.0', 'Afmparse', 'AGPL-1.0-only', 'AGPL-1.0-or-later', 'AGPL-3.0-only', 'AGPL-3.0-or-later', 'Aladdin', 'AMDPLPA', 'AML', 'AML-glslang', 'AMPAS', 'ANTLR-PD', 'ANTLR-PD-fallback', 'Apache-1.0', 'Apache-1.1', 'Apache-2.0', 'APAFML', 'APL-1.0', 'App-s2p', 'APSL-1.0', 'APSL-1.1', 'APSL-1.2', 'APSL-2.0', 'Arphic-1999', 'Artistic-1.0', 'Artistic-1.0-cl8', 'Artistic-1.0-Perl', 'Artistic-2.0', 'ASWF-Digital-Assets-1.0', 'ASWF-Digital-Assets-1.1', 'Baekmuk', 'Bahyph', 'Barr', 'bcrypt-Solar-Designer', 'Beerware', 'Bitstream-Charter', 'Bitstream-Vera', 'BitTorrent-1.0', 'BitTorrent-1.1', 'blessing', 'BlueOak-1.0.0', 'Boehm-GC', 'Borceux', 'Brian-Gladman-2-Clause', 'Brian-Gladman-3-Clause', 'BSD-1-Clause', 'BSD-2-Clause', 'BSD-2-Clause-Darwin', 'BSD-2-Clause-Patent', 'BSD-2-Clause-Views', 'BSD-3-Clause', 'BSD-3-Clause-acpica', 'BSD-3-Clause-Attribution', 'BSD-3-Clause-Clear', 'BSD-3-Clause-flex', 'BSD-3-Clause-HP', 'BSD-3-Clause-LBNL', 'BSD-3-Clause-Modification', 'BSD-3-Clause-No-Military-License', 'BSD-3-Clause-No-Nuclear-License', 'BSD-3-Clause-No-Nuclear-License-2014', 'BSD-3-Clause-No-Nuclear-Warranty', 'BSD-3-Clause-Open-MPI', 'BSD-3-Clause-Sun', 'BSD-4-Clause', 'BSD-4-Clause-Shortened', 'BSD-4-Clause-UC', 'BSD-4.3RENO', 'BSD-4.3TAHOE', 'BSD-Advertising-Acknowledgement', 'BSD-Attribution-HPND-disclaimer', 'BSD-Inferno-Nettverk', 'BSD-Protection', 'BSD-Source-beginning-file', 'BSD-Source-Code', 'BSD-Systemics', 'BSD-Systemics-W3Works', 'BSL-1.0', 'BUSL-1.1', 'bzip2-1.0.6', 'C-UDA-1.0', 'CAL-1.0', 'CAL-1.0-Combined-Work-Exception', 'Caldera', 'Caldera-no-preamble', 'CATOSL-1.1', 'CC-BY-1.0', 'CC-BY-2.0', 'CC-BY-2.5', 'CC-BY-2.5-AU', 'CC-BY-3.0', 'CC-BY-3.0-AT', 'CC-BY-3.0-AU', 'CC-BY-3.0-DE', 'CC-BY-3.0-IGO', 'CC-BY-3.0-NL', 'CC-BY-3.0-US', 'CC-BY-4.0', 'CC-BY-NC-1.0', 'CC-BY-NC-2.0', 'CC-BY-NC-2.5', 'CC-BY-NC-3.0', 'CC-BY-NC-3.0-DE', 'CC-BY-NC-4.0', 'CC-BY-NC-ND-1.0', 'CC-BY-NC-ND-2.0', 'CC-BY-NC-ND-2.5', 'CC-BY-NC-ND-3.0', 'CC-BY-NC-ND-3.0-DE', 'CC-BY-NC-ND-3.0-IGO', 'CC-BY-NC-ND-4.0', 'CC-BY-NC-SA-1.0', 'CC-BY-NC-SA-2.0', 'CC-BY-NC-SA-2.0-DE', 'CC-BY-NC-SA-2.0-FR', 'CC-BY-NC-SA-2.0-UK', 'CC-BY-NC-SA-2.5', 'CC-BY-NC-SA-3.0', 'CC-BY-NC-SA-3.0-DE', 'CC-BY-NC-SA-3.0-IGO', 'CC-BY-NC-SA-4.0', 'CC-BY-ND-1.0', 'CC-BY-ND-2.0', 'CC-BY-ND-2.5', 'CC-BY-ND-3.0', 'CC-BY-ND-3.0-DE', 'CC-BY-ND-4.0', 'CC-BY-SA-1.0', 'CC-BY-SA-2.0', 'CC-BY-SA-2.0-UK', 'CC-BY-SA-2.1-JP', 'CC-BY-SA-2.5', 'CC-BY-SA-3.0', 'CC-BY-SA-3.0-AT', 'CC-BY-SA-3.0-DE', 'CC-BY-SA-3.0-IGO', 'CC-BY-SA-4.0', 'CC-PDDC', 'CC0-1.0', 'CDDL-1.0', 'CDDL-1.1', 'CDL-1.0', 'CDLA-Permissive-1.0', 'CDLA-Permissive-2.0', 'CDLA-Sharing-1.0', 'CECILL-1.0', 'CECILL-1.1', 'CECILL-2.0', 'CECILL-2.1', 'CECILL-B', 'CECILL-C', 'CERN-OHL-1.1', 'CERN-OHL-1.2', 'CERN-OHL-P-2.0', 'CERN-OHL-S-2.0', 'CERN-OHL-W-2.0', 'CFITSIO', 'check-cvs', 'checkmk', 'ClArtistic', 'Clips', 'CMU-Mach', 'CMU-Mach-nodoc', 'CNRI-Jython', 'CNRI-Python', 'CNRI-Python-GPL-Compatible', 'COIL-1.0', 'Community-Spec-1.0', 'Condor-1.1', 'copyleft-next-0.3.0', 'copyleft-next-0.3.1', 'Cornell-Lossless-JPEG', 'CPAL-1.0', 'CPL-1.0', 'CPOL-1.02', 'Cronyx', 'Crossword', 'CrystalStacker', 'CUA-OPL-1.0', 'Cube', 'curl', 'D-FSL-1.0', 'DEC-3-Clause', 'diffmark', 'DL-DE-BY-2.0', 'DL-DE-ZERO-2.0', 'DOC', 'Dotseqn', 'DRL-1.0', 'DRL-1.1', 'DSDP', 'dtoa', 'dvipdfm', 'ECL-1.0', 'ECL-2.0', 'EFL-1.0', 'EFL-2.0', 'eGenix', 'Elastic-2.0', 'Entessa', 'EPICS', 'EPL-1.0', 'EPL-2.0', 'ErlPL-1.1', 'etalab-2.0', 'EUDatagrid', 'EUPL-1.0', 'EUPL-1.1', 'EUPL-1.2', 'Eurosym', 'Fair', 'FBM', 'FDK-AAC', 'Ferguson-Twofish', 'Frameworx-1.0', 'FreeBSD-DOC', 'FreeImage', 'FSFAP', 'FSFAP-no-warranty-disclaimer', 'FSFUL', 'FSFULLR', 'FSFULLRWD', 'FTL', 'Furuseth', 'fwlw', 'GCR-docs', 'GD', 'GFDL-1.1-invariants-only', 'GFDL-1.1-invariants-or-later', 'GFDL-1.1-no-invariants-only', 'GFDL-1.1-no-invariants-or-later', 'GFDL-1.1-only', 'GFDL-1.1-or-later', 'GFDL-1.2-invariants-only', 'GFDL-1.2-invariants-or-later', 'GFDL-1.2-no-invariants-only', 'GFDL-1.2-no-invariants-or-later', 'GFDL-1.2-only', 'GFDL-1.2-or-later', 'GFDL-1.3-invariants-only', 'GFDL-1.3-invariants-or-later', 'GFDL-1.3-no-invariants-only', 'GFDL-1.3-no-invariants-or-later', 'GFDL-1.3-only', 'GFDL-1.3-or-later', 'Giftware', 'GL2PS', 'Glide', 'Glulxe', 'GLWTPL', 'gnuplot', 'GPL-1.0-only', 'GPL-1.0-or-later', 'GPL-2.0-only', 'GPL-2.0-or-later', 'GPL-3.0-only', 'GPL-3.0-or-later', 'Graphics-Gems', 'gSOAP-1.3b', 'gtkbook', 'HaskellReport', 'hdparm', 'Hippocratic-2.1', 'HP-1986', 'HP-1989', 'HPND', 'HPND-DEC', 'HPND-doc', 'HPND-doc-sell', 'HPND-export-US', 'HPND-export-US-modify', 'HPND-Fenneberg-Livingston', 'HPND-INRIA-IMAG', 'HPND-Kevlin-Henney', 'HPND-Markus-Kuhn', 'HPND-MIT-disclaimer', 'HPND-Pbmplus', 'HPND-sell-MIT-disclaimer-xserver', 'HPND-sell-regexpr', 'HPND-sell-variant', 'HPND-sell-variant-MIT-disclaimer', 'HPND-UC', 'HTMLTIDY', 'IBM-pibs', 'ICU', 'IEC-Code-Components-EULA', 'IJG', 'IJG-short', 'ImageMagick', 'iMatix', 'Imlib2', 'Info-ZIP', 'Inner-Net-2.0', 'Intel', 'Intel-ACPI', 'Interbase-1.0', 'IPA', 'IPL-1.0', 'ISC', 'ISC-Veillard', 'Jam', 'JasPer-2.0', 'JPL-image', 'JPNIC', 'JSON', 'Kastrup', 'Kazlib', 'Knuth-CTAN', 'LAL-1.2', 'LAL-1.3', 'Latex2e', 'Latex2e-translated-notice', 'Leptonica', 'LGPL-2.0-only', 'LGPL-2.0-or-later', 'LGPL-2.1-only', 'LGPL-2.1-or-later', 'LGPL-3.0-only', 'LGPL-3.0-or-later', 'LGPLLR', 'Libpng', 'libpng-2.0', 'libselinux-1.0', 'libtiff', 'libutil-David-Nugent', 'LiLiQ-P-1.1', 'LiLiQ-R-1.1', 'LiLiQ-Rplus-1.1', 'Linux-man-pages-1-para', 'Linux-man-pages-copyleft', 'Linux-man-pages-copyleft-2-para', 'Linux-man-pages-copyleft-var', 'Linux-OpenIB', 'LOOP', 'LPD-document', 'LPL-1.0', 'LPL-1.02', 'LPPL-1.0', 'LPPL-1.1', 'LPPL-1.2', 'LPPL-1.3a', 'LPPL-1.3c', 'lsof', 'Lucida-Bitmap-Fonts', 'LZMA-SDK-9.11-to-9.20', 'LZMA-SDK-9.22', 'Mackerras-3-Clause', 'Mackerras-3-Clause-acknowledgment', 'magaz', 'mailprio', 'MakeIndex', 'Martin-Birgmeier', 'McPhee-slideshow', 'metamail', 'Minpack', 'MirOS', 'MIT', 'MIT-0', 'MIT-advertising', 'MIT-CMU', 'MIT-enna', 'MIT-feh', 'MIT-Festival', 'MIT-Modern-Variant', 'MIT-open-group', 'MIT-testregex', 'MIT-Wu', 'MITNFA', 'MMIXware', 'Motosoto', 'MPEG-SSG', 'mpi-permissive', 'mpich2', 'MPL-1.0', 'MPL-1.1', 'MPL-2.0', 'MPL-2.0-no-copyleft-exception', 'mplus', 'MS-LPL', 'MS-PL', 'MS-RL', 'MTLL', 'MulanPSL-1.0', 'MulanPSL-2.0', 'Multics', 'Mup', 'NAIST-2003', 'NASA-1.3', 'Naumen', 'NBPL-1.0', 'NCGL-UK-2.0', 'NCSA', 'Net-SNMP', 'NetCDF', 'Newsletr', 'NGPL', 'NICTA-1.0', 'NIST-PD', 'NIST-PD-fallback', 'NIST-Software', 'NLOD-1.0', 'NLOD-2.0', 'NLPL', 'Nokia', 'NOSL', 'Noweb', 'NPL-1.0', 'NPL-1.1', 'NPOSL-3.0', 'NRL', 'NTP', 'NTP-0', 'O-UDA-1.0', 'OCCT-PL', 'OCLC-2.0', 'ODbL-1.0', 'ODC-By-1.0', 'OFFIS', 'OFL-1.0', 'OFL-1.0-no-RFN', 'OFL-1.0-RFN', 'OFL-1.1', 'OFL-1.1-no-RFN', 'OFL-1.1-RFN', 'OGC-1.0', 'OGDL-Taiwan-1.0', 'OGL-Canada-2.0', 'OGL-UK-1.0', 'OGL-UK-2.0', 'OGL-UK-3.0', 'OGTSL', 'OLDAP-1.1', 'OLDAP-1.2', 'OLDAP-1.3', 'OLDAP-1.4', 'OLDAP-2.0', 'OLDAP-2.0.1', 'OLDAP-2.1', 'OLDAP-2.2', 'OLDAP-2.2.1', 'OLDAP-2.2.2', 'OLDAP-2.3', 'OLDAP-2.4', 'OLDAP-2.5', 'OLDAP-2.6', 'OLDAP-2.7', 'OLDAP-2.8', 'OLFL-1.3', 'OML', 'OpenPBS-2.3', 'OpenSSL', 'OpenSSL-standalone', 'OpenVision', 'OPL-1.0', 'OPL-UK-3.0', 'OPUBL-1.0', 'OSET-PL-2.1', 'OSL-1.0', 'OSL-1.1', 'OSL-2.0', 'OSL-2.1', 'OSL-3.0', 'PADL', 'Parity-6.0.0', 'Parity-7.0.0', 'PDDL-1.0', 'PHP-3.0', 'PHP-3.01', 'Pixar', 'Plexus', 'pnmstitch', 'PolyForm-Noncommercial-1.0.0', 'PolyForm-Small-Business-1.0.0', 'PostgreSQL', 'PSF-2.0', 'psfrag', 'psutils', 'Python-2.0', 'Python-2.0.1', 'python-ldap', 'Qhull', 'QPL-1.0', 'QPL-1.0-INRIA-2004', 'radvd', 'Rdisc', 'RHeCos-1.1', 'RPL-1.1', 'RPL-1.5', 'RPSL-1.0', 'RSA-MD', 'RSCPL', 'Ruby', 'SAX-PD', 'SAX-PD-2.0', 'Saxpath', 'SCEA', 'SchemeReport', 'Sendmail', 'Sendmail-8.23', 'SGI-B-1.0', 'SGI-B-1.1', 'SGI-B-2.0', 'SGI-OpenGL', 'SGP4', 'SHL-0.5', 'SHL-0.51', 'SimPL-2.0', 'SISSL', 'SISSL-1.2', 'SL', 'Sleepycat', 'SMLNJ', 'SMPPL', 'SNIA', 'snprintf', 'softSurfer', 'Soundex', 'Spencer-86', 'Spencer-94', 'Spencer-99', 'SPL-1.0', 'ssh-keyscan', 'SSH-OpenSSH', 'SSH-short', 'SSLeay-standalone', 'SSPL-1.0', 'SugarCRM-1.1.3', 'Sun-PPP', 'SunPro', 'SWL', 'swrule', 'Symlinks', 'TAPR-OHL-1.0', 'TCL', 'TCP-wrappers', 'TermReadKey', 'TGPPL-1.0', 'TMate', 'TORQUE-1.1', 'TOSL', 'TPDL', 'TPL-1.0', 'TTWL', 'TTYP0', 'TU-Berlin-1.0', 'TU-Berlin-2.0', 'UCAR', 'UCL-1.0', 'ulem', 'UMich-Merit', 'Unicode-3.0', 'Unicode-DFS-2015', 'Unicode-DFS-2016', 'Unicode-TOU', 'UnixCrypt', 'Unlicense', 'UPL-1.0', 'URT-RLE', 'Vim', 'VOSTROM', 'VSL-1.0', 'W3C', 'W3C-19980720', 'W3C-20150513', 'w3m', 'Watcom-1.0', 'Widget-Workshop', 'Wsuipa', 'WTFPL', 'X11', 'X11-distribute-modifications-variant', 'Xdebug-1.03', 'Xerox', 'Xfig', 'XFree86-1.1', 'xinetd', 'xkeyboard-config-Zinoviev', 'xlock', 'Xnet', 'xpp', 'XSkat', 'YPL-1.0', 'YPL-1.1', 'Zed', 'Zeeff', 'Zend-2.0', 'Zimbra-1.3', 'Zimbra-1.4', 'Zlib', 'zlib-acknowledgement', 'ZPL-1.1', 'ZPL-2.0', 'ZPL-2.1']]'>

the pydantic root model to validate the string

class LinkedResource(LinkedResourceBase):
218class LinkedResource(LinkedResourceBase):
219    """Reference to a bioimage.io resource"""
220
221    id: ResourceId
222    """A valid resource `id` from the official bioimage.io collection."""

Reference to a bioimage.io resource

A valid resource id from the official bioimage.io collection.

class Maintainer(bioimageio.spec.generic.v0_2.Maintainer):
151class Maintainer(_Maintainer_v0_2):
152    name: Optional[Annotated[str, Predicate(_has_no_slash)]] = None
153    github_user: str
154
155    @field_validator("github_user", mode="after")
156    def validate_gh_user(cls, value: str):
157        return validate_gh_user(value)
name: Optional[Annotated[str, Predicate(func=<function _has_no_slash at 0x7f56297339c0>)]]
github_user: str
@field_validator('github_user', mode='after')
def validate_gh_user(cls, value: str):
155    @field_validator("github_user", mode="after")
156    def validate_gh_user(cls, value: str):
157        return validate_gh_user(value)
142class OrcidId(ValidatedString):
143    """An ORCID identifier, see https://orcid.org/"""
144
145    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[
146        Annotated[str, AfterValidator(_validate_orcid_id)]
147    ]

An ORCID identifier, see https://orcid.org/

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

the pydantic root model to validate the string

class RelativeFilePath(pydantic.root_model.RootModel[PurePath], typing.Generic[~AbsolutePathT]):
188class RelativeFilePath(
189    RelativePathBase[Union[AbsoluteFilePath, HttpUrl, ZipPath]], frozen=True
190):
191    """A path relative to the `rdf.yaml` file (also if the RDF source is a URL)."""
192
193    def model_post_init(self, __context: Any) -> None:
194        """add validation @private"""
195        if not self.root.parts:  # an empty path can only be a directory
196            raise ValueError(f"{self.root} is not a valid file path.")
197
198        super().model_post_init(__context)
199
200    def get_absolute(
201        self, root: "RootHttpUrl | Path | AnyUrl | ZipFile"
202    ) -> "AbsoluteFilePath | HttpUrl | ZipPath":
203        absolute = self._get_absolute_impl(root)
204        if (
205            isinstance(absolute, Path)
206            and (context := get_validation_context()).perform_io_checks
207            and str(self.root) not in context.known_files
208            and not absolute.is_file()
209        ):
210            raise ValueError(f"{absolute} does not point to an existing file")
211
212        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: bioimageio.spec._internal.root_url.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]:
200    def get_absolute(
201        self, root: "RootHttpUrl | Path | AnyUrl | ZipFile"
202    ) -> "AbsoluteFilePath | HttpUrl | ZipPath":
203        absolute = self._get_absolute_impl(root)
204        if (
205            isinstance(absolute, Path)
206            and (context := get_validation_context()).perform_io_checks
207            and str(self.root) not in context.known_files
208            and not absolute.is_file()
209        ):
210            raise ValueError(f"{absolute} does not point to an existing file")
211
212        return absolute
 95class ResourceId(ValidatedString):
 96    root_model: ClassVar[Type[RootModel[Any]]] = RootModel[
 97        Annotated[
 98            NotEmpty[str],
 99            RestrictCharacters(string.ascii_lowercase + string.digits + "_-/."),
100            annotated_types.Predicate(
101                lambda s: not (s.startswith("/") or s.endswith("/"))
102            ),
103        ]
104    ]

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

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

the pydantic root model to validate the string

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 Uploader(bioimageio.spec._internal.node.Node):
110class Uploader(Node):
111    email: EmailStr
112    """Email"""
113    name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None
114    """name"""
email: pydantic.networks.EmailStr

Email

name: Optional[Annotated[str, AfterValidator(func=<function _remove_slashes at 0x7f5632dc6020>)]]

name

VALID_COVER_IMAGE_EXTENSIONS = ('.gif', '.jpeg', '.jpg', '.png', '.svg')
class Version(pydantic.main.BaseModel, typing.Generic[~RootModelRootType]):
 10class Version(RootModel[Union[str, int, float]]):
 11    """wraps a packaging.version.Version instance for validation in pydantic models"""
 12
 13    _version: packaging.version.Version = PrivateAttr()
 14
 15    def __str__(self):
 16        return str(self._version)
 17
 18    def model_post_init(self, __context: Any) -> None:
 19        """set `_version` attribute @private"""
 20        self._version = packaging.version.Version(str(self.root))
 21        return super().model_post_init(__context)
 22
 23    def __lt__(self, other: Version):
 24        return self._version < other._version
 25
 26    def __eq__(self, other: Version):
 27        return self._version == other._version
 28
 29    # the properties below are adopted from and mirror properties of packaging.version.Version
 30    @property
 31    def epoch(self) -> int:
 32        """The epoch of the version.
 33
 34        >>> Version("2.0.0").epoch
 35        0
 36        >>> Version("1!2.0.0").epoch
 37        1
 38        """
 39        return self._version.epoch
 40
 41    @property
 42    def release(self) -> Tuple[int, ...]:
 43        """The components of the "release" segment of the version.
 44
 45        >>> Version("1.2.3").release
 46        (1, 2, 3)
 47        >>> Version("2.0.0").release
 48        (2, 0, 0)
 49        >>> Version("1!2.0.0.post0").release
 50        (2, 0, 0)
 51
 52        Includes trailing zeroes but not the epoch or any pre-release / development /
 53        post-release suffixes.
 54        """
 55        return self._version.release
 56
 57    @property
 58    def pre(self) -> Optional[Tuple[str, int]]:
 59        """The pre-release segment of the version.
 60
 61        >>> print(Version("1.2.3").pre)
 62        None
 63        >>> Version("1.2.3a1").pre
 64        ('a', 1)
 65        >>> Version("1.2.3b1").pre
 66        ('b', 1)
 67        >>> Version("1.2.3rc1").pre
 68        ('rc', 1)
 69        """
 70        return self._version.pre
 71
 72    @property
 73    def post(self) -> Optional[int]:
 74        """The post-release number of the version.
 75
 76        >>> print(Version("1.2.3").post)
 77        None
 78        >>> Version("1.2.3.post1").post
 79        1
 80        """
 81        return self._version.post
 82
 83    @property
 84    def dev(self) -> Optional[int]:
 85        """The development number of the version.
 86
 87        >>> print(Version("1.2.3").dev)
 88        None
 89        >>> Version("1.2.3.dev1").dev
 90        1
 91        """
 92        return self._version.dev
 93
 94    @property
 95    def local(self) -> Optional[str]:
 96        """The local version segment of the version.
 97
 98        >>> print(Version("1.2.3").local)
 99        None
100        >>> Version("1.2.3+abc").local
101        'abc'
102        """
103        return self._version.local
104
105    @property
106    def public(self) -> str:
107        """The public portion of the version.
108
109        >>> Version("1.2.3").public
110        '1.2.3'
111        >>> Version("1.2.3+abc").public
112        '1.2.3'
113        >>> Version("1.2.3+abc.dev1").public
114        '1.2.3'
115        """
116        return self._version.public
117
118    @property
119    def base_version(self) -> str:
120        """The "base version" of the version.
121
122        >>> Version("1.2.3").base_version
123        '1.2.3'
124        >>> Version("1.2.3+abc").base_version
125        '1.2.3'
126        >>> Version("1!1.2.3+abc.dev1").base_version
127        '1!1.2.3'
128
129        The "base version" is the public version of the project without any pre or post
130        release markers.
131        """
132        return self._version.base_version
133
134    @property
135    def is_prerelease(self) -> bool:
136        """Whether this version is a pre-release.
137
138        >>> Version("1.2.3").is_prerelease
139        False
140        >>> Version("1.2.3a1").is_prerelease
141        True
142        >>> Version("1.2.3b1").is_prerelease
143        True
144        >>> Version("1.2.3rc1").is_prerelease
145        True
146        >>> Version("1.2.3dev1").is_prerelease
147        True
148        """
149        return self._version.is_prerelease
150
151    @property
152    def is_postrelease(self) -> bool:
153        """Whether this version is a post-release.
154
155        >>> Version("1.2.3").is_postrelease
156        False
157        >>> Version("1.2.3.post1").is_postrelease
158        True
159        """
160        return self._version.is_postrelease
161
162    @property
163    def is_devrelease(self) -> bool:
164        """Whether this version is a development release.
165
166        >>> Version("1.2.3").is_devrelease
167        False
168        >>> Version("1.2.3.dev1").is_devrelease
169        True
170        """
171        return self._version.is_devrelease
172
173    @property
174    def major(self) -> int:
175        """The first item of :attr:`release` or ``0`` if unavailable.
176
177        >>> Version("1.2.3").major
178        1
179        """
180        return self._version.major
181
182    @property
183    def minor(self) -> int:
184        """The second item of :attr:`release` or ``0`` if unavailable.
185
186        >>> Version("1.2.3").minor
187        2
188        >>> Version("1").minor
189        0
190        """
191        return self._version.minor
192
193    @property
194    def micro(self) -> int:
195        """The third item of :attr:`release` or ``0`` if unavailable.
196
197        >>> Version("1.2.3").micro
198        3
199        >>> Version("1").micro
200        0
201        """
202        return self._version.micro

wraps a packaging.version.Version instance for validation in pydantic models

epoch: int
30    @property
31    def epoch(self) -> int:
32        """The epoch of the version.
33
34        >>> Version("2.0.0").epoch
35        0
36        >>> Version("1!2.0.0").epoch
37        1
38        """
39        return self._version.epoch

The epoch of the version.

>>> Version("2.0.0").epoch
0
>>> Version("1!2.0.0").epoch
1
release: Tuple[int, ...]
41    @property
42    def release(self) -> Tuple[int, ...]:
43        """The components of the "release" segment of the version.
44
45        >>> Version("1.2.3").release
46        (1, 2, 3)
47        >>> Version("2.0.0").release
48        (2, 0, 0)
49        >>> Version("1!2.0.0.post0").release
50        (2, 0, 0)
51
52        Includes trailing zeroes but not the epoch or any pre-release / development /
53        post-release suffixes.
54        """
55        return self._version.release

The components of the "release" segment of the version.

>>> Version("1.2.3").release
(1, 2, 3)
>>> Version("2.0.0").release
(2, 0, 0)
>>> Version("1!2.0.0.post0").release
(2, 0, 0)

Includes trailing zeroes but not the epoch or any pre-release / development / post-release suffixes.

pre: Optional[Tuple[str, int]]
57    @property
58    def pre(self) -> Optional[Tuple[str, int]]:
59        """The pre-release segment of the version.
60
61        >>> print(Version("1.2.3").pre)
62        None
63        >>> Version("1.2.3a1").pre
64        ('a', 1)
65        >>> Version("1.2.3b1").pre
66        ('b', 1)
67        >>> Version("1.2.3rc1").pre
68        ('rc', 1)
69        """
70        return self._version.pre

The pre-release segment of the version.

>>> print(Version("1.2.3").pre)
None
>>> Version("1.2.3a1").pre
('a', 1)
>>> Version("1.2.3b1").pre
('b', 1)
>>> Version("1.2.3rc1").pre
('rc', 1)
post: Optional[int]
72    @property
73    def post(self) -> Optional[int]:
74        """The post-release number of the version.
75
76        >>> print(Version("1.2.3").post)
77        None
78        >>> Version("1.2.3.post1").post
79        1
80        """
81        return self._version.post

The post-release number of the version.

>>> print(Version("1.2.3").post)
None
>>> Version("1.2.3.post1").post
1
dev: Optional[int]
83    @property
84    def dev(self) -> Optional[int]:
85        """The development number of the version.
86
87        >>> print(Version("1.2.3").dev)
88        None
89        >>> Version("1.2.3.dev1").dev
90        1
91        """
92        return self._version.dev

The development number of the version.

>>> print(Version("1.2.3").dev)
None
>>> Version("1.2.3.dev1").dev
1
local: Optional[str]
 94    @property
 95    def local(self) -> Optional[str]:
 96        """The local version segment of the version.
 97
 98        >>> print(Version("1.2.3").local)
 99        None
100        >>> Version("1.2.3+abc").local
101        'abc'
102        """
103        return self._version.local

The local version segment of the version.

>>> print(Version("1.2.3").local)
None
>>> Version("1.2.3+abc").local
'abc'
public: str
105    @property
106    def public(self) -> str:
107        """The public portion of the version.
108
109        >>> Version("1.2.3").public
110        '1.2.3'
111        >>> Version("1.2.3+abc").public
112        '1.2.3'
113        >>> Version("1.2.3+abc.dev1").public
114        '1.2.3'
115        """
116        return self._version.public

The public portion of the version.

>>> Version("1.2.3").public
'1.2.3'
>>> Version("1.2.3+abc").public
'1.2.3'
>>> Version("1.2.3+abc.dev1").public
'1.2.3'
base_version: str
118    @property
119    def base_version(self) -> str:
120        """The "base version" of the version.
121
122        >>> Version("1.2.3").base_version
123        '1.2.3'
124        >>> Version("1.2.3+abc").base_version
125        '1.2.3'
126        >>> Version("1!1.2.3+abc.dev1").base_version
127        '1!1.2.3'
128
129        The "base version" is the public version of the project without any pre or post
130        release markers.
131        """
132        return self._version.base_version

The "base version" of the version.

>>> Version("1.2.3").base_version
'1.2.3'
>>> Version("1.2.3+abc").base_version
'1.2.3'
>>> Version("1!1.2.3+abc.dev1").base_version
'1!1.2.3'

The "base version" is the public version of the project without any pre or post release markers.

is_prerelease: bool
134    @property
135    def is_prerelease(self) -> bool:
136        """Whether this version is a pre-release.
137
138        >>> Version("1.2.3").is_prerelease
139        False
140        >>> Version("1.2.3a1").is_prerelease
141        True
142        >>> Version("1.2.3b1").is_prerelease
143        True
144        >>> Version("1.2.3rc1").is_prerelease
145        True
146        >>> Version("1.2.3dev1").is_prerelease
147        True
148        """
149        return self._version.is_prerelease

Whether this version is a pre-release.

>>> Version("1.2.3").is_prerelease
False
>>> Version("1.2.3a1").is_prerelease
True
>>> Version("1.2.3b1").is_prerelease
True
>>> Version("1.2.3rc1").is_prerelease
True
>>> Version("1.2.3dev1").is_prerelease
True
is_postrelease: bool
151    @property
152    def is_postrelease(self) -> bool:
153        """Whether this version is a post-release.
154
155        >>> Version("1.2.3").is_postrelease
156        False
157        >>> Version("1.2.3.post1").is_postrelease
158        True
159        """
160        return self._version.is_postrelease

Whether this version is a post-release.

>>> Version("1.2.3").is_postrelease
False
>>> Version("1.2.3.post1").is_postrelease
True
is_devrelease: bool
162    @property
163    def is_devrelease(self) -> bool:
164        """Whether this version is a development release.
165
166        >>> Version("1.2.3").is_devrelease
167        False
168        >>> Version("1.2.3.dev1").is_devrelease
169        True
170        """
171        return self._version.is_devrelease

Whether this version is a development release.

>>> Version("1.2.3").is_devrelease
False
>>> Version("1.2.3.dev1").is_devrelease
True
major: int
173    @property
174    def major(self) -> int:
175        """The first item of :attr:`release` or ``0`` if unavailable.
176
177        >>> Version("1.2.3").major
178        1
179        """
180        return self._version.major

The first item of release or 0 if unavailable.

>>> Version("1.2.3").major
1
minor: int
182    @property
183    def minor(self) -> int:
184        """The second item of :attr:`release` or ``0`` if unavailable.
185
186        >>> Version("1.2.3").minor
187        2
188        >>> Version("1").minor
189        0
190        """
191        return self._version.minor

The second item of release or 0 if unavailable.

>>> Version("1.2.3").minor
2
>>> Version("1").minor
0
micro: int
193    @property
194    def micro(self) -> int:
195        """The third item of :attr:`release` or ``0`` if unavailable.
196
197        >>> Version("1.2.3").micro
198        3
199        >>> Version("1").micro
200        0
201        """
202        return self._version.micro

The third item of release or 0 if unavailable.

>>> Version("1.2.3").micro
3
>>> Version("1").micro
0