Repository: streamlit/streamlit

Issue:
st.radio with DataFrame fails on rerun
### Summary

When you pass a DataFrame as the options in an st.radio, every rerun throws an error (but the first run works).

### Steps to reproduce

Code snippet:

```
import streamlit as st
import pandas as pd

df = pd.DataFrame({'foo': ['one', 'two']})
st.radio('Foo', df)
```

1. Run the code above.
2. Press "R" to rerun the code above.

**Expected behavior:**

The rerun works, just like the first run.

**Actual behavior:**

The app hangs (stays in running state forever) and shows the error below in the terminal:

```
Exception in thread ScriptRunner.scriptThread:
Traceback (most recent call last):
  File "/usr/local/Cellar/python@3.9/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 954, in _bootstrap_inner
    self.run()
  File "/usr/local/Cellar/python@3.9/3.9.5/Frameworks/Python.framework/Versions/3.9/lib/python3.9/threading.py", line 892, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/script_runner.py", line 210, in _process_request_queue
    widget_states = self._session_state.as_widget_states()
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/state/session_state.py", line 560, in as_widget_states
    return self._new_widget_state.as_widget_states()
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/state/session_state.py", line 211, in as_widget_states
    states = [
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/state/session_state.py", line 214, in <listcomp>
    if self.get_serialized(widget_id)
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/state/session_state.py", line 190, in get_serialized
    serialized = metadata.serializer(item.value)
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/elements/radio.py", line 136, in serialize_radio
    return index_(options, v)
  File "/Users/[HIDDEN]/.venv/lib/python3.9/site-packages/streamlit/util.py", line 129, in index_
    raise ValueError("{} is not in iterable".format(str(x)))
ValueError: one is not in iterable
```


### Is this a regression?

yes 

Previous known working version = 0.84.0

### Debug info

- Streamlit version: 1.4.0
- Python version: 3.9.5

### Additional information

A meta-bug related to this: I'm not sure why this error is thrown in the terminal rather than inside the Streamlit app. Previously, our goal was to have _every_ error appear in the app, so you never had to check the terminal. It would be great to see if some code change unexpectedly changed this behavior.


Discussion:

Resolving patch:
diff --git a/e2e/scripts/st_radio.py b/e2e/scripts/st_radio.py
--- a/e2e/scripts/st_radio.py
+++ b/e2e/scripts/st_radio.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import pandas as pd
 import streamlit as st
 
 options = ("female", "male")
@@ -30,11 +31,15 @@
 i5 = st.radio("radio 5", options, horizontal=True)
 st.write("value 5:", i5)
 
+i6 = st.radio("radio 6", pd.DataFrame({"foo": list(options)}))
+st.write("value 6:", i6)
+
+
 if st._is_running_with_streamlit:
 
     def on_change():
         st.session_state.radio_changed = True
 
-    st.radio("radio 6", options, 1, key="radio6", on_change=on_change)
-    st.write("value 6:", st.session_state.radio6)
+    st.radio("radio 7", options, 1, key="radio7", on_change=on_change)
+    st.write("value 7:", st.session_state.radio7)
     st.write("radio changed:", "radio_changed" in st.session_state)
diff --git a/lib/streamlit/elements/radio.py b/lib/streamlit/elements/radio.py
--- a/lib/streamlit/elements/radio.py
+++ b/lib/streamlit/elements/radio.py
@@ -169,9 +169,9 @@ def deserialize_radio(ui_value, widget_id=""):
             return opt[idx] if len(opt) > 0 and opt[idx] is not None else None
 
         def serialize_radio(v):
-            if len(options) == 0:
+            if len(opt) == 0:
                 return 0
-            return index_(options, v)
+            return index_(opt, v)
 
         widget_state = register_widget(
             "radio",


Test patch: