diff --git a/docs/source/examples/Widget List.ipynb b/docs/source/examples/Widget List.ipynb index f28e03f1ba..a33c1e4038 100644 --- a/docs/source/examples/Widget List.ipynb +++ b/docs/source/examples/Widget List.ipynb @@ -470,7 +470,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "There are several widgets that can be used to display single selection lists, and two that can be used to select multiple values. All inherit from the same base class. You can specify the **enumeration of selectable options by passing a list** (options are either (label, value) pairs, or simply values for which the labels are derived by calling `str`)." + "There are several widgets that can be used to display single selection lists, and two that can be used to select multiple values. All inherit from the same base class. You can specify the **enumeration of selectable options by passing a list** (options are either (label, value) pairs, or simply values for which the labels are derived by calling `str`).\n", + "\n", + "
\n", + "Changes in *ipywidgets 8*:\n", + " \n", + "Selection widgets no longer accept a dictionary of options. Pass a list of key-value pairs instead.\n", + "
" ] }, { @@ -639,11 +645,11 @@ "outputs": [], "source": [ "import datetime\n", - "dates = [datetime.date(2015,i,1) for i in range(1,13)]\n", + "dates = [datetime.date(2015, i, 1) for i in range(1, 13)]\n", "options = [(i.strftime('%b'), i) for i in dates]\n", "widgets.SelectionRangeSlider(\n", " options=options,\n", - " index=(0,11),\n", + " index=(0, 11),\n", " description='Months (2015)',\n", " disabled=False\n", ")" diff --git a/ipywidgets/widgets/tests/test_interaction.py b/ipywidgets/widgets/tests/test_interaction.py index bf3d43e6c6..5002009b4f 100644 --- a/ipywidgets/widgets/tests/test_interaction.py +++ b/ipywidgets/widgets/tests/test_interaction.py @@ -187,17 +187,8 @@ def test_dict(): 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) + with pytest.raises(TypeError): + c = interactive(f, d=d) def test_ordereddict(): @@ -205,16 +196,8 @@ def test_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) + with pytest.raises(TypeError): + c = interactive(f, lis=values) def test_iterable(): def yield_values(): @@ -583,13 +566,14 @@ def test_multiple_selection(): check_widget(w, value=(1, 2)) # dict style - w.options = {1: 1} - check_widget(w, options={1:1}) + with pytest.raises(TypeError): + w = smw(options={1: 1}) # updating + w.options = (1,) with pytest.raises(TraitError): w.value = (2,) - check_widget(w, options={1:1}) + check_widget(w, options=(1,)) def test_interact_noinspect(): diff --git a/ipywidgets/widgets/tests/test_widget_selection.py b/ipywidgets/widgets/tests/test_widget_selection.py index 83dc3a3c4c..747dec1cba 100644 --- a/ipywidgets/widgets/tests/test_widget_selection.py +++ b/ipywidgets/widgets/tests/test_widget_selection.py @@ -2,9 +2,10 @@ # Distributed under the terms of the Modified BSD License. import inspect -import warnings from unittest import TestCase +import pytest + from traitlets import TraitError from ipywidgets import Dropdown, SelectionSlider, Select @@ -15,19 +16,29 @@ class TestDropdown(TestCase): def test_construction(self): Dropdown() - def test_deprecation_warning_mapping_options(self): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - - # Clearing the internal __warningregistry__ seems to be required for - # Python 2 (but not for Python 3) - module = inspect.getmodule(Dropdown) - getattr(module, '__warningregistry__', {}).clear() - + def test_raise_mapping_options(self): + with pytest.raises(TypeError): Dropdown(options={'One': 1, 'Two': 2, 'Three': 3}) - assert len(w) > 0 - assert issubclass(w[-1].category, DeprecationWarning) - assert "Support for mapping types has been deprecated" in str(w[-1].message) + + def test_setting_options_from_list(self): + d = Dropdown() + assert d.options == () + d.options = ['One', 'Two', 'Three'] + assert d.get_state('_options_labels') == {'_options_labels': ('One', 'Two', 'Three')} + + def test_setting_options_from_list_tuples(self): + d = Dropdown() + assert d.options == () + d.options = [('One', 1), ('Two', 2), ('Three', 3)] + assert d.get_state('_options_labels') == {'_options_labels': ('One', 'Two', 'Three')} + d.value = 2 + assert d.get_state('index') == {'index': 1} + + def test_setting_options_from_dict(self): + d = Dropdown() + assert d.options == () + with pytest.raises(TypeError): + d.options = {'One': 1} class TestSelectionSlider(TestCase): diff --git a/ipywidgets/widgets/widget_selection.py b/ipywidgets/widgets/widget_selection.py index 4cadd6d14a..65ce04e303 100644 --- a/ipywidgets/widgets/widget_selection.py +++ b/ipywidgets/widgets/widget_selection.py @@ -52,14 +52,11 @@ _doc_snippets['multiple_selection_params'] = """ options: dict or list The options for the dropdown. This can either be a list of values, e.g. - ``['Galileo', 'Brahe', 'Hubble']`` or ``[0, 1, 2]``, a list of + ``['Galileo', 'Brahe', 'Hubble']`` or ``[0, 1, 2]``, or a list of (label, value) pairs, e.g. - ``[('Galileo', 0), ('Brahe', 1), ('Hubble', 2)]``, - or a dictionary mapping the labels to the values, e.g. ``{'Galileo': 0, - 'Brahe': 1, 'Hubble': 2}``. The labels are the strings that will be - displayed in the UI, representing the actual Python choices, and should - be unique. If this is a dictionary, the order in which they are - displayed is not guaranteed. + ``[('Galileo', 0), ('Brahe', 1), ('Hubble', 2)]``. + The labels are the strings that will be displayed in the UI, + representing the actual Python choices, and should be unique. index: iterable of int The indices of the options that are selected. @@ -106,11 +103,8 @@ def _make_options(x): * an iterable of (label, value) pairs * an iterable of values, and labels will be generated """ - # Check if x is a mapping of labels to values if isinstance(x, Mapping): - import warnings - warnings.warn("Support for mapping types has been deprecated and will be dropped in a future release.", DeprecationWarning) - return tuple((str(k), v) for k, v in x.items()) + raise TypeError("options must be a list of values or a list of (label, value) tuples") # only iterate once through the options. xlist = tuple(x) @@ -132,10 +126,10 @@ def findvalue(array, value, compare = lambda x, y: x == y): class _Selection(DescriptionWidget, ValueWidget, CoreWidget): """Base class for Selection widgets - ``options`` can be specified as a list of values, list of (label, value) - tuples, or a dict of {label: value}. The labels are the strings that will be - displayed in the UI, representing the actual Python choices, and should be - unique. If labels are not specified, they are generated from the values. + ``options`` can be specified as a list of values or a list of (label, value) + tuples. The labels are the strings that will be displayed in the UI, + representing the actual Python choices, and should be unique. + If labels are not specified, they are generated from the values. When programmatically setting the value, a reverse lookup is performed among the options to check that the value is valid. The reverse lookup uses @@ -149,7 +143,7 @@ class _Selection(DescriptionWidget, ValueWidget, CoreWidget): index = Int(None, help="Selected index", allow_none=True).tag(sync=True) options = Any((), - help="""Iterable of values, (label, value) pairs, or a mapping of {label: value} pairs that the user can select. + help="""Iterable of values or (label, value) pairs that the user can select. The labels are the strings that will be displayed in the UI, representing the actual Python choices, and should be unique. @@ -291,7 +285,7 @@ class _MultipleSelection(DescriptionWidget, ValueWidget, CoreWidget): index = TypedTuple(trait=Int(), help="Selected indices").tag(sync=True) options = Any((), - help="""Iterable of values, (label, value) pairs, or a mapping of {label: value} pairs that the user can select. + help="""Iterable of values or (label, value) pairs that the user can select. The labels are the strings that will be displayed in the UI, representing the actual Python choices, and should be unique.