Coverage for bioimageio/spec/_internal/node_converter.py: 100%
22 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
1from __future__ import annotations
3from abc import ABC, abstractmethod
4from typing import (
5 Any,
6 Dict,
7 Final,
8 Generic,
9 Type,
10 Union,
11 cast,
12)
14from typing_extensions import (
15 TypeVar,
16 TypeVarTuple,
17 Unpack,
18)
20from .node import Node
21from .utils import (
22 assert_all_params_set_explicitly,
23)
24from .validated_string import ValidatedString
26SRC = TypeVar("SRC", bound=Union[Node, ValidatedString])
27TGT = TypeVar("TGT", bound=Node)
30# converter without any additional args or kwargs:
31# class Converter(Generic[SRC, TGT], ABC):
32# # src: ClassVar[Type[SRC]]
33# # tgt: ClassVar[Type[TGT]]
34# # note: the above is not yet possible, see https://github.com/python/typing/discussions/1424
35# # we therefore use an instance
36# def __init__(self, src: Type[SRC], tgt: Type[TGT], /):
37# super().__init__()
38# self.src: Final[Type[SRC]] = src
39# self.tgt: Final[Type[TGT]] = tgt
41# @abstractmethod
42# def _convert(self, src: SRC, tgt: "type[TGT | dict[str, Any]] ", /) -> "TGT | dict[str, Any]":
43# ...
45# def convert(self, source: SRC, /) -> TGT:
46# """convert `source` node
48# Args:
49# source: A bioimageio description node
51# Raises:
52# ValidationError: conversion failed
53# """
54# data = self.convert_as_dict(source)
55# return assert_all_params_set_explicitly(self.tgt)(**data)
57# def convert_as_dict(self, source: SRC) -> Dict[str, Any]:
58# return cast(Dict[str, Any], self._convert(source, dict))
61# A TypeVar bound to a TypedDict seemed like a good way to add converter kwargs:
62# ```
63# class ConverterKwargs(TypedDict):
64# pass
65# KW = TypeVar("KW", bound=ConverterKwargs, default=ConverterKwargs)
66# ```
67# sadly we cannot use a TypeVar bound to TypedDict and then unpack it in the Converter methods,
68# see https://github.com/python/typing/issues/1399
69# Therefore we use a TypeVarTuple and positional only args instead
70# (We are avoiding ParamSpec for its ambiguity 'args vs kwargs')
71CArgs = TypeVarTuple("CArgs")
74class Converter(Generic[SRC, TGT, Unpack[CArgs]], ABC):
75 # src: ClassVar[Type[SRC]]
76 # tgt: ClassVar[Type[TGT]]
77 # note: the above is not yet possible, see https://github.com/python/typing/discussions/1424
78 # we therefore use an instance
79 def __init__(self, src: Type[SRC], tgt: Type[TGT], /):
80 super().__init__()
81 self.src: Final[Type[SRC]] = src
82 self.tgt: Final[Type[TGT]] = tgt
84 @abstractmethod
85 def _convert(
86 self, src: SRC, tgt: "type[TGT | dict[str, Any]]", /, *args: Unpack[CArgs]
87 ) -> "TGT | dict[str, Any]": ...
89 # note: the following is not (yet) allowed, see https://github.com/python/typing/issues/1399
90 # we therefore use `kwargs` (and not `**kwargs`)
91 # def convert(self, source: SRC, /, **kwargs: Unpack[KW]) -> TGT:
92 def convert(self, source: SRC, /, *args: Unpack[CArgs]) -> TGT:
93 """convert `source` node
95 Args:
96 source: A bioimageio description node
98 Raises:
99 ValidationError: conversion failed
100 """
101 data = self.convert_as_dict(source, *args)
102 return assert_all_params_set_explicitly(self.tgt)(**data)
104 def convert_as_dict(self, source: SRC, /, *args: Unpack[CArgs]) -> Dict[str, Any]:
105 return cast(Dict[str, Any], self._convert(source, dict, *args))