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

1"""implementation details for building a bioimage.io resource description""" 

2 

3from typing import Any, Callable, List, Literal, Mapping, Optional, Type, TypeVar, Union 

4 

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) 

13 

14ResourceDescrT = TypeVar("ResourceDescrT", bound=ResourceDescrBase) 

15 

16 

17DISCOVER: Literal["discover"] = "discover" 

18"""placeholder for whatever format version an RDF specifies""" 

19 

20 

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 

37 

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 

45 

46 descr_versions = descriptions_map[typ] 

47 return descr_versions.get(use_format_version, descr_versions[None]) 

48 

49 

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 = {} 

83 

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 

95 

96 typ = content["type"] 

97 rd_class = get_rd_class(typ, content["format_version"]) 

98 rd = rd_class.load(content, context=context) 

99 

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 

111 

112 return rd