def test_load_local_config(self): """Test that $CWD/.streamlit/config.toml is read, even if ~/.streamlit/config.toml is missing. """ local_config = """ [theme] base = "light" textColor = "#FFFFFF" """ local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") open_patch = patch("streamlit.config.open", mock_open(read_data=local_config)) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == local_config_path with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("#FFFFFF", config.get_option("theme.textColor")) self.assertIsNone(config.get_option("theme.font"))
def test_parsing_toml(self): """Test config._update_config_with_toml().""" # Some useful variables. DUMMY_VAL_1, DUMMY_VAL_2 = "Christopher", "Walken" DUMMY_DEFINITION = "<test definition>" # Create a dummy default option. config._create_option( "_test.tomlTest", description="This option tests the TOML parser.", default_val=DUMMY_VAL_1, ) config.get_config_options(force_reparse=True) self.assertEqual(config.get_option("_test.tomlTest"), DUMMY_VAL_1) self.assertEqual( config.get_where_defined("_test.tomlTest"), ConfigOption.DEFAULT_DEFINITION ) # Override it with some TOML NEW_TOML = ( """ [_test] tomlTest="%s" """ % DUMMY_VAL_2 ) config._update_config_with_toml(NEW_TOML, DUMMY_DEFINITION) self.assertEqual(config.get_option("_test.tomlTest"), DUMMY_VAL_2) self.assertEqual(config.get_where_defined("_test.tomlTest"), DUMMY_DEFINITION)
def test_config_options_warn_on_server_change(self, get_logger): """Test that a warning is logged if a user changes a config file in the server section.""" global_config_path = "/mock/home/folder/.streamlit/config.toml" makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == global_config_path mock_logger = get_logger() global_config = """ [server] address = "localhost" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() global_config = """ [server] address = "streamlit.io" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options(force_reparse=True) mock_logger.warning.assert_any_call( "An update to the [server] config option section was detected." " To have these changes be reflected, please restart streamlit." )
def test_config_options_removed_on_reparse(self): """Test that config options that are removed in a file are also removed from our _config_options dict.""" global_config_path = "/mock/home/folder/.streamlit/config.toml" makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == global_config_path global_config = """ [s3] bucket = "bucket" accessKeyId = "accessKeyId" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("bucket", config.get_option("s3.bucket")) self.assertEqual("accessKeyId", config.get_option("s3.accessKeyId")) global_config = """ [s3] accessKeyId = "accessKeyId" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options(force_reparse=True) self.assertEqual(None, config.get_option("s3.bucket")) self.assertEqual("accessKeyId", config.get_option("s3.accessKeyId"))
def test_load_local_config(self): """Test that $CWD/.streamlit/config.toml is read, even if ~/.streamlit/config.toml is missing. """ local_config = """ [s3] bucket = "local_bucket" accessKeyId = "local_accessKeyId" """ local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") open_patch = patch("streamlit.config.open", mock_open(read_data=local_config)) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == local_config_path with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("local_bucket", config.get_option("s3.bucket")) self.assertEqual("local_accessKeyId", config.get_option("s3.accessKeyId")) self.assertIsNone(config.get_option("s3.url"))
def test_parsing_env_vars_in_toml(self): """Test that environment variables get parsed in the TOML file.""" # Some useful variables. DEFAULT_VAL, DESIRED_VAL = "Christopher", "Walken" DUMMY_DEFINITION = "<test definition>" # Create a dummy default option. config._create_option( "_test.tomlTest", description="This option tests the TOML parser.", default_val=DEFAULT_VAL, ) config.get_config_options(force_reparse=True) self.assertEqual(config.get_option("_test.tomlTest"), DEFAULT_VAL) self.assertEqual( config.get_where_defined("_test.tomlTest"), ConfigOption.DEFAULT_DEFINITION ) os.environ["TEST_ENV_VAR"] = DESIRED_VAL # Override it with some TOML NEW_TOML = """ [_test] tomlTest="env:TEST_ENV_VAR" """ config._update_config_with_toml(NEW_TOML, DUMMY_DEFINITION) self.assertEqual(config.get_option("_test.tomlTest"), DESIRED_VAL) self.assertEqual(config.get_where_defined("_test.tomlTest"), DUMMY_DEFINITION)
def test_get_set_and_complex_config_options(self): """Verify that changing one option changes another, dependent one. This also implicitly tests simple and complex ConfigOptions as well as get_option() and set_option(). """ # Some useful variables. DUMMY_VAL_1, DUMMY_VAL_2, DUMMY_VAL_3 = "Steven", "Vincent", "Buscemi" # Set up both options. config._create_option( "_test.independentOption", description="This option can change at will", default_val=DUMMY_VAL_1, ) @config._create_option("_test.dependentOption") def _test_dependent_option(): """Depend on the value of _test.independentOption.""" return config.get_option("_test.independentOption") config.get_config_options(force_reparse=True) # Check that the default values are good. self.assertEqual(config.get_option("_test.independentOption"), DUMMY_VAL_1) self.assertEqual(config.get_option("_test.dependentOption"), DUMMY_VAL_1) self.assertEqual( config.get_where_defined("_test.independentOption"), ConfigOption.DEFAULT_DEFINITION, ) self.assertEqual( config.get_where_defined("_test.dependentOption"), ConfigOption.DEFAULT_DEFINITION, ) # Override the independent option. Both update! config.set_option("_test.independentOption", DUMMY_VAL_2) self.assertEqual(config.get_option("_test.independentOption"), DUMMY_VAL_2) self.assertEqual(config.get_option("_test.dependentOption"), DUMMY_VAL_2) self.assertEqual(config.get_where_defined("_test.independentOption"), config._USER_DEFINED) self.assertEqual( config.get_where_defined("_test.dependentOption"), ConfigOption.DEFAULT_DEFINITION, ) # Override the dependent option. Only that updates! config.set_option("_test.dependentOption", DUMMY_VAL_3) self.assertEqual(config.get_option("_test.independentOption"), DUMMY_VAL_2) self.assertEqual(config.get_option("_test.dependentOption"), DUMMY_VAL_3) self.assertEqual(config.get_where_defined("_test.independentOption"), config._USER_DEFINED) self.assertEqual(config.get_where_defined("_test.dependentOption"), config._USER_DEFINED)
def test_missing_config(self): """Test that we can initialize our config even if the file is missing.""" with patch("streamlit.config.os.path.exists") as path_exists: path_exists.return_value = False config.get_config_options() self.assertEqual(True, config.get_option("client.caching")) self.assertIsNone(config.get_option("s3.bucket"))
def test_load_global_local_config(self): """Test that $CWD/.streamlit/config.toml gets overlaid on ~/.streamlit/config.toml at parse time. """ global_config = """ [s3] bucket = "global_bucket" url = "global_url" """ local_config = """ [s3] bucket = "local_bucket" accessKeyId = "local_accessKeyId" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") global_open = mock_open(read_data=global_config) local_open = mock_open(read_data=local_config) open = mock_open() open.side_effect = [global_open.return_value, local_open.return_value] open_patch = patch("streamlit.config.open", open) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path in [ global_config_path, local_config_path, ] with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() # s3.bucket set in both local and global self.assertEqual("local_bucket", config.get_option("s3.bucket")) # s3.url is set in global, and not in local self.assertEqual("global_url", config.get_option("s3.url")) # s3.accessKeyId is set in local and not in global self.assertEqual("local_accessKeyId", config.get_option("s3.accessKeyId"))
def test_load_global_local_config(self): """Test that $CWD/.streamlit/config.toml gets overlaid on ~/.streamlit/config.toml at parse time. """ global_config = """ [theme] base = "dark" font = "sans serif" """ local_config = """ [theme] base = "light" textColor = "#FFFFFF" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") global_open = mock_open(read_data=global_config) local_open = mock_open(read_data=local_config) open = mock_open() open.side_effect = [global_open.return_value, local_open.return_value] open_patch = patch("streamlit.config.open", open) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path in [ global_config_path, local_config_path, ] with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() # theme.base set in both local and global self.assertEqual("light", config.get_option("theme.base")) # theme.font is set in global, and not in local self.assertEqual("sans serif", config.get_option("theme.font")) # theme.textColor is set in local and not in global self.assertEqual("#FFFFFF", config.get_option("theme.textColor"))
def test_load_global_local_flag_config(self): """Test that CLI flags have higher priority than both ~/.streamlit/config.toml and $CWD/.streamlit/config.toml at parse time. """ global_config = """ [s3] bucket = "global_bucket" url = "global_url" """ local_config = """ [s3] bucket = "local_bucket" accessKeyId = "local_accessKeyId" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") global_open = mock_open(read_data=global_config) local_open = mock_open(read_data=local_config) open = mock_open() open.side_effect = [global_open.return_value, local_open.return_value] open_patch = patch("streamlit.config.open", open) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path in [ global_config_path, local_config_path, ] with open_patch, makedirs_patch, pathexists_patch: config.get_config_options( options_from_flags={"s3.accessKeyId": "flag_accessKeyId"} ) self.assertEqual("local_bucket", config.get_option("s3.bucket")) self.assertEqual("global_url", config.get_option("s3.url")) self.assertEqual("flag_accessKeyId", config.get_option("s3.accessKeyId"))
def test_delete_option(self): # Create a dummy default option. config._create_option( "_test.testDeleteOption", description="This option tests the _delete_option function.", default_val="delete me!", ) config.get_config_options(force_reparse=True) self.assertEqual(config.get_option("_test.testDeleteOption"), "delete me!") config._delete_option("_test.testDeleteOption") with pytest.raises(RuntimeError) as e: config.get_option("_test.testDeleteOption") self.assertEqual( str(e.value), 'Config key "_test.testDeleteOption" not defined.' ) config._delete_option("_test.testDeleteOption")
def test_load_global_local_flag_config(self): """Test that CLI flags have higher priority than both ~/.streamlit/config.toml and $CWD/.streamlit/config.toml at parse time. """ global_config = """ [theme] base = "dark" font = "sans serif" textColor = "#FFFFFF" """ local_config = """ [theme] base = "light" font = "serif" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" local_config_path = os.path.join(os.getcwd(), ".streamlit/config.toml") global_open = mock_open(read_data=global_config) local_open = mock_open(read_data=local_config) open = mock_open() open.side_effect = [global_open.return_value, local_open.return_value] open_patch = patch("streamlit.config.open", open) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path in [ global_config_path, local_config_path, ] with open_patch, makedirs_patch, pathexists_patch: config.get_config_options( options_from_flags={"theme.font": "monospace"}) self.assertEqual("light", config.get_option("theme.base")) self.assertEqual("#FFFFFF", config.get_option("theme.textColor")) self.assertEqual("monospace", config.get_option("theme.font"))
def test_load_global_config(self): """Test that ~/.streamlit/config.toml is read.""" global_config = """ [s3] bucket = "global_bucket" url = "global_url" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == global_config_path with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("global_bucket", config.get_option("s3.bucket")) self.assertEqual("global_url", config.get_option("s3.url")) self.assertIsNone(config.get_option("s3.accessKeyId"))
def test_load_global_config(self): """Test that ~/.streamlit/config.toml is read.""" global_config = """ [theme] base = "dark" font = "sans serif" """ global_config_path = "/mock/home/folder/.streamlit/config.toml" open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) # patch streamlit.*.os.* instead of os.* for py35 compat makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == global_config_path with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("sans serif", config.get_option("theme.font")) self.assertIsNone(config.get_option("theme.textColor"))
def load_config_options(flag_options: Dict[str, Any]) -> None: """Load config options from config.toml files, then overlay the ones set by flag_options. The "streamlit run" command supports passing Streamlit's config options as flags. This function reads through the config options set via flag, massages them, and passes them to get_config_options() so that they overwrite config option defaults and those loaded from config.toml files. Parameters ---------- flag_options : Dict[str, Any] A dict of config options where the keys are the CLI flag version of the config option names. """ options_from_flags = { name.replace("_", "."): val for name, val in flag_options.items() if val is not None } # Force a reparse of config files (if they exist). The result is cached # for future calls. config.get_config_options(force_reparse=True, options_from_flags=options_from_flags)
def test_config_options_removed_on_reparse(self): """Test that config options that are removed in a file are also removed from our _config_options dict.""" global_config_path = "/mock/home/folder/.streamlit/config.toml" makedirs_patch = patch("streamlit.config.os.makedirs") makedirs_patch.return_value = True pathexists_patch = patch("streamlit.config.os.path.exists") pathexists_patch.side_effect = lambda path: path == global_config_path global_config = """ [theme] base = "dark" font = "sans serif" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options() self.assertEqual("dark", config.get_option("theme.base")) self.assertEqual("sans serif", config.get_option("theme.font")) global_config = """ [theme] base = "dark" """ open_patch = patch("streamlit.config.open", mock_open(read_data=global_config)) with open_patch, makedirs_patch, pathexists_patch: config.get_config_options(force_reparse=True) self.assertEqual("dark", config.get_option("theme.base")) self.assertEqual(None, config.get_option("theme.font"))
[global] sharingMode = "off" unitTest = true [browser] gatherUsageStats = false """ with patch( "streamlit.config.open", mock_open(read_data=CONFIG_FILE_CONTENTS), create=True), patch("streamlit.config.os.path.exists") as path_exists: # Import streamlit even if we don't do anything with it below as we want to # be sure to catch any instances of calling config.get_option() when # first importing a file. We disallow this because doing so means that we # miss config options set via flag or environment variable. import streamlit as st from streamlit import file_util from streamlit import config assert (not config._config_options ), "config.get_option() should not be called on file import!" config_path = file_util.get_streamlit_file_path("config.toml") path_exists.side_effect = lambda path: path == config_path # Force a reparse of our config options with CONFIG_FILE_CONTENTS so the # result gets cached. config.get_config_options(force_reparse=True)