Skip to content

himena.types

Parametric = NewType('Parametric', Any) module-attribute

Callback for a parametric function.

This type can be interpreted by the injection store processor. For example, in the following code, my_plugin_function will be converted into a parametric widget with inputs a and b..

from himena.plugin import register_function
@register_function(...)
def my_plugin_function(...) -> Parametric:
    def callback_func(a: int, b: str) -> WidgetDataModel:
        ...
    return my_plugin_function

WidgetConstructor = NewType('WidgetConstructor', object) module-attribute

This type is used for the return annotation.

from himena.plugin import register_function
@register_function(...)
def my_plugin_function() -> WidgetConstructor:
    return MyWidget

WidgetType = NewType('WidgetType', object) module-attribute

This type is used for the return annotation.

from himena.plugin import register_function
@register_function(...)
def my_plugin_function() -> WidgetType:
    return MyWidget()

BackendInstructions

Instructions for the backend that are only relevant to user interface.

Parameters:

Name Type Description Default
animate bool

Whether to animate

True
confirm bool

Whether to show a confirmation dialog

True
choose_one_dialog_response Callable[list, Any] | None

If provided, choose-one dialog will be skipped and this function will be called to get the response.

None
file_dialog_response Callable[list, Any] | None

If provided, file dialog will be skipped and this function will be called to get the response.

None
gui_execution bool
True
process_model_output bool
True
unwrap_future bool
False
Source code in src\himena\types.py
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
class BackendInstructions(BaseModel):
    """Instructions for the backend that are only relevant to user interface."""

    model_config = PYDANTIC_CONFIG_STRICT

    animate: bool = Field(
        default=True,
        description="Whether to animate",
        frozen=True,
    )
    confirm: bool = Field(
        default=True,
        description="Whether to show a confirmation dialog",
        frozen=True,
    )
    choose_one_dialog_response: Callable[[], Any] | None = Field(
        default=None,
        description="If provided, choose-one dialog will be skipped and this function "
        "will be called to get the response.",
        frozen=True,
    )
    file_dialog_response: Callable[[], Any] | None = Field(
        default=None,
        description="If provided, file dialog will be skipped and this function will "
        "be called to get the response.",
        frozen=True,
    )
    gui_execution: bool = Field(default=True)
    process_model_output: bool = Field(default=True)
    unwrap_future: bool = Field(default=False)

    def updated(self, **kwargs) -> "BackendInstructions":
        return self.model_copy(update=kwargs)

ClipboardDataModel

Data model for a clipboard data.

Parameters:

Name Type Description Default
text str | None

Text in the clipboard if exists.

None
html str | None

HTML in the clipboard if exists.

None
image Any | None

Image in the clipboard if exists.

None
files list[Path]

List of file paths in the clipboard if exists.

<dynamic>
internal_data Any | None

Application specific data in the clipboard if exists. This data cannot be used across application, but is useful to send Python object to other widgets.

None
Source code in src\himena\types.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
class ClipboardDataModel(BaseModel):
    """Data model for a clipboard data."""

    model_config = PYDANTIC_CONFIG_STRICT

    text: str | None = Field(
        default=None,
        description="Text in the clipboard if exists.",
    )
    html: str | None = Field(
        default=None,
        description="HTML in the clipboard if exists.",
    )
    image: Any | None = Field(
        default=None,
        description="Image in the clipboard if exists.",
    )
    files: list[Path] = Field(
        default_factory=list,
        description="List of file paths in the clipboard if exists.",
    )
    internal_data: Any | None = Field(
        default=None,
        description="Application specific data in the clipboard if exists. This data "
        "cannot be used across application, but is useful to send Python object to "
        "other widgets.",
    )

    def with_internal_data(self, internal_data) -> "ClipboardDataModel":
        return self.model_copy(update={"internal_data": internal_data})

DockArea

Area of the dock widget.

Source code in src\himena\types.py
37
38
39
40
41
42
43
class DockArea(StrEnum):
    """Area of the dock widget."""

    TOP = "top"
    BOTTOM = "bottom"
    LEFT = "left"
    RIGHT = "right"

