Repository: streamlit/streamlit

Issue:
On rerun, faded elements are becoming opaque one by one. Instead they become opaque all at once.
Steps to repro:
1. Run `examples/reference.py`
2. When done, rerun it.

**Expected:** on rerun, all elements fade out and then become opaque one by one even before the run is done.
**Actual:** on rerun, all elements fade out and only become opaque when the entire run is done.

I believe this bug was introduced with the Sidebar code.


Discussion:

Resolving patch:
diff --git a/lib/streamlit/ConfigOption.py b/lib/streamlit/ConfigOption.py
--- a/lib/streamlit/ConfigOption.py
+++ b/lib/streamlit/ConfigOption.py
@@ -88,6 +88,10 @@ def _proxy_port():
     # that the option default was not overridden.
     DEFAULT_DEFINITION = "<default>"
 
+    # This is a special value for ConfigOption.where_defined which indicates
+    # that the options was defined by Streamlit's own code.
+    STREAMLIT_DEFINITION = "<streamlit>"
+
     def __init__(
         self,
         key,
diff --git a/lib/streamlit/config.py b/lib/streamlit/config.py
--- a/lib/streamlit/config.py
+++ b/lib/streamlit/config.py
@@ -583,7 +583,10 @@ def is_manually_set(option_name):
         True if the option has been set by the user.
 
     """
-    return get_where_defined(option_name) != ConfigOption.DEFAULT_DEFINITION
+    return get_where_defined(option_name) not in (
+        ConfigOption.DEFAULT_DEFINITION,
+        ConfigOption.STREAMLIT_DEFINITION
+    )
 
 
 def show_config():
diff --git a/lib/streamlit/server/Server.py b/lib/streamlit/server/Server.py
--- a/lib/streamlit/server/Server.py
+++ b/lib/streamlit/server/Server.py
@@ -15,6 +15,7 @@
 
 import logging
 import threading
+import socket
 import sys
 import errno
 from enum import Enum
@@ -100,41 +101,50 @@ def server_port_is_manually_set():
     return config.is_manually_set("server.port")
 
 
-def start_listening(app, call_count=0):
+def start_listening(app):
     """Takes the server start listening at the configured port.
 
-    In case the port is already taken it tries listening to the next available port.
-    It will error after MAX_PORT_SEARCH_RETRIES attempts.
+    In case the port is already taken it tries listening to the next available
+    port.  It will error after MAX_PORT_SEARCH_RETRIES attempts.
 
     """
 
-    port = config.get_option("server.port")
-    try:
-        app.listen(port)
-    except OSError as e:
-        if e.errno == errno.EADDRINUSE:
-            if call_count >= MAX_PORT_SEARCH_RETRIES:
-                raise RetriesExceeded(
-                    "Cannot start Streamlit server. Port %s is already in use, and Streamlit was unable to find a free port after %s attempts.",
-                    port,
-                    MAX_PORT_SEARCH_RETRIES,
-                )
-            if server_port_is_manually_set():
-                LOGGER.error("Port %s is already in use", port)
-                sys.exit(1)
-            else:
-                LOGGER.debug(
-                    "Port %s already in use, trying to use the next one.", port
-                )
-                port += 1
-                # Save port 3000 because it is used for the development server in the front end.
-                if port == 3000:
+    call_count = 0
+
+    while call_count < MAX_PORT_SEARCH_RETRIES:
+        port = config.get_option("server.port")
+
+        try:
+            app.listen(port)
+            break  # It worked! So let's break out of the loop.
+
+        except (OSError, socket.error) as e:
+            if e.errno == errno.EADDRINUSE:
+                if server_port_is_manually_set():
+                    LOGGER.error("Port %s is already in use", port)
+                    sys.exit(1)
+                else:
+                    LOGGER.debug(
+                        "Port %s already in use, trying to use the next one.",
+                        port)
                     port += 1
+                    # Save port 3000 because it is used for the development
+                    # server in the front end.
+                    if port == 3000:
+                        port += 1
+
+                    config._set_option(
+                        "server.port", port,
+                        config.ConfigOption.STREAMLIT_DEFINITION)
+                    call_count += 1
+            else:
+                raise
 
-                config._set_option("server.port", port, "server initialization")
-                start_listening(app, call_count + 1)
-        else:
-            raise
+    if call_count >= MAX_PORT_SEARCH_RETRIES:
+        raise RetriesExceeded(
+            "Cannot start Streamlit server. Port %s is already in use, and "
+            "Streamlit was unable to find a free port after %s attempts.",
+            port, MAX_PORT_SEARCH_RETRIES)
 
 
 class Server(object):
@@ -160,7 +170,8 @@ def __init__(self, ioloop, script_path, command_line):
 
         """
         if Server._singleton is not None:
-            raise RuntimeError("Server already initialized. Use .get_current() instead")
+            raise RuntimeError(
+                "Server already initialized. Use .get_current() instead")
 
         Server._singleton = self
 
@@ -240,7 +251,11 @@ def _create_app(self):
                         StaticFileHandler,
                         {"path": "%s/index.html" % static_path},
                     ),
-                    (r"/(.*)", StaticFileHandler, {"path": "%s/" % static_path}),
+                    (
+                        r"/(.*)",
+                        StaticFileHandler,
+                        {"path": "%s/" % static_path}
+                    ),
                 ]
             )
 
@@ -472,7 +487,8 @@ def on_message(self, payload):
             elif msg_type == "clear_cache":
                 self._session.handle_clear_cache_request()
             elif msg_type == "set_run_on_save":
-                self._session.handle_set_run_on_save_request(msg.set_run_on_save)
+                self._session.handle_set_run_on_save_request(
+                    msg.set_run_on_save)
             elif msg_type == "stop_report":
                 self._session.handle_stop_script_request()
             elif msg_type == "update_widgets":


Test patch:
diff --git a/lib/tests/streamlit/Server_test.py b/lib/tests/streamlit/Server_test.py
--- a/lib/tests/streamlit/Server_test.py
+++ b/lib/tests/streamlit/Server_test.py
@@ -330,13 +330,12 @@ def get_app(self):
 
     def test_rotates_a_hundred_ports(self):
         app = self.get_app()
-        with pytest.raises(SystemExit) as pytest_wrapped_e:
+        RetriesExceeded = streamlit.server.Server.RetriesExceeded
+        with pytest.raises(RetriesExceeded) as pytest_wrapped_e:
             start_listening(app)
-
-            assert pytest_wrapped_e.type == SystemExit
-            assert pytest_wrapped_e.value.code == errno.EADDRINUSE
-
-            assert app.listen.call_count == MAX_PORT_SEARCH_RETRIES
+            self.assertEqual(pytest_wrapped_e.type, SystemExit)
+            self.assertEqual(pytest_wrapped_e.value.code, errno.EADDRINUSE)
+            self.assertEqual(app.listen.call_count, MAX_PORT_SEARCH_RETRIES)
 
 
 class PortRotateOneTest(unittest.TestCase):
@@ -366,7 +365,7 @@ def test_rotates_one_port(
             PortRotateOneTest.which_port.assert_called_with(8502)
 
             patched__set_option.assert_called_with(
-                "server.port", 8501, "server initialization"
+                "server.port", 8501, config.ConfigOption.STREAMLIT_DEFINITION
             )