123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- # Copyright (c) Jupyter Development Team.
- # Distributed under the terms of the Modified BSD License.
- """Test trait types of the widget packages."""
- import array
- import datetime as dt
- import pytest
- from unittest import TestCase
- from traitlets import HasTraits, Int, TraitError
- from traitlets.tests.test_traitlets import TraitTestBase
- from ipywidgets import Color, NumberFormat
- from ipywidgets.widgets.widget import _remove_buffers, _put_buffers
- from ipywidgets.widgets.trait_types import date_serialization, TypedTuple
- class NumberFormatTrait(HasTraits):
- value = NumberFormat(".3f")
- class TestNumberFormat(TraitTestBase):
- obj = NumberFormatTrait()
- _good_values = [
- '.2f', '.0%', '($.2f', '+20', '.^20', '.2s', '#x', ',.2r',
- ' .2f', '.2', ''
- ]
- _bad_values = [52, False, 'broken', '..2f', '.2a']
- class ColorTrait(HasTraits):
- value = Color("black")
- class TestColor(TraitTestBase):
- obj = ColorTrait()
- _good_values = [
- "blue", # valid color name
- "#AA0", # single digit hex
- "#FFFFFF", # double digit hex
- "transparent", # special color name
- '#aaaa', # single digit hex with alpha
- '#ffffffff', # double digit hex with alpha
- 'rgb(0, 0, 0)', # rgb
- 'rgb( 20,70,50 )', # rgb with spaces
- 'rgba(10,10,10, 0.5)', # rgba with float alpha
- 'rgba(255, 255, 255, 255)', # out of bounds alpha (spec says clamp to 1)
- 'hsl(0.0, .0, 0)', # hsl
- 'hsl( 0.5,0.3,0 )', # hsl with spaces
- 'hsla(10,10,10, 0.5)', # rgba with float alpha
- ]
- _bad_values = [
- "vanilla", "blues", # Invald color names
- 1.2, 0.0, # Should fail with float input
- 0, 1, 2, # Should fail with int input
- 'rgb(0.4, 512, -40)',
- 'hsl(0.4, 512, -40)',
- 'rgba(0, 0, 0)',
- 'hsla(0, 0, 0)',
- None,
- ]
- class ColorTraitWithNone(HasTraits):
- value = Color("black", allow_none=True)
- class TestColorWithNone(TraitTestBase):
- obj = ColorTraitWithNone()
- _good_values = TestColor._good_values + [None]
- _bad_values = list(filter(lambda v: v is not None, TestColor._bad_values))
- class TestDateSerialization(TestCase):
- def setUp(self):
- self.to_json = date_serialization['to_json']
- self.dummy_manager = None
- def test_serialize_none(self):
- self.assertIs(self.to_json(None, self.dummy_manager), None)
- def test_serialize_date(self):
- date = dt.date(1900, 2, 18)
- expected = {
- 'year': 1900,
- 'month': 1,
- 'date': 18
- }
- self.assertEqual(self.to_json(date, self.dummy_manager), expected)
- class TestDateDeserialization(TestCase):
- def setUp(self):
- self.from_json = date_serialization['from_json']
- self.dummy_manager = None
- def test_deserialize_none(self):
- self.assertIs(self.from_json(None, self.dummy_manager), None)
- def test_deserialize_date(self):
- serialized_date = {
- 'year': 1900,
- 'month': 1,
- 'date': 18
- }
- expected = dt.date(1900, 2, 18)
- self.assertEqual(
- self.from_json(serialized_date, self.dummy_manager),
- expected
- )
- class TestBuffers(TestCase):
- def test_remove_and_put_buffers(self):
- mv1 = memoryview(b'test1')
- mv2 = memoryview(b'test2')
- state = {'plain': [0, 'text'], # should not get removed
- 'x': {'ar': mv1}, # should result in an empty dict
- 'y': {'shape': (10, 10), 'data': mv1},
- 'z': (mv1, mv2), # tests tuple assigment
- 'top': mv1, # test a top level removal
- 'deep': {'a': 1, 'b':[0,{'deeper':mv2}]}} # deeply nested
- plain = state['plain']
- x = state['x']
- y = state['y']
- y_shape = y['shape']
- state_before = state
- state, buffer_paths, buffers = _remove_buffers(state)
- # check if buffers are removed
- self.assertIn('plain', state)
- self.assertIn('shape', state['y'])
- self.assertNotIn('ar', state['x'])
- self.assertEqual(state['x'], {})
- self.assertNotIn('data', state['y'])
- self.assertNotIn(mv1, state['z'])
- self.assertNotIn(mv1, state['z'])
- self.assertNotIn('top', state)
- self.assertIn('deep', state)
- self.assertIn('b', state['deep'])
- self.assertNotIn('deeper', state['deep']['b'][1])
- # check that items that didn't need change aren't touched
- self.assertIsNot(state, state_before)
- self.assertIs(state['plain'], plain)
- self.assertIsNot(state['x'], x)
- self.assertIsNot(state['y'], y)
- self.assertIs(state['y']['shape'], y_shape)
- # check that the buffer paths really point to the right buffer
- for path, buffer in [(['x', 'ar'], mv1), (['y', 'data'], mv1), (['z', 0], mv1), (['z', 1], mv2),\
- (['top'], mv1), (['deep', 'b', 1, 'deeper'], mv2)]:
- self.assertIn(path, buffer_paths, "%r not in path" % path)
- index = buffer_paths.index(path)
- self.assertEqual(buffer, buffers[index])
- # and check that we can put it back together again
- _put_buffers(state, buffer_paths, buffers)
- # we know that tuples get converted to list, so help the comparison by changing the tuple to a list
- state_before['z'] = list(state_before['z'])
- self.assertEqual(state_before, state)
- def test_typed_tuple_uninitialized_ints():
- class TestCase(HasTraits):
- value = TypedTuple(trait=Int())
- obj = TestCase()
- assert obj.value == ()
- def test_typed_tuple_init_ints():
- class TestCase(HasTraits):
- value = TypedTuple(trait=Int())
- obj = TestCase(value=(1, 2, 3))
- assert obj.value == (1, 2, 3)
- def test_typed_tuple_set_ints():
- class TestCase(HasTraits):
- value = TypedTuple(trait=Int())
- obj = TestCase()
- obj.value = (1, 2, 3)
- assert obj.value == (1, 2, 3)
- def test_typed_tuple_default():
- class TestCase(HasTraits):
- value = TypedTuple(default_value=(1, 2, 3))
- obj = TestCase()
- assert obj.value == (1, 2, 3)
- def test_typed_tuple_mixed_default():
- class TestCase(HasTraits):
- value = TypedTuple(default_value=(1, 2, 'foobar'))
- obj = TestCase()
- assert obj.value == (1, 2, 'foobar')
- def test_typed_tuple_bad_default():
- class TestCase(HasTraits):
- value = TypedTuple(trait=Int(), default_value=(1, 2, 'foobar'))
- with pytest.raises(TraitError):
- obj = TestCase()
- a = obj.value # a read might be needed to trigger default validation
- def test_typed_tuple_bad_set():
- class TestCase(HasTraits):
- value = TypedTuple(trait=Int())
- obj = TestCase()
- with pytest.raises(TraitError):
- obj.value = (1, 2, 'foobar')
- def test_typed_tuple_positional_trait():
- class TestCase(HasTraits):
- value = TypedTuple(Int())
- obj = TestCase(value=(1, 2, 3))
- assert obj.value == (1, 2, 3)
- def test_typed_tuple_positional_default():
- class TestCase(HasTraits):
- value = TypedTuple((1, 2, 3))
- obj = TestCase()
- assert obj.value == (1, 2, 3)
|