DragDataModel

Parameters:

Name Type Description Default
getter Callable[list, WidgetDataModel] | WidgetDataModel

Getter function to get the data model.

required
type str | None

Type of the internal data.

None
Source code in src\himena\types.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
class DragDataModel(BaseModel):
    model_config = PYDANTIC_CONFIG_STRICT
    getter: Callable[[], WidgetDataModel] | WidgetDataModel = Field(
        ..., description="Getter function to get the data model."
    )
    type: str | None = Field(None, description="Type of the internal data.")

    def inferred_type(self) -> str:
        if self.type is not None:
            return self.type
        if callable(self.getter):
            model = self.getter()
        else:
            model = self.getter
        return model.type

    def data_model(self) -> WidgetDataModel:
        if isinstance(self.getter, WidgetDataModel):
            model = self.getter
        else:
            model = self.getter()
        return model

    def widget_accepts_me(self, widget: Any) -> bool:
        """Return true if the widget accepts this data model to be dropped."""
        if hasattr(widget, "allowed_drop_types"):
            types = widget.allowed_drop_types()
            if self.type is None:
                return True  # not specified. Just allow it.
            if self.type in types:
                return True
        elif hasattr(widget, "dropped_callback"):
            return True
        return False
widget_accepts_me(widget)

Return true if the widget accepts this data model to be dropped.

Source code in src\himena\types.py
381
382
383
384
385
386
387
388
389
390
391
def widget_accepts_me(self, widget: Any) -> bool:
    """Return true if the widget accepts this data model to be dropped."""
    if hasattr(widget, "allowed_drop_types"):
        types = widget.allowed_drop_types()
        if self.type is None:
            return True  # not specified. Just allow it.
        if self.type in types:
            return True
    elif hasattr(widget, "dropped_callback"):
        return True
    return False

DropResult dataclass

Model that can be returned by dropped_callback protocol.

Parameters:

Name Type Description Default
delete_input bool
False
command_id str | None
None
with_params dict[str, object] | None
None

Attributes:

Name Type Description
delete_input bool

Whether to delete the input data if drop succeeded.

command_id str | None

Command that will be executed when the drop succeeded.

with_params dict[str, object] | None

Parameters that will be passed to the command.

Source code in src\himena\types.py
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
@dataclass(frozen=True)
class DropResult:
    """Model that can be returned by `dropped_callback` protocol.

    Attributes
    ----------
    delete_input : bool
        Whether to delete the input data if drop succeeded.
    command_id : str | None
        Command that will be executed when the drop succeeded.
    with_params : dict[str, object] | None
        Parameters that will be passed to the command.
    """

    delete_input: bool = False
    command_id: str | None = None
    with_params: dict[str, object] | None = None

FutureInfo dataclass

FutureInfo(type_hint: Any, track: himena.types.ModelTrack | None = None, kwargs: dict[str, typing.Any] = , top_left: tuple[int, int] | None = None, size: Optional[himena.types.Size[int]] = None)

Parameters:

Name Type Description Default
type_hint Any
required
track ModelTrack | None
None
top_left tuple[int, int] | None
None
size Size[int] | None
None
Source code in src\himena\types.py
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
@dataclass(frozen=True)
class FutureInfo(_HasDynamicAttribute):
    _ATTR_NAME: ClassVar[str] = "__himena_future_info__"

    type_hint: Any
    track: ModelTrack | None = None
    kwargs: dict[str, Any] = field(default_factory=dict)
    top_left: tuple[int, int] | None = None
    size: Size[int] | None = None

    def resolve_type_hint(self, ns: dict[str, Any]) -> "FutureInfo":
        if isinstance(self.type_hint, str):
            typ = ns.get(self.type_hint)
            if typ is None:
                raise ValueError(f"Could not resolve the type hint: {self.type_hint}")
            type_hint = typ
        else:
            type_hint = self.type_hint
        return FutureInfo(
            type_hint=type_hint,
            track=self.track,
            kwargs=self.kwargs,
            top_left=self.top_left,
            size=self.size,
        )

GenericModel

