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
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'.
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
update pydantic model config to allow additional unknown keys
∈📦 File attachments
109class Uploader(Node): 110 email: EmailStr 111 """Email""" 112 name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None 113 """name"""
Subpart of a resource description
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
Inherited Members
136class Maintainer(_Person): 137 name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None 138 github_user: str
Subpart of a resource description
Inherited Members
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
badge label to display on hover
badge icon
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
A digital object identifier (DOI) is the prefered citation reference.
See https://www.doi.org/ for details. (alternatively specify url
)
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
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
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
A human-friendly name of the resource description
∈📦 Cover images. Please use an image smaller than 500KB and an aspect ratio width to height of 2:1.
UTF-8 emoji for display alongside the id
.
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)
URL to download the resource from (deprecated)
A URL to the Git repository where the resource is being developed.
An icon for illustration
IDs of other bioimage.io resources
Maintainers of this resource.
If not specified authors
are maintainers and at least some of them should specify their github_user
name
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.
The version of the resource following SemVer 2.0.
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.
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
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.
∈📦 URL or relative path to a markdown file with additional documentation.
The recommended documentation file name is README.md
. An .md
suffix is mandatory.
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.
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
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.
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.
The resource type assigns a broad category to the resource.
bioimage.io-wide unique resource identifier assigned by bioimage.io; version unspecific.
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
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.