bioimageio.core.axis
1from __future__ import annotations 2 3from dataclasses import dataclass 4from typing import Literal, Mapping, Optional, TypeVar, Union 5 6from typing_extensions import assert_never 7 8from bioimageio.spec.model import v0_5 9 10 11def _guess_axis_type(a: str): 12 if a in ("b", "batch"): 13 return "batch" 14 elif a in ("t", "time"): 15 return "time" 16 elif a in ("i", "index"): 17 return "index" 18 elif a in ("c", "channel"): 19 return "channel" 20 elif a in ("x", "y", "z"): 21 return "space" 22 else: 23 raise ValueError( 24 f"Failed to infer axis type for axis id '{a}'." 25 + " Consider using one of: '" 26 + "', '".join( 27 ["b", "batch", "t", "time", "i", "index", "c", "channel", "x", "y", "z"] 28 ) 29 + "'. Or creating an `Axis` object instead." 30 ) 31 32 33S = TypeVar("S", bound=str) 34 35 36AxisId = v0_5.AxisId 37"""An axis identifier, e.g. 'batch', 'channel', 'z', 'y', 'x'""" 38 39T = TypeVar("T") 40PerAxis = Mapping[AxisId, T] 41 42BatchSize = int 43 44AxisLetter = Literal["b", "i", "t", "c", "z", "y", "x"] 45AxisLike = Union[AxisId, AxisLetter, v0_5.AnyAxis, "Axis"] 46 47 48@dataclass 49class Axis: 50 id: AxisId 51 type: Literal["batch", "channel", "index", "space", "time"] 52 53 def __post_init__(self): 54 if self.type == "batch": 55 self.id = AxisId("batch") 56 elif self.type == "channel": 57 self.id = AxisId("channel") 58 59 @classmethod 60 def create(cls, axis: AxisLike) -> Axis: 61 if isinstance(axis, cls): 62 return axis 63 elif isinstance(axis, Axis): 64 return Axis(id=axis.id, type=axis.type) 65 elif isinstance(axis, v0_5.AxisBase): 66 return Axis(id=AxisId(axis.id), type=axis.type) 67 elif isinstance(axis, str): 68 return Axis(id=AxisId(axis), type=_guess_axis_type(axis)) 69 else: 70 assert_never(axis) 71 72 73@dataclass 74class AxisInfo(Axis): 75 maybe_singleton: bool # TODO: replace 'maybe_singleton' with size min/max for better axis guessing 76 77 @classmethod 78 def create(cls, axis: AxisLike, maybe_singleton: Optional[bool] = None) -> AxisInfo: 79 if isinstance(axis, AxisInfo): 80 return axis 81 82 axis_base = super().create(axis) 83 if maybe_singleton is None: 84 if isinstance(axis, (Axis, str)): 85 maybe_singleton = True 86 else: 87 if axis.size is None: 88 maybe_singleton = True 89 elif isinstance(axis.size, int): 90 maybe_singleton = axis.size == 1 91 elif isinstance(axis.size, v0_5.SizeReference): 92 maybe_singleton = ( 93 True # TODO: check if singleton is ok for a `SizeReference` 94 ) 95 elif isinstance( 96 axis.size, (v0_5.ParameterizedSize, v0_5.DataDependentSize) 97 ): 98 try: 99 maybe_size_one = axis.size.validate_size( 100 1 101 ) # TODO: refactor validate_size() to have boolean func here 102 except ValueError: 103 maybe_singleton = False 104 else: 105 maybe_singleton = maybe_size_one == 1 106 else: 107 assert_never(axis.size) 108 109 return AxisInfo( 110 id=axis_base.id, type=axis_base.type, maybe_singleton=maybe_singleton 111 )
class
AxisId(bioimageio.spec._internal.types.LowerCaseIdentifier):
229class AxisId(LowerCaseIdentifier): 230 root_model: ClassVar[Type[RootModel[Any]]] = RootModel[ 231 Annotated[ 232 LowerCaseIdentifierAnno, 233 MaxLen(16), 234 AfterValidator(_normalize_axis_id), 235 ] 236 ]
An axis identifier, e.g. 'batch', 'channel', 'z', 'y', 'x'
PerAxis =
typing.Mapping[AxisId, ~T]
BatchSize =
<class 'int'>
AxisLetter =
typing.Literal['b', 'i', 't', 'c', 'z', 'y', 'x']
AxisLike =
typing.Union[AxisId, typing.Literal['b', 'i', 't', 'c', 'z', 'y', 'x'], typing.Annotated[typing.Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexInputAxis, bioimageio.spec.model.v0_5.TimeInputAxis, bioimageio.spec.model.v0_5.SpaceInputAxis], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], typing.Annotated[typing.Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexOutputAxis, typing.Annotated[typing.Union[typing.Annotated[bioimageio.spec.model.v0_5.TimeOutputAxis, Tag(tag='wo_halo')], typing.Annotated[bioimageio.spec.model.v0_5.TimeOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)], typing.Annotated[typing.Union[typing.Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxis, Tag(tag='wo_halo')], typing.Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], ForwardRef('Axis')]
@dataclass
class
Axis:
49@dataclass 50class Axis: 51 id: AxisId 52 type: Literal["batch", "channel", "index", "space", "time"] 53 54 def __post_init__(self): 55 if self.type == "batch": 56 self.id = AxisId("batch") 57 elif self.type == "channel": 58 self.id = AxisId("channel") 59 60 @classmethod 61 def create(cls, axis: AxisLike) -> Axis: 62 if isinstance(axis, cls): 63 return axis 64 elif isinstance(axis, Axis): 65 return Axis(id=axis.id, type=axis.type) 66 elif isinstance(axis, v0_5.AxisBase): 67 return Axis(id=AxisId(axis.id), type=axis.type) 68 elif isinstance(axis, str): 69 return Axis(id=AxisId(axis), type=_guess_axis_type(axis)) 70 else: 71 assert_never(axis)
Axis( id: AxisId, type: Literal['batch', 'channel', 'index', 'space', 'time'])
id: AxisId
@classmethod
def
create( cls, axis: Union[AxisId, Literal['b', 'i', 't', 'c', 'z', 'y', 'x'], Annotated[Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexInputAxis, bioimageio.spec.model.v0_5.TimeInputAxis, bioimageio.spec.model.v0_5.SpaceInputAxis], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexOutputAxis, Annotated[Union[Annotated[bioimageio.spec.model.v0_5.TimeOutputAxis, Tag(tag='wo_halo')], Annotated[bioimageio.spec.model.v0_5.TimeOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxis, Tag(tag='wo_halo')], Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Axis]) -> Axis:
60 @classmethod 61 def create(cls, axis: AxisLike) -> Axis: 62 if isinstance(axis, cls): 63 return axis 64 elif isinstance(axis, Axis): 65 return Axis(id=axis.id, type=axis.type) 66 elif isinstance(axis, v0_5.AxisBase): 67 return Axis(id=AxisId(axis.id), type=axis.type) 68 elif isinstance(axis, str): 69 return Axis(id=AxisId(axis), type=_guess_axis_type(axis)) 70 else: 71 assert_never(axis)
74@dataclass 75class AxisInfo(Axis): 76 maybe_singleton: bool # TODO: replace 'maybe_singleton' with size min/max for better axis guessing 77 78 @classmethod 79 def create(cls, axis: AxisLike, maybe_singleton: Optional[bool] = None) -> AxisInfo: 80 if isinstance(axis, AxisInfo): 81 return axis 82 83 axis_base = super().create(axis) 84 if maybe_singleton is None: 85 if isinstance(axis, (Axis, str)): 86 maybe_singleton = True 87 else: 88 if axis.size is None: 89 maybe_singleton = True 90 elif isinstance(axis.size, int): 91 maybe_singleton = axis.size == 1 92 elif isinstance(axis.size, v0_5.SizeReference): 93 maybe_singleton = ( 94 True # TODO: check if singleton is ok for a `SizeReference` 95 ) 96 elif isinstance( 97 axis.size, (v0_5.ParameterizedSize, v0_5.DataDependentSize) 98 ): 99 try: 100 maybe_size_one = axis.size.validate_size( 101 1 102 ) # TODO: refactor validate_size() to have boolean func here 103 except ValueError: 104 maybe_singleton = False 105 else: 106 maybe_singleton = maybe_size_one == 1 107 else: 108 assert_never(axis.size) 109 110 return AxisInfo( 111 id=axis_base.id, type=axis_base.type, maybe_singleton=maybe_singleton 112 )
AxisInfo( id: AxisId, type: Literal['batch', 'channel', 'index', 'space', 'time'], maybe_singleton: bool)
@classmethod
def
create( cls, axis: Union[AxisId, Literal['b', 'i', 't', 'c', 'z', 'y', 'x'], Annotated[Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexInputAxis, bioimageio.spec.model.v0_5.TimeInputAxis, bioimageio.spec.model.v0_5.SpaceInputAxis], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[bioimageio.spec.model.v0_5.BatchAxis, bioimageio.spec.model.v0_5.ChannelAxis, bioimageio.spec.model.v0_5.IndexOutputAxis, Annotated[Union[Annotated[bioimageio.spec.model.v0_5.TimeOutputAxis, Tag(tag='wo_halo')], Annotated[bioimageio.spec.model.v0_5.TimeOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)], Annotated[Union[Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxis, Tag(tag='wo_halo')], Annotated[bioimageio.spec.model.v0_5.SpaceOutputAxisWithHalo, Tag(tag='with_halo')]], Discriminator(discriminator=<function _get_halo_axis_discriminator_value>, custom_error_type=None, custom_error_message=None, custom_error_context=None)]], Discriminator(discriminator='type', custom_error_type=None, custom_error_message=None, custom_error_context=None)], Axis], maybe_singleton: Optional[bool] = None) -> AxisInfo:
78 @classmethod 79 def create(cls, axis: AxisLike, maybe_singleton: Optional[bool] = None) -> AxisInfo: 80 if isinstance(axis, AxisInfo): 81 return axis 82 83 axis_base = super().create(axis) 84 if maybe_singleton is None: 85 if isinstance(axis, (Axis, str)): 86 maybe_singleton = True 87 else: 88 if axis.size is None: 89 maybe_singleton = True 90 elif isinstance(axis.size, int): 91 maybe_singleton = axis.size == 1 92 elif isinstance(axis.size, v0_5.SizeReference): 93 maybe_singleton = ( 94 True # TODO: check if singleton is ok for a `SizeReference` 95 ) 96 elif isinstance( 97 axis.size, (v0_5.ParameterizedSize, v0_5.DataDependentSize) 98 ): 99 try: 100 maybe_size_one = axis.size.validate_size( 101 1 102 ) # TODO: refactor validate_size() to have boolean func here 103 except ValueError: 104 maybe_singleton = False 105 else: 106 maybe_singleton = maybe_size_one == 1 107 else: 108 assert_never(axis.size) 109 110 return AxisInfo( 111 id=axis_base.id, type=axis_base.type, maybe_singleton=maybe_singleton 112 )