Source code in src\himena\types.py
75
76
77
class GenericModel(BaseModel):
    def __class_getitem__(cls, item):
        return cls

GuiConfiguration dataclass

Configuration for parametric widget (interpreted by the injection processor)

Parameters:

Name Type Description Default
title str | None
None
preview bool
False
auto_close bool
True
show_parameter_labels bool
True
run_async bool
False
result_as Literal[str, str, str]
'window'
Source code in src\himena\types.py
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
@dataclass
class GuiConfiguration(_HasDynamicAttribute):
    """Configuration for parametric widget (interpreted by the injection processor)"""

    _ATTR_NAME: ClassVar[str] = "__himena_gui_config__"

    title: str | None = None
    preview: bool = False
    auto_close: bool = True
    show_parameter_labels: bool = True
    run_async: bool = False
    result_as: Literal["window", "below", "right"] = "window"

    def asdict(self) -> dict[str, Any]:
        """Return the configuration as a dictionary."""
        return asdict(self)
asdict()

Return the configuration as a dictionary.

Source code in src\himena\types.py
591
592
593
def asdict(self) -> dict[str, Any]:
    """Return the configuration as a dictionary."""
    return asdict(self)

Margins dataclass

Margins(left: ~_V, top: ~_V, right: ~_V, bottom: ~_V)

Parameters:

Name Type Description Default
left TypeVar
required
top TypeVar
required
right TypeVar
required
bottom TypeVar
required
Source code in src\himena\types.py
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
@dataclass(frozen=True)
class Margins(Generic[_V]):
    left: _V
    top: _V
    right: _V
    bottom: _V

    def __iter__(self):
        """Iterate over the field to make this class tuple-like."""
        return iter((self.left, self.top, self.right, self.bottom))

    @classmethod
    def from_rects(cls, inner: Rect[_V], outer: Rect[_V]) -> "Margins[_V]":
        """Calculate the margins from the inner and outer rectangles."""
        return cls(
            inner.left - outer.left,
            inner.top - outer.top,
            outer.right - inner.right,
            outer.bottom - inner.bottom,
        )
__iter__()

Iterate over the field to make this class tuple-like.

Source code in src\himena\types.py
552
553
554
def __iter__(self):
    """Iterate over the field to make this class tuple-like."""
    return iter((self.left, self.top, self.right, self.bottom))
from_rects(inner, outer) classmethod

Calculate the margins from the inner and outer rectangles.

Source code in src\himena\types.py
556
557
558
559
560
561
562
563
564
@classmethod
def from_rects(cls, inner: Rect[_V], outer: Rect[_V]) -> "Margins[_V]":
    """Calculate the margins from the inner and outer rectangles."""
    return cls(
        inner.left - outer.left,
        inner.top - outer.top,
        outer.right - inner.right,
        outer.bottom - inner.bottom,
    )

ModelTrack dataclass

Model to track how model is created.

Parameters:

Name Type Description Default
command_id str
required
contexts list[Union[ModelParameter, WindowParameter]]

Built-in mutable sequence.

If no argument is given, the constructor creates a new empty list. The argument must be an iterable if specified.

<dynamic>
workflow Workflow

Container of WorkflowStep instances.

The data structure of a workflow is a directed acyclic graph. Each node is a WorkflowStep instance, and the edges are defined inside each CommandExecution instance. Each node is tagged with a unique ID named id, which is used as a mathematical identifier for the node.

<dynamic>
time_start float
0.0
Source code in src\himena\types.py
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
@dataclass(frozen=True)
class ModelTrack(_HasDynamicAttribute):
    """Model to track how model is created."""

    _ATTR_NAME: ClassVar[str] = "__himena_model_track__"

    command_id: str
    contexts: list[ModelParameter | WindowParameter] = field(default_factory=list)
    workflow: Workflow = field(default_factory=Workflow)
    time_start: float = field(default=0.0)

    def to_workflow(self, parameters: dict[str, Any]) -> Workflow:
        """Construct a workflow based on the given parameters."""
        params = []
        more_workflows: list[Workflow] = []
        for k, v in parameters.items():
            if k == "is_previewing":
                continue
            param, wf = parse_parameter(k, v)
            params.append(param)
            more_workflows.append(wf)
        workflow = Workflow.concat([self.workflow] + more_workflows)
        return workflow.with_step(
            CommandExecution(
                command_id=self.command_id,
                contexts=self.contexts,
                parameters=params,
                execution_time=timeit.default_timer() - self.time_start,
            )
        )
