Repository: streamlit/streamlit

Issue:
Create config option to set Mapbox API token
Create `mabox.token` config option


Discussion:

Resolving patch:
diff --git a/lib/streamlit/DeltaGenerator.py b/lib/streamlit/DeltaGenerator.py
--- a/lib/streamlit/DeltaGenerator.py
+++ b/lib/streamlit/DeltaGenerator.py
@@ -2310,6 +2310,15 @@ def map(self, element, data, zoom=None):
         This is a wrapper around st.deck_gl_chart to quickly create scatterplot
         charts on top of a map, with auto-centering and auto-zoom.
 
+        When using this method, we advise all users to use a personal Mapbox
+        token. This ensures the map tiles used in this chart are more
+        robust. You can do this with the mapbox.token config option.
+
+        To get a token for yourself, create an account at
+        https://mapbox.com. It's free! (for moderate usage levels) See
+        https://streamlit.io/docs/cli.html#view-all-config-options for more
+        info on how to set config options.
+
         Parameters
         ----------
         data : pandas.DataFrame, pandas.Styler, numpy.ndarray, Iterable, dict,
@@ -2349,6 +2358,15 @@ def deck_gl_chart(self, element, spec=None, **kwargs):
         (https://deck.gl/#/documentation), with a few small adaptations and
         some syntax sugar.
 
+        When using this method, we advise all users to use a personal Mapbox
+        token. This ensures the map tiles used in this chart are more
+        robust. You can do this with the mapbox.token config option.
+
+        To get a token for yourself, create an account at
+        https://mapbox.com. It's free! (for moderate usage levels) See
+        https://streamlit.io/docs/cli.html#view-all-config-options for more
+        info on how to set config options.
+
         Parameters
         ----------
 
diff --git a/lib/streamlit/ReportSession.py b/lib/streamlit/ReportSession.py
--- a/lib/streamlit/ReportSession.py
+++ b/lib/streamlit/ReportSession.py
@@ -349,6 +349,8 @@ def _maybe_enqueue_initialize_message(self):
             "global.maxCachedMessageAge"
         )
 
+        imsg.config.mapbox_token = config.get_option("mapbox.token")
+
         LOGGER.debug(
             "New browser connection: "
             "gather_usage_stats=%s, "
diff --git a/lib/streamlit/config.py b/lib/streamlit/config.py
--- a/lib/streamlit/config.py
+++ b/lib/streamlit/config.py
@@ -38,7 +38,6 @@
 
 LOGGER = get_logger(__name__)
 
-
 # Config System Global State #
 
 # Descriptions of each of the possible config sections.
@@ -189,7 +188,6 @@ def _delete_option(key):
 
 _create_section("global", "Global options that apply across all of Streamlit.")
 
-
 _create_option(
     "global.disableWatchdogWarning",
     description="""
@@ -217,7 +215,6 @@ def _delete_option(key):
     default_val="off",
 )
 
-
 _create_option(
     "global.showWarningOnDirectExecution",
     description="""
@@ -273,7 +270,6 @@ def _global_unit_test():
     type_=bool,
 )
 
-
 _create_option(
     "global.metrics",
     description="Whether to serve prometheus metrics from /metrics.",
@@ -282,7 +278,6 @@ def _global_unit_test():
     type_=bool,
 )
 
-
 _create_option(
     "global.minCachedMessageSize",
     description="""Only cache ForwardMsgs that are greater than or equal to
@@ -292,7 +287,6 @@ def _global_unit_test():
     type_=int,
 )  # 10k
 
-
 _create_option(
     "global.maxCachedMessageAge",
     description="""Expire cached ForwardMsgs whose age is greater than this
@@ -303,7 +297,6 @@ def _global_unit_test():
     type_=int,
 )
 
-
 # Config Section: Client #
 
 _create_section("client", "Settings for scripts that use Streamlit.")
@@ -325,7 +318,6 @@ def _global_unit_test():
     scriptable=True,
 )
 
-
 # Config Section: Runner #
 
 _create_section("runner", "Settings for how Streamlit executes your script")
@@ -365,7 +357,6 @@ def _global_unit_test():
 
 _create_section("server", "Settings for the Streamlit server")
 
