You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2025/07/28 04:16:42 UTC

(superset) branch config_refactor created (now 5fa6d1d43c)

This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a change to branch config_refactor
in repository https://gitbox.apache.org/repos/asf/superset.git


      at 5fa6d1d43c chore: proper current_app.config proxy usage

This branch includes the following new commits:

     new 5fa6d1d43c chore: proper current_app.config proxy usage

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(superset) 01/01: chore: proper current_app.config proxy usage

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch config_refactor
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 5fa6d1d43c489ef112ffc2e0623d9c40bb40de82
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Sun Jul 27 20:58:47 2025 -0700

    chore: proper current_app.config proxy usage
---
 superset/available_domains/api.py  |  5 ++--
 superset/connectors/sqla/models.py |  3 +--
 superset/models/core.py            | 30 ++++++++++++------------
 superset/models/helpers.py         | 11 +++++----
 superset/sql_lab.py                |  2 +-
 superset/sqllab/api.py             |  6 ++---
 superset/views/base.py             | 47 +++++++++++++++++++++++---------------
 7 files changed, 56 insertions(+), 48 deletions(-)

diff --git a/superset/available_domains/api.py b/superset/available_domains/api.py
index 0b8253d942..1e90f1ff4b 100644
--- a/superset/available_domains/api.py
+++ b/superset/available_domains/api.py
@@ -16,10 +16,9 @@
 # under the License.
 import logging
 
-from flask import Response
+from flask import current_app, Response
 from flask_appbuilder.api import expose, protect, safe
 
-from superset import conf
 from superset.available_domains.schemas import AvailableDomainsSchema
 from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP
 from superset.extensions import event_logger
@@ -70,6 +69,6 @@ class AvailableDomainsRestApi(BaseSupersetApi):
               $ref: '#/components/responses/403'
         """
         result = self.available_domains_schema.dump(
-            {"domains": conf.get("SUPERSET_WEBSERVER_DOMAINS")}
+            {"domains": current_app.config.get("SUPERSET_WEBSERVER_DOMAINS")}
         )
         return self.response(200, result=result)
diff --git a/superset/connectors/sqla/models.py b/superset/connectors/sqla/models.py
index 5bbafda72d..a31892c8fd 100644
--- a/superset/connectors/sqla/models.py
+++ b/superset/connectors/sqla/models.py
@@ -111,10 +111,9 @@ from superset.superset_typing import (
 from superset.utils import core as utils, json
 from superset.utils.backports import StrEnum
 
-config = app.config
+config = app.config  # TODO-CONF: module-scoped config usage with extracted values
 metadata = Model.metadata  # pylint: disable=no-member
 logger = logging.getLogger(__name__)
-ADVANCED_DATA_TYPES = config["ADVANCED_DATA_TYPES"]
 VIRTUAL_TABLE_ALIAS = "virtual_table"
 
 # a non-exhaustive set of additive metrics
diff --git a/superset/models/core.py b/superset/models/core.py
index 0a5bb515e0..35bbb2ebc6 100755
--- a/superset/models/core.py
+++ b/superset/models/core.py
@@ -36,7 +36,7 @@ import numpy
 import pandas as pd
 import sqlalchemy as sqla
 import sshtunnel
-from flask import g
+from flask import current_app, g
 from flask_appbuilder import Model
 from marshmallow.exceptions import ValidationError
 from sqlalchemy import (
@@ -61,7 +61,7 @@ from sqlalchemy.pool import NullPool
 from sqlalchemy.schema import UniqueConstraint
 from sqlalchemy.sql import ColumnElement, expression, Select
 
-from superset import app, db, db_engine_specs, is_feature_enabled
+from superset import db, db_engine_specs, is_feature_enabled
 from superset.commands.database.exceptions import DatabaseInvalidError
 from superset.constants import LRU_CACHE_MAX_SIZE, PASSWORD_MASK
 from superset.databases.utils import make_url_safe
@@ -90,10 +90,9 @@ from superset.utils.oauth2 import (
     OAuth2ClientConfigSchema,
 )
 
-config = app.config
-custom_password_store = config["SQLALCHEMY_CUSTOM_PASSWORD_STORE"]
-stats_logger = config["STATS_LOGGER"]
-log_query = config["QUERY_LOGGER"]
+# Shorter alias for current_app.config
+conf = current_app.config
+
 metadata = Model.metadata  # pylint: disable=no-member
 logger = logging.getLogger(__name__)
 
@@ -101,8 +100,6 @@ if TYPE_CHECKING:
     from superset.databases.ssh_tunnel.models import SSHTunnel
     from superset.models.sql_lab import Query
 
-DB_CONNECTION_MUTATOR = config["DB_CONNECTION_MUTATOR"]
-
 
 class KeyValue(Model):  # pylint: disable=too-few-public-methods
     """Used for any type of key-value store"""
@@ -395,6 +392,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
 
     def set_sqlalchemy_uri(self, uri: str) -> None:
         conn = make_url_safe(uri.strip())
+        custom_password_store = conf["SQLALCHEMY_CUSTOM_PASSWORD_STORE"]
         if conn.password != PASSWORD_MASK and not custom_password_store:
             # do not over-write the password with the password mask
             self.password = conn.password
@@ -464,7 +462,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
                     ssh_context,
                 )
 
-            engine_context_manager = config["ENGINE_CONTEXT_MANAGER"]
+            engine_context_manager = conf["ENGINE_CONTEXT_MANAGER"]
             with engine_context_manager(self, catalog, schema):
                 with check_for_oauth2(self):
                     yield self._get_sqla_engine(
@@ -533,7 +531,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
 
         self.update_params_from_encrypted_extra(engine_kwargs)
 
-        if DB_CONNECTION_MUTATOR:
+        if DB_CONNECTION_MUTATOR := conf["DB_CONNECTION_MUTATOR"]:  # noqa: N806
             source = source or get_query_source_from_request()
 
             sqlalchemy_url, engine_kwargs = DB_CONNECTION_MUTATOR(
@@ -654,8 +652,8 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
           on the group of queries as a whole. Here the called passes the context
           as to whether the SQL is split or already.
         """  # noqa: E501
