Repository: streamlit/streamlit

Issue:
Setting `default` on multiselect widget that uses pandas.Series as `options` causes an error
### Summary

[`st.multiselect`](https://docs.streamlit.io/en/stable/api.html?highlight=options#streamlit.multiselect) is supposed to accept `pandas.Series` objects as labels for the select options. Setting a `default` value while using `options=pandas.Series` leads to:

> StreamlitAPIException : Every Multiselect default value must exist in options 

### Steps to reproduce
Run the below code snippet.

Code snippet:

```python
import streamlit as st
import pandas as pd

names = pd.DataFrame({'labels':["Green","Yellow","Red","Blue"]})
nameSelect = st.multiselect(
    "What are your favorite colors",
    options=names['labels'],
    default=["Yellow"]
)
```

### Is this a regression?

Possibly a core regression.

### Debug info

- Streamlit version: 0.82.0
- Python version: 3.8.5
- OS version: Ubuntu 20.04.2 LTS
- Browser version: Firefox 89.0 (64-bit)

### Additional information

Original source: https://discuss.streamlit.io/t/setting-default-value-on-multiselect-that-uses-a-series-for-the-options/13630



Discussion:

Resolving patch:
diff --git a/lib/streamlit/elements/multiselect.py b/lib/streamlit/elements/multiselect.py
--- a/lib/streamlit/elements/multiselect.py
+++ b/lib/streamlit/elements/multiselect.py
@@ -19,6 +19,7 @@
 from streamlit.proto.MultiSelect_pb2 import MultiSelect as MultiSelectProto
 from streamlit.state.widgets import register_widget
 from streamlit.type_util import is_type, ensure_iterable
+
 from .form import current_form_id
 from .utils import check_callback_rules, check_session_state_rules
 
@@ -112,6 +113,9 @@ def _check_and_convert_to_indices(options, default_values):
                 else:
                     default_values = list(default_values)
 
+            if not isinstance(options, list):
+                options = list(options)
+
             for value in default_values:
                 if value not in options:
                     raise StreamlitAPIException(


Test patch:
diff --git a/lib/tests/streamlit/multiselect_test.py b/lib/tests/streamlit/multiselect_test.py
--- a/lib/tests/streamlit/multiselect_test.py
+++ b/lib/tests/streamlit/multiselect_test.py
@@ -99,6 +99,12 @@ def test_no_options(self, options):
         self.assertListEqual(c.default[:], [])
         self.assertEqual(c.options, [])
 
+    @parameterized.expand([(15, TypeError), ("str", TypeError)])
+    def test_invalid_options(self, options, expected):
+        """Test that it handles invalid options."""
+        with self.assertRaises(expected):
+            st.multiselect("the label", options)
+
     @parameterized.expand([(None, []), ([], []), (["Tea", "Water"], [1, 2])])
     def test_defaults(self, defaults, expected):
         """Test that valid default can be passed as expected."""
@@ -127,6 +133,50 @@ def test_default_types(self, defaults, expected):
         self.assertListEqual(c.default[:], expected)
         self.assertEqual(c.options, ["Coffee", "Tea", "Water"])
 
+    @parameterized.expand(
+        [
+            (
+                pd.Series(np.array(["green", "blue", "red", "yellow", "brown"])),
+                ["yellow"],
+                ["green", "blue", "red", "yellow", "brown"],
+                [3],
+            ),
+            (
+                np.array(["green", "blue", "red", "yellow", "brown"]),
+                ["green", "red"],
+                ["green", "blue", "red", "yellow", "brown"],
+                [0, 2],
+            ),
+            (
+                ("green", "blue", "red", "yellow", "brown"),
+                ["blue"],
+                ["green", "blue", "red", "yellow", "brown"],
+                [1],
+            ),
+            (
+                ["green", "blue", "red", "yellow", "brown"],
+                ["brown"],
+                ["green", "blue", "red", "yellow", "brown"],
+                [4],
+            ),
+            (
+                pd.DataFrame({"col1": ["male", "female"], "col2": ["15", "10"]}),
+                ["male", "female"],
+                ["male", "female"],
+                [0, 1],
+            ),
+        ]
+    )
+    def test_options_with_default_types(
+        self, options, defaults, expected_options, expected_default
+    ):
+        st.multiselect("label", options, defaults)
+
+        c = self.get_delta_from_queue().new_element.multiselect
+        self.assertEqual(c.label, "label")
+        self.assertListEqual(c.default[:], expected_default)
+        self.assertEqual(c.options, expected_options)
+
     @parameterized.expand(
         [
             (["Tea", "Vodka", None], StreamlitAPIException),