bioimageio.spec.generic.v0_2

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

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, AfterValidator, RestrictCharacters, Predicate]]'>

the pydantic root model to validate the string

KNOWN_SPECIFIC_RESOURCE_TYPES = ('application', 'collection', 'dataset', 'model', 'notebook')
VALID_COVER_IMAGE_EXTENSIONS = ('.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff')
CoverImageSource = 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')]), WithSuffix(suffix=('.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff'), case_sensitive=False), PlainSerializer(func=<function _package>, return_type=PydanticUndefined, when_used='unless-none')]
class AttachmentsDescr(bioimageio.spec._internal.node.Node):
 98class AttachmentsDescr(Node):
 99    model_config = {**Node.model_config, "extra": "allow"}
100    """update pydantic model config to allow additional unknown keys"""
101    files: List[ImportantFileSource] = Field(default_factory=list)
102    """∈📦 File attachments"""

Subpart of a resource description

model_config = {'extra': 'allow', 'frozen': False, 'populate_by_name': True, 'revalidate_instances': 'never', 'validate_assignment': True, 'validate_default': False, 'validate_return': True, 'use_attribute_docstrings': True}

update pydantic model config to allow additional unknown keys

files: List[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')]]

∈📦 File attachments

class Uploader(bioimageio.spec._internal.node.Node):
109class Uploader(Node):
110    email: EmailStr
111    """Email"""
112    name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None
113    """name"""

Subpart of a resource description

email: pydantic.networks.EmailStr

Email

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

name

class Author(_Person):
131class Author(_Person):
132    name: Annotated[str, AfterValidator(_remove_slashes)]
133    github_user: Optional[str] = None  # TODO: validate github_user

Subpart of a resource description

name: Annotated[str, AfterValidator(func=<function _remove_slashes at 0x7f9a7cb40680>)]
github_user: Optional[str]
Inherited Members
_Person
affiliation
email
orcid
class Maintainer(_Person):
136class Maintainer(_Person):
137    name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None
138    github_user: str

Subpart of a resource description

name: Optional[Annotated[str, AfterValidator(func=<function _remove_slashes at 0x7f9a7cb40680>)]]
github_user: str
Inherited Members
_Person
affiliation
email
orcid
class BadgeDescr(bioimageio.spec._internal.node.Node):
141class BadgeDescr(Node, title="Custom badge"):
142    """A custom badge"""
143
144    label: Annotated[str, Field(examples=["Open in Colab"])]
145    """badge label to display on hover"""
146
147    icon: Annotated[
148        Optional[InPackageIfLocalFileSource],
149        Field(examples=["https://colab.research.google.com/assets/colab-badge.svg"]),
150    ] = None
151    """badge icon"""
152
153    url: Annotated[
154        HttpUrl,
155        Field(
156            examples=[
157                "https://colab.research.google.com/github/HenriquesLab/ZeroCostDL4Mic/blob/master/Colab_notebooks/U-net_2D_ZeroCostDL4Mic.ipynb"
158            ]
159        ),
160    ]
161    """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')], bioimageio.spec._internal.io.RelativeFilePath], AfterValidator(func=<function wo_special_file_name at 0x7f9a7f3b8ea0>), PlainSerializer(func=<function _package at 0x7f9a7f3b9620>, return_type=PydanticUndefined, when_used='unless-none')], bioimageio.spec._internal.url.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[bioimageio.spec._internal.url.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):
164class CiteEntry(Node):
165    text: str
166    """free text description"""
167
168    doi: Optional[Doi] = None
169    """A digital object identifier (DOI) is the prefered citation reference.
170    See https://www.doi.org/ for details. (alternatively specify `url`)"""
171
172    @field_validator("doi", mode="before")
173    @classmethod
174    def accept_prefixed_doi(cls, doi: Any) -> Any:
175        if isinstance(doi, str):
176            for doi_prefix in ("https://doi.org/", "http://dx.doi.org/"):
177                if doi.startswith(doi_prefix):
178                    doi = doi[len(doi_prefix) :]
179                    break
180
181        return doi
182
183    url: Optional[str] = None
184    """URL to cite (preferably specify a `doi` instead)"""
185
186    @model_validator(mode="after")
187    def _check_doi_or_url(self) -> Self:
188        if not self.doi and not self.url:
189            raise ValueError("Either 'doi' or 'url' is required")
190
191        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)

