Coverage for bioimageio/spec/_description_impl.py: 94%
48 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-02 14:21 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-02 14:21 +0000
1"""implementation details for building a bioimage.io resource description"""
3from typing import Any, Callable, List, Literal, Mapping, Optional, Type, TypeVar, Union
5from ._internal.common_nodes import InvalidDescr, ResourceDescrBase
6from ._internal.io import BioimageioYamlContent
7from ._internal.types import FormatVersionPlaceholder
8from ._internal.validation_context import ValidationContext, get_validation_context
9from .summary import (
10 ErrorEntry,
11 ValidationDetail,
12)
14ResourceDescrT = TypeVar("ResourceDescrT", bound=ResourceDescrBase)
17DISCOVER: Literal["discover"] = "discover"
18"""placeholder for whatever format version an RDF specifies"""
21def get_rd_class_impl(
22 typ: Any,
23 format_version: Any,
24 descriptions_map: Mapping[
25 Optional[str], Mapping[Optional[str], Type[ResourceDescrT]]
26 ],
27) -> Type[ResourceDescrT]:
28 assert None in descriptions_map
29 assert all(None in version_map for version_map in descriptions_map.values())
30 assert all(
31 fv is None or fv.count(".") == 1
32 for version_map in descriptions_map.values()
33 for fv in version_map
34 )
35 if not isinstance(typ, str) or typ not in descriptions_map:
36 typ = None
38 format_version = str(format_version)
39 if (ndots := format_version.count(".")) == 0:
40 use_format_version = format_version + ".0"
41 elif ndots == 2:
42 use_format_version = format_version[: format_version.rfind(".")]
43 else:
44 use_format_version = None
46 descr_versions = descriptions_map[typ]
47 return descr_versions.get(use_format_version, descr_versions[None])
50def build_description_impl(
51 content: BioimageioYamlContent,
52 /,
53 *,
54 context: Optional[ValidationContext] = None,
55 format_version: Union[FormatVersionPlaceholder, str] = DISCOVER,
56 get_rd_class: Callable[[Any, Any], Type[ResourceDescrT]],
57) -> Union[ResourceDescrT, InvalidDescr]:
58 context = context or get_validation_context()
59 errors: List[ErrorEntry] = []
60 if isinstance(content, dict):
61 for minimum in ("type", "format_version"):
62 if minimum not in content:
63 errors.append(
64 ErrorEntry(
65 loc=(minimum,), msg=f"Missing field '{minimum}'", type="error"
66 )
67 )
68 elif not isinstance(content[minimum], str):
69 errors.append(
70 ErrorEntry(
71 loc=(minimum,),
72 msg=f"Invalid type '{type(content[minimum])}'",
73 type="error",
74 )
75 )
76 else:
77 errors.append(
78 ErrorEntry(
79 loc=(), msg=f"Invalid content of type '{type(content)}'", type="error"
80 )
81 )
82 content = {}
84 if errors:
85 ret = InvalidDescr(**content) # pyright: ignore[reportArgumentType]
86 ret.validation_summary.add_detail(
87 ValidationDetail(
88 name="extract fields to chose description class",
89 status="failed",
90 errors=errors,
91 context=context.summary,
92 )
93 )
94 return ret
96 typ = content["type"]
97 rd_class = get_rd_class(typ, content["format_version"])
98 rd = rd_class.load(content, context=context)
100 if str(format_version).lower() not in (
101 DISCOVER,
102 rd_class.implemented_format_version,
103 ".".join(map(str, rd_class.implemented_format_version_tuple[:2])),
104 ):
105 # load with requested format_version
106 discover_details = rd.validation_summary.details
107 as_rd_class = get_rd_class(typ, format_version)
108 rd = as_rd_class.load(content, context=context)
109 assert rd.validation_summary is not None
110 rd.validation_summary.details[:0] = discover_details
112 return rd