bioimageio.spec.generic.v0_3
1from __future__ import annotations 2 3import string 4from functools import partial 5from typing import ( 6 Any, 7 ClassVar, 8 Dict, 9 List, 10 Literal, 11 Optional, 12 Sequence, 13 Type, 14 TypeVar, 15 Union, 16) 17 18import annotated_types 19from annotated_types import Len, LowerCase, MaxLen, MinLen 20from pydantic import Field, RootModel, ValidationInfo, field_validator, model_validator 21from typing_extensions import Annotated 22 23from .._internal.common_nodes import Node, ResourceDescrBase 24from .._internal.constants import TAG_CATEGORIES 25from .._internal.field_validation import validate_gh_user 26from .._internal.field_warning import as_warning, warn 27from .._internal.io import ( 28 BioimageioYamlContent, 29 FileDescr, 30 V_suffix, 31 YamlValue, 32 include_in_package_serializer, 33 validate_suffix, 34) 35from .._internal.io_basics import AbsoluteFilePath, Sha256 36from .._internal.license_id import DeprecatedLicenseId, LicenseId 37from .._internal.node_converter import Converter 38from .._internal.types import ImportantFileSource, NotEmpty, RelativeFilePath 39from .._internal.url import HttpUrl 40from .._internal.validated_string import ValidatedString 41from .._internal.validator_annotations import ( 42 AfterValidator, 43 Predicate, 44 RestrictCharacters, 45) 46from .._internal.version_type import Version 47from .._internal.warning_levels import ALERT, INFO 48from ._v0_3_converter import convert_from_older_format 49from .v0_2 import Author as _Author_v0_2 50from .v0_2 import BadgeDescr, CoverImageSource, Doi, OrcidId, Uploader 51from .v0_2 import Maintainer as _Maintainer_v0_2 52 53__all__ = [ 54 "Author", 55 "BadgeDescr", 56 "CiteEntry", 57 "DeprecatedLicenseId", 58 "Doi", 59 "FileDescr", 60 "GenericDescr", 61 "HttpUrl", 62 "KNOWN_SPECIFIC_RESOURCE_TYPES", 63 "LicenseId", 64 "LinkedResource", 65 "Maintainer", 66 "OrcidId", 67 "RelativeFilePath", 68 "ResourceId", 69 "Sha256", 70 "Uploader", 71 "VALID_COVER_IMAGE_EXTENSIONS", 72 "Version", 73] 74 75KNOWN_SPECIFIC_RESOURCE_TYPES = ( 76 "application", 77 "collection", 78 "dataset", 79 "model", 80 "notebook", 81) 82VALID_COVER_IMAGE_EXTENSIONS = ( 83 ".gif", 84 ".jpeg", 85 ".jpg", 86 ".png", 87 ".svg", 88) 89 90 91class ResourceId(ValidatedString): 92 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 93 Annotated[ 94 NotEmpty[str], 95 RestrictCharacters(string.ascii_lowercase + string.digits + "_-/."), 96 annotated_types.Predicate( 97 lambda s: not (s.startswith("/") or s.endswith("/")) 98 ), 99 ] 100 ] 101 102 103def _validate_md_suffix(value: V_suffix) -> V_suffix: 104 return validate_suffix(value, suffix=".md", case_sensitive=True) 105 106 107DocumentationSource = Annotated[ 108 Union[AbsoluteFilePath, RelativeFilePath, HttpUrl], 109 Field(union_mode="left_to_right"), 110 AfterValidator(_validate_md_suffix), 111 include_in_package_serializer, 112] 113 114 115def _has_no_slash(s: str) -> bool: 116 return "/" not in s and "\\" not in s 117 118 119class Author(_Author_v0_2): 120 name: Annotated[str, Predicate(_has_no_slash)] 121 github_user: Optional[str] = None 122 123 @field_validator("github_user", mode="after") 124 def _validate_gh_user(cls, value: Optional[str]): 125 if value is None: 126 return None 127 else: 128 return validate_gh_user(value) 129 130 131class _AuthorConv(Converter[_Author_v0_2, Author]): 132 def _convert( 133 self, src: _Author_v0_2, tgt: "type[Author] | type[dict[str, Any]]" 134 ) -> "Author | dict[str, Any]": 135 return tgt( 136 name=src.name, 137 github_user=src.github_user, 138 affiliation=src.affiliation, 139 email=src.email, 140 orcid=src.orcid, 141 ) 142 143 144_author_conv = _AuthorConv(_Author_v0_2, Author) 145 146 147class Maintainer(_Maintainer_v0_2): 148 name: Optional[Annotated[str, Predicate(_has_no_slash)]] = None 149 github_user: str 150 151 @field_validator("github_user", mode="after") 152 def validate_gh_user(cls, value: str): 153 return validate_gh_user(value) 154 155 156class _MaintainerConv(Converter[_Maintainer_v0_2, Maintainer]): 157 def _convert( 158 self, src: _Maintainer_v0_2, tgt: "type[Maintainer | dict[str, Any]]" 159 ) -> "Maintainer | dict[str, Any]": 160 return tgt( 161 name=src.name, 162 github_user=src.github_user, 163 affiliation=src.affiliation, 164 email=src.email, 165 orcid=src.orcid, 166 ) 167 168 169_maintainer_conv = _MaintainerConv(_Maintainer_v0_2, Maintainer) 170 171 172class CiteEntry(Node): 173 text: str 174 """free text description""" 175 176 doi: Optional[Doi] = None 177 """A digital object identifier (DOI) is the prefered citation reference. 178 See https://www.doi.org/ for details. (alternatively specify `url`)""" 179 180 url: Optional[HttpUrl] = None 181 """URL to cite (preferably specify a `doi` instead)""" 182 183 @model_validator(mode="after") 184 def _check_doi_or_url(self): 185 if not self.doi and not self.url: 186 raise ValueError("Either 'doi' or 'url' is required") 187 188 return self 189 190 191class LinkedResourceBase(Node): 192 193 @model_validator(mode="before") 194 def _remove_version_number( # pyright: ignore[reportUnknownParameterType] 195 cls, value: Union[Any, Dict[Any, Any]] 196 ): 197 if isinstance(value, dict): 198 vn: Any = value.pop("version_number", None) 199 if vn is not None and value.get("version") is None: 200 value["version"] = vn 201 202 return value # pyright: ignore[reportUnknownVariableType] 203 204 version: Optional[Version] = None 205 """The version of the linked resource following SemVer 2.0.""" 206 207 208class LinkedResource(LinkedResourceBase): 209 """Reference to a bioimage.io resource""" 210 211 id: ResourceId 212 """A valid resource `id` from the official bioimage.io collection.""" 213 214 215class GenericModelDescrBase(ResourceDescrBase): 216 """Base for all resource descriptions including of model descriptions""" 217 218 name: Annotated[ 219 Annotated[ 220 str, RestrictCharacters(string.ascii_letters + string.digits + "_- ()") 221 ], 222 MinLen(5), 223 MaxLen(128), 224 warn(MaxLen(64), "Name longer than 64 characters.", INFO), 225 ] 226 name: Annotated[NotEmpty[str], MaxLen(128)] 227 """A human-friendly name of the resource description. 228 May only contains letters, digits, underscore, minus, parentheses and spaces.""" 229 230 description: Annotated[ 231 str, MaxLen(1024), warn(MaxLen(512), "Description longer than 512 characters.") 232 ] 233 """A string containing a brief description.""" 234 235 covers: Annotated[ 236 List[CoverImageSource], 237 Field( 238 examples=[], 239 description=( 240 "Cover images. Please use an image smaller than 500KB and an aspect" 241 " ratio width to height of 2:1 or 1:1.\nThe supported image formats" 242 f" are: {VALID_COVER_IMAGE_EXTENSIONS}" 243 ), 244 ), 245 ] = Field(default_factory=list) 246 """∈📦 Cover images.""" 247 248 id_emoji: Optional[ 249 Annotated[str, Len(min_length=1, max_length=2), Field(examples=["🦈", "🦥"])] 250 ] = None 251 """UTF-8 emoji for display alongside the `id`.""" 252 253 authors: NotEmpty[List[Author]] 254 """The authors are the creators of this resource description and the primary points of contact.""" 255 256 attachments: List[FileDescr] = Field(default_factory=list) 257 """file attachments""" 258 259 cite: NotEmpty[List[CiteEntry]] 260 """citations""" 261 262 license: Annotated[ 263 Annotated[ 264 Union[LicenseId, DeprecatedLicenseId], Field(union_mode="left_to_right") 265 ], 266 warn( 267 LicenseId, 268 "{value} is deprecated, see https://spdx.org/licenses/{value}.html", 269 ), 270 Field(examples=["CC0-1.0", "MIT", "BSD-2-Clause"]), 271 ] 272 """A [SPDX license identifier](https://spdx.org/licenses/). 273 We do not support custom license beyond the SPDX license list, if you need that please 274 [open a GitHub issue](https://github.com/bioimage-io/spec-bioimage-io/issues/new/choose) 275 to discuss your intentions with the community.""" 276 277 config: Annotated[ 278 Dict[str, YamlValue], 279 Field( 280 examples=[ 281 dict( 282 bioimageio={ 283 "my_custom_key": 3837283, 284 "another_key": {"nested": "value"}, 285 }, 286 imagej={"macro_dir": "path/to/macro/file"}, 287 ) 288 ], 289 ), 290 ] = Field(default_factory=dict) 291 """A field for custom configuration that can contain any keys not present in the RDF spec. 292 This means you should not store, for example, a GitHub repo URL in `config` since there is a `git_repo` field. 293 Keys in `config` may be very specific to a tool or consumer software. To avoid conflicting definitions, 294 it is recommended to wrap added configuration into a sub-field named with the specific domain or tool name, 295 for example: 296 ```yaml 297 config: 298 bioimageio: # here is the domain name 299 my_custom_key: 3837283 300 another_key: 301 nested: value 302 imagej: # config specific to ImageJ 303 macro_dir: path/to/macro/file 304 ``` 305 If possible, please use [`snake_case`](https://en.wikipedia.org/wiki/Snake_case) for keys in `config`. 306 You may want to list linked files additionally under `attachments` to include them when packaging a resource. 307 (Packaging a resource means downloading/copying important linked files and creating a ZIP archive that contains 308 an altered rdf.yaml file with local references to the downloaded files.)""" 309 310 git_repo: Annotated[ 311 Optional[HttpUrl], 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[ 321 Annotated[str, Len(min_length=1, max_length=2)], ImportantFileSource, None 322 ] = None 323 """An icon for illustration, e.g. on bioimage.io""" 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 maintainers: List[Maintainer] = Field(default_factory=list) 343 """Maintainers of this resource. 344 If not specified, `authors` are maintainers and at least some of them has to specify their `github_user` name""" 345 346 @partial(as_warning, severity=ALERT) 347 @field_validator("maintainers", mode="after") 348 @classmethod 349 def check_maintainers_exist( 350 cls, maintainers: List[Maintainer], info: ValidationInfo 351 ) -> List[Maintainer]: 352 if not maintainers and "authors" in info.data: 353 authors: List[Author] = info.data["authors"] 354 if all(a.github_user is None for a in authors): 355 raise ValueError( 356 "Missing `maintainers` or any author in `authors` with a specified" 357 + " `github_user` name." 358 ) 359 360 return maintainers 361 362 tags: Annotated[ 363 List[str], 364 Field(examples=[("unet2d", "pytorch", "nucleus", "segmentation", "dsb2018")]), 365 ] = Field(default_factory=list) 366 """Associated tags""" 367 368 @as_warning 369 @field_validator("tags") 370 @classmethod 371 def warn_about_tag_categories( 372 cls, value: List[str], info: ValidationInfo 373 ) -> List[str]: 374 categories = TAG_CATEGORIES.get(info.data["type"], {}) 375 missing_categories: List[Dict[str, Sequence[str]]] = [] 376 for cat, entries in categories.items(): 377 if not any(e in value for e in entries): 378 missing_categories.append({cat: entries}) 379 380 if missing_categories: 381 raise ValueError( 382 f"Missing tags from bioimage.io categories: {missing_categories}" 383 ) 384 385 return value 386 387 version: Optional[Version] = None 388 """The version of the resource following SemVer 2.0.""" 389 390 @model_validator(mode="before") 391 def _remove_version_number( # pyright: ignore[reportUnknownParameterType] 392 cls, value: Union[Any, Dict[Any, Any]] 393 ): 394 if isinstance(value, dict): 395 vn: Any = value.pop("version_number", None) 396 if vn is not None and value.get("version") is None: 397 value["version"] = vn 398 399 return value # pyright: ignore[reportUnknownVariableType] 400 401 402class GenericDescrBase(GenericModelDescrBase): 403 """Base for all resource descriptions except for the model descriptions""" 404 405 format_version: Literal["0.3.0"] = "0.3.0" 406 """The **format** version of this resource specification""" 407 408 @model_validator(mode="before") 409 @classmethod 410 def _convert_from_older_format( 411 cls, data: BioimageioYamlContent, / 412 ) -> BioimageioYamlContent: 413 convert_from_older_format(data) 414 return data 415 416 documentation: Annotated[ 417 Optional[DocumentationSource], 418 Field( 419 examples=[ 420 "https://raw.githubusercontent.com/bioimage-io/spec-bioimage-io/main/example_descriptions/models/unet2d_nuclei_broad/README.md", 421 "README.md", 422 ], 423 ), 424 ] = None 425 """∈📦 URL or relative path to a markdown file encoded in UTF-8 with additional documentation. 426 The recommended documentation file name is `README.md`. An `.md` suffix is mandatory.""" 427 428 badges: List[BadgeDescr] = Field(default_factory=list) 429 """badges associated with this resource""" 430 431 432ResourceDescrType = TypeVar("ResourceDescrType", bound=GenericDescrBase) 433 434 435class GenericDescr(GenericDescrBase, extra="ignore"): 436 """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF). 437 438 An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook. 439 Note that those resources are described with a type-specific RDF. 440 Use this generic resource description, if none of the known specific types matches your resource. 441 """ 442 443 type: Annotated[str, LowerCase] = Field("generic", frozen=True) 444 """The resource type assigns a broad category to the resource.""" 445 446 id: Optional[ 447 Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])] 448 ] = None 449 """bioimage.io-wide unique resource identifier 450 assigned by bioimage.io; version **un**specific.""" 451 452 parent: Optional[ResourceId] = None 453 """The description from which this one is derived""" 454 455 source: Optional[HttpUrl] = None 456 """The primary source of the resource""" 457 458 @field_validator("type", mode="after") 459 @classmethod 460 def check_specific_types(cls, value: str) -> str: 461 if value in KNOWN_SPECIFIC_RESOURCE_TYPES: 462 raise ValueError( 463 f"Use the {value} description instead of this generic description for" 464 + f" your '{value}' resource." 465 ) 466 467 return value
120class Author(_Author_v0_2): 121 name: Annotated[str, Predicate(_has_no_slash)] 122 github_user: Optional[str] = None 123 124 @field_validator("github_user", mode="after") 125 def _validate_gh_user(cls, value: Optional[str]): 126 if value is None: 127 return None 128 else: 129 return validate_gh_user(value)
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
173class CiteEntry(Node): 174 text: str 175 """free text description""" 176 177 doi: Optional[Doi] = None 178 """A digital object identifier (DOI) is the prefered citation reference. 179 See https://www.doi.org/ for details. (alternatively specify `url`)""" 180 181 url: Optional[HttpUrl] = None 182 """URL to cite (preferably specify a `doi` instead)""" 183 184 @model_validator(mode="after") 185 def _check_doi_or_url(self): 186 if not self.doi and not self.url: 187 raise ValueError("Either 'doi' or 'url' is required") 188 189 return self
A digital object identifier (DOI) is the prefered citation reference.
See https://www.doi.org/ for details. (alternatively specify url
)
Inherited Members
24class DeprecatedLicenseId(ValidatedString): 25 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[DeprecatedLicenseIdLiteral]
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'.
the pydantic root model to validate the string
109class Doi(ValidatedString): 110 """A digital object identifier, see https://www.doi.org/""" 111 112 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 113 Annotated[str, StringConstraints(pattern=DOI_REGEX)] 114 ]
A digital object identifier, see https://www.doi.org/
768class FileDescr(Node): 769 source: ImportantFileSource 770 """∈📦 file source""" 771 772 sha256: Optional[Sha256] = None 773 """SHA256 checksum of the source file""" 774 775 @model_validator(mode="after") 776 def validate_sha256(self) -> Self: 777 context = validation_context_var.get() 778 if not context.perform_io_checks: 779 return self 780 elif (src_str := str(self.source)) in context.known_files: 781 actual_sha = context.known_files[src_str] 782 else: 783 local_source = download(self.source, sha256=self.sha256).path 784 actual_sha = get_sha256(local_source) 785 context.known_files[str(self.source)] = actual_sha 786 787 if self.sha256 is None: 788 self.sha256 = actual_sha 789 elif self.sha256 != actual_sha: 790 raise ValueError( 791 f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got " 792 + f"{actual_sha}. Update expected `sha256` or point to the matching " 793 + "file." 794 ) 795 796 return self 797 798 def download(self): 799 800 return download(self.source, sha256=self.sha256)
∈📦 file source
775 @model_validator(mode="after") 776 def validate_sha256(self) -> Self: 777 context = validation_context_var.get() 778 if not context.perform_io_checks: 779 return self 780 elif (src_str := str(self.source)) in context.known_files: 781 actual_sha = context.known_files[src_str] 782 else: 783 local_source = download(self.source, sha256=self.sha256).path 784 actual_sha = get_sha256(local_source) 785 context.known_files[str(self.source)] = actual_sha 786 787 if self.sha256 is None: 788 self.sha256 = actual_sha 789 elif self.sha256 != actual_sha: 790 raise ValueError( 791 f"Sha256 mismatch for {self.source}. Expected {self.sha256}, got " 792 + f"{actual_sha}. Update expected `sha256` or point to the matching " 793 + "file." 794 ) 795 796 return self
Inherited Members
436class GenericDescr(GenericDescrBase, extra="ignore"): 437 """Specification of the fields used in a generic bioimage.io-compliant resource description file (RDF). 438 439 An RDF is a YAML file that describes a resource such as a model, a dataset, or a notebook. 440 Note that those resources are described with a type-specific RDF. 441 Use this generic resource description, if none of the known specific types matches your resource. 442 """ 443 444 type: Annotated[str, LowerCase] = Field("generic", frozen=True) 445 """The resource type assigns a broad category to the resource.""" 446 447 id: Optional[ 448 Annotated[ResourceId, Field(examples=["affable-shark", "ambitious-sloth"])] 449 ] = None 450 """bioimage.io-wide unique resource identifier 451 assigned by bioimage.io; version **un**specific.""" 452 453 parent: Optional[ResourceId] = None 454 """The description from which this one is derived""" 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
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.
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
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
118class HttpUrl(RootHttpUrl): 119 """A URL with the HTTP or HTTPS scheme.""" 120 121 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[pydantic.HttpUrl] 122 _exists: Optional[bool] = None 123 124 def _after_validator(self): 125 self = super()._after_validator() 126 context = validation_context_var.get() 127 if ( 128 context.perform_io_checks 129 and str(self._validated) not in context.known_files 130 ): 131 self._validated = _validate_url(self._validated) 132 self._exists = True 133 134 return self 135 136 def exists(self): 137 """True if URL is available""" 138 if self._exists is None: 139 try: 140 self._validated = _validate_url(self._validated) 141 except Exception as e: 142 logger.info(e) 143 self._exists = False 144 else: 145 self._exists = True 146 147 return self._exists
A URL with the HTTP or HTTPS scheme.
the pydantic root model to validate the string
136 def exists(self): 137 """True if URL is available""" 138 if self._exists is None: 139 try: 140 self._validated = _validate_url(self._validated) 141 except Exception as e: 142 logger.info(e) 143 self._exists = False 144 else: 145 self._exists = True 146 147 return self._exists
True if URL is available
20class LicenseId(ValidatedString): 21 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[LicenseIdLiteral]
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'.
the pydantic root model to validate the string
209class LinkedResource(LinkedResourceBase): 210 """Reference to a bioimage.io resource""" 211 212 id: ResourceId 213 """A valid resource `id` from the official bioimage.io collection."""
Reference to a bioimage.io resource
Inherited Members
148class Maintainer(_Maintainer_v0_2): 149 name: Optional[Annotated[str, Predicate(_has_no_slash)]] = None 150 github_user: str 151 152 @field_validator("github_user", mode="after") 153 def validate_gh_user(cls, value: str): 154 return validate_gh_user(value)
136class OrcidId(ValidatedString): 137 """An ORCID identifier, see https://orcid.org/""" 138 139 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 140 Annotated[str, AfterValidator(_validate_orcid_id)] 141 ]
An ORCID identifier, see https://orcid.org/
186class RelativeFilePath( 187 RelativePathBase[Union[AbsoluteFilePath, HttpUrl, ZipPath]], frozen=True 188): 189 """A path relative to the `rdf.yaml` file (also if the RDF source is a URL).""" 190 191 def model_post_init(self, __context: Any) -> None: 192 """add validation @private""" 193 if not self.root.parts: # an empty path can only be a directory 194 raise ValueError(f"{self.root} is not a valid file path.") 195 196 super().model_post_init(__context) 197 198 def get_absolute( 199 self, root: "RootHttpUrl | Path | AnyUrl | ZipFile" 200 ) -> "AbsoluteFilePath | HttpUrl | ZipPath": 201 absolute = self._get_absolute_impl(root) 202 if ( 203 isinstance(absolute, Path) 204 and (context := validation_context_var.get()).perform_io_checks 205 and str(self.root) not in context.known_files 206 and not absolute.is_file() 207 ): 208 raise ValueError(f"{absolute} does not point to an existing file") 209 210 return absolute
A path relative to the rdf.yaml
file (also if the RDF source is a URL).
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.
198 def get_absolute( 199 self, root: "RootHttpUrl | Path | AnyUrl | ZipFile" 200 ) -> "AbsoluteFilePath | HttpUrl | ZipPath": 201 absolute = self._get_absolute_impl(root) 202 if ( 203 isinstance(absolute, Path) 204 and (context := validation_context_var.get()).perform_io_checks 205 and str(self.root) not in context.known_files 206 and not absolute.is_file() 207 ): 208 raise ValueError(f"{absolute} does not point to an existing file") 209 210 return absolute
Inherited Members
92class ResourceId(ValidatedString): 93 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 94 Annotated[ 95 NotEmpty[str], 96 RestrictCharacters(string.ascii_lowercase + string.digits + "_-/."), 97 annotated_types.Predicate( 98 lambda s: not (s.startswith("/") or s.endswith("/")) 99 ), 100 ] 101 ]
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'.
33class Sha256(ValidatedString): 34 """A SHA-256 hash value""" 35 36 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 37 Annotated[ 38 str, 39 StringConstraints( 40 strip_whitespace=True, to_lower=True, min_length=64, max_length=64 41 ), 42 ] 43 ]
A SHA-256 hash value
109class Uploader(Node): 110 email: EmailStr 111 """Email""" 112 name: Optional[Annotated[str, AfterValidator(_remove_slashes)]] = None 113 """name"""
name
Inherited Members
10class Version(RootModel[Union[str, int, float]]): 11 """wraps a packaging.version.Version instance for validation in pydantic models""" 12 13 _version: packaging.version.Version = PrivateAttr() 14 15 def __str__(self): 16 return str(self._version) 17 18 def model_post_init(self, __context: Any) -> None: 19 """set `_version` attribute @private""" 20 self._version = packaging.version.Version(str(self.root)) 21 return super().model_post_init(__context) 22 23 def __lt__(self, other: Version): 24 return self._version < other._version 25 26 def __eq__(self, other: Version): 27 return self._version == other._version 28 29 # the properties below are adopted from and mirror properties of packaging.version.Version 30 @property 31 def epoch(self) -> int: 32 """The epoch of the version. 33 34 >>> Version("2.0.0").epoch 35 0 36 >>> Version("1!2.0.0").epoch 37 1 38 """ 39 return self._version.epoch 40 41 @property 42 def release(self) -> Tuple[int, ...]: 43 """The components of the "release" segment of the version. 44 45 >>> Version("1.2.3").release 46 (1, 2, 3) 47 >>> Version("2.0.0").release 48 (2, 0, 0) 49 >>> Version("1!2.0.0.post0").release 50 (2, 0, 0) 51 52 Includes trailing zeroes but not the epoch or any pre-release / development / 53 post-release suffixes. 54 """ 55 return self._version.release 56 57 @property 58 def pre(self) -> Optional[Tuple[str, int]]: 59 """The pre-release segment of the version. 60 61 >>> print(Version("1.2.3").pre) 62 None 63 >>> Version("1.2.3a1").pre 64 ('a', 1) 65 >>> Version("1.2.3b1").pre 66 ('b', 1) 67 >>> Version("1.2.3rc1").pre 68 ('rc', 1) 69 """ 70 return self._version.pre 71 72 @property 73 def post(self) -> Optional[int]: 74 """The post-release number of the version. 75 76 >>> print(Version("1.2.3").post) 77 None 78 >>> Version("1.2.3.post1").post 79 1 80 """ 81 return self._version.post 82 83 @property 84 def dev(self) -> Optional[int]: 85 """The development number of the version. 86 87 >>> print(Version("1.2.3").dev) 88 None 89 >>> Version("1.2.3.dev1").dev 90 1 91 """ 92 return self._version.dev 93 94 @property 95 def local(self) -> Optional[str]: 96 """The local version segment of the version. 97 98 >>> print(Version("1.2.3").local) 99 None 100 >>> Version("1.2.3+abc").local 101 'abc' 102 """ 103 return self._version.local 104 105 @property 106 def public(self) -> str: 107 """The public portion of the version. 108 109 >>> Version("1.2.3").public 110 '1.2.3' 111 >>> Version("1.2.3+abc").public 112 '1.2.3' 113 >>> Version("1.2.3+abc.dev1").public 114 '1.2.3' 115 """ 116 return self._version.public 117 118 @property 119 def base_version(self) -> str: 120 """The "base version" of the version. 121 122 >>> Version("1.2.3").base_version 123 '1.2.3' 124 >>> Version("1.2.3+abc").base_version 125 '1.2.3' 126 >>> Version("1!1.2.3+abc.dev1").base_version 127 '1!1.2.3' 128 129 The "base version" is the public version of the project without any pre or post 130 release markers. 131 """ 132 return self._version.base_version 133 134 @property 135 def is_prerelease(self) -> bool: 136 """Whether this version is a pre-release. 137 138 >>> Version("1.2.3").is_prerelease 139 False 140 >>> Version("1.2.3a1").is_prerelease 141 True 142 >>> Version("1.2.3b1").is_prerelease 143 True 144 >>> Version("1.2.3rc1").is_prerelease 145 True 146 >>> Version("1.2.3dev1").is_prerelease 147 True 148 """ 149 return self._version.is_prerelease 150 151 @property 152 def is_postrelease(self) -> bool: 153 """Whether this version is a post-release. 154 155 >>> Version("1.2.3").is_postrelease 156 False 157 >>> Version("1.2.3.post1").is_postrelease 158 True 159 """ 160 return self._version.is_postrelease 161 162 @property 163 def is_devrelease(self) -> bool: 164 """Whether this version is a development release. 165 166 >>> Version("1.2.3").is_devrelease 167 False 168 >>> Version("1.2.3.dev1").is_devrelease 169 True 170 """ 171 return self._version.is_devrelease 172 173 @property 174 def major(self) -> int: 175 """The first item of :attr:`release` or ``0`` if unavailable. 176 177 >>> Version("1.2.3").major 178 1 179 """ 180 return self._version.major 181 182 @property 183 def minor(self) -> int: 184 """The second item of :attr:`release` or ``0`` if unavailable. 185 186 >>> Version("1.2.3").minor 187 2 188 >>> Version("1").minor 189 0 190 """ 191 return self._version.minor 192 193 @property 194 def micro(self) -> int: 195 """The third item of :attr:`release` or ``0`` if unavailable. 196 197 >>> Version("1.2.3").micro 198 3 199 >>> Version("1").micro 200 0 201 """ 202 return self._version.micro
wraps a packaging.version.Version instance for validation in pydantic models
30 @property 31 def epoch(self) -> int: 32 """The epoch of the version. 33 34 >>> Version("2.0.0").epoch 35 0 36 >>> Version("1!2.0.0").epoch 37 1 38 """ 39 return self._version.epoch
The epoch of the version.
>>> Version("2.0.0").epoch
0
>>> Version("1!2.0.0").epoch
1
41 @property 42 def release(self) -> Tuple[int, ...]: 43 """The components of the "release" segment of the version. 44 45 >>> Version("1.2.3").release 46 (1, 2, 3) 47 >>> Version("2.0.0").release 48 (2, 0, 0) 49 >>> Version("1!2.0.0.post0").release 50 (2, 0, 0) 51 52 Includes trailing zeroes but not the epoch or any pre-release / development / 53 post-release suffixes. 54 """ 55 return self._version.release
The components of the "release" segment of the version.
>>> Version("1.2.3").release
(1, 2, 3)
>>> Version("2.0.0").release
(2, 0, 0)
>>> Version("1!2.0.0.post0").release
(2, 0, 0)
Includes trailing zeroes but not the epoch or any pre-release / development / post-release suffixes.
57 @property 58 def pre(self) -> Optional[Tuple[str, int]]: 59 """The pre-release segment of the version. 60 61 >>> print(Version("1.2.3").pre) 62 None 63 >>> Version("1.2.3a1").pre 64 ('a', 1) 65 >>> Version("1.2.3b1").pre 66 ('b', 1) 67 >>> Version("1.2.3rc1").pre 68 ('rc', 1) 69 """ 70 return self._version.pre
The pre-release segment of the version.
>>> print(Version("1.2.3").pre)
None
>>> Version("1.2.3a1").pre
('a', 1)
>>> Version("1.2.3b1").pre
('b', 1)
>>> Version("1.2.3rc1").pre
('rc', 1)
72 @property 73 def post(self) -> Optional[int]: 74 """The post-release number of the version. 75 76 >>> print(Version("1.2.3").post) 77 None 78 >>> Version("1.2.3.post1").post 79 1 80 """ 81 return self._version.post
The post-release number of the version.
>>> print(Version("1.2.3").post)
None
>>> Version("1.2.3.post1").post
1
83 @property 84 def dev(self) -> Optional[int]: 85 """The development number of the version. 86 87 >>> print(Version("1.2.3").dev) 88 None 89 >>> Version("1.2.3.dev1").dev 90 1 91 """ 92 return self._version.dev
The development number of the version.
>>> print(Version("1.2.3").dev)
None
>>> Version("1.2.3.dev1").dev
1
94 @property 95 def local(self) -> Optional[str]: 96 """The local version segment of the version. 97 98 >>> print(Version("1.2.3").local) 99 None 100 >>> Version("1.2.3+abc").local 101 'abc' 102 """ 103 return self._version.local
The local version segment of the version.
>>> print(Version("1.2.3").local)
None
>>> Version("1.2.3+abc").local
'abc'
105 @property 106 def public(self) -> str: 107 """The public portion of the version. 108 109 >>> Version("1.2.3").public 110 '1.2.3' 111 >>> Version("1.2.3+abc").public 112 '1.2.3' 113 >>> Version("1.2.3+abc.dev1").public 114 '1.2.3' 115 """ 116 return self._version.public
The public portion of the version.
>>> Version("1.2.3").public
'1.2.3'
>>> Version("1.2.3+abc").public
'1.2.3'
>>> Version("1.2.3+abc.dev1").public
'1.2.3'
118 @property 119 def base_version(self) -> str: 120 """The "base version" of the version. 121 122 >>> Version("1.2.3").base_version 123 '1.2.3' 124 >>> Version("1.2.3+abc").base_version 125 '1.2.3' 126 >>> Version("1!1.2.3+abc.dev1").base_version 127 '1!1.2.3' 128 129 The "base version" is the public version of the project without any pre or post 130 release markers. 131 """ 132 return self._version.base_version
The "base version" of the version.
>>> Version("1.2.3").base_version
'1.2.3'
>>> Version("1.2.3+abc").base_version
'1.2.3'
>>> Version("1!1.2.3+abc.dev1").base_version
'1!1.2.3'
The "base version" is the public version of the project without any pre or post release markers.
134 @property 135 def is_prerelease(self) -> bool: 136 """Whether this version is a pre-release. 137 138 >>> Version("1.2.3").is_prerelease 139 False 140 >>> Version("1.2.3a1").is_prerelease 141 True 142 >>> Version("1.2.3b1").is_prerelease 143 True 144 >>> Version("1.2.3rc1").is_prerelease 145 True 146 >>> Version("1.2.3dev1").is_prerelease 147 True 148 """ 149 return self._version.is_prerelease
Whether this version is a pre-release.
>>> Version("1.2.3").is_prerelease
False
>>> Version("1.2.3a1").is_prerelease
True
>>> Version("1.2.3b1").is_prerelease
True
>>> Version("1.2.3rc1").is_prerelease
True
>>> Version("1.2.3dev1").is_prerelease
True
151 @property 152 def is_postrelease(self) -> bool: 153 """Whether this version is a post-release. 154 155 >>> Version("1.2.3").is_postrelease 156 False 157 >>> Version("1.2.3.post1").is_postrelease 158 True 159 """ 160 return self._version.is_postrelease
Whether this version is a post-release.
>>> Version("1.2.3").is_postrelease
False
>>> Version("1.2.3.post1").is_postrelease
True
162 @property 163 def is_devrelease(self) -> bool: 164 """Whether this version is a development release. 165 166 >>> Version("1.2.3").is_devrelease 167 False 168 >>> Version("1.2.3.dev1").is_devrelease 169 True 170 """ 171 return self._version.is_devrelease
Whether this version is a development release.
>>> Version("1.2.3").is_devrelease
False
>>> Version("1.2.3.dev1").is_devrelease
True
173 @property 174 def major(self) -> int: 175 """The first item of :attr:`release` or ``0`` if unavailable. 176 177 >>> Version("1.2.3").major 178 1 179 """ 180 return self._version.major
The first item of release
or 0
if unavailable.
>>> Version("1.2.3").major
1
182 @property 183 def minor(self) -> int: 184 """The second item of :attr:`release` or ``0`` if unavailable. 185 186 >>> Version("1.2.3").minor 187 2 188 >>> Version("1").minor 189 0 190 """ 191 return self._version.minor
The second item of release
or 0
if unavailable.
>>> Version("1.2.3").minor
2
>>> Version("1").minor
0
193 @property 194 def micro(self) -> int: 195 """The third item of :attr:`release` or ``0`` if unavailable. 196 197 >>> Version("1.2.3").micro 198 3 199 >>> Version("1").micro 200 0 201 """ 202 return self._version.micro
The third item of release
or 0
if unavailable.
>>> Version("1.2.3").micro
3
>>> Version("1").micro
0