@field_validator('doi', mode='before')
@classmethod
def accept_prefixed_doi(cls, doi: Any) -> Any:
172    @field_validator("doi", mode="before")
173    @classmethod
174    def accept_prefixed_doi(cls, doi: Any) -> Any:
175        if isinstance(doi, str):
176            for doi_prefix in ("https://doi.org/", "http://dx.doi.org/"):
177                if doi.startswith(doi_prefix):
178                    doi = doi[len(doi_prefix) :]
179                    break
180
181        return doi
url: Optional[str]

URL to cite (preferably specify a doi instead)

class LinkedResource(bioimageio.spec._internal.node.Node):
194class LinkedResource(Node):
195    """Reference to a bioimage.io resource"""
196
197    id: ResourceId
198    """A valid resource `id` from the bioimage.io collection."""
199
200    version_number: Optional[int] = None
201    """version number (n-th published version, not the semantic version) of linked resource"""

Reference to a bioimage.io resource

A valid resource id from the bioimage.io collection.

version_number: Optional[int]

version number (n-th published version, not the semantic version) of linked resource

class GenericModelDescrBase(bioimageio.spec._internal.common_nodes.ResourceDescrBase):
204class GenericModelDescrBase(ResourceDescrBase):
205    """Base for all resource descriptions including of model descriptions"""
206
207    name: Annotated[NotEmpty[str], warn(MaxLen(128), "Longer than 128 characters.")]
208    """A human-friendly name of the resource description"""
209
210    description: str
211
212    covers: Annotated[
213        List[CoverImageSource],
214        Field(
215            examples=["cover.png"],
216            description=(
217                "Cover images. Please use an image smaller than 500KB and an aspect"
218                " ratio width to height of 2:1.\nThe supported image formats are:"
219                f" {VALID_COVER_IMAGE_EXTENSIONS}"
220            ),
221        ),
222    ] = Field(
223        default_factory=list,
224    )
225    """∈📦 Cover images. Please use an image smaller than 500KB and an aspect ratio width to height of 2:1."""
226
227    id_emoji: Optional[Annotated[str, Len(min_length=1, max_length=1)]] = None
228    """UTF-8 emoji for display alongside the `id`."""
229
230    authors: List[Author] = Field(default_factory=list)
231    """The authors are the creators of the RDF and the primary points of contact."""
232
233    @field_validator("authors", mode="before")
234    @classmethod
235    def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any:
236        """we unofficially accept strings as author entries"""
237        if is_sequence(authors):
238            authors = [{"name": a} if isinstance(a, str) else a for a in authors]
239
240        if not authors:
241            issue_warning("missing", value=authors, field="authors")
242
243        return authors
244
245    attachments: Optional[AttachmentsDescr] = None
246    """file and other attachments"""
247
248    cite: List[CiteEntry] = Field(default_factory=list)
249    """citations"""
250
251    @field_validator("cite", mode="after")
252    @classmethod
253    def _warn_empty_cite(cls, value: Any):
254        if not value:
255            issue_warning("missing", value=value, field="cite")
256
257        return value
258
259    config: Annotated[
260        Dict[str, YamlValue],
261        Field(
262            examples=[
263                dict(
264                    bioimageio={
265                        "my_custom_key": 3837283,
266                        "another_key": {"nested": "value"},
267                    },
268                    imagej={"macro_dir": "path/to/macro/file"},
269                )
270            ],
271        ),
272    ] = Field(default_factory=dict)
273    """A field for custom configuration that can contain any keys not present in the RDF spec.
274    This means you should not store, for example, a github repo URL in `config` since we already have the
275    `git_repo` field defined in the spec.
276    Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions,
277    it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name,
278    for example:
279    ```yaml
280    config:
281        bioimageio:  # here is the domain name
282            my_custom_key: 3837283
283            another_key:
284                nested: value
285        imagej:       # config specific to ImageJ
286            macro_dir: path/to/macro/file
287    ```
288    If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`.
289    You may want to list linked files additionally under `attachments` to include them when packaging a resource
290    (packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains
291    an altered rdf.yaml file with local references to the downloaded files)"""
292
293    download_url: Optional[HttpUrl] = None
294    """URL to download the resource from (deprecated)"""
295
296    git_repo: Annotated[
297        Optional[str],
298        Field(
299            examples=[
300                "https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad"
301            ],
302        ),
303    ] = None
304    """A URL to the Git repository where the resource is being developed."""
305
306    icon: Union[
307        Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None
308    ] = None
309    """An icon for illustration"""
310
311    links: Annotated[
312        List[str],
313        Field(
314            examples=[
315                (
316                    "ilastik/ilastik",
317                    "deepimagej/deepimagej",
318                    "zero/notebook_u-net_3d_zerocostdl4mic",
319                )
320            ],
321        ),
322    ] = Field(default_factory=list)
323    """IDs of other bioimage.io resources"""
324
325    uploader: Optional[Uploader] = None
326    """The person who uploaded the model (e.g. to bioimage.io)"""
327
328    maintainers: List[Maintainer] = Field(default_factory=list)
329    """Maintainers of this resource.
330    If not specified `authors` are maintainers and at least some of them should specify their `github_user` name"""
331
332    rdf_source: Optional[FileSource] = None
333    """Resource description file (RDF) source; used to keep track of where an rdf.yaml was loaded from.
334    Do not set this field in a YAML file."""
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[Mapping[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                "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    version_number: Optional[int] = None
365    """version number (n-th published version, not the semantic version)"""

Base for all resource descriptions including of model descriptions

name: Annotated[str, MinLen(min_length=1), AfterWarner(func=<function as_warning.<locals>.wrapper at 0x7f9a7cb27380>, severity=30, msg='Longer than 128 characters.', context={'typ': Annotated[Any, MaxLen(max_length=128)]})]

A human-friendly name of the resource description

description: str
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.\nThe supported image formats are: ('.gif', '.jpeg', '.jpg', '.png', '.svg', '.tif', '.tiff')", examples=['cover.png'])]

∈📦 Cover images. Please use an image smaller than 500KB and an aspect ratio width to height of 2:1.

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

UTF-8 emoji for display alongside the id.

authors: List[Author]

The authors are the creators of the RDF and the primary points of contact.

@field_validator('authors', mode='before')
@classmethod
def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any:
233    @field_validator("authors", mode="before")
234    @classmethod
235    def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any:
236        """we unofficially accept strings as author entries"""
237        if is_sequence(authors):
238            authors = [{"name": a} if isinstance(a, str) else a for a in authors]
239
240        if not authors:
241            issue_warning("missing", value=authors, field="authors")
242
243        return authors

we unofficially accept strings as author entries

attachments: Optional[AttachmentsDescr]

file and other attachments

cite: List[CiteEntry]

citations

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 we already have the git_repo field defined in the spec. 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)

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

URL to download the resource from (deprecated)

git_repo: Annotated[Optional[str], 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

uploader: Optional[Uploader]

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 should specify their github_user name

rdf_source: Optional[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')])]]

Resource description file (RDF) source; used to keep track of where an rdf.yaml was loaded from. Do not set this field in a YAML file.

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.

version_number: Optional[int]

version number (n-th published version, not the semantic version)

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):
368class GenericDescrBase(GenericModelDescrBase):
369    """Base for all resource descriptions except for the model descriptions"""
370
371    format_version: Literal["0.2.4"] = "0.2.4"
372    """The format version of this resource specification
373    (not the `version` of the resource description)
374    When creating a new resource always use the latest micro/patch version described here.
375    The `format_version` is important for any consumer software to understand how to parse the fields.
376    """
377
378    @model_validator(mode="before")
379    @classmethod
380    def _convert_from_older_format(
381        cls, data: BioimageioYamlContent, /
382    ) -> BioimageioYamlContent:
383        _convert_from_older_format(data)
384        return data
385
386    badges: List[BadgeDescr] = Field(default_factory=list)
387    """badges associated with this resource"""
388
389    documentation: Annotated[
390        Optional[ImportantFileSource],
391        Field(
392            examples=[
393                "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_descriptions/models/unet2d_nuclei_broad/README.md",
394                "README.md",
395            ],
396        ),
397    ] = None
398    """∈📦 URL or relative path to a markdown file with additional documentation.
399    The recommended documentation file name is `README.md`. An `.md` suffix is mandatory."""
400
401    license: Annotated[
402        Union[LicenseId, DeprecatedLicenseId, str, None],
403        Field(union_mode="left_to_right", examples=["CC0-1.0", "MIT", "BSD-2-Clause"]),
404    ] = None
405    """A [SPDX license identifier](https://spdx.org/licenses/).
406    We do not support custom license beyond the SPDX license list, if you need that please
407    [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose
408    ) to discuss your intentions with the community."""
409
410    @field_validator("license", mode="after")
411    @classmethod
412    def deprecated_spdx_license(
413        cls, value: Optional[Union[LicenseId, DeprecatedLicenseId, str]]
414    ):
415        if isinstance(value, LicenseId):
416            pass
417        elif value is None:
418            issue_warning("missing", value=value, field="license")
419        elif isinstance(value, DeprecatedLicenseId):
420            issue_warning(
421                "'{value}' is a deprecated license identifier.",
422                value=value,
423                field="license",
424            )
425        elif isinstance(value, str):
426            issue_warning(
427                "'{value}' is an unknown license identifier.",
428                value=value,
429                field="license",
430            )
431        else:
432            assert_never(value)
433
434        return value

Base for all resource descriptions except for the model descriptions

format_version: Literal['0.2.4']

The format version of this resource specification (not the version of the resource description) When creating a new resource always use the latest micro/patch version described here. The format_version is important for any consumer software to understand how to parse the fields.

badges: List[BadgeDescr]

badges associated with this resource

documentation: Annotated[Optional[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')]], 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 with additional documentation. The recommended documentation file name is README.md. An .md suffix is mandatory.

license: Annotated[Union[bioimageio.spec._internal.license_id.LicenseId, bioimageio.spec._internal.license_id.DeprecatedLicenseId, str, NoneType], FieldInfo(annotation=NoneType, required=True, examples=['CC0-1.0', 'MIT', 'BSD-2-Clause'], metadata=[_PydanticGeneralMetadata(union_mode='left_to_right')])]

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.

@field_validator('license', mode='after')
@classmethod
def deprecated_spdx_license( cls, value: Union[bioimageio.spec._internal.license_id.LicenseId, bioimageio.spec._internal.license_id.DeprecatedLicenseId, str, NoneType]):
410    @field_validator("license", mode="after")
411    @classmethod
412    def deprecated_spdx_license(
413        cls, value: Optional[Union[LicenseId, DeprecatedLicenseId, str]]
414    ):
415        if isinstance(value, LicenseId):
416            pass
417        elif value is None:
418            issue_warning("missing", value=value, field="license")
419        elif isinstance(value, DeprecatedLicenseId):
420            issue_warning(
421                "'{value}' is a deprecated license identifier.",
422                value=value,
423                field="license",
424            )
425        elif isinstance(value, str):
426            issue_warning(
427                "'{value}' is an unknown license identifier.",
428                value=value,
429                field="license",
430            )
431        else:
432            assert_never(value)
433
434        return value
implemented_format_version: ClassVar[str] = '0.2.4'
implemented_format_version_tuple: ClassVar[Tuple[int, int, int]] = (0, 2, 4)
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):
440class GenericDescr(
441    GenericDescrBase, extra="ignore", title="bioimage.io generic specification"
442):
443    """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF).
444
445    An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook.
446    Note that those resources are described with a type-specific RDF.
447    Use this generic resource description, if none of the known specific types matches your resource.
448    """
449
450    type: Annotated[str, LowerCase, Field(frozen=True)] = "generic"
451    """The resource type assigns a broad category to the resource."""
452
453    id: Optional[ResourceId] = None
454    """bioimage.io-wide unique resource identifier
455    assigned by bioimage.io; version **un**specific."""
456
457    source: Optional[HttpUrl] = None
458    """The primary source of the resource"""
459
460    @field_validator("type", mode="after")
461    @classmethod
462    def check_specific_types(cls, value: str) -> str:
463        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
464            raise ValueError(
465                f"Use the {value} description instead of this generic description for"
466                + f" your '{value}' resource."
467            )
468
469        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)], FieldInfo(annotation=NoneType, required=True, frozen=True)]

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.

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:
460    @field_validator("type", mode="after")
461    @classmethod
462    def check_specific_types(cls, value: str) -> str:
463        if value in KNOWN_SPECIFIC_RESOURCE_TYPES:
464            raise ValueError(
465                f"Use the {value} description instead of this generic description for"
466                + f" your '{value}' resource."
467            )
468
469        return value
implemented_format_version: ClassVar[str] = '0.2.4'
implemented_format_version_tuple: ClassVar[Tuple[int, int, int]] = (0, 2, 4)
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.