to_workflow(parameters)

Construct a workflow based on the given parameters.

Source code in src\himena\types.py
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
def to_workflow(self, parameters: dict[str, Any]) -> Workflow:
    """Construct a workflow based on the given parameters."""
    params = []
    more_workflows: list[Workflow] = []
    for k, v in parameters.items():
        if k == "is_previewing":
            continue
        param, wf = parse_parameter(k, v)
        params.append(param)
        more_workflows.append(wf)
    workflow = Workflow.concat([self.workflow] + more_workflows)
    return workflow.with_step(
        CommandExecution(
            command_id=self.command_id,
            contexts=self.contexts,
            parameters=params,
            execution_time=timeit.default_timer() - self.time_start,
        )
    )

NewWidgetBehavior

Behavior of adding a widget.

Source code in src\himena\types.py
59
60
61
62
63
class NewWidgetBehavior(StrEnum):
    """Behavior of adding a widget."""

    TAB = "tab"
    WINDOW = "window"

ParametricWidgetProtocol

Protocol used for return annotation of a parametric widget.

Source code in src\himena\types.py
673
674
675
676
677
678
679
680
681
682
class ParametricWidgetProtocol:
    """Protocol used for return annotation of a parametric widget."""

    def __new__(cls, *args, **kwargs) -> None:
        if cls is ParametricWidgetProtocol:
            raise TypeError("ParametricWidgetProtocol cannot be instantiated.")
        return super().__new__(cls)

    def get_output(self, *args, **kwargs) -> Any:
        raise NotImplementedError

Rect dataclass

Rectangle use for any place.

Parameters:

Name Type Description Default
left TypeVar
required
top TypeVar
required
width TypeVar
required
height TypeVar
required
Source code in src\himena\types.py
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
@dataclass(frozen=True)
class Rect(Generic[_V]):
    """Rectangle use for any place."""

    left: _V
    top: _V
    width: _V
    height: _V

    @property
    def right(self):
        return self.left + self.width

    @property
    def bottom(self):
        return self.top + self.height

    def with_left(self, left: _V) -> "Rect[_V]":
        return Rect(left, self.top, self.width, self.height)

    def with_top(self, top: _V) -> "Rect[_V]":
        return Rect(self.left, top, self.width, self.height)

    def with_width(self, width: _V) -> "Rect[_V]":
        return Rect(self.left, self.top, width, self.height)

    def with_height(self, height: _V) -> "Rect[_V]":
        return Rect(self.left, self.top, self.width, height)

    def with_right(self, right: _V) -> "Rect[_V]":
        return Rect(right - self.width, self.top, self.width, self.height)

    def with_bottom(self, bottom: _V) -> "Rect[_V]":
        return Rect(self.left, bottom - self.height, self.width, self.height)

    def __iter__(self):
        """Iterate over the field to make this class tuple-like."""
        return iter((self.left, self.top, self.width, self.height))

    def size(self) -> Size[_V]:
        return Size(self.width, self.height)

    def adjust_to_int(
        self,
        how: Literal["inner", "outer"] = "inner",
    ) -> "Rect[int]":
        right = self.right
        bottom = self.bottom
        if how == "inner":
            left = int(math.ceil(self.left))
            top = int(math.ceil(self.top))
            right = int(math.floor(right))
            bottom = int(math.floor(bottom))
        else:
            left = int(math.floor(self.left))
            top = int(math.floor(self.top))
            right = int(math.ceil(right))
            bottom = int(math.ceil(bottom))
        return Rect(left, top, right - left, bottom - top)

    def limit_to(self, xmax: _T, ymax: _T) -> "Rect[_T]":
        """Limit the size of the Rect to the given maximum size."""
        left = max(self.left, 0)
        top = max(self.top, 0)
        right = min(self.right, xmax)
        bottom = min(self.bottom, ymax)
        return Rect(left, top, right - left, bottom - top)

    def move_top_left(self, left: _V, top: _V) -> "Rect[_V]":
        return Rect(left, top, self.width, self.height)

    def move_top_right(self, right: _V, top: _V) -> "Rect[_V]":
        return Rect(right - self.width, top, self.width, self.height)

    def move_bottom_left(self, left: _V, bottom: _V) -> "Rect[_V]":
        return Rect(left, bottom - self.height, self.width, self.height)

    def move_bottom_right(self, right: _V, bottom: _V) -> "Rect[_V]":
        return Rect(right - self.width, bottom - self.height, self.width, self.height)
