123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- "Testing widget layout templates"
- from unittest import TestCase
- try:
- from unittest import mock
- except ImportError:
- import mock
- import pytest
- import traitlets
- import ipywidgets as widgets
- from ipywidgets.widgets.widget_templates import LayoutProperties
- class TestTwoByTwoLayout(TestCase):
- """test layout templates"""
- def test_merge_cells(self): #pylint: disable=no-self-use
- """test merging cells with missing widgets"""
- button1 = widgets.Button()
- button2 = widgets.Button()
- button3 = widgets.Button()
- button4 = widgets.Button()
- box = widgets.TwoByTwoLayout(top_left=button1,
- top_right=button2,
- bottom_left=button3,
- bottom_right=button4)
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"bottom-left bottom-right"')
- assert box.top_left.layout.grid_area == 'top-left'
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.bottom_left.layout.grid_area == 'bottom-left'
- assert box.bottom_right.layout.grid_area == 'bottom-right'
- assert len(box.get_state()['children']) == 4
- box = widgets.TwoByTwoLayout(top_left=button1,
- top_right=button2,
- bottom_left=None,
- bottom_right=button4)
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"top-left bottom-right"')
- assert box.top_left.layout.grid_area == 'top-left'
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.bottom_left is None
- assert box.bottom_right.layout.grid_area == 'bottom-right'
- assert len(box.get_state()['children']) == 3
- box = widgets.TwoByTwoLayout(top_left=None,
- top_right=button2,
- bottom_left=button3,
- bottom_right=button4)
- assert box.layout.grid_template_areas == ('"bottom-left top-right"\n' +
- '"bottom-left bottom-right"')
- assert box.top_left is None
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.bottom_left.layout.grid_area == 'bottom-left'
- assert box.bottom_right.layout.grid_area == 'bottom-right'
- assert len(box.get_state()['children']) == 3
- box = widgets.TwoByTwoLayout(top_left=None,
- top_right=button2,
- bottom_left=None,
- bottom_right=button4)
- assert box.layout.grid_template_areas == ('"top-right top-right"\n' +
- '"bottom-right bottom-right"')
- assert box.top_left is None
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.bottom_left is None
- assert box.bottom_right.layout.grid_area == 'bottom-right'
- assert len(box.get_state()['children']) == 2
- box = widgets.TwoByTwoLayout(top_left=button1,
- top_right=None,
- bottom_left=button3,
- bottom_right=button4)
- assert box.layout.grid_template_areas == ('"top-left bottom-right"\n' +
- '"bottom-left bottom-right"')
- assert box.top_left.layout.grid_area == 'top-left'
- assert box.top_right is None
- assert box.bottom_left.layout.grid_area == 'bottom-left'
- assert box.bottom_right.layout.grid_area == 'bottom-right'
- assert len(box.get_state()['children']) == 3
- box = widgets.TwoByTwoLayout(top_left=button1,
- top_right=None,
- bottom_left=None,
- bottom_right=None)
- assert box.layout.grid_template_areas == ('"top-left top-left"\n' +
- '"top-left top-left"')
- assert box.top_left is button1
- assert box.top_left.layout.grid_area == 'top-left'
- assert box.top_right is None
- assert box.bottom_left is None
- assert box.bottom_right is None
- assert len(box.get_state()['children']) == 1
- box = widgets.TwoByTwoLayout(top_left=None,
- top_right=button1,
- bottom_left=None,
- bottom_right=None)
- assert box.layout.grid_template_areas == ('"top-right top-right"\n' +
- '"top-right top-right"')
- assert box.top_right is button1
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.top_left is None
- assert box.bottom_left is None
- assert box.bottom_right is None
- assert len(box.get_state()['children']) == 1
- box = widgets.TwoByTwoLayout(top_left=None,
- top_right=None,
- bottom_left=None,
- bottom_right=None)
- assert box.layout.grid_template_areas is None
- assert box.top_left is None
- assert box.top_right is None
- assert box.bottom_left is None
- assert box.bottom_right is None
- assert not box.get_state()['children']
- box = widgets.TwoByTwoLayout(top_left=None,
- top_right=button1,
- bottom_left=None,
- bottom_right=None,
- merge=False)
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"bottom-left bottom-right"')
- assert box.top_right is button1
- assert box.top_right.layout.grid_area == 'top-right'
- assert box.top_left is None
- assert box.bottom_left is None
- assert box.bottom_right is None
- assert len(box.get_state()['children']) == 1
- def test_keep_layout_options(self): #pylint: disable=no-self-use
- """test whether layout options are passed down to GridBox"""
- layout = widgets.Layout(align_items="center")
- button1 = widgets.Button()
- button2 = widgets.Button()
- button3 = widgets.Button()
- button4 = widgets.Button()
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button2,
- bottom_left=button3, bottom_right=button4,
- layout=layout)
- assert box.layout.align_items == 'center'
- def test_pass_layout_options(self): #pylint: disable=no-self-use
- """test whether the extra layout options of the template class are
- passed down to Layout object"""
- button1 = widgets.Button()
- button2 = widgets.Button()
- button3 = widgets.Button()
- button4 = widgets.Button()
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button2,
- bottom_left=button3, bottom_right=button4,
- grid_gap="10px", justify_content="center",
- align_items="center")
- assert box.layout.grid_gap == "10px"
- assert box.layout.justify_content == "center"
- assert box.layout.align_items == "center"
- # we still should be able to pass them through layout
- layout = widgets.Layout(grid_gap="10px", justify_content="center",
- align_items="center")
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button2,
- bottom_left=button3, bottom_right=button4,
- layout=layout
- )
- assert box.layout.grid_gap == "10px"
- assert box.layout.justify_content == "center"
- assert box.layout.align_items == "center"
- # values passed directly in the constructor should overwite layout options
- layout = widgets.Layout(grid_gap="10px", justify_content="center",
- align_items="center")
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button2,
- bottom_left=button3, bottom_right=button4,
- layout=layout, grid_gap="30px"
- )
- assert box.layout.grid_gap == "30px"
- assert box.layout.justify_content == "center"
- assert box.layout.align_items == "center"
- @mock.patch("ipywidgets.Layout.send_state")
- def test_update_dynamically(self, send_state): #pylint: disable=no-self-use
- """test whether it's possible to add widget outside __init__"""
- button1 = widgets.Button()
- button2 = widgets.Button()
- button3 = widgets.Button()
- button4 = widgets.Button()
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button3,
- bottom_left=None, bottom_right=button4)
- from ipykernel.kernelbase import Kernel
- state = box.get_state()
- assert len(state['children']) == 3
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"top-left bottom-right"')
- box.layout.comm.kernel = mock.MagicMock(spec=Kernel) #for mocking purposes
- send_state.reset_mock()
- box.bottom_left = button2
- state = box.get_state()
- assert len(state['children']) == 4
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"bottom-left bottom-right"')
- # check whether frontend was informed
- send_state.assert_called_once_with(key="grid_template_areas")
- box = widgets.TwoByTwoLayout(top_left=button1, top_right=button3,
- bottom_left=None, bottom_right=button4)
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"top-left bottom-right"')
- box.layout.comm.kernel = mock.MagicMock(spec=Kernel) #for mocking purposes
- send_state.reset_mock()
- box.merge = False
- assert box.layout.grid_template_areas == ('"top-left top-right"\n' +
- '"bottom-left bottom-right"')
- send_state.assert_called_once_with(key="grid_template_areas")
- class TestAppLayout(TestCase):
- """test layout templates"""
- def test_create_with_defaults(self):
- "test creating with default values"
- footer = widgets.Button()
- header = widgets.Button()
- center = widgets.Button()
- left_sidebar = widgets.Button()
- right_sidebar = widgets.Button()
- box = widgets.AppLayout(
- footer=footer,
- header=header,
- center=center,
- left_sidebar=left_sidebar,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"left-sidebar center right-sidebar"\n' +
- '"footer footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert len(box.get_state()['children']) == 5
- # empty layout should produce no effects
- box = widgets.AppLayout()
- assert box.layout.grid_template_areas is None
- assert box.layout.grid_template_columns is None
- assert box.layout.grid_template_rows is None
- assert len(box.get_state()['children']) == 0
- def test_merge_empty_cells(self):
- "test if cells are correctly merged"
- footer = widgets.Button()
- header = widgets.Button()
- center = widgets.Button()
- left_sidebar = widgets.Button()
- right_sidebar = widgets.Button()
- # merge all if only one widget
- box = widgets.AppLayout(
- center=center
- )
- assert box.layout.grid_template_areas == ('"center center center"\n' +
- '"center center center"\n' +
- '"center center center"')
- assert box.center.layout.grid_area == 'center'
- assert len(box.get_state()['children']) == 1
- box = widgets.AppLayout(
- left_sidebar=left_sidebar
- )
- assert box.layout.grid_template_areas == ('"left-sidebar left-sidebar left-sidebar"\n' +
- '"left-sidebar left-sidebar left-sidebar"\n' +
- '"left-sidebar left-sidebar left-sidebar"')
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert len(box.get_state()['children']) == 1
- # merge left and right sidebars with center
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- left_sidebar=left_sidebar,
- center=center
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"left-sidebar center center"\n' +
- '"footer footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert len(box.get_state()['children']) == 4
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- right_sidebar=right_sidebar,
- center=center
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"center center right-sidebar"\n' +
- '"footer footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center.layout.grid_area == 'center'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert len(box.get_state()['children']) == 4
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- center=center
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"center center center"\n' +
- '"footer footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center.layout.grid_area == 'center'
- assert len(box.get_state()['children']) == 3
- # if only center missing, remove it from view
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- center=None,
- left_sidebar=left_sidebar,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == ('"header header"\n' +
- '"left-sidebar right-sidebar"\n' +
- '"footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert box.center is None
- assert len(box.get_state()['children']) == 4
- # center and one sidebar missing -> 3 row arrangement
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- center=None,
- left_sidebar=None,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == ('"header header"\n' +
- '"right-sidebar right-sidebar"\n' +
- '"footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.left_sidebar is None
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert box.center is None
- assert len(box.get_state()['children']) == 3
- # remove middle row is both sidebars and center missing
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- center=None,
- left_sidebar=None,
- right_sidebar=None
- )
- assert box.layout.grid_template_areas == ('"header"\n' +
- '"footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center is None
- assert box.left_sidebar is None
- assert box.right_sidebar is None
- assert len(box.get_state()['children']) == 2
- # do not merge if merge=False
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- center=center,
- merge=False
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"left-sidebar center right-sidebar"\n' +
- '"footer footer footer"')
- assert box.footer.layout.grid_area == 'footer'
- assert box.header.layout.grid_area == 'header'
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar is None
- assert box.right_sidebar is None
- assert len(box.get_state()['children']) == 3
- # merge header and footer simply removes it from view
- box = widgets.AppLayout(
- footer=footer,
- center=center,
- left_sidebar=left_sidebar,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == ('"left-sidebar center right-sidebar"\n' +
- '"footer footer footer"')
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert box.footer.layout.grid_area == 'footer'
- assert box.header is None
- assert len(box.get_state()['children']) == 4
- box = widgets.AppLayout(
- header=header,
- center=center,
- left_sidebar=left_sidebar,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == ('"header header header"\n' +
- '"left-sidebar center right-sidebar"')
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert box.header.layout.grid_area == 'header'
- assert box.footer is None
- assert len(box.get_state()['children']) == 4
- box = widgets.AppLayout(
- center=center,
- left_sidebar=left_sidebar,
- right_sidebar=right_sidebar
- )
- assert box.layout.grid_template_areas == '"left-sidebar center right-sidebar"'
- assert box.center.layout.grid_area == 'center'
- assert box.left_sidebar.layout.grid_area == 'left-sidebar'
- assert box.right_sidebar.layout.grid_area == 'right-sidebar'
- assert box.footer is None
- assert box.header is None
- assert len(box.get_state()['children']) == 3
- # merge all if only one widget
- box = widgets.AppLayout(
- center=center
- )
- assert box.layout.grid_template_areas == ('"center center center"\n' +
- '"center center center"\n' +
- '"center center center"')
- assert box.center.layout.grid_area == 'center'
- assert len(box.get_state()['children']) == 1
- def test_size_to_css(self):
- box = widgets.AppLayout()
- assert box._size_to_css("100px") == '100px'
- assert box._size_to_css("1fr") == '1fr'
- assert box._size_to_css("2.5fr") == '2.5fr'
- assert box._size_to_css('2.5') == '2.5fr'
- assert box._size_to_css('25%') == '25%'
- with pytest.raises(TypeError):
- box._size_to_css('this is not correct size')
- def test_set_pane_widths_heights(self):
- footer = widgets.Button()
- header = widgets.Button()
- center = widgets.Button()
- left_sidebar = widgets.Button()
- right_sidebar = widgets.Button()
- box = widgets.AppLayout(
- header=header,
- footer=footer,
- left_sidebar=left_sidebar,
- right_sidebar=left_sidebar,
- center=center
- )
- with pytest.raises(traitlets.TraitError):
- box.pane_widths = ['1fx', '1fx', '1fx', '1fx']
- with pytest.raises(traitlets.TraitError):
- box.pane_widths = ['1fx', '1fx']
- with pytest.raises(traitlets.TraitError):
- box.pane_heights = ['1fx', '1fx', '1fx', '1fx']
- with pytest.raises(traitlets.TraitError):
- box.pane_heights = ['1fx', '1fx']
- assert box.layout.grid_template_rows == "1fr 3fr 1fr"
- assert box.layout.grid_template_columns == "1fr 2fr 1fr"
- box.pane_heights = ['3fr', '100px', 20]
- assert box.layout.grid_template_rows == "3fr 100px 20fr"
- assert box.layout.grid_template_columns == "1fr 2fr 1fr"
- box.pane_widths = [3, 3, 1]
- assert box.layout.grid_template_rows == "3fr 100px 20fr"
- assert box.layout.grid_template_columns == "3fr 3fr 1fr"
- class TestGridspecLayout(TestCase):
- "test GridspecLayout"
- def test_init(self):
- with pytest.raises(traitlets.TraitError):
- box = widgets.GridspecLayout()
- with pytest.raises(traitlets.TraitError):
- box = widgets.GridspecLayout(n_rows=-1, n_columns=1)
- box = widgets.GridspecLayout(n_rows=5, n_columns=3)
- assert box.n_rows == 5
- assert box.n_columns == 3
- assert len(box._grid_template_areas) == 5
- assert len(box._grid_template_areas[0]) == 3
- box = widgets.GridspecLayout(1, 2)
- assert box.n_rows == 1
- assert box.n_columns == 2
- with pytest.raises(traitlets.TraitError):
- box = widgets.GridspecLayout(0, 0)
- def test_setitem_index(self):
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- button2 = widgets.Button()
- button3 = widgets.Button()
- button4 = widgets.Button()
- box[0, 0] = button1
- button1_label = button1.layout.grid_area
- assert button1 in box.children
- assert box.layout.grid_template_areas == '''"{} . ."\n". . ."'''.format(button1_label)
- box[-1, -1] = button2
- button2_label = button2.layout.grid_area
- assert button1_label != button2_label
- assert button2 in box.children
- assert box.layout.grid_template_areas == '''"{} . ."\n". . {}"'''.format(button1_label,
- button2_label)
- box[1, 0] = button3
- button3_label = button3.layout.grid_area
- assert button1_label != button3_label
- assert button2_label != button3_label
- assert button3 in box.children
- assert box.layout.grid_template_areas == '''"{b1} . ."\n"{b3} . {b2}"'''.format(b1=button1_label,
- b2=button2_label,
- b3=button3_label)
- #replace widget
- box[1, 0] = button4
- button4_label = button4.layout.grid_area
- assert button1_label != button4_label
- assert button2_label != button4_label
- assert button4 in box.children
- assert button3 not in box.children
- assert box.layout.grid_template_areas == '''"{b1} . ."\n"{b4} . {b2}"'''.format(b1=button1_label,
- b2=button2_label,
- b4=button4_label)
- def test_setitem_slices(self):
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- box[:2, 0] = button1
- assert len(box.children) == 1
- assert button1 in box.children
- button1_label = button1.layout.grid_area
- assert box.layout.grid_template_areas == '''"{b1} . ."\n"{b1} . ."'''.format(b1=button1_label)
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- button2 = widgets.Button()
- box[:2, 1:] = button1
- assert len(box.children) == 1
- assert button1 in box.children
- button1_label = button1.layout.grid_area
- assert box.layout.grid_template_areas == '''". {b1} {b1}"\n". {b1} {b1}"'''.format(b1=button1_label)
- # replace button
- box[:2, 1:] = button2
- assert len(box.children) == 1
- assert button2 in box.children
- button2_label = button2.layout.grid_area
- assert box.layout.grid_template_areas == '''". {b1} {b1}"\n". {b1} {b1}"'''.format(b1=button2_label)
- def test_getitem_index(self):
- "test retrieving widget"
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- box[0, 0] = button1
- assert box[0, 0] is button1
- def test_getitem_slices(self):
- "test retrieving widgets with slices"
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- box[:2, 0] = button1
- assert box[:2, 0] is button1
- box = widgets.GridspecLayout(2, 3)
- button1 = widgets.Button()
- button2 = widgets.Button()
- box[0, 0] = button1
- box[1, 0] = button2
- assert box[0, 0] is button1
- assert box[1, 0] is button2
- with pytest.raises(TypeError, match="The slice spans"):
- button = box[:2, 0]
- class TestLayoutProperties(TestCase):
- """test mixin with layout properties"""
- class DummyTemplate(widgets.GridBox, LayoutProperties):
- location = traitlets.Instance(widgets.Widget, allow_none=True)
- def test_layout_updated_on_trait_change(self):
- "test whether respective layout traits are updated when traits change"
- template = self.DummyTemplate(width="100%")
- assert template.width == '100%'
- assert template.layout.width == '100%'
- template.width = 'auto'
- assert template.width == 'auto'
- assert template.layout.width == 'auto'
- def test_align_items_extra_options(self):
- template = self.DummyTemplate(align_items='top')
- assert template.align_items == 'top'
- assert template.layout.align_items == 'flex-start'
- template.align_items = 'bottom'
- assert template.align_items == 'bottom'
- assert template.layout.align_items == 'flex-end'
- def test_validate_properties(self):
- prop_obj = self.DummyTemplate()
- for prop in LayoutProperties.align_items.values:
- prop_obj.align_items = prop
- assert prop_obj.align_items == prop
- with pytest.raises(traitlets.TraitError):
- prop_obj.align_items = 'any default position'
|