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): 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[ 227 Annotated[str, Len(min_length=1, max_length=1), Field(examples=["🦈", "🦥"])] 228 ] = None 229 """UTF-8 emoji for display alongside the `id`.""" 230 231 authors: List[Author] = Field(default_factory=list) 232 """The authors are the creators of the RDF and the primary points of contact.""" 233 234 @field_validator("authors", mode="before") 235 @classmethod 236 def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any: 237 """we unofficially accept strings as author entries""" 238 if is_sequence(authors): 239 authors = [{"name": a} if isinstance(a, str) else a for a in authors] 240 241 if not authors: 242 issue_warning("missing", value=authors, field="authors") 243 244 return authors 245 246 attachments: Optional[AttachmentsDescr] = None 247 """file and other attachments""" 248 249 cite: List[CiteEntry] = Field(default_factory=list) 250 """citations""" 251 252 @field_validator("cite", mode="after") 253 @classmethod 254 def _warn_empty_cite(cls, value: Any): 255 if not value: 256 issue_warning("missing", value=value, field="cite") 257 258 return value 259 260 config: Annotated[ 261 Dict[str, YamlValue], 262 Field( 263 examples=[ 264 dict( 265 bioimageio={ 266 "my_custom_key": 3837283, 267 "another_key": {"nested": "value"}, 268 }, 269 imagej={"macro_dir": "path/to/macro/file"}, 270 ) 271 ], 272 ), 273 ] = Field(default_factory=dict) 274 """A field for custom configuration that can contain any keys not present in the RDF spec. 275 This means you should not store, for example, a github repo URL in `config` since we already have the 276 `git_repo` field defined in the spec. 277 Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions, 278 it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name, 279 for example: 280 ```yaml 281 config: 282 bioimageio: # here is the domain name 283 my_custom_key: 3837283 284 another_key: 285 nested: value 286 imagej: # config specific to ImageJ 287 macro_dir: path/to/macro/file 288 ``` 289 If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`. 290 You may want to list linked files additionally under `attachments` to include them when packaging a resource 291 (packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains 292 an altered rdf.yaml file with local references to the downloaded files)""" 293 294 download_url: Optional[HttpUrl] = None 295 """URL to download the resource from (deprecated)""" 296 297 git_repo: Annotated[ 298 Optional[str], 299 Field( 300 examples=[ 301 "https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad" 302 ], 303 ), 304 ] = None 305 """A URL to the Git repository where the resource is being developed.""" 306 307 icon: Union[ 308 Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None 309 ] = None 310 """An icon for illustration""" 311 312 links: Annotated[ 313 List[str], 314 Field( 315 examples=[ 316 ( 317 "ilastik/ilastik", 318 "deepimagej/deepimagej", 319 "zero/notebook_u-net_3d_zerocostdl4mic", 320 ) 321 ], 322 ), 323 ] = Field(default_factory=list) 324 """IDs of other bioimage.io resources""" 325 326 uploader: Optional[Uploader] = None 327 """The person who uploaded the model (e.g. to bioimage.io)""" 328 329 maintainers: List[Maintainer] = Field(default_factory=list) 330 """Maintainers of this resource. 331 If not specified `authors` are maintainers and at least some of them should specify their `github_user` name""" 332 333 rdf_source: Optional[FileSource] = None 334 """Resource description file (RDF) source; used to keep track of where an rdf.yaml was loaded from. 335 Do not set this field in a YAML file.""" 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[Mapping[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 "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 version_number: Optional[int] = None 366 """version number (n-th published version, not the semantic version)""" 367 368 369class GenericDescrBase(GenericModelDescrBase): 370 """Base for all resource descriptions except for the model descriptions""" 371 372 format_version: Literal["0.2.4"] = "0.2.4" 373 """The format version of this resource specification 374 (not the `version` of the resource description) 375 When creating a new resource always use the latest micro/patch version described here. 376 The `format_version` is important for any consumer software to understand how to parse the fields. 377 """ 378 379 @model_validator(mode="before") 380 @classmethod 381 def _convert_from_older_format( 382 cls, data: BioimageioYamlContent, / 383 ) -> BioimageioYamlContent: 384 _convert_from_older_format(data) 385 return data 386 387 badges: List[BadgeDescr] = Field(default_factory=list) 388 """badges associated with this resource""" 389 390 documentation: Annotated[ 391 Optional[ImportantFileSource], 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 with additional documentation. 400 The recommended documentation file name is `README.md`. An `.md` suffix is mandatory.""" 401 402 license: Annotated[ 403 Union[LicenseId, DeprecatedLicenseId, str, None], 404 Field(union_mode="left_to_right", examples=["CC0-1.0", "MIT", "BSD-2-Clause"]), 405 ] = None 406 """A [SPDX license identifier](https://spdx.org/licenses/). 407 We do not support custom license beyond the SPDX license list, if you need that please 408 [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose 409 ) to discuss your intentions with the community.""" 410 411 @field_validator("license", mode="after") 412 @classmethod 413 def deprecated_spdx_license( 414 cls, value: Optional[Union[LicenseId, DeprecatedLicenseId, str]] 415 ): 416 if isinstance(value, LicenseId): 417 pass 418 elif value is None: 419 issue_warning("missing", value=value, field="license") 420 elif isinstance(value, DeprecatedLicenseId): 421 issue_warning( 422 "'{value}' is a deprecated license identifier.", 423 value=value, 424 field="license", 425 ) 426 elif isinstance(value, str): 427 issue_warning( 428 "'{value}' is an unknown license identifier.", 429 value=value, 430 field="license", 431 ) 432 else: 433 assert_never(value) 434 435 return value 436 437 438ResourceDescrType = TypeVar("ResourceDescrType", bound=GenericDescrBase) 439 440 441class GenericDescr(GenericDescrBase, extra="ignore"): 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[ 453 Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])] 454 ] = None 455 """bioimage.io-wide unique resource identifier 456 assigned by bioimage.io; version **un**specific.""" 457 458 source: Optional[HttpUrl] = None 459 """The primary source of the resource""" 460 461 @field_validator("type", mode="after") 462 @classmethod 463 def check_specific_types(cls, value: str) -> str: 464 if value in KNOWN_SPECIFIC_RESOURCE_TYPES: 465 raise ValueError( 466 f"Use the {value} description instead of this generic description for" 467 + f" your '{value}' resource." 468 ) 469 470 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"""
update pydantic model config to allow additional unknown keys
∈📦 File attachments
Inherited Members
109class Uploader(Node): 110 email: EmailStr 111 """Email""" 112 name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None 113 """name"""
name
Inherited Members
131class Author(_Person): 132 name: Annotated[str, AfterValidator(_remove_slashes)] 133 github_user: Optional[str] = None # TODO: validate github_user
Inherited Members
136class Maintainer(_Person): 137 name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None 138 github_user: str
Inherited Members
141class BadgeDescr(Node): 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
target URL
Inherited Members
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
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
Inherited Members
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
version number (n-th published version, not the semantic version) of linked resource
Inherited Members
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[ 228 Annotated[str, Len(min_length=1, max_length=1), Field(examples=["🦈", "🦥"])] 229 ] = None 230 """UTF-8 emoji for display alongside the `id`.""" 231 232 authors: List[Author] = Field(default_factory=list) 233 """The authors are the creators of the RDF and the primary points of contact.""" 234 235 @field_validator("authors", mode="before") 236 @classmethod 237 def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any: 238 """we unofficially accept strings as author entries""" 239 if is_sequence(authors): 240 authors = [{"name": a} if isinstance(a, str) else a for a in authors] 241 242 if not authors: 243 issue_warning("missing", value=authors, field="authors") 244 245 return authors 246 247 attachments: Optional[AttachmentsDescr] = None 248 """file and other attachments""" 249 250 cite: List[CiteEntry] = Field(default_factory=list) 251 """citations""" 252 253 @field_validator("cite", mode="after") 254 @classmethod 255 def _warn_empty_cite(cls, value: Any): 256 if not value: 257 issue_warning("missing", value=value, field="cite") 258 259 return value 260 261 config: Annotated[ 262 Dict[str, YamlValue], 263 Field( 264 examples=[ 265 dict( 266 bioimageio={ 267 "my_custom_key": 3837283, 268 "another_key": {"nested": "value"}, 269 }, 270 imagej={"macro_dir": "path/to/macro/file"}, 271 ) 272 ], 273 ), 274 ] = Field(default_factory=dict) 275 """A field for custom configuration that can contain any keys not present in the RDF spec. 276 This means you should not store, for example, a github repo URL in `config` since we already have the 277 `git_repo` field defined in the spec. 278 Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions, 279 it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name, 280 for example: 281 ```yaml 282 config: 283 bioimageio: # here is the domain name 284 my_custom_key: 3837283 285 another_key: 286 nested: value 287 imagej: # config specific to ImageJ 288 macro_dir: path/to/macro/file 289 ``` 290 If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`. 291 You may want to list linked files additionally under `attachments` to include them when packaging a resource 292 (packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains 293 an altered rdf.yaml file with local references to the downloaded files)""" 294 295 download_url: Optional[HttpUrl] = None 296 """URL to download the resource from (deprecated)""" 297 298 git_repo: Annotated[ 299 Optional[str], 300 Field( 301 examples=[ 302 "https://github.com/bioimage-io/spec-bioimage-io/tree/main/example_descriptions/models/unet2d_nuclei_broad" 303 ], 304 ), 305 ] = None 306 """A URL to the Git repository where the resource is being developed.""" 307 308 icon: Union[ 309 Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None 310 ] = None 311 """An icon for illustration""" 312 313 links: Annotated[ 314 List[str], 315 Field( 316 examples=[ 317 ( 318 "ilastik/ilastik", 319 "deepimagej/deepimagej", 320 "zero/notebook_u-net_3d_zerocostdl4mic", 321 ) 322 ], 323 ), 324 ] = Field(default_factory=list) 325 """IDs of other bioimage.io resources""" 326 327 uploader: Optional[Uploader] = None 328 """The person who uploaded the model (e.g. to bioimage.io)""" 329 330 maintainers: List[Maintainer] = Field(default_factory=list) 331 """Maintainers of this resource. 332 If not specified `authors` are maintainers and at least some of them should specify their `github_user` name""" 333 334 rdf_source: Optional[FileSource] = None 335 """Resource description file (RDF) source; used to keep track of where an rdf.yaml was loaded from. 336 Do not set this field in a YAML file.""" 337 338 tags: Annotated[ 339 List[str], 340 Field(examples=[("unet2d", "pytorch", "nucleus", "segmentation", "dsb2018")]), 341 ] = Field(default_factory=list) 342 """Associated tags""" 343 344 @as_warning 345 @field_validator("tags") 346 @classmethod 347 def warn_about_tag_categories( 348 cls, value: List[str], info: ValidationInfo 349 ) -> List[str]: 350 categories = TAG_CATEGORIES.get(info.data["type"], {}) 351 missing_categories: List[Mapping[str, Sequence[str]]] = [] 352 for cat, entries in categories.items(): 353 if not any(e in value for e in entries): 354 missing_categories.append({cat: entries}) 355 356 if missing_categories: 357 raise ValueError( 358 "Missing tags from bioimage.io categories: {missing_categories}" 359 ) 360 361 return value 362 363 version: Optional[Version] = None 364 """The version of the resource following SemVer 2.0.""" 365 366 version_number: Optional[int] = None 367 """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.
Inherited Members
370class GenericDescrBase(GenericModelDescrBase): 371 """Base for all resource descriptions except for the model descriptions""" 372 373 format_version: Literal["0.2.4"] = "0.2.4" 374 """The format version of this resource specification 375 (not the `version` of the resource description) 376 When creating a new resource always use the latest micro/patch version described here. 377 The `format_version` is important for any consumer software to understand how to parse the fields. 378 """ 379 380 @model_validator(mode="before") 381 @classmethod 382 def _convert_from_older_format( 383 cls, data: BioimageioYamlContent, / 384 ) -> BioimageioYamlContent: 385 _convert_from_older_format(data) 386 return data 387 388 badges: List[BadgeDescr] = Field(default_factory=list) 389 """badges associated with this resource""" 390 391 documentation: Annotated[ 392 Optional[ImportantFileSource], 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 with additional documentation. 401 The recommended documentation file name is `README.md`. An `.md` suffix is mandatory.""" 402 403 license: Annotated[ 404 Union[LicenseId, DeprecatedLicenseId, str, None], 405 Field(union_mode="left_to_right", examples=["CC0-1.0", "MIT", "BSD-2-Clause"]), 406 ] = None 407 """A [SPDX license identifier](https://spdx.org/licenses/). 408 We do not support custom license beyond the SPDX license list, if you need that please 409 [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose 410 ) to discuss your intentions with the community.""" 411 412 @field_validator("license", mode="after") 413 @classmethod 414 def deprecated_spdx_license( 415 cls, value: Optional[Union[LicenseId, DeprecatedLicenseId, str]] 416 ): 417 if isinstance(value, LicenseId): 418 pass 419 elif value is None: 420 issue_warning("missing", value=value, field="license") 421 elif isinstance(value, DeprecatedLicenseId): 422 issue_warning( 423 "'{value}' is a deprecated license identifier.", 424 value=value, 425 field="license", 426 ) 427 elif isinstance(value, str): 428 issue_warning( 429 "'{value}' is an unknown license identifier.", 430 value=value, 431 field="license", 432 ) 433 else: 434 assert_never(value) 435 436 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.
412 @field_validator("license", mode="after") 413 @classmethod 414 def deprecated_spdx_license( 415 cls, value: Optional[Union[LicenseId, DeprecatedLicenseId, str]] 416 ): 417 if isinstance(value, LicenseId): 418 pass 419 elif value is None: 420 issue_warning("missing", value=value, field="license") 421 elif isinstance(value, DeprecatedLicenseId): 422 issue_warning( 423 "'{value}' is a deprecated license identifier.", 424 value=value, 425 field="license", 426 ) 427 elif isinstance(value, str): 428 issue_warning( 429 "'{value}' is an unknown license identifier.", 430 value=value, 431 field="license", 432 ) 433 else: 434 assert_never(value) 435 436 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.
Inherited Members
442class GenericDescr(GenericDescrBase, extra="ignore"): 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[ 454 Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])] 455 ] = None 456 """bioimage.io-wide unique resource identifier 457 assigned by bioimage.io; version **un**specific.""" 458 459 source: Optional[HttpUrl] = None 460 """The primary source of the resource""" 461 462 @field_validator("type", mode="after") 463 @classmethod 464 def check_specific_types(cls, value: str) -> str: 465 if value in KNOWN_SPECIFIC_RESOURCE_TYPES: 466 raise ValueError( 467 f"Use the {value} description instead of this generic description for" 468 + f" your '{value}' resource." 469 ) 470 471 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.
462 @field_validator("type", mode="after") 463 @classmethod 464 def check_specific_types(cls, value: str) -> str: 465 if value in KNOWN_SPECIFIC_RESOURCE_TYPES: 466 raise ValueError( 467 f"Use the {value} description instead of this generic description for" 468 + f" your '{value}' resource." 469 ) 470 471 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.