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