Skip to content

Commit 7258f03

Browse files
authored
Merge pull request #2679 from jtpio/remove-mutable-dropdown
Drop support for Mapping types as Selection options
2 parents 78cdfcb + 5a73074 commit 7258f03

File tree

4 files changed

+52
-57
lines changed

4 files changed

+52
-57
lines changed

docs/source/examples/Widget List.ipynb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,13 @@
470470
"cell_type": "markdown",
471471
"metadata": {},
472472
"source": [
473-
"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`)."
473+
"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",
474+
"\n",
475+
"<div class=\"alert alert-info\">\n",
476+
"Changes in *ipywidgets 8*:\n",
477+
" \n",
478+
"Selection widgets no longer accept a dictionary of options. Pass a list of key-value pairs instead.\n",
479+
"</div>"
474480
]
475481
},
476482
{
@@ -639,11 +645,11 @@
639645
"outputs": [],
640646
"source": [
641647
"import datetime\n",
642-
"dates = [datetime.date(2015,i,1) for i in range(1,13)]\n",
648+
"dates = [datetime.date(2015, i, 1) for i in range(1, 13)]\n",
643649
"options = [(i.strftime('%b'), i) for i in dates]\n",
644650
"widgets.SelectionRangeSlider(\n",
645651
" options=options,\n",
646-
" index=(0,11),\n",
652+
" index=(0, 11),\n",
647653
" description='Months (2015)',\n",
648654
" disabled=False\n",
649655
")"

ipywidgets/widgets/tests/test_interaction.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -187,34 +187,17 @@ def test_dict():
187187
dict(a=5),
188188
dict(a=5, b='b', c=dict),
189189
]:
190-
c = interactive(f, d=d)
191-
w = c.children[0]
192-
check = dict(
193-
cls=widgets.Dropdown,
194-
description='d',
195-
value=next(iter(d.values())),
196-
options=d,
197-
_options_labels=tuple(d.keys()),
198-
_options_values=tuple(d.values()),
199-
)
200-
check_widget(w, **check)
190+
with pytest.raises(TypeError):
191+
c = interactive(f, d=d)
201192

202193

203194
def test_ordereddict():
204195
from collections import OrderedDict
205196
items = [(3, 300), (1, 100), (2, 200)]
206197
first = items[0][1]
207198
values = OrderedDict(items)
208-
c = interactive(f, lis=values)
209-
assert len(c.children) == 2
210-
d = dict(
211-
cls=widgets.Dropdown,
212-
value=first,
213-
options=values,
214-
_options_labels=("3", "1", "2"),
215-
_options_values=(300, 100, 200),
216-
)
217-
check_widgets(c, lis=d)
199+
with pytest.raises(TypeError):
200+
c = interactive(f, lis=values)
218201

219202
def test_iterable():
220203
def yield_values():
@@ -583,13 +566,14 @@ def test_multiple_selection():
583566
check_widget(w, value=(1, 2))
584567

585568
# dict style
586-
w.options = {1: 1}
587-
check_widget(w, options={1:1})
569+
with pytest.raises(TypeError):
570+
w = smw(options={1: 1})
588571

589572
# updating
573+
w.options = (1,)
590574
with pytest.raises(TraitError):
591575
w.value = (2,)
592-
check_widget(w, options={1:1})
576+
check_widget(w, options=(1,))
593577

594578

595579
def test_interact_noinspect():

ipywidgets/widgets/tests/test_widget_selection.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
# Distributed under the terms of the Modified BSD License.
33

44
import inspect
5-
import warnings
65
from unittest import TestCase
76

7+
import pytest
8+
89
from traitlets import TraitError
910

1011
from ipywidgets import Dropdown, SelectionSlider, Select
@@ -15,19 +16,29 @@ class TestDropdown(TestCase):
1516
def test_construction(self):
1617
Dropdown()
1718

18-
def test_deprecation_warning_mapping_options(self):
19-
with warnings.catch_warnings(record=True) as w:
20-
warnings.simplefilter("always")
21-
22-
# Clearing the internal __warningregistry__ seems to be required for
23-
# Python 2 (but not for Python 3)
24-
module = inspect.getmodule(Dropdown)
25-
getattr(module, '__warningregistry__', {}).clear()
26-
19+
def test_raise_mapping_options(self):
20+
with pytest.raises(TypeError):
2721
Dropdown(options={'One': 1, 'Two': 2, 'Three': 3})
28-
assert len(w) > 0
29-
assert issubclass(w[-1].category, DeprecationWarning)
30-
assert "Support for mapping types has been deprecated" in str(w[-1].message)
22+
23+
def test_setting_options_from_list(self):
24+
d = Dropdown()
25+
assert d.options == ()
26+
d.options = ['One', 'Two', 'Three']
27+
assert d.get_state('_options_labels') == {'_options_labels': ('One', 'Two', 'Three')}
28+
29+
def test_setting_options_from_list_tuples(self):
30+
d = Dropdown()
31+
assert d.options == ()
32+
d.options = [('One', 1), ('Two', 2), ('Three', 3)]
33+
assert d.get_state('_options_labels') == {'_options_labels': ('One', 'Two', 'Three')}
34+
d.value = 2
35+
assert d.get_state('index') == {'index': 1}
36+
37+
def test_setting_options_from_dict(self):
38+
d = Dropdown()
39+
assert d.options == ()
40+
with pytest.raises(TypeError):
41+
d.options = {'One': 1}
3142

3243

3344
class TestSelectionSlider(TestCase):

ipywidgets/widgets/widget_selection.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,11 @@
5252
_doc_snippets['multiple_selection_params'] = """
5353
options: dict or list
5454
The options for the dropdown. This can either be a list of values, e.g.
55-
``['Galileo', 'Brahe', 'Hubble']`` or ``[0, 1, 2]``, a list of
55+
``['Galileo', 'Brahe', 'Hubble']`` or ``[0, 1, 2]``, or a list of
5656
(label, value) pairs, e.g.
57-
``[('Galileo', 0), ('Brahe', 1), ('Hubble', 2)]``,
58-
or a dictionary mapping the labels to the values, e.g. ``{'Galileo': 0,
59-
'Brahe': 1, 'Hubble': 2}``. The labels are the strings that will be
60-
displayed in the UI, representing the actual Python choices, and should
61-
be unique. If this is a dictionary, the order in which they are
62-
displayed is not guaranteed.
57+
``[('Galileo', 0), ('Brahe', 1), ('Hubble', 2)]``.
58+
The labels are the strings that will be displayed in the UI,
59+
representing the actual Python choices, and should be unique.
6360
6461
index: iterable of int
6562
The indices of the options that are selected.
@@ -106,11 +103,8 @@ def _make_options(x):
106103
* an iterable of (label, value) pairs
107104
* an iterable of values, and labels will be generated
108105
"""
109-
# Check if x is a mapping of labels to values
110106
if isinstance(x, Mapping):
111-
import warnings
112-
warnings.warn("Support for mapping types has been deprecated and will be dropped in a future release.", DeprecationWarning)
113-
return tuple((str(k), v) for k, v in x.items())
107+
raise TypeError("options must be a list of values or a list of (label, value) tuples")
114108

115109
# only iterate once through the options.
116110
xlist = tuple(x)
@@ -132,10 +126,10 @@ def findvalue(array, value, compare = lambda x, y: x == y):
132126
class _Selection(DescriptionWidget, ValueWidget, CoreWidget):
133127
"""Base class for Selection widgets
134128
135-
``options`` can be specified as a list of values, list of (label, value)
136-
tuples, or a dict of {label: value}. The labels are the strings that will be
137-
displayed in the UI, representing the actual Python choices, and should be
138-
unique. If labels are not specified, they are generated from the values.
129+
``options`` can be specified as a list of values or a list of (label, value)
130+
tuples. The labels are the strings that will be displayed in the UI,
131+
representing the actual Python choices, and should be unique.
132+
If labels are not specified, they are generated from the values.
139133
140134
When programmatically setting the value, a reverse lookup is performed
141135
among the options to check that the value is valid. The reverse lookup uses
@@ -149,7 +143,7 @@ class _Selection(DescriptionWidget, ValueWidget, CoreWidget):
149143
index = Int(None, help="Selected index", allow_none=True).tag(sync=True)
150144

151145
options = Any((),
152-
help="""Iterable of values, (label, value) pairs, or a mapping of {label: value} pairs that the user can select.
146+
help="""Iterable of values or (label, value) pairs that the user can select.
153147
154148
The labels are the strings that will be displayed in the UI, representing the
155149
actual Python choices, and should be unique.
@@ -291,7 +285,7 @@ class _MultipleSelection(DescriptionWidget, ValueWidget, CoreWidget):
291285
index = TypedTuple(trait=Int(), help="Selected indices").tag(sync=True)
292286

293287
options = Any((),
294-
help="""Iterable of values, (label, value) pairs, or a mapping of {label: value} pairs that the user can select.
288+
help="""Iterable of values or (label, value) pairs that the user can select.
295289
296290
The labels are the strings that will be displayed in the UI, representing the
297291
actual Python choices, and should be unique.

0 commit comments

Comments
 (0)