Skip to content

Commit cf8ef63

Browse files
author
Alan Fleming
committed
Add Children for Box (and subclasses) to support validation of any type of iterable plus a configurable option to omit invalid items (including closed widgets) and log a warning or error.
1 parent b9d043e commit cf8ef63

File tree

1 file changed

+43
-9
lines changed

1 file changed

+43
-9
lines changed

python/ipywidgets/ipywidgets/widgets/widget_box.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
# Copyright (c) Jupyter Development Team.
23
# Distributed under the terms of the Modified BSD License.
34

@@ -7,14 +8,16 @@
78
group other widgets together and control their
89
relative layouts.
910
"""
11+
from __future__ import annotations
12+
13+
import typing
14+
15+
from traitlets import CaselessStrEnum, TraitError, TraitType, Unicode
1016

11-
from .widget import register, widget_serialization, Widget
17+
from .docutils import doc_subst
1218
from .domwidget import DOMWidget
19+
from .widget import Widget, register, widget_serialization
1320
from .widget_core import CoreWidget
14-
from .docutils import doc_subst
15-
from .trait_types import TypedTuple
16-
from traitlets import Unicode, CaselessStrEnum, Instance
17-
1821

1922
_doc_snippets = {}
2023
_doc_snippets['box_params'] = """
@@ -25,8 +28,35 @@
2528
one of 'success', 'info', 'warning' or 'danger', or ''.
2629
Applies a predefined style to the box. Defaults to '',
2730
which applies no pre-defined style.
31+
32+
validate_mode: str
33+
one of 'raise', 'warning', error'.
34+
How invalid children will be treated.
35+
'raise' will raise a trait error.
36+
'warning' and 'error' will log an error using box.log dropping
37+
the invalid items from children.
2838
"""
2939

40+
class Children(TraitType['tuple[Widget,...]', typing.Iterable[Widget]]):
41+
default_value = ()
42+
43+
def validate(self, obj: Box, value: typing.Iterable[Widget]):
44+
valid, invalid = [], []
45+
for v in value:
46+
if isinstance(v, Widget) and v._repr_mimebundle_:
47+
valid.append(v)
48+
else:
49+
invalid.append(v)
50+
if invalid:
51+
msg = f'Invalid or closed items found: {invalid}'
52+
if obj.validate_mode == 'log_warning':
53+
obj.log.warning(msg)
54+
elif obj.validate_mode == 'log_error':
55+
obj.log.error(msg)
56+
else:
57+
raise TraitError(msg)
58+
return tuple(valid)
59+
3060

3161
@register
3262
@doc_subst(_doc_snippets)
@@ -48,19 +78,23 @@ class Box(DOMWidget, CoreWidget):
4878
"""
4979
_model_name = Unicode('BoxModel').tag(sync=True)
5080
_view_name = Unicode('BoxView').tag(sync=True)
81+
tooltip = Unicode('', allow_none=True, help='A tooltip caption.').tag(sync=True)
82+
validate_mode = CaselessStrEnum(['raise', 'log_warning', 'log_error'], 'raise')
5183

5284
# Child widgets in the container.
5385
# Using a tuple here to force reassignment to update the list.
5486
# When a proper notifying-list trait exists, use that instead.
55-
children = TypedTuple(trait=Instance(Widget), help="List of widget children").tag(
56-
sync=True, **widget_serialization)
87+
children = Children(help='List of widget children').tag(
88+
sync=True, **widget_serialization
89+
)
5790

5891
box_style = CaselessStrEnum(
5992
values=['success', 'info', 'warning', 'danger', ''], default_value='',
6093
help="""Use a predefined styling for the box.""").tag(sync=True)
61-
94+
6295
def __init__(self, children=(), **kwargs):
63-
kwargs['children'] = children
96+
if children:
97+
kwargs['children'] = children
6498
super().__init__(**kwargs)
6599

66100
@register

0 commit comments

Comments
 (0)