diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a30a7795c2..cda776186c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -605,9 +605,9 @@ export enum FeatureFlag { } ``` -`superset/config.py` contains `FEATURE_FLAGS` with their default values which will be -overwritten by -those specified under FEATURE_FLAGS in `superset_config.py`. +`superset/config.py` contains `DEFAULT_FEATURE_FLAGS` which will be overwritten by +those specified under FEATURE_FLAGS in `superset_config.py`. For example, `DEFAULT_FEATURE_FLAGS = { 'FOO': True, 'BAR': False }` in `superset/config.py` and `FEATURE_FLAGS = { 'BAR': True, 'BAZ': True }` in `superset_config.py` will result +in combined feature flags of `{ 'FOO': True, 'BAR': True, 'BAZ': True }`. The current status of the usability of each flag (stable vs testing, etc) can be found in `RESOURCES/FEATURE_FLAGS.md`. diff --git a/superset/cli.py b/superset/cli.py index 663d2bcfe3..15a8ce9e14 100755 --- a/superset/cli.py +++ b/superset/cli.py @@ -42,7 +42,7 @@ from superset.utils.urls import get_url_path logger = logging.getLogger(__name__) -feature_flags = config.FEATURE_FLAGS.copy() +feature_flags = config.DEFAULT_FEATURE_FLAGS.copy() feature_flags.update(config.FEATURE_FLAGS) feature_flags_func = config.GET_FEATURE_FLAGS_FUNC if feature_flags_func: diff --git a/superset/config.py b/superset/config.py index c769330c5e..ff73edd94e 100644 --- a/superset/config.py +++ b/superset/config.py @@ -310,8 +310,12 @@ LANGUAGES = {} # --------------------------------------------------- # Feature flags # --------------------------------------------------- -# Feature flags that are set by default go here. -FEATURE_FLAGS: Dict[str, bool] = { +# Feature flags that are set by default go here. Their values can be +# overwritten by those specified under FEATURE_FLAGS in superset_config.py +# For example, DEFAULT_FEATURE_FLAGS = { 'FOO': True, 'BAR': False } here +# and FEATURE_FLAGS = { 'BAR': True, 'BAZ': True } in superset_config.py +# will result in combined feature flags of { 'FOO': True, 'BAR': True, 'BAZ': True } +DEFAULT_FEATURE_FLAGS: Dict[str, bool] = { # allow dashboard to use sub-domains to send chart request # you also need ENABLE_CORS and # SUPERSET_WEBSERVER_DOMAINS for list of domains @@ -390,7 +394,7 @@ FEATURE_FLAGS: Dict[str, bool] = { } # Feature flags may also be set via 'SUPERSET_FEATURE_' prefixed environment vars. -FEATURE_FLAGS.update( +DEFAULT_FEATURE_FLAGS.update( { k[len("SUPERSET_FEATURE_") :]: parse_boolean_string(v) for k, v in os.environ.items() @@ -398,7 +402,11 @@ FEATURE_FLAGS.update( } ) +# This is merely a default. +FEATURE_FLAGS: Dict[str, bool] = {} + # A function that receives a dict of all feature flags +# (DEFAULT_FEATURE_FLAGS merged with FEATURE_FLAGS) # can alter it, and returns a similar dict. Note the dict of feature # flags passed to the function is a deepcopy of the dict in the config, # and can therefore be mutated without side-effect diff --git a/superset/utils/feature_flag_manager.py b/superset/utils/feature_flag_manager.py index fc42a398ab..88f19c2f46 100644 --- a/superset/utils/feature_flag_manager.py +++ b/superset/utils/feature_flag_manager.py @@ -28,7 +28,8 @@ class FeatureFlagManager: def init_app(self, app: Flask) -> None: self._get_feature_flags_func = app.config["GET_FEATURE_FLAGS_FUNC"] - self._feature_flags = app.config["FEATURE_FLAGS"].copy() + self._feature_flags = app.config["DEFAULT_FEATURE_FLAGS"] + self._feature_flags.update(app.config["FEATURE_FLAGS"]) def get_feature_flags(self) -> Dict[str, Any]: if self._get_feature_flags_func: diff --git a/tests/cli_tests.py b/tests/cli_tests.py index 911a9f348b..7ea4b9350b 100644 --- a/tests/cli_tests.py +++ b/tests/cli_tests.py @@ -82,7 +82,7 @@ def test_export_datasources_original(app_context, fs): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @mock.patch.dict( - "superset.config.FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True + "superset.config.DEFAULT_FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True ) def test_export_dashboards_versioned_export(app_context, fs): """ @@ -107,7 +107,7 @@ def test_export_dashboards_versioned_export(app_context, fs): @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") @mock.patch.dict( - "superset.config.FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True + "superset.config.DEFAULT_FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True ) def test_export_datasources_versioned_export(app_context, fs): """ @@ -131,7 +131,7 @@ def test_export_datasources_versioned_export(app_context, fs): @mock.patch.dict( - "superset.config.FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True + "superset.config.DEFAULT_FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True ) @mock.patch("superset.dashboards.commands.importers.dispatcher.ImportDashboardsCommand") def test_import_dashboards_versioned_export(import_dashboards_command, app_context, fs): @@ -170,7 +170,7 @@ def test_import_dashboards_versioned_export(import_dashboards_command, app_conte @mock.patch.dict( - "superset.config.FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True + "superset.config.DEFAULT_FEATURE_FLAGS", {"VERSIONED_EXPORT": True}, clear=True ) @mock.patch("superset.datasets.commands.importers.dispatcher.ImportDatasetsCommand") def test_import_datasets_versioned_export(import_datasets_command, app_context, fs):