Vehicle-Anti-Theft-Face-Rec.../venv/Lib/site-packages/ipywidgets/widgets/tests/test_interaction.py

732 lines
19 KiB
Python

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
"""Test interact and interactive."""
from __future__ import print_function
try:
from unittest.mock import patch
except ImportError:
from mock import patch
import os
from collections import OrderedDict
import pytest
import ipywidgets as widgets
from traitlets import TraitError
from ipywidgets import (interact, interact_manual, interactive,
interaction, Output)
from ipython_genutils.py3compat import annotate
#-----------------------------------------------------------------------------
# Utility stuff
#-----------------------------------------------------------------------------
from .utils import setup, teardown
def f(**kwargs):
pass
displayed = []
@pytest.fixture()
def clear_display():
global displayed
displayed = []
def record_display(*args):
displayed.extend(args)
#-----------------------------------------------------------------------------
# Actual tests
#-----------------------------------------------------------------------------
def check_widget(w, **d):
"""Check a single widget against a dict"""
for attr, expected in d.items():
if attr == 'cls':
assert w.__class__ is expected
else:
value = getattr(w, attr)
assert value == expected, "%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected)
# For numeric values, the types should match too
if isinstance(value, (int, float)):
tv = type(value)
te = type(expected)
assert tv is te, "type(%s.%s) = %r != %r" % (w.__class__.__name__, attr, tv, te)
def check_widgets(container, **to_check):
"""Check that widgets are created as expected"""
# build a widget dictionary, so it matches
widgets = {}
for w in container.children:
if not isinstance(w, Output):
widgets[w.description] = w
for key, d in to_check.items():
assert key in widgets
check_widget(widgets[key], **d)
def test_single_value_string():
a = u'hello'
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.Text,
description='a',
value=a,
)
def test_single_value_bool():
for a in (True, False):
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.Checkbox,
description='a',
value=a,
)
def test_single_value_float():
for a in (2.25, 1.0, -3.5, 0.0):
if not a:
expected_min = 0.0
expected_max = 1.0
elif a > 0:
expected_min = -a
expected_max = 3*a
else:
expected_min = 3*a
expected_max = -a
c = interactive(f, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.FloatSlider,
description='a',
value=a,
min=expected_min,
max=expected_max,
step=0.1,
readout=True,
)
def test_single_value_int():
for a in (1, 5, -3, 0):
if not a:
expected_min = 0
expected_max = 1
elif a > 0:
expected_min = -a
expected_max = 3*a
else:
expected_min = 3*a
expected_max = -a
c = interactive(f, a=a)
assert len(c.children) == 2
w = c.children[0]
check_widget(w,
cls=widgets.IntSlider,
description='a',
value=a,
min=expected_min,
max=expected_max,
step=1,
readout=True,
)
def test_list_str():
values = ['hello', 'there', 'guy']
first = values[0]
c = interactive(f, lis=values)
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=tuple(values),
_options_labels=tuple(values),
_options_values=tuple(values),
)
check_widgets(c, lis=d)
def test_list_int():
values = [3, 1, 2]
first = values[0]
c = interactive(f, lis=values)
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=tuple(values),
_options_labels=tuple(str(v) for v in values),
_options_values=tuple(values),
)
check_widgets(c, lis=d)
def test_list_tuple():
values = [(3, 300), (1, 100), (2, 200)]
first = values[0][1]
c = interactive(f, lis=values)
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=tuple(values),
_options_labels=("3", "1", "2"),
_options_values=(300, 100, 200),
)
check_widgets(c, lis=d)
def test_list_tuple_invalid():
for bad in [
(),
]:
with pytest.raises(ValueError):
print(bad) # because there is no custom message in assert_raises
c = interactive(f, tup=bad)
def test_dict():
for d in [
dict(a=5),
dict(a=5, b='b', c=dict),
]:
c = interactive(f, d=d)
w = c.children[0]
check = dict(
cls=widgets.Dropdown,
description='d',
value=next(iter(d.values())),
options=d,
_options_labels=tuple(d.keys()),
_options_values=tuple(d.values()),
)
check_widget(w, **check)
def test_ordereddict():
from collections import OrderedDict
items = [(3, 300), (1, 100), (2, 200)]
first = items[0][1]
values = OrderedDict(items)
c = interactive(f, lis=values)
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=values,
_options_labels=("3", "1", "2"),
_options_values=(300, 100, 200),
)
check_widgets(c, lis=d)
def test_iterable():
def yield_values():
yield 3
yield 1
yield 2
first = next(yield_values())
c = interactive(f, lis=yield_values())
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=(3, 1, 2),
_options_labels=("3", "1", "2"),
_options_values=(3, 1, 2),
)
check_widgets(c, lis=d)
def test_iterable_tuple():
values = [(3, 300), (1, 100), (2, 200)]
first = values[0][1]
c = interactive(f, lis=iter(values))
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=tuple(values),
_options_labels=("3", "1", "2"),
_options_values=(300, 100, 200),
)
check_widgets(c, lis=d)
def test_mapping():
from collections import Mapping, OrderedDict
class TestMapping(Mapping):
def __init__(self, values):
self.values = values
def __getitem__(self):
raise NotImplementedError
def __len__(self):
raise NotImplementedError
def __iter__(self):
raise NotImplementedError
def items(self):
return self.values
items = [(3, 300), (1, 100), (2, 200)]
first = items[0][1]
values = TestMapping(items)
c = interactive(f, lis=values)
assert len(c.children) == 2
d = dict(
cls=widgets.Dropdown,
value=first,
options=tuple(items),
_options_labels=("3", "1", "2"),
_options_values=(300, 100, 200),
)
check_widgets(c, lis=d)
def test_defaults():
@annotate(n=10)
def f(n, f=4.5, g=1):
pass
c = interactive(f)
check_widgets(c,
n=dict(
cls=widgets.IntSlider,
value=10,
),
f=dict(
cls=widgets.FloatSlider,
value=4.5,
),
g=dict(
cls=widgets.IntSlider,
value=1,
),
)
def test_default_values():
@annotate(n=10, f=(0, 10.), g=5, h=OrderedDict([('a',1), ('b',2)]), j=['hi', 'there'])
def f(n, f=4.5, g=1, h=2, j='there'):
pass
c = interactive(f)
check_widgets(c,
n=dict(
cls=widgets.IntSlider,
value=10,
),
f=dict(
cls=widgets.FloatSlider,
value=4.5,
),
g=dict(
cls=widgets.IntSlider,
value=5,
),
h=dict(
cls=widgets.Dropdown,
options=OrderedDict([('a',1), ('b',2)]),
value=2
),
j=dict(
cls=widgets.Dropdown,
options=('hi', 'there'),
value='there'
),
)
def test_default_out_of_bounds():
@annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there'])
def f(f='hi', h=5, j='other'):
pass
c = interactive(f)
check_widgets(c,
f=dict(
cls=widgets.FloatSlider,
value=5.,
),
h=dict(
cls=widgets.Dropdown,
options={'a': 1},
value=1,
),
j=dict(
cls=widgets.Dropdown,
options=('hi', 'there'),
value='hi',
),
)
def test_annotations():
@annotate(n=10, f=widgets.FloatText())
def f(n, f):
pass
c = interactive(f)
check_widgets(c,
n=dict(
cls=widgets.IntSlider,
value=10,
),
f=dict(
cls=widgets.FloatText,
),
)
def test_priority():
@annotate(annotate='annotate', kwarg='annotate')
def f(kwarg='default', annotate='default', default='default'):
pass
c = interactive(f, kwarg='kwarg')
check_widgets(c,
kwarg=dict(
cls=widgets.Text,
value='kwarg',
),
annotate=dict(
cls=widgets.Text,
value='annotate',
),
)
def test_decorator_kwarg(clear_display):
with patch.object(interaction, 'display', record_display):
@interact(a=5)
def foo(a):
pass
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.IntSlider,
value=5,
)
def test_interact_instancemethod(clear_display):
class Foo(object):
def show(self, x):
print(x)
f = Foo()
with patch.object(interaction, 'display', record_display):
g = interact(f.show, x=(1,10))
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.IntSlider,
value=5,
)
def test_decorator_no_call(clear_display):
with patch.object(interaction, 'display', record_display):
@interact
def foo(a='default'):
pass
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.Text,
value='default',
)
def test_call_interact(clear_display):
def foo(a='default'):
pass
with patch.object(interaction, 'display', record_display):
ifoo = interact(foo)
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.Text,
value='default',
)
def test_call_interact_on_trait_changed_none_return(clear_display):
def foo(a='default'):
pass
with patch.object(interaction, 'display', record_display):
ifoo = interact(foo)
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.Text,
value='default',
)
with patch.object(interaction, 'display', record_display):
w.value = 'called'
assert len(displayed) == 1
def test_call_interact_kwargs(clear_display):
def foo(a='default'):
pass
with patch.object(interaction, 'display', record_display):
ifoo = interact(foo, a=10)
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.IntSlider,
value=10,
)
def test_call_decorated_on_trait_change(clear_display):
"""test calling @interact decorated functions"""
d = {}
with patch.object(interaction, 'display', record_display):
@interact
def foo(a='default'):
d['a'] = a
return a
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.Text,
value='default',
)
# test calling the function directly
a = foo('hello')
assert a == 'hello'
assert d['a'] == 'hello'
# test that setting trait values calls the function
with patch.object(interaction, 'display', record_display):
w.value = 'called'
assert d['a'] == 'called'
assert len(displayed) == 2
assert w.value == displayed[-1]
def test_call_decorated_kwargs_on_trait_change(clear_display):
"""test calling @interact(foo=bar) decorated functions"""
d = {}
with patch.object(interaction, 'display', record_display):
@interact(a='kwarg')
def foo(a='default'):
d['a'] = a
return a
assert len(displayed) == 1
w = displayed[0].children[0]
check_widget(w,
cls=widgets.Text,
value='kwarg',
)
# test calling the function directly
a = foo('hello')
assert a == 'hello'
assert d['a'] == 'hello'
# test that setting trait values calls the function
with patch.object(interaction, 'display', record_display):
w.value = 'called'
assert d['a'] == 'called'
assert len(displayed) == 2
assert w.value == displayed[-1]
def test_fixed():
c = interactive(f, a=widgets.fixed(5), b='text')
assert len(c.children) == 2
w = c.children[0]
check_widget(w,
cls=widgets.Text,
value='text',
description='b',
)
def test_default_description():
c = interactive(f, b='text')
w = c.children[0]
check_widget(w,
cls=widgets.Text,
value='text',
description='b',
)
def test_custom_description():
d = {}
def record_kwargs(**kwargs):
d.clear()
d.update(kwargs)
c = interactive(record_kwargs, b=widgets.Text(value='text', description='foo'))
w = c.children[0]
check_widget(w,
cls=widgets.Text,
value='text',
description='foo',
)
w.value = 'different text'
assert d == {'b': 'different text'}
def test_interact_manual_button():
c = interact.options(manual=True).widget(f)
w = c.children[0]
check_widget(w, cls=widgets.Button)
def test_interact_manual_nocall():
callcount = 0
def calltest(testarg):
callcount += 1
c = interact.options(manual=True)(calltest, testarg=5).widget
c.children[0].value = 10
assert callcount == 0
def test_interact_call():
w = interact.widget(f)
w.update()
w = interact_manual.widget(f)
w.update()
def test_interact_options():
def f(x):
return x
w = interact.options(manual=False).options(manual=True)(f, x=21).widget
assert w.manual == True
w = interact_manual.options(manual=False).options()(x=21).widget(f)
assert w.manual == False
w = interact(x=21)().options(manual=True)(f).widget
assert w.manual == True
def test_interact_options_bad():
with pytest.raises(ValueError):
interact.options(bad="foo")
def test_int_range_logic():
irsw = widgets.IntRangeSlider
w = irsw(value=(2, 4), min=0, max=6)
check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
w.upper = 3
w.max = 3
check_widget(w, cls=irsw, value=(2, 3), min=0, max=3)
w.min = 0
w.max = 6
w.lower = 2
w.upper = 4
check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
w.value = (0, 1) #lower non-overlapping range
check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
w.value = (5, 6) #upper non-overlapping range
check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
w.lower = 2
check_widget(w, cls=irsw, value=(2, 6), min=0, max=6)
with pytest.raises(TraitError):
w.min = 7
with pytest.raises(TraitError):
w.max = -1
w = irsw(min=2, max=3, value=(2, 3))
check_widget(w, min=2, max=3, value=(2, 3))
w = irsw(min=100, max=200, value=(125, 175))
check_widget(w, value=(125, 175))
with pytest.raises(TraitError):
irsw(min=2, max=1)
def test_float_range_logic():
frsw = widgets.FloatRangeSlider
w = frsw(value=(.2, .4), min=0., max=.6)
check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
w.min = 0.
w.max = .6
w.lower = .2
w.upper = .4
check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
w.value = (0., .1) #lower non-overlapping range
check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
w.value = (.5, .6) #upper non-overlapping range
check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
w.lower = .2
check_widget(w, cls=frsw, value=(.2, .6), min=0., max=.6)
with pytest.raises(TraitError):
w.min = .7
with pytest.raises(TraitError):
w.max = -.1
w = frsw(min=2, max=3, value=(2.2, 2.5))
check_widget(w, min=2., max=3.)
with pytest.raises(TraitError):
frsw(min=.2, max=.1)
def test_multiple_selection():
smw = widgets.SelectMultiple
# degenerate multiple select
w = smw()
check_widget(w, value=tuple())
# don't accept random other value when no options
with pytest.raises(TraitError):
w.value = (2,)
check_widget(w, value=tuple())
# basic multiple select
w = smw(options=[(1, 1)], value=[1])
check_widget(w, cls=smw, value=(1,), options=((1, 1),))
# don't accept random other value
with pytest.raises(TraitError):
w.value = w.value + (2,)
check_widget(w, value=(1,))
# change options, which resets value
w.options = w.options + ((2, 2),)
check_widget(w, options=((1, 1), (2,2)), value=())
# change value
w.value = (1,2)
check_widget(w, value=(1, 2))
# dict style
w.options = {1: 1}
check_widget(w, options={1:1})
# updating
with pytest.raises(TraitError):
w.value = (2,)
check_widget(w, options={1:1})
def test_interact_noinspect():
a = u'hello'
c = interactive(print, a=a)
w = c.children[0]
check_widget(w,
cls=widgets.Text,
description='a',
value=a,
)
def test_get_interact_value():
from ipywidgets.widgets import ValueWidget
from traitlets import Unicode
class TheAnswer(ValueWidget):
_model_name = Unicode('TheAnswer')
description = Unicode()
def get_interact_value(self):
return 42
w = TheAnswer()
c = interactive(lambda v: v, v=w)
c.update()
assert c.result == 42
def test_state_schema():
from ipywidgets.widgets import IntSlider, Widget
import json
import jsonschema
s = IntSlider()
state = Widget.get_manager_state(drop_defaults=True)
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../', 'state.schema.json')) as f:
schema = json.load(f)
jsonschema.validate(state, schema)