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