Repository: streamlit/streamlit

Issue:
Comment out config options in `streamlit config show` if they are set to their default values
NOTE: we'll need to verify that this is indeed what we want the behavior to be before doing any work on this.

Consider the following sequence of actions a user might take
1. Populate a `config.toml` file by running `streamlit config show > ~/.streamlit/config.toml`
2. In the file, change the `server.port` config option to something other than 8501 (the default), let's say it's changed to 8502
3. Start up streamlit: `streamlit run my_app.py`
4. See the following message being logged and wonder why the port change apparently didn't take effect (note the server will be serving on http://localhost:8502)
```
  You can now view your Streamlit app in your browser.

  Local URL: http://localhost:8501
  Network URL: http://192.168.0.19:8501
```

The cause of this confusing behavior is that `streamlit config show` prints the current values of config options when run, but this can cause weird interactions with config options with default values when using the command to initially populate a `config.toml` file.

In the example above, the default value for `server.port` is 8501, and the default value for `browser.serverPort` is to match the value of `server.port`. `streamlit config show` prints the following
```toml
[server]
# The port where the server will listen for browser connections.
# Default: 8501
port = 8501

[browser]
# Port where users should point their browsers in order to connect to the app.
# This is used to: - Set the correct URL for CORS and XSRF protection purposes. - Show the URL on the terminal - Open the browser
# Default: whatever value is set in server.port.
serverPort = 8501
```
When the user uses the output of the command to initially populate a config file, then later changes `server.port`, the value of `browser.serverPort` is still explicitly set to 8501 within the config file, resulting in confusion. Most likely, the desired behavior was to have `browser.serverPort` use the default value instead of unintentionally fixing it in `config.toml`

If we instead print something like
```toml
[server]
# The port where the server will listen for browser connections.
# Default: 8501
# port = 8501

[browser]
# Port where users should point their browsers in order to connect to the app.
# This is used to: - Set the correct URL for CORS and XSRF protection purposes. - Show the URL on the terminal - Open the browser
# Default: whatever value is set in server.port.
# serverPort = 8501
```
there's no chance that some options are accidentally fixed within a config file when the intention was to use the default.


Discussion:
### CONTRIBUTION
Hello i will be contributing trying to solve this issue for hacktoberfest
btw this is my first time trying to code something larger than a function so if you want to help me my discord is akrer#5272

Are goals for this being discussed elsewhere? I like the `streamlit config show > ./.streamlit/config.toml` option for per-project configuration, but prefer the defaults commented out and option to ignore global, so I took a crack at this with a `streamlit config generate` CLI command for my own usecase.

I see this is already assigned so I won't open any PR, but these are the main changes: [generate CLI option](https://github.com/gerardrbentley/streamlit/commit/b10b46e95f8407cc187467c8a669bf396e5f5a3a), [de-click output text from show_config](https://github.com/gerardrbentley/streamlit/commit/4e55993a846cecf57a34edb2d4413b5a0fe18a6f)

What I think works as intended:
- `streamlit config generate --defaults`
  - Produces `./.strealit/config.toml` with all default values, all commented out. Ignores any global streamlit config or other cli args.
- `streamlit config generate --global.disableWatchdogWarning True`
  - Produces `./.streamlit/config.toml` with values that would be produced by `streamlit config show`. Default values are commented out, custom values (such as watchdogWarning in this case) are uncommented

What doesn't work:
- Derived values from CLI
  - `streamlit config generate --server.port 8502`
    - Produces uncommented `port = 8502`, but commented `#serverPort = 8502`
  - This does work with uncommented custom values from global `~/.streamlit/config.toml` port and serverPort
  - First thought would take some kind of callable for the `where_defined` of ConfigOption similar to the `_get_value_func`, so I didn't want to dig into the weeds...

Cheers! I could be off the mark on what general users want / do, so feel free to go with something more fitting.

Resolving patch:
diff --git a/lib/streamlit/config.py b/lib/streamlit/config.py
--- a/lib/streamlit/config.py
+++ b/lib/streamlit/config.py
@@ -355,7 +355,7 @@ def _logger_message_format() -> str:
     [Python's documentation](https://docs.python.org/2.6/library/logging.html#formatter-objects)
     for available attributes.
 
-    Default: None
+    Default: "%(asctime)s %(message)s"
     """
     if get_option("global.developmentMode"):
         from streamlit.logger import DEFAULT_LOG_MESSAGE
diff --git a/lib/streamlit/config_util.py b/lib/streamlit/config_util.py
--- a/lib/streamlit/config_util.py
+++ b/lib/streamlit/config_util.py
@@ -114,7 +114,9 @@ def append_newline():
             toml_setting = toml.dumps({key: option.value})
 
             if len(toml_setting) == 0:
-                toml_setting = "#%s =\n" % key
+                toml_setting = f"# {key} =\n"
+            elif not option_is_manually_set:
+                toml_setting = f"# {toml_setting}"
 
             append_setting(toml_setting)
 


Test patch:
diff --git a/lib/tests/streamlit/config_util_test.py b/lib/tests/streamlit/config_util_test.py
--- a/lib/tests/streamlit/config_util_test.py
+++ b/lib/tests/streamlit/config_util_test.py
@@ -15,7 +15,9 @@
 """Config Util Unittest."""
 import copy
 import textwrap
+import re
 import unittest
+from unittest.mock import patch
 
 from parameterized import parameterized
 
@@ -23,6 +25,7 @@
 from streamlit import config
 
 CONFIG_OPTIONS_TEMPLATE = config._config_options_template
+CONFIG_SECTION_DESCRIPTIONS = copy.deepcopy(config._section_descriptions)
 
 
 def create_config_options(overrides):
@@ -60,6 +63,30 @@ def test_clean_paragraphs(self):
         result = config_util._clean_paragraphs(input)
         self.assertEqual(truth, result)
 
+    @patch("streamlit.config_util.click.echo")
+    def test_default_config_options_commented_out(self, patched_echo):
+        config_options = create_config_options(
+            {
+                "server.address": "example.com",  # overrides default
+                "server.port": 8501,  # explicitly set to default
+            }
+        )
+
+        config_util.show_config(CONFIG_SECTION_DESCRIPTIONS, config_options)
+
+        [(args, _)] = patched_echo.call_args_list
+        # Remove the ascii escape sequences used to color terminal output.
+        output = re.compile(r"\x1b[^m]*m").sub("", args[0])
+        lines = set(output.split("\n"))
+
+        # Config options not explicitly set should be commented out.
+        assert "# runOnSave = false" in lines
+
+        # Config options explicitly set should *not* be commented out, even if
+        # they are set to their default values.
+        assert 'address = "example.com"' in lines
+        assert "port = 8501" in lines
+
     @parameterized.expand(
         [
             # Nothing changed.