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