Coverage for src/bioimageio/spec/_internal/node_converter.py: 100%

20 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-18 09:17 +0000

1from __future__ import annotations 

2 

3from abc import ABC, abstractmethod 

4from typing import ( 

5 Any, 

6 Dict, 

7 Final, 

8 Generic, 

9 Union, 

10 cast, 

11) 

12 

13from typing_extensions import ( 

14 TypeVar, 

15 TypeVarTuple, 

16 Unpack, 

17) 

18 

19from .node import Node 

20from .utils import ( 

21 assert_all_params_set_explicitly, 

22) 

23from .validated_string import ValidatedString 

24 

25SRC = TypeVar("SRC", bound=Union[Node, ValidatedString]) 

26TGT = TypeVar("TGT", bound=Node) 

27 

28 

29# converter without any additional args or kwargs: 

30# class Converter(Generic[SRC, TGT], ABC): 

31# # src: ClassVar[Type[SRC]] 

32# # tgt: ClassVar[Type[TGT]] 

33# # note: the above is not yet possible, see https://github.com/python/typing/discussions/1424 

34# # we therefore use an instance 

35# def __init__(self, src: Type[SRC], tgt: Type[TGT], /): 

36# super().__init__() 

37# self.src: Final[Type[SRC]] = src 

38# self.tgt: Final[Type[TGT]] = tgt 

39 

40# @abstractmethod 

41# def _convert(self, src: SRC, tgt: "type[TGT | dict[str, Any]] ", /) -> "TGT | dict[str, Any]": 

42# ... 

43 

44# def convert(self, source: SRC, /) -> TGT: 

45# """convert `source` node 

46 

47# Args: 

48# source: A bioimageio description node 

49 

50# Raises: 

51# ValidationError: conversion failed 

52# """ 

53# data = self.convert_as_dict(source) 

54# return assert_all_params_set_explicitly(self.tgt)(**data) 

55 

56# def convert_as_dict(self, source: SRC) -> Dict[str, Any]: 

57# return cast(Dict[str, Any], self._convert(source, dict)) 

58 

59 

60# A TypeVar bound to a TypedDict seemed like a good way to add converter kwargs: 

61# ``` 

62# class ConverterKwargs(TypedDict): 

63# pass 

64# KW = TypeVar("KW", bound=ConverterKwargs, default=ConverterKwargs) 

65# ``` 

66# sadly we cannot use a TypeVar bound to TypedDict and then unpack it in the Converter methods, 

67# see https://github.com/python/typing/issues/1399 

68# Therefore we use a TypeVarTuple and positional only args instead 

69# (We are avoiding ParamSpec for its ambiguity 'args vs kwargs') 

70CArgs = TypeVarTuple("CArgs") 

71 

72 

73class Converter(ABC, Generic[SRC, TGT, Unpack[CArgs]]): 

74 # src: ClassVar[Type[SRC]] 

75 # tgt: ClassVar[Type[TGT]] 

76 # note: the above is not yet possible, see https://github.com/python/typing/discussions/1424 

77 # we therefore use an instance 

78 def __init__(self, src: type[SRC], tgt: type[TGT], /): 

79 super().__init__() 

80 self.src: Final[type[SRC]] = src 

81 self.tgt: Final[type[TGT]] = tgt 

82 

83 @abstractmethod 

84 def _convert( 

85 self, src: SRC, tgt: type[TGT | dict[str, Any]], /, *args: Unpack[CArgs] 

86 ) -> TGT | dict[str, Any]: ... 

87 

88 # note: the following is not (yet) allowed, see https://github.com/python/typing/issues/1399 

89 # we therefore use `kwargs` (and not `**kwargs`) 

90 # def convert(self, source: SRC, /, **kwargs: Unpack[KW]) -> TGT: 

91 def convert(self, source: SRC, /, *args: Unpack[CArgs]) -> TGT: 

92 """convert `source` node 

93 

94 Args: 

95 source: A bioimageio description node 

96 

97 Raises: 

98 ValidationError: conversion failed 

99 """ 

100 data = self.convert_as_dict(source, *args) 

101 return assert_all_params_set_explicitly(self.tgt)(**data) 

102 

103 def convert_as_dict(self, source: SRC, /, *args: Unpack[CArgs]) -> dict[str, Any]: 

104 return cast(Dict[str, Any], self._convert(source, dict, *args))