Repository: streamlit/streamlit

Issue:
Can't call st.write() on a class that has repr_html
### Summary

When you call `st.write()` any **class** that has `_repr_html_` it throws an error.

(But you can call `st.write` on _instances_ of those classes just fine)


### Steps to reproduce

Code snippet:

```
import streamlit as st                                                                                   
import pandas as pd                                                                                      
                                                                                                         
x = pd.DataFrame([{"a": 1, "b": 2}, {"a": 3, "b": 4}])                                                   

"## st.text"
st.text(type(x))  # This works.                                                                          

"## st.write"
st.write(type(x))  # This doesn't work.                                                                  
```

**Expected behavior:**

`st.text` and `st.write` print the exact same thing.

**Actual behavior:**

You get this beautiful error:

![image](https://user-images.githubusercontent.com/690814/141047330-abbed5a5-76ab-4540-afe9-7e5980238e50.png)

Why this fails: `st.write` uses `_repr_html_()` when it's available. `DataFrame` contains that method, but it requires a `self` to be passed. So when you call it directly as `DataFrame._repr_html_()` there's no `self` and we get an exception.

**Solution:**

When `st.write()` receives a class as input we should just call `st.text()` on it.

You can use `inspect.isclass` to check for this.


### Is this a regression?

Yes, but not a recent one. It was introduced in https://github.com/streamlit/streamlit/pull/3154 , 7 months ago.

### Debug info

- Streamlit version: 1.1



Discussion:

Resolving patch:
diff --git a/lib/streamlit/elements/write.py b/lib/streamlit/elements/write.py
--- a/lib/streamlit/elements/write.py
+++ b/lib/streamlit/elements/write.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import inspect
 import json as json
 import types
 from typing import cast, Any, List, Tuple, Type
@@ -219,6 +220,9 @@ def flush_buffer():
             elif type_util.is_pydeck(arg):
                 flush_buffer()
                 self.dg.pydeck_chart(arg)
+            elif inspect.isclass(arg):
+                flush_buffer()
+                self.dg.text(arg)
             elif hasattr(arg, "_repr_html_"):
                 self.dg.markdown(
                     arg._repr_html_(),


Test patch:
diff --git a/lib/tests/streamlit/write_test.py b/lib/tests/streamlit/write_test.py
--- a/lib/tests/streamlit/write_test.py
+++ b/lib/tests/streamlit/write_test.py
@@ -206,6 +206,23 @@ def __str__(self):
                 "`1 * 2 - 3 = 4 \\`ok\\` !`", unsafe_allow_html=False
             )
 
+    def test_class(self):
+        """Test st.write with a class."""
+
+        class SomeClass(object):
+            pass
+
+        with patch("streamlit.delta_generator.DeltaGenerator.text") as p:
+            st.write(SomeClass)
+
+            p.assert_called_once_with(SomeClass)
+
+        with patch("streamlit.delta_generator.DeltaGenerator.text") as p:
+            empty_df = pd.DataFrame()
+            st.write(type(empty_df))
+
+            p.assert_called_once_with(type(empty_df))
+
     def test_exception(self):
         """Test st.write that raises an exception."""
         # We patch streamlit.exception to observe it, but we also make sure