__iter__()

Iterate over the field to make this class tuple-like.

Source code in src\himena\types.py
457
458
459
def __iter__(self):
    """Iterate over the field to make this class tuple-like."""
    return iter((self.left, self.top, self.width, self.height))
limit_to(xmax, ymax)

Limit the size of the Rect to the given maximum size.

Source code in src\himena\types.py
482
483
484
485
486
487
488
def limit_to(self, xmax: _T, ymax: _T) -> "Rect[_T]":
    """Limit the size of the Rect to the given maximum size."""
    left = max(self.left, 0)
    top = max(self.top, 0)
    right = min(self.right, xmax)
    bottom = min(self.bottom, ymax)
    return Rect(left, top, right - left, bottom - top)

Size dataclass

Size use for any place.

Parameters:

Name Type Description Default
width TypeVar
required
height TypeVar
required
Source code in src\himena\types.py
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
@dataclass(frozen=True)
class Size(Generic[_V]):
    """Size use for any place."""

    width: _V
    height: _V

    def __iter__(self):
        """Iterate over the field to make this class tuple-like."""
        return iter((self.width, self.height))

    def __getitem__(self, index: int):
        if index == 0:
            return self.width
        elif index == 1:
            return self.height
        raise IndexError(f"Index {index!r} out of range.")

    def with_width(self, width: _V) -> "Size[_V]":
        return Size(width, self.height)

    def with_height(self, height: _V) -> "Size[_V]":
        return Size(self.width, height)
__iter__()

Iterate over the field to make this class tuple-like.

Source code in src\himena\types.py
404
405
406
def __iter__(self):
    """Iterate over the field to make this class tuple-like."""
    return iter((self.width, self.height))

WidgetClassTuple

Class for storing registered widget class.

Parameters:

Name Type Description Default
type str
None
widget_class ForwardRef(type | Callable)
None
priority int
100
widget_id str | None
None
Source code in src\himena\types.py
720
721
722
723
724
725
726
class WidgetClassTuple(NamedTuple):
    """Class for storing registered widget class."""

    type: str
    widget_class: "type | Callable"  # factory function
    priority: int = 100
    widget_id: str | None = None

WidgetDataModel

A data model that represents a widget containing an internal data.

Parameters:

Name Type Description Default
value TypeVar

Internal value.

required
type str

Type of the internal data.

required
title str | None

Default title for the widget.

None
extension_default str | None

Default file extension for saving.

None
extensions list[str]

List of allowed file extensions.

<dynamic>
metadata object | None

Metadata that may be used for storing additional information of the internal data or describing the state of the widget.

None
workflow Workflow

Container of WorkflowStep instances.

The data structure of a workflow is a directed acyclic graph. Each node is a WorkflowStep instance, and the edges are defined inside each CommandExecution instance. Each node is tagged with a unique ID named id, which is used as a mathematical identifier for the node.

<dynamic>
force_open_with str | None

Force open with a specific plugin if given.

None
save_behavior_override SaveBehavior | None

Override the default save behavior.

None
editable bool

Whether the widget is editable.

True
update_inplace bool

Whether to update the input data instead of creating a new window.

False
window_rect_override Callable[list, WindowRect] | None
None

Attributes:

Name Type Description
value Any

Internal value.

type (str, optional)