-
 _create_option(
     "server.folderWatchBlacklist",
     description="""List of folders that should not be watched for changes. This
@@ -411,7 +402,8 @@ def _server_headless():
         os.getenv("IS_RUNNING_IN_STREAMLIT_EDITOR_PLUGIN") is not None
     )
     return (
-        is_live_save_on or (is_linux and has_display_env) or is_running_in_editor_plugin
+        is_live_save_on or (
+            is_linux and has_display_env) or is_running_in_editor_plugin
     )
 
 
@@ -497,9 +489,26 @@ def _browser_server_port():
     return get_option("server.port")
 
 
+# Config Section: Mapbox #
+
+_create_section("mapbox", "Mapbox configuration that is being used by DeckGL.")
+
+_create_option("mapbox.token",
+                description="""Configure Streamlit to use a custom Mapbox 
+                token for elements like st.deck_gl_chart and st.map. If you 
+                don't do this you'll be using Streamlit's own token, 
+                which has limitations and is not guaranteed to always work. 
+                To get a token for yourself, create an account at 
+                https://mapbox.com. It's free! (for moderate usage levels)""",
+                visibility="obfuscated",
+                default_val="pk.eyJ1IjoidGhpYWdvdCIsImEiOiJjamh3bm85NnkwMng4M3"
+                            "dydnNveWwzeWNzIn0.vCBDzNsEF2uFSFk2AM0WZQ")
+
+
 # Config Section: S3 #
 
-_create_section("s3", 'Configuration for when global.sharingMode is set to "s3".')
+_create_section("s3",
+                'Configuration for when global.sharingMode is set to "s3".')
 
 
 @_create_option("s3.bucket")
@@ -707,7 +716,8 @@ def append_newline():
                 append_comment("#")
                 append_comment("# " + click.style("DEPRECATED.", fg="yellow"))
                 append_comment(
-                    "# %s" % "\n".join(_clean_paragraphs(option.deprecation_text))
+                    "# %s" % "\n".join(
+                        _clean_paragraphs(option.deprecation_text))
                 )
                 append_comment(
                     "# This option will be removed on or after %s."
@@ -720,7 +730,8 @@ def append_newline():
             )
 
             if option_is_manually_set:
-                append_comment("# The value below was set in %s" % option.where_defined)
+                append_comment(
+                    "# The value below was set in %s" % option.where_defined)
 
             toml_setting = toml.dumps({key: option.value})
 
@@ -799,8 +810,9 @@ def _maybe_read_env_variable(value):
         variable.
 
     """
-    if isinstance(value, string_types) and value.startswith("env:"):  # noqa F821
-        var_name = value[len("env:") :]
+    if isinstance(value, string_types) and value.startswith(
+        "env:"):  # noqa F821
+        var_name = value[len("env:"):]
         env_var = os.environ.get(var_name)
 
         if env_var is None:
@@ -893,7 +905,8 @@ def _check_conflicts():
         both_are_set = is_manually_set("s3.accessKeyId") and is_manually_set(
             "s3.secretAccessKey"
         )
-        both_are_unset = _is_unset("s3.accessKeyId") and _is_unset("s3.secretAccessKey")
+        both_are_unset = _is_unset("s3.accessKeyId") and _is_unset(
+            "s3.secretAccessKey")
         assert both_are_set or both_are_unset, (
             "In config.toml, s3.accessKeyId and s3.secretAccessKey must "
             "either both be set or both be unset."


Test patch:
diff --git a/lib/tests/streamlit/config_test.py b/lib/tests/streamlit/config_test.py
--- a/lib/tests/streamlit/config_test.py
+++ b/lib/tests/streamlit/config_test.py
@@ -252,7 +252,7 @@ def test_delete_option(self):
 
     def test_sections_order(self):
         sections = sorted(
-            ["_test", u"browser", u"client", u"global", u"runner", u"s3", u"server"]
+            ["_test", u"browser", u"client", u"global", u"mapbox", u"runner", u"s3", u"server"]
         )
         keys = sorted(list(config._section_descriptions.keys()))
         self.assertEqual(sections, keys)
@@ -278,6 +278,7 @@ def test_config_option_keys(self):
                 u"runner.magicEnabled",
                 u"runner.installTracer",
                 u"runner.fixMatplotlib",
+                u"mapbox.token",
                 u"s3.accessKeyId",
                 u"s3.bucket",
                 u"s3.keyPrefix",