-        sql_mutator = config["SQL_QUERY_MUTATOR"]
-        if sql_mutator and (is_split == config["MUTATE_AFTER_SPLIT"]):
+        sql_mutator = conf["SQL_QUERY_MUTATOR"]
+        if sql_mutator and (is_split == conf["MUTATE_AFTER_SPLIT"]):
             return sql_mutator(
                 sql_,
                 security_manager=security_manager,
@@ -674,6 +672,8 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
         with self.get_sqla_engine(catalog=catalog, schema=schema) as engine:
             engine_url = engine.url
 
+        log_query = conf["QUERY_LOGGER"]
+
         def _log_query(sql: str) -> None:
             if log_query:
                 log_query(
@@ -1050,9 +1050,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
             allowed_databases = literal_eval(allowed_databases)
 
         if hasattr(g, "user"):
-            extra_allowed_databases = config["ALLOWED_USER_CSV_SCHEMA_FUNC"](
-                self, g.user
-            )
+            extra_allowed_databases = conf["ALLOWED_USER_CSV_SCHEMA_FUNC"](self, g.user)
             allowed_databases += extra_allowed_databases
         return set(allowed_databases)
 
@@ -1064,7 +1062,7 @@ class Database(Model, AuditMixinNullable, ImportExportMixin):  # pylint: disable
             # if the URI is invalid, ignore and return a placeholder url
             # (so users see 500 less often)
             return "dialect://invalid_uri"
-        if custom_password_store:
+        if custom_password_store := conf["SQLALCHEMY_CUSTOM_PASSWORD_STORE"]:
             conn = conn.set(password=custom_password_store(conn))
         else:
             conn = conn.set(password=self.password)
diff --git a/superset/models/helpers.py b/superset/models/helpers.py
index 6b7c07b784..9d7720a275 100644
--- a/superset/models/helpers.py
+++ b/superset/models/helpers.py
@@ -35,7 +35,7 @@ import pandas as pd
 import pytz
 import sqlalchemy as sa
 import yaml
-from flask import g
+from flask import current_app, g
 from flask_appbuilder import Model
 from flask_appbuilder.models.decorators import renders
 from flask_appbuilder.models.mixins import AuditMixin
@@ -52,7 +52,7 @@ from sqlalchemy.sql.expression import Label, Select, TextAsFrom
 from sqlalchemy.sql.selectable import Alias, TableClause
 from sqlalchemy_utils import UUIDType
 
-from superset import app, db, is_feature_enabled
+from superset import db, is_feature_enabled
 from superset.advanced_data_type.types import AdvancedDataTypeResponse
 from superset.common.db_query_status import QueryStatus
 from superset.common.utils.time_range_utils import get_since_until_from_time_range
@@ -97,12 +97,11 @@ if TYPE_CHECKING:
     from superset.models.core import Database
 
 
-config = app.config
+config = current_app.config
 logger = logging.getLogger(__name__)
 
 VIRTUAL_TABLE_ALIAS = "virtual_table"
 SERIES_LIMIT_SUBQ_ALIAS = "series_limit"
-ADVANCED_DATA_TYPES = config["ADVANCED_DATA_TYPES"]
 
 
 def validate_adhoc_subquery(
@@ -1868,6 +1867,10 @@ class ExploreMixin:  # pylint: disable=too-many-public-methods
                     is_list_target=is_list_target,
                     db_engine_spec=db_engine_spec,
                 )
+
+                # Get ADVANCED_DATA_TYPES from config when needed
+                ADVANCED_DATA_TYPES = current_app.config.get("ADVANCED_DATA_TYPES", {})  # noqa: N806
+
                 if (
                     col_advanced_data_type != ""
                     and feature_flag_manager.is_feature_enabled(
diff --git a/superset/sql_lab.py b/superset/sql_lab.py
index 57b6410ece..21d655d6f7 100644
--- a/superset/sql_lab.py
+++ b/superset/sql_lab.py
@@ -72,7 +72,7 @@ from superset.utils.rls import apply_rls
 if TYPE_CHECKING:
     from superset.models.core import Database
 
-config = app.config
+config = app.config  # TODO-CONF: module-scoped config usage with extracted values
 stats_logger = config["STATS_LOGGER"]
 SQLLAB_TIMEOUT = config["SQLLAB_ASYNC_TIME_LIMIT_SEC"]
 SQLLAB_HARD_TIMEOUT = SQLLAB_TIMEOUT + 60
diff --git a/superset/sqllab/api.py b/superset/sqllab/api.py
index cdb2436e58..f123b07f58 100644
--- a/superset/sqllab/api.py
+++ b/superset/sqllab/api.py
@@ -18,13 +18,13 @@ import logging
 from typing import Any, cast, Optional
 from urllib import parse
 
-from flask import request, Response
+from flask import current_app, request, Response
 from flask_appbuilder import permission_name
 from flask_appbuilder.api import expose, protect, rison, safe
 from flask_appbuilder.models.sqla.interface import SQLAInterface
 from marshmallow import ValidationError
 
-from superset import app, is_feature_enabled
+from superset import is_feature_enabled
 from superset.commands.sql_lab.estimate import QueryEstimationCommand
 from superset.commands.sql_lab.execute import CommandResult, ExecuteSqlCommand
 from superset.commands.sql_lab.export import SqlResultExportCommand
@@ -65,7 +65,7 @@ from superset.utils import core as utils, json
 from superset.views.base import CsvResponse, generate_download_headers, json_success
 from superset.views.base_api import BaseSupersetApi, requires_json, statsd_metrics
 
-config = app.config
+config = current_app.config
 logger = logging.getLogger(__name__)
 
 
diff --git a/superset/views/base.py b/superset/views/base.py
index 540d7e9a2c..d1b5401a59 100644
--- a/superset/views/base.py
+++ b/superset/views/base.py
@@ -26,6 +26,7 @@ from typing import Any, Callable
 from babel import Locale
 from flask import (
     abort,
+    current_app,
     flash,
     g,
     get_flashed_messages,
@@ -50,7 +51,6 @@ from wtforms.fields.core import Field, UnboundField
 from superset import (
     app as superset_app,
     appbuilder,
-    conf,
     db,
     get_feature_flags,
     is_feature_enabled,
@@ -72,6 +72,8 @@ from superset.views.error_handling import json_error_response
 
 from .utils import bootstrap_user_data, get_config_value
 
+conf = current_app.config
+
 DEFAULT_THEME_SETTINGS = {
     "enforced": False,
     "allowSwitching": True,
@@ -129,11 +131,10 @@ FRONTEND_CONF_KEYS = (
 )
 
 logger = logging.getLogger(__name__)
-config = superset_app.config
 
 
 def get_error_msg() -> str:
-    if conf.get("SHOW_STACKTRACE"):
+    if current_app.config.get("SHOW_STACKTRACE"):
         error_msg = traceback.format_exc()
     else:
         error_msg = "FATAL ERROR \n"
@@ -360,11 +361,15 @@ def cached_common_bootstrap_data(  # pylint: disable=unused-argument
 
     # should not expose API TOKEN to frontend
     frontend_config = {
-        k: (list(conf.get(k)) if isinstance(conf.get(k), set) else conf.get(k))
+        k: (
+            list(current_app.config.get(k))
+            if isinstance(current_app.config.get(k), set)
+            else current_app.config.get(k)
+        )
         for k in FRONTEND_CONF_KEYS
     }
 
-    if conf.get("SLACK_API_TOKEN"):
+    if current_app.config.get("SLACK_API_TOKEN"):
         frontend_config["ALERT_REPORTS_NOTIFICATION_METHODS"] = [
             ReportRecipientType.EMAIL,
             ReportRecipientType.SLACK,
@@ -416,21 +421,27 @@ def cached_common_bootstrap_data(  # pylint: disable=unused-argument
         frontend_config["AUTH_PROVIDERS"] = oid_providers
 
     bootstrap_data = {
-        "application_root": conf["APPLICATION_ROOT"],
-        "static_assets_prefix": conf["STATIC_ASSETS_PREFIX"],
+        "application_root": current_app.config["APPLICATION_ROOT"],
+        "static_assets_prefix": current_app.config["STATIC_ASSETS_PREFIX"],
         "conf": frontend_config,
         "locale": language,
-        "d3_format": conf.get("D3_FORMAT"),
-        "d3_time_format": conf.get("D3_TIME_FORMAT"),
-        "currencies": conf.get("CURRENCIES"),
-        "deckgl_tiles": conf.get("DECKGL_BASE_MAP"),
+        "d3_format": current_app.config.get("D3_FORMAT"),
+        "d3_time_format": current_app.config.get("D3_TIME_FORMAT"),
+        "currencies": current_app.config.get("CURRENCIES"),
+        "deckgl_tiles": current_app.config.get("DECKGL_BASE_MAP"),
         "feature_flags": get_feature_flags(),
-        "extra_sequential_color_schemes": conf["EXTRA_SEQUENTIAL_COLOR_SCHEMES"],
-        "extra_categorical_color_schemes": conf["EXTRA_CATEGORICAL_COLOR_SCHEMES"],
+        "extra_sequential_color_schemes": current_app.config[
+            "EXTRA_SEQUENTIAL_COLOR_SCHEMES"
+        ],
+        "extra_categorical_color_schemes": current_app.config[
+            "EXTRA_CATEGORICAL_COLOR_SCHEMES"
+        ],
         "menu_data": menu_data(g.user),
     }
 
-    bootstrap_data.update(conf["COMMON_BOOTSTRAP_OVERRIDES_FUNC"](bootstrap_data))
+    bootstrap_data.update(
+        current_app.config["COMMON_BOOTSTRAP_OVERRIDES_FUNC"](bootstrap_data)
+    )
     bootstrap_data.update(get_theme_bootstrap_data())
 
     return bootstrap_data
@@ -549,7 +560,7 @@ class CsvResponse(Response):
     Override Response to take into account csv encoding from config.py
     """
 
-    charset = conf["CSV_EXPORT"].get("encoding", "utf-8")
+    charset = current_app.config["CSV_EXPORT"].get("encoding", "utf-8")
     default_mimetype = "text/csv"
 
 
@@ -589,11 +600,9 @@ def apply_http_headers(response: Response) -> Response:
     """Applies the configuration's http headers to all responses"""
 
     # HTTP_HEADERS is deprecated, this provides backwards compatibility
-    response.headers.extend(
-        {**config["OVERRIDE_HTTP_HEADERS"], **config["HTTP_HEADERS"]}
-    )
+    response.headers.extend({**conf["OVERRIDE_HTTP_HEADERS"], **conf["HTTP_HEADERS"]})
 
-    for k, v in config["DEFAULT_HTTP_HEADERS"].items():
+    for k, v in conf["DEFAULT_HTTP_HEADERS"].items():
         if k not in response.headers:
             response.headers[k] = v
     return response