Skip to content

Commit

Permalink
WIP update format updating
Browse files Browse the repository at this point in the history
  • Loading branch information
FynnBe committed Sep 26, 2023
1 parent 3186b03 commit f731c1b
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 9 deletions.
6 changes: 5 additions & 1 deletion bioimageio/spec/_internal/base_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ def __pydantic_init_subclass__(cls, **kwargs: Any):

@classmethod
def _update_context(cls, context: InternalValidationContext, data: RdfContent) -> None:
pass
# set original format if possible
original_format = data.get("format_version")
if "original_format" not in context and isinstance(original_format, str) and original_format.count(".") == 2:
context["original_format"] = cast(Tuple[int, int, int], tuple(map(int, original_format.split("."))))
assert len(context["original_format"]) == 3

@classmethod
def model_validate(
Expand Down
8 changes: 6 additions & 2 deletions bioimageio/spec/_internal/validation_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class InternalValidationContext(TypedDict):
warning_level: WarningLevel
"""raise warnings of severity s as validation errors if s >= `warning_level`"""

original_format: NotRequired[Tuple[int, int, int]]
"""original format version of the validation data (set dynamically during validation of resource descriptions)."""

collection_base_content: NotRequired[Dict[str, Any]]
"""Collection base content (set dynamically during validation of collection resource descriptions)."""

Expand All @@ -52,7 +55,8 @@ def get_internal_validation_context(
file_name=file_name or given_context.get("file_name", "rdf.bioimageio.yaml"),
warning_level=warning_level or given_context.get(WARNING_LEVEL_CONTEXT_KEY, ERROR),
)
if "collection_base_content" in given_context:
ret["collection_base_content"] = given_context["collection_base_content"]
for k in {"original_format", "collection_base_content"}: # TypedDict.__optional_keys__ requires py>=3.9
if k in given_context:
ret[k] = given_context[k]

return ret
42 changes: 36 additions & 6 deletions bioimageio/spec/generic/v0_2.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections.abc import Mapping, Sequence
from typing import TYPE_CHECKING, List, Literal, Optional, Tuple, TypeVar, Union
from typing import Any, List, Literal, Optional, Tuple, TypeVar, Union

from annotated_types import Len, LowerCase, MaxLen, MinLen
from annotated_types import Len, LowerCase, MaxLen, MinLen, Predicate
from pydantic import EmailStr, Field, FieldValidationInfo, HttpUrl, field_validator
from typing_extensions import Annotated

Expand All @@ -19,7 +19,7 @@
RdfContent,
Version,
)
from bioimageio.spec._internal.validation_context import InternalValidationContext
from bioimageio.spec._internal.validation_context import InternalValidationContext, get_internal_validation_context
from bioimageio.spec.generic.v0_2_converter import convert_from_older_format

KNOWN_SPECIFIC_RESOURCE_TYPES = ("application", "collection", "dataset", "model", "notebook")
Expand All @@ -41,8 +41,18 @@ class Attachments(Node, frozen=True):


class _Person(Node, frozen=True):
name: Optional[str]
name: Optional[Annotated[str, Predicate(lambda s: "/" not in s and "\\" not in s)]]
"""Full name"""

@field_validator("name", mode="before")
@classmethod
def convert_name(cls, name: Any, info: FieldValidationInfo):
ctxt = get_internal_validation_context(info.context)
if "original_format" in ctxt and ctxt["original_format"] < (0, 2, 3) and isinstance(name, str):
name = name.replace("/", "").replace("\\", "")

return name

affiliation: Optional[str] = None
"""Affiliation"""
email: Optional[EmailStr] = None
Expand All @@ -58,12 +68,12 @@ class _Person(Node, frozen=True):


class Author(_Person, frozen=True):
name: str
name: Annotated[str, Predicate(lambda s: "/" not in s and "\\" not in s)]
github_user: Optional[str] = None


class Maintainer(_Person, frozen=True):
name: Optional[str] = None
name: Optional[Annotated[str, Predicate(lambda s: "/" not in s and "\\" not in s)]] = None
github_user: str


Expand Down Expand Up @@ -97,6 +107,17 @@ class CiteEntry(Node, frozen=True):
"""A digital object identifier (DOI) is the prefered citation reference.
See https://www.doi.org/ for details. (alternatively specify `url`)"""

@field_validator("doi", mode="before")
@classmethod
def accept_prefixed_doi(cls, doi: Any) -> Any:
if isinstance(doi, str):
for doi_prefix in ("https://doi.org/", "http://dx.doi.org/"):
if doi.startswith(doi_prefix):
doi = doi[len(doi_prefix) :]
break

return doi

url: Optional[str] = None
"""URL to cite (preferably specify a `doi` instead)"""

Expand Down Expand Up @@ -165,6 +186,15 @@ class GenericBaseNoSource(ResourceDescriptionBase, frozen=True):
authors: Annotated[Tuple[Author, ...], warn(MinLen(1), "No author specified.")] = ()
"""The authors are the creators of the RDF and the primary points of contact."""

@field_validator("authors", mode="before")
@classmethod
def accept_author_strings(cls, authors: Union[Any, Sequence[Any]]) -> Any:
"""we unofficially accept strings as author entries"""
if isinstance(authors, Sequence):
authors = [{"name": a} if isinstance(a, str) else a for a in authors]

return authors

attachments: Optional[Attachments] = None
"""file and other attachments"""

Expand Down

0 comments on commit f731c1b

Please sign in to comment.