Type of the internal data. Type hierarchy is separated by dots. For example, "text.plain" is a subtype of "text".

title (str, optional)

Title for the widget. If not given, the title will be generated from the source path when this model is added to the GUI.

extension_default (str, optional)

Default file extension for saving. This is used when the user saves the data without specifying the file extension.

extensions (list[str], optional)

List of allowed file extensions to save this data.

metadata (Any, optional)

Metadata that may be used for storing additional information of the internal data or describing the state of the widget.

workflow (WorkflowList, optional)

History of how this data is created.

force_open_with (str, optional)

Force open with a specific plugin if given.

Source code in src\himena\types.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
class WidgetDataModel(GenericModel[_T]):
    """A data model that represents a widget containing an internal data.

    Attributes
    ----------
    value : Any
        Internal value.
    type : str, optional
        Type of the internal data. Type hierarchy is separated by dots. For example,
        "text.plain" is a subtype of "text".
    title : str, optional
        Title for the widget. If not given, the title will be generated from the source
        path when this model is added to the GUI.
    extension_default : str, optional
        Default file extension for saving. This is used when the user saves the data
        without specifying the file extension.
    extensions : list[str], optional
        List of allowed file extensions to save this data.
    metadata : Any, optional
        Metadata that may be used for storing additional information of the internal
        data or describing the state of the widget.
    workflow : WorkflowList, optional
        History of how this data is created.
    force_open_with : str, optional
        Force open with a specific plugin if given.
    """

    model_config = PYDANTIC_CONFIG_STRICT

    value: _T = Field(..., description="Internal value.")
    type: str = Field(..., description="Type of the internal data.")
    title: str | None = Field(
        default=None,
        description="Default title for the widget.",
    )
    extension_default: str | None = Field(
        default=None,
        description="Default file extension for saving.",
    )
    extensions: list[str] = Field(
        default_factory=list,
        description="List of allowed file extensions.",
    )
    metadata: object | None = Field(
        default=None,
        description="Metadata that may be used for storing additional information of "
        "the internal data or describing the state of the widget.",
    )  # fmt: skip
    workflow: Workflow = Field(default_factory=Workflow)
    force_open_with: str | None = Field(
        default=None,
        description="Force open with a specific plugin if given.",
    )
    save_behavior_override: SaveBehavior | None = Field(
        default=None,
        description="Override the default save behavior.",
    )
    editable: bool = Field(True, description="Whether the widget is editable.")
    update_inplace: bool = Field(
        False,
        description="Whether to update the input data instead of creating a new window.",
    )
    window_rect_override: Callable[["Size"], "WindowRect"] | None = Field(None)

    def with_value(
        self,
        value: _U,
        type: str | None = None,
        *,
        title: str | None = None,
        metadata: object | None = _void,
        save_behavior_override: SaveBehavior | _Void | None = _void,
        update_inplace: bool = False,
    ) -> "WidgetDataModel[_U]":
        """Return a model with the new value."""
        update = {"value": value}
        if type is not None:
            update["type"] = type
        if metadata is not _void:
            update["metadata"] = metadata
        if title is not None:
            update["title"] = title
        if save_behavior_override is not _void:
            update["save_behavior_override"] = save_behavior_override
        update.update(
            workflow=Workflow(),
            force_open_with=None,
            update_inplace=update_inplace,
        )  # these parameters must be reset
        return self.model_copy(update=update)

    def astype(self, new_type: str):
        update = {"type": new_type}
        return self.model_copy(update=update)

    def _with_source(
        self,
        source: str | Path | list[str | Path],
        plugin: "PluginInfo | None" = None,
        id: uuid.UUID | None = None,
    ) -> "WidgetDataModel[_T]":
        """Return a new instance with the source path."""
        if plugin is None:
            plugin_name = None
        else:
            plugin_name = plugin.to_str()
        if isinstance(source, list):
            path = [Path(s).resolve() for s in source]
        else:
            path = Path(source).resolve()
        wf = LocalReaderMethod(
            path=path,
            plugin=plugin_name,
            output_model_type=self.type,
            id=id or uuid.uuid4(),
        ).construct_workflow()
        to_update = {"workflow": wf}
        if self.title is None:
            if isinstance(path, list):
                to_update.update({"title": "File group"})
            else:
                to_update.update({"title": path.name})
        return self.model_copy(update=to_update)

    def with_open_plugin(
        self,
        open_with: str,
        *,
        workflow: Workflow | _Void | None = _void,
        save_behavior_override: SaveBehavior | _Void | None = _void,
    ) -> "WidgetDataModel[_T]":
        update = {"force_open_with": open_with}
        if workflow is not _void:
            update["workflow"] = workflow
        if save_behavior_override is not _void:
            update["save_behavior_override"] = save_behavior_override
        return self.model_copy(update=update)

    def with_metadata(
        self,
        metadata: Any,
        update_inplace: bool = False,
    ) -> "WidgetDataModel[_T]":
        """Return a new instance with the given metadata."""
        update = {"metadata": metadata, "update_inplace": update_inplace}
        return self.model_copy(update=update)

    def write_to_directory(
        self,
        directory: str | Path,
        *,
        plugin: str | None = None,
    ) -> Path:
        from himena import _providers

        ins = _providers.WriterStore.instance()
        title = self.title or "Untitled"
        path = Path(directory) / title
        if path.suffix == "":
            if ext := self.extension_default:
                path = path.with_suffix(ext)
            elif exts := self.extensions:
                path = path.with_suffix(exts[0])
            else:
                raise ValueError("Could not determine the file extension.")
        ins.run(self, path, min_priority=0, plugin=plugin)
        return path

    @property
    def source(self) -> Path | list[Path] | None:
        """The direct source path of the data."""
        if isinstance(step := self.workflow.last(), LocalReaderMethod):
            return step.path
        return None

    def is_subtype_of(self, supertype: str) -> bool:
        """Check if the type is a subtype of the given type."""
        return is_subtype(self.type, supertype)

    def with_title_numbering(self, copy: bool = False) -> "WidgetDataModel[_T]":
        """Add [n] suffix to the title."""
        title = self.title
        if title is None:
            title = "Untitled"
        if "." in title:
            stem, ext = title.rsplit(".", 1)
            ext = f".{ext}"
        else:
            stem = title
            ext = ""
        if (
            (last_part := stem.rsplit(" ", 1)[-1]).startswith("[")
            and last_part.endswith("]")
            and last_part[1:-1].isdigit()
        ):
            nth = int(last_part[1:-1])
            stem = stem.rsplit(" ", 1)[0] + f" [{nth + 1}]"
        else:
            stem = stem + " [1]"
        new_title = stem + ext
        if copy:
            return self.model_copy(update={"title": new_title})
        else:
            self.title = new_title
            return self

    @field_validator("extension_default", mode="after")
    def _validate_extension_default(cls, v: str, values):
        if v is None:
            return None
        if not v.startswith("."):
            return f".{v}"
        return v

    @field_validator("extensions", mode="before")
    def _validate_extensions(cls, v):
        if isinstance(v, str):
            v = [v]
        if not all(isinstance(ext, str) for ext in v):
            raise TypeError(f"Invalid type for `extensions`: {type(v)}")
        return [s if s.startswith(".") else f".{s}" for s in v]

    def __repr__(self):
        value_repr = f"<{type(self.value).__name__}>"
        if isinstance(source := self.source, Path):
            source_repr = source.as_posix()
        elif isinstance(source, list):
            if len(source) > 0:
                source_repr = f"[{source[0].as_posix()}, ...]"
            else:
                source_repr = "[]"
        else:
            source_repr = None
        return (
            f"{self.__class__.__name__}(value={value_repr}, source={source_repr}, "
            f"type={self.type!r}, title={self.title!r})"
        )
