|
| 1 | +"""nodes for the general RDF spec |
| 2 | +
|
| 3 | +nodes represent the content of any RDF. |
| 4 | +""" |
| 5 | +import dataclasses |
| 6 | +import pathlib |
| 7 | + |
| 8 | +import packaging.version |
| 9 | +import warnings |
| 10 | +from dataclasses import dataclass |
| 11 | +from pathlib import Path, PurePosixPath |
| 12 | +from typing import Any, Dict, List, Optional, Sequence, Tuple, Union, Annotated |
| 13 | + |
| 14 | +from pydantic import EmailStr, Extra, Field, FilePath, HttpUrl, ValidationError, constr, validator |
| 15 | +from bioimageio.spec.shared.nodes import Node |
| 16 | + |
| 17 | +from typing import Literal |
| 18 | + |
| 19 | +from bioimageio.spec.shared.types_ import RawMapping |
| 20 | +from bioimageio.spec.shared.utils import is_valid_orcid_id |
| 21 | + |
| 22 | +FormatVersion = Literal[ |
| 23 | + "0.2.0", "0.2.1", "0.2.2", "0.2.3" |
| 24 | +] # newest format needs to be last (used to determine latest format version) |
| 25 | + |
| 26 | + |
| 27 | +class Attachments(Node, extra=Extra.allow): |
| 28 | + files: Union[Tuple[Union[HttpUrl, PurePosixPath], ...], None] = Field( |
| 29 | + description="File attachments; included when packaging the resource.", in_package=True |
| 30 | + ) |
| 31 | + |
| 32 | + |
| 33 | +class _Person(Node): |
| 34 | + name: Optional[str] = Field(None, description="Full name") |
| 35 | + affiliation: Optional[str] = Field(None, description="Affiliation") |
| 36 | + email: Optional[EmailStr] = Field(None, description="Email") |
| 37 | + github_user: Optional[str] = Field(None, description="GitHub user name") |
| 38 | + orcid: Optional[str] = Field( |
| 39 | + None, |
| 40 | + description=( |
| 41 | + "An [ORCID iD](https://support.orcid.org/hc/en-us/sections/360001495313-What-is-ORCID)" |
| 42 | + "in hyphenated groups of 4 digits, e.g. '0000-0001-2345-6789' (and [valid](" |
| 43 | + "https://support.orcid.org/hc/en-us/articles/360006897674-Structure-of-the-ORCID-Identifier" |
| 44 | + ") as per ISO 7064 11,2.)" |
| 45 | + ), |
| 46 | + ) |
| 47 | + |
| 48 | + @validator("orcid") |
| 49 | + def check_orcid(cls, orcid: str): |
| 50 | + if ( |
| 51 | + len(orcid) != 19 |
| 52 | + or any(orcid[idx] != "-" for idx in [4, 9, 14]) |
| 53 | + or not is_valid_orcid_id(orcid.replace("-", "")) |
| 54 | + ): |
| 55 | + raise ValueError(f"'{orcid} is not a valid ORCID iD in hyphenated groups of 4 digits") |
| 56 | + |
| 57 | + |
| 58 | +class Author(_Person): |
| 59 | + name: str = Field(..., description="Full name") |
| 60 | + |
| 61 | + |
| 62 | +class Maintainer(_Person): |
| 63 | + github_user: str = Field(..., description="GitHub user name") |
| 64 | + |
| 65 | + |
| 66 | +class CiteEntry(Node): |
| 67 | + text: str |
| 68 | + doi: Optional[str] = None |
| 69 | + url: Optional[str] = None |
| 70 | + |
| 71 | + @validator("url", always=True) |
| 72 | + def check_doi_or_url(cls, url: Optional[str], values: RawMapping): |
| 73 | + if not values.get("doi") and not url: |
| 74 | + raise ValueError("Either 'doi' or 'url' is required") |
| 75 | + return url |
| 76 | + |
| 77 | + |
| 78 | +class Badge(Node): |
| 79 | + label: str |
| 80 | + icon: Union[HttpUrl, Annotated[str, constr(min_length=1, max_length=2), PurePosixPath], None] = None |
| 81 | + url: HttpUrl |
| 82 | + |
| 83 | + |
| 84 | +# @dataclass |
| 85 | +# class RDF_Base(ResourceDescription): |
| 86 | +# attachments: Union[_Missing, Attachments] = missing |
| 87 | +# authors: Union[_Missing, List[Author]] = missing |
| 88 | +# badges: Union[_Missing, List[Badge]] = missing |
| 89 | +# cite: Union[_Missing, List[CiteEntry]] = missing |
| 90 | +# config: Union[_Missing, dict] = missing |
| 91 | +# covers: Union[_Missing, List[Union[URI, Path]]] = missing |
| 92 | +# description: str = missing |
| 93 | +# documentation: Union[_Missing, Path, URI] = missing |
| 94 | +# download_url: Union[_Missing, Path, URI] = missing |
| 95 | +# format_version: str = missing |
| 96 | +# git_repo: Union[_Missing, str] = missing |
| 97 | +# id: Union[_Missing, str] = missing |
| 98 | +# icon: Union[_Missing, str] = missing |
| 99 | +# license: Union[_Missing, str] = missing |
| 100 | +# links: Union[_Missing, List[str]] = missing |
| 101 | +# maintainers: Union[_Missing, List[Maintainer]] = missing |
| 102 | +# rdf_source: Union[_Missing, URI] = missing |
| 103 | +# source: Union[_Missing, URI, Path] = missing |
| 104 | +# tags: Union[_Missing, List[str]] = missing |
| 105 | + |
| 106 | +# # manual __init__ to allow for unknown kwargs |
| 107 | +# def __init__( |
| 108 | +# self, |
| 109 | +# *, |
| 110 | +# # ResourceDescription |
| 111 | +# format_version: str, |
| 112 | +# name: str, |
| 113 | +# type: str = missing, |
| 114 | +# version: Union[_Missing, packaging.version.Version] = missing, |
| 115 | +# root_path: pathlib.Path = pathlib.Path(), |
| 116 | +# # RDF |
| 117 | +# attachments: Union[_Missing, Dict[str, Any]] = missing, |
| 118 | +# authors: Union[_Missing, List[Author]] = missing, |
| 119 | +# badges: Union[_Missing, List[Badge]] = missing, |
| 120 | +# cite: Union[_Missing, List[CiteEntry]] = missing, |
| 121 | +# config: Union[_Missing, dict] = missing, |
| 122 | +# covers: Union[_Missing, List[Union[URI, Path]]] = missing, |
| 123 | +# description: str, |
| 124 | +# documentation: Union[_Missing, Path, URI] = missing, |
| 125 | +# download_url: Union[_Missing, Path, URI] = missing, |
| 126 | +# git_repo: Union[_Missing, str] = missing, |
| 127 | +# id: Union[_Missing, str] = missing, |
| 128 | +# icon: Union[_Missing, str] = missing, |
| 129 | +# license: Union[_Missing, str] = missing, |
| 130 | +# links: Union[_Missing, List[str]] = missing, |
| 131 | +# maintainers: Union[_Missing, List[Maintainer]] = missing, |
| 132 | +# rdf_source: Union[_Missing, URI] = missing, |
| 133 | +# source: Union[_Missing, URI, Path] = missing, |
| 134 | +# tags: Union[_Missing, List[str]] = missing, |
| 135 | +# **unknown_kwargs, |
| 136 | +# ): |
| 137 | +# self.attachments = attachments |
| 138 | +# self.authors = authors |
| 139 | +# self.badges = badges |
| 140 | +# self.cite = cite |
| 141 | +# self.config = config |
| 142 | +# self.covers = covers |
| 143 | +# self.description = description |
| 144 | +# self.documentation = documentation |
| 145 | +# self.download_url = download_url |
| 146 | +# self.git_repo = git_repo |
| 147 | +# self.id = id |
| 148 | +# self.icon = icon |
| 149 | +# self.license = license |
| 150 | +# self.links = links |
| 151 | +# self.maintainers = maintainers |
| 152 | +# self.rdf_source = rdf_source |
| 153 | +# self.source = source |
| 154 | +# self.tags = tags |
| 155 | +# super().__init__(format_version=format_version, name=name, type=type, version=version, root_path=root_path) |
| 156 | + |
| 157 | +# if unknown_kwargs: |
| 158 | +# # make sure we didn't forget a defined field |
| 159 | +# field_names = set(f.name for f in dataclasses.fields(self)) |
| 160 | +# for uk in unknown_kwargs: |
| 161 | +# assert uk not in field_names, uk |
| 162 | + |
| 163 | +# warnings.warn(f"discarding unknown RDF fields: {unknown_kwargs}") |
| 164 | + |
| 165 | +# def __post_init__(self): |
| 166 | +# if self.type is missing: |
| 167 | +# self.type = self.__class__.__name__.lower() |
| 168 | + |
| 169 | +# super().__post_init__() |
| 170 | + |
| 171 | + |
| 172 | +# @dataclass(init=False) |
| 173 | +# class RDF(RDF_Base): |
| 174 | +# format_version: FormatVersion = missing |
0 commit comments