bioimageio.spec.generic.v0_3

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

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

DocumentationSource = typing.Annotated[typing.Union[typing.Annotated[pathlib.Path, PathType(path_type='file'), Predicate(is_absolute)], bioimageio.spec._internal.io.RelativeFilePath, bioimageio.spec._internal.url.HttpUrl], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')]), AfterValidator(func=<function _validate_md_suffix>), PlainSerializer(func=<function _package>, return_type=PydanticUndefined, when_used='unless-none')]
class Author(bioimageio.spec.generic.v0_2.Author):
113class Author(_Author_v0_2):
114    name: Annotated[str, Predicate(_has_no_slash)]
115    github_user: Optional[str] = None
116
117    @field_validator("github_user", mode="after")
118    def _validate_gh_user(cls, value: Optional[str]):
119        if value is None:
120            return None
121        else:
122            return validate_gh_user(value)

Subpart of a resource description

name: Annotated[str, Predicate(func=<function _has_no_slash at 0x7f9a73794040>)]
github_user: Optional[str]
class Maintainer(bioimageio.spec.generic.v0_2.Maintainer):
141class Maintainer(_Maintainer_v0_2):
142    name: Optional[Annotated[str, Predicate(_has_no_slash)]] = None
143    github_user: str
144
145    @field_validator("github_user", mode="after")
146    def validate_gh_user(cls, value: str):
147        return validate_gh_user(value)

Subpart of a resource description

name: Optional[Annotated[str, Predicate(func=<function _has_no_slash at 0x7f9a73794040>)]]
github_user: str
@field_validator('github_user', mode='after')
def validate_gh_user(cls, value: str):
145    @field_validator("github_user", mode="after")
146    def validate_gh_user(cls, value: str):
147        return validate_gh_user(value)
class CiteEntry(bioimageio.spec._internal.node.Node):
166class CiteEntry(Node):
167    text: str
168    """free text description"""
169
170    doi: Optional[Doi] = None
171    """A digital object identifier (DOI) is the prefered citation reference.
172    See https://www.doi.org/ for details. (alternatively specify `url`)"""
173
174    url: Optional[HttpUrl] = None
175    """URL to cite (preferably specify a `doi` instead)"""
176
177    @model_validator(mode="after")
178    def _check_doi_or_url(self):
179        if not self.doi and not self.url:
180            raise ValueError("Either 'doi' or 'url' is required")
181
182        return self

Subpart of a resource description

text: str

free text description

doi: Optional[bioimageio.spec._internal.types.Doi]

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

url: Optional[bioimageio.spec._internal.url.HttpUrl]

URL to cite (preferably specify a doi instead)

class LinkedResource(bioimageio.spec._internal.node.Node):
185class LinkedResource(Node):
186    """Reference to a bioimage.io resource"""
187
188    id: ResourceId
189    """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 GenericModelDescrBase(bioimageio.spec._internal.common_nodes.ResourceDescrBase):
192class GenericModelDescrBase(ResourceDescrBase):
193    """Base for all resource descriptions including of model descriptions"""
194
195    name: Annotated[
196        Annotated[
197            str, RestrictCharacters(string.ascii_letters + string.digits + "_- ()")
198        ],
199        MinLen(5),
200        MaxLen(128),
201        warn(MaxLen(64), "Name longer than 64 characters.", INFO),
202    ]
203    name: Annotated[NotEmpty[str], MaxLen(128)]
204    """A human-friendly name of the resource description.
205    May only contains letters, digits, underscore, minus, parentheses and spaces."""
206
207    description: Annotated[
208        str, MaxLen(1024), warn(MaxLen(512), "Description longer than 512 characters.")
209    ]
210    """A string containing a brief description."""
211
212    covers: Annotated[
213        List[CoverImageSource],
214        Field(
215            examples=[],
216            description=(
217                "Cover images. Please use an image smaller than 500KB and an aspect"
218                " ratio width to height of 2:1 or 1:1.\nThe supported image formats"
219                f" are: {VALID_COVER_IMAGE_EXTENSIONS}"
220            ),
221        ),
222    ] = Field(default_factory=list)
223    """∈📦 Cover images."""
224
225    id_emoji: Optional[Annotated[str, Len(min_length=1, max_length=2)]] = None
226    """UTF-8 emoji for display alongside the `id`."""
227
228    authors: NotEmpty[List[Author]]
229    """The authors are the creators of this resource description and the primary points of contact."""
230
231    attachments: List[FileDescr] = Field(default_factory=list)
232    """file attachments"""
233
234    cite: NotEmpty[List[CiteEntry]]
235    """citations"""
236
237    license: Annotated[
238        Annotated[
239            Union[LicenseId, DeprecatedLicenseId], Field(union_mode="left_to_right")
240        ],
241        warn(
242            LicenseId,
243            "{value} is deprecated, see https://spdx.org/licenses/{value}.html",
244        ),
245        Field(examples=["CC0-1.0", "MIT", "BSD-2-Clause"]),
246    ]
247    """A [SPDX license identifier](https://spdx.org/licenses/).
248    We do not support custom license beyond the SPDX license list, if you need that please
249    [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose)
250    to discuss your intentions with the community."""
251
252    config: Annotated[
253        Dict[str, YamlValue],
254        Field(
255            examples=[
256                dict(
257                    bioimageio={
258                        "my_custom_key": 3837283,
259                        "another_key": {"nested": "value"},
260                    },
261                    imagej={"macro_dir": "path/to/macro/file"},
262                )
263            ],
264        ),
265    ] = Field(default_factory=dict)
266    """A field for custom configuration that can contain any keys not present in the RDF spec.
267    This means you should not store, for example, a GitHub repo URL in `config` since there is a `git_repo` field.
268    Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions,
269    it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name,
270    for example:
271    ```yaml
272    config:
273        bioimageio:  # here is the domain name
274            my_custom_key: 3837283
275            another_key:
276                nested: value
277        imagej:       # config specific to ImageJ
278            macro_dir: path/to/macro/file
279    ```
280    If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`.
281    You may want to list linked files additionally under `attachments` to include them when packaging a resource.
282    (Packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains
283    an altered rdf.yaml file with local references to the downloaded files.)"""
284
285    git_repo: Annotated[
286        Optional[HttpUrl],
287        Field(
288            examples=[
289                "https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad"
290            ],
291        ),
292    ] = None
293    """A URL to the Git repository where the resource is being developed."""
294
295    icon: Union[
296        Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None
297    ] = None
298    """An icon for illustration, e.g. on bioimage.io"""
299
300    links: Annotated[
301        List[str],
302        Field(
303            examples=[
304                (
305                    "ilastik/ilastik",
306                    "deepimagej/deepimagej",
307                    "zero/notebook_u-net_3d_zerocostdl4mic",
308                )
309            ],
310        ),
311    ] = Field(default_factory=list)
312    """IDs of other bioimage.io resources"""
313
314    uploader: Optional[Uploader] = None
315    """The person who uploaded the model (e.g. to bioimage.io)"""
316
317    maintainers: List[Maintainer] = Field(default_factory=list)
318    """Maintainers of this resource.
319    If not specified, `authors` are maintainers and at least some of them has to specify their `github_user` name"""
320
321    @partial(as_warning, severity=ALERT)
322    @field_validator("maintainers", mode="after")
323    @classmethod
324    def check_maintainers_exist(
325        cls, maintainers: List[Maintainer], info: ValidationInfo
326    ) -> List[Maintainer]:
327        if not maintainers and "authors" in info.data:
328            authors: List[Author] = info.data["authors"]
329            if all(a.github_user is None for a in authors):
330                raise ValueError(
331                    "Missing `maintainers` or any author in `authors` with a specified"
332                    + " `github_user` name."
333                )
334
335        return maintainers
336
337    tags: Annotated[
338        List[str],
339        Field(examples=[("unet2d", "pytorch", "nucleus", "segmentation", "dsb2018")]),
340    ] = Field(default_factory=list)
341    """Associated tags"""
342
343    @as_warning
344    @field_validator("tags")
345    @classmethod
346    def warn_about_tag_categories(
347        cls, value: List[str], info: ValidationInfo
348    ) -> List[str]:
349        categories = TAG_CATEGORIES.get(info.data["type"], {})
350        missing_categories: List[Dict[str, Sequence[str]]] = []
351        for cat, entries in categories.items():
352            if not any(e in value for e in entries):
353                missing_categories.append({cat: entries})
354
355        if missing_categories:
356            raise ValueError(
357                f"Missing tags from bioimage.io categories: {missing_categories}"
358            )
359
360        return value
361
362    version: Optional[Version] = None
363    """The version of the resource following SemVer 2.0."""
364
365    @model_validator(mode="before")
366    def _remove_version_number(  # pyright: ignore[reportUnknownParameterType]
367        cls, value: Union[Any, Dict[Any, Any]]
368    ):
369        if isinstance(value, dict):
370            vn: Any = value.pop("version_number", None)
371            if vn is not None and value.get("version") is None:
372                value["version"] = vn
373
374        return value  # pyright: ignore[reportUnknownVariableType]

Base for all resource descriptions including of model descriptions

name: Annotated[str, MinLen(min_length=1), MaxLen(max_length=128)]

A human-friendly name of the resource description. May only contains letters, digits, underscore, minus, parentheses and spaces.

description: Annotated[str, MaxLen(max_length=1024), AfterWarner(func=<function as_warning.<locals>.wrapper at 0x7f9a6e1096c0>, severity=30, msg='Description longer than 512 characters.', context={'typ': Annotated[Any, MaxLen(max_length=512)]})]

A string containing a brief description.

covers: Annotated[List[Annotated[Union[Annotated[pathlib.Path, PathType(path_type='file'), Predicate(is_absolute)], bioimageio.spec._internal.io.RelativeFilePath, bioimageio.spec._internal.url.HttpUrl], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')]), WithSuffix(suffix=('.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff'), case_sensitive=False), PlainSerializer(func=<function _package at 0x7f9a7f3b9620>, return_type=PydanticUndefined, when_used='unless-none')]], FieldInfo(annotation=NoneType, required=True, description="Cover images. Please use an image smaller than 500KB and an aspect ratio width to height of 2:1 or 1:1.\nThe supported image formats are: ('.gif', '.jpeg', '.jpg', '.png', '.svg')", examples=[])]

∈📦 Cover images.

id_emoji: Optional[Annotated[str, Len(min_length=1, max_length=2)]]

UTF-8 emoji for display alongside the id.

authors: Annotated[List[Author], MinLen(min_length=1)]

The authors are the creators of this resource description and the primary points of contact.

attachments: List[bioimageio.spec._internal.io.FileDescr]

file attachments

cite: Annotated[List[CiteEntry], MinLen(min_length=1)]

citations

license: Annotated[Union[bioimageio.spec._internal.license_id.LicenseId, bioimageio.spec._internal.license_id.DeprecatedLicenseId], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')]), AfterWarner(func=<function as_warning.<locals>.wrapper at 0x7f9a6e10a480>, severity=30, msg='{value} is deprecated, see https://spdx.org/licenses/{value}.html', context={'typ': <class 'bioimageio.spec._internal.license_id.LicenseId'>}), FieldInfo(annotation=NoneType, required=True, examples=['CC0-1.0', 'MIT', 'BSD-2-Clause'])]

A SPDX license identifier. We do not support custom license beyond the SPDX license list, if you need that please open a GitHub issue to discuss your intentions with the community.

config: Annotated[Dict[str, YamlValue], FieldInfo(annotation=NoneType, required=True, examples=[{'bioimageio': {'my_custom_key': 3837283, 'another_key': {'nested': 'value'}}, 'imagej': {'macro_dir': 'path/to/macro/file'}}])]

A field for custom configuration that can contain any keys not present in the RDF spec. This means you should not store, for example, a GitHub repo URL in config since there is a git_repo field. Keys in config may be very specific to a tool or consumer software. To avoid conflicting definitions, it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name, for example:

config:
    bioimageio:  # here is the domain name
        my_custom_key: 3837283
        another_key:
            nested: value
    imagej:       # config specific to ImageJ
        macro_dir: path/to/macro/file

If possible, please use snake_case for keys in config. You may want to list linked files additionally under attachments to include them when packaging a resource. (Packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains an altered rdf.yaml file with local references to the downloaded files.)

git_repo: Annotated[Optional[bioimageio.spec._internal.url.HttpUrl], FieldInfo(annotation=NoneType, required=True, examples=['https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad'])]

A URL to the Git repository where the resource is being developed.

icon: Union[Annotated[str, Len(min_length=1, max_length=2)], Annotated[Union[bioimageio.spec._internal.url.HttpUrl, bioimageio.spec._internal.io.RelativeFilePath, Annotated[pathlib.Path, PathType(path_type='file')]], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')]), AfterValidator(func=<function wo_special_file_name at 0x7f9a7f3b8ea0>), PlainSerializer(func=<function _package at 0x7f9a7f3b9620>, return_type=PydanticUndefined, when_used='unless-none')], NoneType]

An icon for illustration, e.g. on bioimage.io

The person who uploaded the model (e.g. to bioimage.io)

maintainers: List[Maintainer]

Maintainers of this resource. If not specified, authors are maintainers and at least some of them has to specify their github_user name

def check_maintainers_exist(value: Any, info: pydantic_core.core_schema.ValidationInfo) -> Any:
75    def wrapper(value: Any, info: ValidationInfo) -> Any:
76        try:
77            call_validator_func(func, mode, value, info)
78        except (AssertionError, ValueError) as e:
79            issue_warning(
80                msg or ",".join(e.args),
81                value=value,
82                severity=severity,
83                msg_context=msg_context,
84            )
85
86        return value
tags: Annotated[List[str], FieldInfo(annotation=NoneType, required=True, examples=[('unet2d', 'pytorch', 'nucleus', 'segmentation', 'dsb2018')])]

Associated tags

def warn_about_tag_categories(value: Any, info: pydantic_core.core_schema.ValidationInfo) -> Any:
75    def wrapper(value: Any, info: ValidationInfo) -> Any:
76        try:
77            call_validator_func(func, mode, value, info)
78        except (AssertionError, ValueError) as e:
79            issue_warning(
80                msg or ",".join(e.args),
81                value=value,
82                severity=severity,
83                msg_context=msg_context,
84            )
85
86        return value
version: Optional[bioimageio.spec._internal.version_type.Version]

The version of the resource following SemVer 2.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.

class GenericDescrBase(GenericModelDescrBase):
377class GenericDescrBase(GenericModelDescrBase):
378    """Base for all resource descriptions except for the model descriptions"""
379
380    format_version: Literal["0.3.0"] = "0.3.0"
381    """The **format** version of this resource specification"""
382
383    @model_validator(mode="before")
384    @classmethod
385    def _convert_from_older_format(
386        cls, data: BioimageioYamlContent, /
387    ) -> BioimageioYamlContent:
388        convert_from_older_format(data)
389        return data
390
391    documentation: Annotated[
392        Optional[DocumentationSource],
393        Field(
394            examples=[
395                "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_descriptions/models/unet2d_nuclei_broad/README.md",
396                "README.md",
397            ],
398        ),
399    ] = None
400    """∈📦 URL or relative path to a markdown file encoded in UTF-8 with additional documentation.
401    The recommended documentation file name is `README.md`. An `.md` suffix is mandatory."""
402
403    badges: List[BadgeDescr] = Field(default_factory=list)
404    """badges associated with this resource"""

Base for all resource descriptions except for the model descriptions

format_version: Literal['0.3.0']

The format version of this resource specification

documentation: Annotated[Optional[Annotated[Union[Annotated[pathlib.Path, PathType(path_type='file'), Predicate(is_absolute)], bioimageio.spec._internal.io.RelativeFilePath, bioimageio.spec._internal.url.HttpUrl], FieldInfo(annotation=NoneType, required=True, metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')]), AfterValidator(func=<function _validate_md_suffix at 0x7f9a7e7b3e20>), PlainSerializer(func=<function _package at 0x7f9a7f3b9620>, return_type=PydanticUndefined, when_used='unless-none')]], FieldInfo(annotation=NoneType, required=True, examples=['https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_descriptions/models/unet2d_nuclei_broad/README.md', 'README.md'])]

∈📦 URL or relative path to a markdown file encoded in UTF-8 with additional documentation. The recommended documentation file name is README.md. An .md suffix is mandatory.

badges associated with this resource

implemented_format_version: ClassVar[str] = '0.3.0'
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.

class GenericDescr(GenericDescrBase):
410class GenericDescr(
411    GenericDescrBase, extra="ignore", title="bioimage.io generic specification"
412):
413    """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF).
414
415    An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook.
416    Note that those resources are described with a type-specific RDF.
417    Use this generic resource description, if none of the known specific types matches your resource.
418    """
419
420    type: Annotated[str, LowerCase] = Field("generic", frozen=True)
421    """The resource type assigns a broad category to the resource."""
422
423    id: Optional[ResourceId] = None
424    """bioimage.io-wide unique resource identifier
425    assigned by bioimage.io; version **un**specific."""
426
427    parent: Optional[ResourceId] = None
428    """The description from which this one is derived"""
429
430    source: Optional[HttpUrl] = None
431    """The primary source of the resource"""
432
433    @field_validator("type", mode="after")
434    @classmethod
435    def check_specific_types(cls, value: str) -> str:
436        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
437            raise ValueError(
438                f"Use the {value} description instead of this generic description for"
439                + f" your '{value}' resource."
440            )
441
442        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[ResourceId]

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[bioimageio.spec._internal.url.HttpUrl]

The primary source of the resource

@field_validator('type', mode='after')
@classmethod
def check_specific_types(cls, value: str) -> str:
433    @field_validator("type", mode="after")
434    @classmethod
435    def check_specific_types(cls, value: str) -> str:
436        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
437            raise ValueError(
438                f"Use the {value} description instead of this generic description for"
439                + f" your '{value}' resource."
440            )
441
442        return value
implemented_format_version: ClassVar[str] = '0.3.0'
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.

class LinkedResourceNode(bioimageio.spec._internal.node.Node):
445class LinkedResourceNode(Node):
446
447    @model_validator(mode="before")
448    def _remove_version_number(  # pyright: ignore[reportUnknownParameterType]
449        cls, value: Union[Any, Dict[Any, Any]]
450    ):
451        if isinstance(value, dict):
452            vn: Any = value.pop("version_number", None)
453            if vn is not None and value.get("version") is None:
454                value["version"] = vn
455
456        return value  # pyright: ignore[reportUnknownVariableType]
457
458    version: Optional[Version] = None
459    """The version of the linked resource following SemVer 2.0."""

Subpart of a resource description

version: Optional[bioimageio.spec._internal.version_type.Version]

The version of the linked resource following SemVer 2.0.