source property

The direct source path of the data.

is_subtype_of(supertype)

Check if the type is a subtype of the given type.

Source code in src\himena\types.py
262
263
264
def is_subtype_of(self, supertype: str) -> bool:
    """Check if the type is a subtype of the given type."""
    return is_subtype(self.type, supertype)
with_metadata(metadata, update_inplace=False)

Return a new instance with the given metadata.

Source code in src\himena\types.py
225
226
227
228
229
230
231
232
def with_metadata(
    self,
    metadata: Any,
    update_inplace: bool = False,
) -> "WidgetDataModel[_T]":
    """Return a new instance with the given metadata."""
    update = {"metadata": metadata, "update_inplace": update_inplace}
    return self.model_copy(update=update)
with_title_numbering(copy=False)

Add [n] suffix to the title.

Source code in src\himena\types.py
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
def with_title_numbering(self, copy: bool = False) -> "WidgetDataModel[_T]":
    """Add [n] suffix to the title."""
    title = self.title
    if title is None:
        title = "Untitled"
    if "." in title:
        stem, ext = title.rsplit(".", 1)
        ext = f".{ext}"
    else:
        stem = title
        ext = ""
    if (
        (last_part := stem.rsplit(" ", 1)[-1]).startswith("[")
        and last_part.endswith("]")
        and last_part[1:-1].isdigit()
    ):
        nth = int(last_part[1:-1])
        stem = stem.rsplit(" ", 1)[0] + f" [{nth + 1}]"
    else:
        stem = stem + " [1]"
    new_title = stem + ext
    if copy:
        return self.model_copy(update={"title": new_title})
    else:
        self.title = new_title
        return self
with_value(value, type=None, *, title=None, metadata=_void, save_behavior_override=_void, update_inplace=False)

Return a model with the new value.

Source code in src\himena\types.py
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def with_value(
    self,
    value: _U,
    type: str | None = None,
    *,
    title: str | None = None,
    metadata: object | None = _void,
    save_behavior_override: SaveBehavior | _Void | None = _void,
    update_inplace: bool = False,
) -> "WidgetDataModel[_U]":
    """Return a model with the new value."""
    update = {"value": value}
    if type is not None:
        update["type"] = type
    if metadata is not _void:
        update["metadata"] = metadata
    if title is not None:
        update["title"] = title
    if save_behavior_override is not _void:
        update["save_behavior_override"] = save_behavior_override
    update.update(
        workflow=Workflow(),
        force_open_with=None,
        update_inplace=update_inplace,
    )  # these parameters must be reset
    return self.model_copy(update=update)

WindowRect dataclass

Rectangle of a window.

Parameters:

Name Type Description Default
left TypeVar
required
top TypeVar
required
width TypeVar
required
height TypeVar
required
Source code in src\himena\types.py
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
@dataclass(frozen=True)
class WindowRect(Rect[int]):
    """Rectangle of a window."""

    @classmethod
    def from_tuple(cls, left, top, width, height) -> "WindowRect":
        return cls(int(left), int(top), int(width), int(height))

    def align_left(self, area_size: Size[int]) -> "WindowRect":
        return WindowRect(0, self.top, self.width, self.height)

    def align_right(self, area_size: Size[int]) -> "WindowRect":
        w0, _ = area_size
        return WindowRect(w0 - self.width, self.top, self.width, self.height)

    def align_top(self, area_size: Size[int]) -> "WindowRect":
        return WindowRect(self.left, 0, self.width, self.height)

    def align_bottom(self, area_size: Size[int]) -> "WindowRect":
        _, h0 = area_size
        return WindowRect(self.left, h0 - self.height, self.width, self.height)

    def align_center(self, area_size: Size[int]) -> "WindowRect":
        w0, h0 = area_size
        return WindowRect(
            (w0 - self.width) / 2,
            (h0 - self.height) / 2,
            self.width,
            self.height,
        )

    def resize_relative(self, wratio: float, hratio: float) -> "WindowRect":
        if wratio <= 0 or hratio <= 0:
            raise ValueError("Ratios must be positive.")
        return WindowRect(
            self.left,
            self.top,
            round(self.width * wratio),
            round(self.height * hratio),
        )

WindowState

State of the sub window.

Source code in src\himena\types.py
46
47
48
49
50
51
52
class WindowState(StrEnum):
    """State of the sub window."""

    MIN = "min"
    MAX = "max"
    NORMAL = "normal"
    FULL = "full"