apache-superset完整配置项解读
在superset中,有config.py配置文件,我们自定义的superset_config.py文件配置项来源于此。在使用或者二次开发过程中,有必要了解superset给我们提供了哪些可选配置,这会极大减少工作量。
以apache-superset-4.1.1为例,下面是它config.py的文件各个配置的注释说明:
# 根据 Apache 软件基金会(ASF)的贡献者许可协议授权
# 请查看随附的 NOTICE 文件获取版权相关的额外信息
# ASF 根据 Apache 许可证 2.0 版本("许可证")授权您使用此文件
# 除非符合许可证要求,否则不得使用此文件
# 您可以在以下网址获取许可证副本:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 除非适用法律要求或书面同意,否则软件依据"现状"分发
# 不提供任何明示或暗示的担保或条件
# 请查阅许可证了解具体的语言权限和使用限制
"""Superset 的主配置文件
本文件中的所有配置都可以通过在您的 PYTHONPATH 中提供 superset_config 来覆盖
因为本文件末尾有 ``from superset_config import *`` 语句
"""
# mypy: 忽略错误
# pylint: 禁用=行数过多
from __future__ import annotations
import imp # pylint: 禁用=废弃模块
import importlib.util
import json
import logging
import os
import re
import sys
from collections import OrderedDict
from datetime import timedelta
from email.mime.multipart import MIMEMultipart
from importlib.resources import files
from typing import Any, Callable, Literal, TYPE_CHECKING, TypedDict
import click
import pkg_resources
from celery.schedules import crontab
from flask import Blueprint
from flask_appbuilder.security.manager import AUTH_DB
from flask_caching.backends.base import BaseCache
from pandas import Series
from pandas._libs.parsers import STR_NA_VALUES
from sqlalchemy.engine.url import URL
from sqlalchemy.orm.query import Query
from superset.advanced_data_type.plugins.internet_address import internet_address
from superset.advanced_data_type.plugins.internet_port import internet_port
from superset.advanced_data_type.types import AdvancedDataType
from superset.constants import CHANGE_ME_SECRET_KEY
from superset.jinja_context import BaseTemplateProcessor
from superset.key_value.types import JsonKeyValueCodec
from superset.stats_logger import DummyStatsLogger
from superset.superset_typing import CacheConfig
from superset.tasks.types import ExecutorType
from superset.utils import core as utils
from superset.utils.core import is_test, NO_TIME_RANGE, parse_boolean_string
from superset.utils.encrypt import SQLAlchemyUtilsAdapter
from superset.utils.log import DBEventLogger
from superset.utils.logging_configurator import DefaultLoggingConfigurator
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from flask_appbuilder.security.sqla import models
from sqlglot import Dialect, Dialects
from superset.connectors.sqla.models import SqlaTable
from superset.models.core import Database
from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
# 实时统计记录器,已有 StatsD 的实现
STATS_LOGGER = DummyStatsLogger()
# 默认使用 `DBEventLogger` 将事件记录到元数据库
# 注意:调试时可使用 `StdOutEventLogger`
# 注意:可通过扩展 `AbstractEventLogger` 自定义事件记录器
# https://github.com/apache/superset/blob/master/superset/utils/log.py
EVENT_LOGGER = DBEventLogger()
SUPERSET_LOG_VIEW = True
# 基础目录设置
BASE_DIR = pkg_resources.resource_filename("superset", "")
# 检查环境变量优先使用自定义目录
if "SUPERSET_HOME" in os.environ:
DATA_DIR = os.environ["SUPERSET_HOME"]
else:
DATA_DIR = os.path.expanduser("~/.superset") # 默认用户目录
# ---------------------------------------------------------
# Superset 专用配置区域
# ---------------------------------------------------------
# 后端版本信息文件路径
VERSION_INFO_FILE = str(files("superset") / "static/version_info.json")
# 前端包管理文件路径
PACKAGE_JSON_FILE = str(files("superset") / "static/assets/package.json")
# 可以在此指定多个网站图标。"href"属性是必需的,
# 而"sizes"、"type"和"rel"是可选的。
# 例如:
# {
# "href":path/to/image.png",
# "sizes": "16x16",
# "type": "image/png"
# "rel": "icon"
# },
FAVICONS = [{"href": "/static/assets/images/favicon.png"}]
def _try_json_readversion(filepath: str) -> str | None:
try:
with open(filepath) as f:
return json.load(f).get("version")
except Exception: # pylint: disable=broad-except
return None
def _try_json_readsha(filepath: str, length: int) -> str | None:
try:
with open(filepath) as f:
return json.load(f).get("GIT_SHA")[:length]
except Exception: # pylint: disable=broad-except
return None
#
# 如果为True,将跳过加载alembic.init中找到的日志配置
#
ALEMBIC_SKIP_LOG_CONFIG = False
# 根据加载此配置的上下文环境,
# version_info.json文件可能可用也可能不可用,
# 因为它是在安装时通过setup.py生成的。
# 当我们实际运行Superset时,它应该已经安装,
# 因此文件会存在。但在运行单元测试时,
# 文件不会存在,此时我们回退到读取package.json
VERSION_STRING = _try_json_readversion(VERSION_INFO_FILE) or _try_json_readversion(
PACKAGE_JSON_FILE
)
VERSION_SHA_LENGTH = 8
VERSION_SHA = _try_json_readsha(VERSION_INFO_FILE, VERSION_SHA_LENGTH)
# 构建编号,如果可用将显示在"关于"部分。
# 可以在构建时替换以暴露构建信息。
BUILD_NUMBER = None
# 在图表探索器和SQL Lab探索中使用的默认可视化类型
DEFAULT_VIZ_TYPE = "table"
# 请求图表数据时的默认行数限制
ROW_LIMIT = 50000
# 在探索视图中从数据源请求样本时的默认行数限制
SAMPLES_ROW_LIMIT = 1000
# 原生过滤器的默认行数限制
NATIVE_FILTER_DEFAULT_ROW_LIMIT = 1000
# 过滤器选择自动完成检索的最大行数
FILTER_SELECT_ROW_LIMIT = 10000
# 探索视图中的默认时间过滤器
# 值可以是"Last day"、"Last week"、"<ISO date> : now"等
DEFAULT_TIME_FILTER = NO_TIME_RANGE
# 这是一个重要设置,应该低于您的
# [负载均衡器/代理/envoy/kong/...]的超时设置。
# 您还需要确保将WSGI服务器
# (gunicorn、nginx、apache等)的超时设置配置为小于等于此值
SUPERSET_WEBSERVER_TIMEOUT = int(timedelta(minutes=1).total_seconds())
# 这两个设置用于仪表板定期强制刷新功能
# 当用户选择自动强制刷新频率
# < SUPERSET_DASHBOARD_PERIODICAL_REFRESH_LIMIT
# 时,他们将在刷新间隔模态框中看到警告消息。
# 请查看PR #9886
SUPERSET_DASHBOARD_PERIODICAL_REFRESH_LIMIT = 0
SUPERSET_DASHBOARD_PERIODICAL_REFRESH_WARNING_MESSAGE = None
SUPERSET_DASHBOARD_POSITION_DATA_LIMIT = 65535
CUSTOM_SECURITY_MANAGER = None
SQLALCHEMY_TRACK_MODIFICATIONS = False
# ---------------------------------------------------------
# 您的应用密钥。请确保在superset_config.py中覆盖它
# 或使用`SUPERSET_SECRET_KEY`环境变量。
# 使用一个强复杂的字母数字字符串,并使用工具帮助生成
# 足够随机的序列,例如:openssl rand -base64 42"
SECRET_KEY = os.environ.get("SUPERSET_SECRET_KEY") or CHANGE_ME_SECRET_KEY
# SQLAlchemy连接字符串
SQLALCHEMY_DATABASE_URI = (
f"""sqlite:///{os.path.join(DATA_DIR, "superset.db")}?check_same_thread=false"""
)
# SQLALCHEMY_DATABASE_URI = 'mysql://myapp@localhost/myapp'
# SQLALCHEMY_DATABASE_URI = 'postgresql://root:password@localhost/myapp'
# 该配置通过flask-sqlalchemy暴露,可用于设置元数据
# 数据库连接参数。您可以用它来设置特定于您使用的
# 数据库引擎的任意连接参数。
# 注意:可用此设置数据库隔离级别,例如:
# `SQLALCHEMY_ENGINE_OPTIONS = {"isolation_level": "READ COMMITTED"}`
# 同时建议常规操作使用READ COMMITTED隔离级别。
# 更多信息请参考:
# https://flask-sqlalchemy.palletsprojects.com/en/3.1.x/config/
SQLALCHEMY_ENGINE_OPTIONS = {}
# 要为所有SQLALCHEMY连接配置自定义密码存储,
# 需实现一个接收'sqla.engine.url'类型参数、
# 返回密码的函数,并赋值给SQLALCHEMY_CUSTOM_PASSWORD_STORE。
#
# 示例:
# def lookup_password(url):
# return 'secret'
# SQLALCHEMY_CUSTOM_PASSWORD_STORE = lookup_password
SQLALCHEMY_CUSTOM_PASSWORD_STORE = None
#
# EncryptedFieldTypeAdapter用于构建包含敏感字段的SqlAlchemy模型时,
# 这些字段在发送到数据库前会进行应用层加密。
#
# 注意:默认实现使用SqlAlchemyUtils的EncryptedType,
# 其底层使用AES-128算法,以应用的SECRET_KEY作为密钥材料。
# 需注意AesEngine支持对加密字段进行查询。
#
# 要更改默认加密引擎,需自定义适配器:
#
# 示例:
#
# class AesGcmEncryptedAdapter(
# AbstractEncryptedFieldAdapter
# ):
# def create(
# self,
# app_config: Optional[Dict[str, Any]],
# *args: List[Any],
# **kwargs: Optional[Dict[str, Any]],
# ) -> TypeDecorator:
# if app_config:
# return EncryptedType(
# *args, app_config["SECRET_KEY"], engine=AesGcmEngine, **kwargs
# )
# raise Exception("Missing app_config kwarg")
#
#
# SQLALCHEMY_ENCRYPTED_FIELD_TYPE_ADAPTER = AesGcmEncryptedAdapter
SQLALCHEMY_ENCRYPTED_FIELD_TYPE_ADAPTER = ( # pylint: disable=invalid-name
SQLAlchemyUtilsAdapter
)
# 使用额外方言扩展默认SQLGlot方言
SQLGLOT_DIALECTS_EXTENSIONS: dict[str, Dialects | type[Dialect]] = {}
# 查询搜索的获取结果数量限制
QUERY_SEARCH_LIMIT = 1000
# Flask-WTF的CSRF保护开关
WTF_CSRF_ENABLED = True
# 需要免除CSRF保护的端点列表
WTF_CSRF_EXEMPT_LIST = [
"superset.views.core.log",
"superset.views.core.explore_json",
"superset.charts.data.api.data",
"superset.dashboards.api.cache_dashboard_screenshot",
]
# 是否以调试模式运行web服务器
DEBUG = parse_boolean_string(os.environ.get("FLASK_DEBUG"))
FLASK_USE_RELOAD = True
# 启用Python调用性能分析。开启后,在URL后追加``?_instrument=1``
# 即可查看调用堆栈。
PROFILING = False
# 当该功能开启时,Superset允许向用户显示服务端Python堆栈跟踪。
# 这可能存在安全隐患,在生产环境中关闭更为安全。
SHOW_STACKTRACE = False
# 当ENABLE_PROXY_FIX为True时,使用所有X-Forwarded头。
# 代理到不同端口时,设置"x_port"为0以避免下游问题。
ENABLE_PROXY_FIX = False
PROXY_FIX_CONFIG = {"x_for": 1, "x_proto": 1, "x_host": 1, "x_port": 1, "x_prefix": 1}
# SQL Lab中调度查询的配置
SCHEDULED_QUERIES: dict[str, Any] = {}
# FAB速率限制:防止DDOS攻击的安全功能。默认开启以确保Superset安全性,
# 但您应根据需求调整限制参数。更多参数说明请参考:
# https://flask-limiter.readthedocs.io/en/stable/configuration.html
RATELIMIT_ENABLED = os.environ.get("SUPERSET_ENV") == "production"
RATELIMIT_APPLICATION = "50 per second"
AUTH_RATE_LIMITED = True
AUTH_RATE_LIMIT = "5 per second"
# 符合storage-scheme方案的存储位置配置。允许的值请参考limits库:
# https://limits.readthedocs.io/en/stable/storage.html
# RATELIMIT_STORAGE_URI = "redis://host:port"
# 可调用对象,返回当前请求的唯一标识
# RATELIMIT_REQUEST_IDENTIFIER = flask.Request.endpoint
# ------------------------------
# 应用构建器全局配置
# ------------------------------
# 取消注释以设置您的应用名称
APP_NAME = "Superset"
# 指定应用图标
APP_ICON = "/static/assets/images/superset-logo-horiz.png"
# 指定点击logo时的跳转目标
# None的默认值将跳转到'/superset/welcome'
# 可以指定相对URL如'/superset/welcome'或'/dashboards/list'
# 也可以指定完整URL如'https://foo.bar'
LOGO_TARGET_PATH = None
# 指定鼠标悬停在应用图标/logo上时显示的工具提示
LOGO_TOOLTIP = ""
# 指定logo右侧显示的文本
LOGO_RIGHT_TEXT: Callable[[], str] | str = ""
# 为Superset的openapi规范启用SWAGGER UI
# 示例:http://localhost:8080/swagger/v1
FAB_API_SWAGGER_UI = True
# ----------------------------------------------------
# 认证配置
# ----------------------------------------------------
# 认证类型:
# AUTH_OID : OpenID认证
# AUTH_DB : 数据库认证(用户名/密码)
# AUTH_LDAP : LDAP认证
# AUTH_REMOTE_USER : 使用web服务器的REMOTE_USER
AUTH_TYPE = AUTH_DB
# 取消注释设置管理员角色名称
# AUTH_ROLE_ADMIN = 'Admin'
# 取消注释设置公共角色名称,无需认证
# AUTH_ROLE_PUBLIC = 'Public'
# 允许用户自助注册
# AUTH_USER_REGISTRATION = True
# 用户自助注册的默认角色
# AUTH_USER_REGISTRATION_ROLE = "Public"
# 使用LDAP认证时,配置LDAP服务器
# AUTH_LDAP_SERVER = "ldap://ldapserver.new"
# 取消注释设置OpenID认证的提供者示例
# OPENID_PROVIDERS = [
# { 'name': 'Yahoo', 'url': 'https://open.login.yahoo.com/' },
# { 'name': 'Flickr', 'url': 'https://www.flickr.com/<username>' },
# ---------------------------------------------------
# 角色配置
# ---------------------------------------------------
# 为公共角色授予与所选内置角色相同的权限集
# 这在需要允许匿名用户查看仪表板时很有用
# 仍需在特定数据集上明确授权
PUBLIC_ROLE_LIKE: str | None = None
# ---------------------------------------------------
# 国际化翻译配置
# ---------------------------------------------------
# 设置默认语言
BABEL_DEFAULT_LOCALE = "en"
# 应用的默认翻译路径
BABEL_DEFAULT_FOLDER = "superset/translations"
# 应用允许的语言
LANGUAGES = {
"en": {"flag": "us", "name": "English"},
"es": {"flag": "es", "name": "Spanish"},
"it": {"flag": "it", "name": "Italian"},
"fr": {"flag": "fr", "name": "French"},
"zh": {"flag": "cn", "name": "Chinese"},
"zh_TW": {"flag": "tw", "name": "Traditional Chinese"},
"ja": {"flag": "jp", "name": "Japanese"},
"de": {"flag": "de", "name": "German"},
"pt": {"flag": "pt", "name": "Portuguese"},
"pt_BR": {"flag": "br", "name": "Brazilian Portuguese"},
"ru": {"flag": "ru", "name": "Russian"},
"ko": {"flag": "kr", "name": "Korean"},
"sk": {"flag": "sk", "name": "Slovak"},
"sl": {"flag": "si", "name": "Slovenian"},
"nl": {"flag": "nl", "name": "Dutch"},
"uk": {"flag": "uk", "name": "Ukranian"},
}
# 默认关闭i18n,因为大多数语言的翻译
# 不完整且维护不佳
LANGUAGES = {}
# 覆盖默认的d3数字格式本地化设置
# 默认值等效于:
# D3_FORMAT = {
# "decimal": ".", # - 小数点符号(如".")
# "thousands": ",", # - 千分位分隔符(如",")
# "grouping": [3], # - 分组大小数组(如[3]),按需循环使用
# "currency": ["$", ""] # - 货币前缀/后缀字符串(如["$", ""])
# }
# 参考:https://github.com/d3/d3-format/blob/main/README.md#formatLocale
class D3Format(TypedDict, total=False):
decimal: str
thousands: str
grouping: list[int]
currency: list[str]
D3_FORMAT: D3Format = {}
# 覆盖默认的d3时间格式本地化设置
# 默认值等效于:
# D3_TIME_FORMAT = {
# "dateTime": "%x, %X",
# "date": "%-m/%-d/%Y",
# "time": "%-I:%M:%S %p",
# "periods": ["AM", "PM"],
# "days": ["Sunday", "Monday", "Tuesday", "Wednesday",
# "Thursday", "Friday", "Saturday"],
# "shortDays": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
# "months": ["January", "February", "March", "April",
# "May", "June", "July", "August",
# "September", "October", "November", "December"],
# "shortMonths": ["Jan", "Feb", "Mar", "Apr",
# "May", "Jun", "Jul", "Aug",
# "Sep", "Oct", "Nov", "Dec"]
# }
# 参考:https://github.com/d3/d3-time-format/tree/main#locales
class D3TimeFormat(TypedDict, total=False):
date: str
dateTime: str
time: str
periods: list[str]
days: list[str]
shortDays: list[str]
months: list[str]
shortMonths: list[str]
D3_TIME_FORMAT: D3TimeFormat = {}
CURRENCIES = ["USD", "EUR", "GBP", "INR", "MXN", "JPY", "CNY"]
# ---------------------------------------------------
# 功能开关配置
# ---------------------------------------------------
# 默认启用的功能开关配置在此处。它们的值可以被superset_config.py中
# FEATURE_FLAGS指定的值覆盖。例如:
# 此处 DEFAULT_FEATURE_FLAGS = { 'FOO': True, 'BAR': False }
# 而 superset_config.py 中 FEATURE_FLAGS = { 'BAR': True, 'BAZ': True }
# 最终合并后的功能开关将是 { 'FOO': True, 'BAR': True, 'BAZ': True }
DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
# 当使用支持JOIN的新版Druid时开启此选项
"DRUID_JOINS": False,
"DYNAMIC_PLUGINS": False,
# 在Superset 2.0中,我们更新了默认设置,不再显示旧版数据源编辑器
# 目前设置为false以显示编辑器选项,但我们将逐步弃用它
"DISABLE_LEGACY_DATASOURCE_EDITOR": True,
"ENABLE_TEMPLATE_PROCESSING": True,
# 允许使用JavaScript控制组件
# 这使程序员能够通过在控件中输入JavaScript来自定义某些图表(如地理空间图表)
# 这会带来XSS安全漏洞风险
"ENABLE_JAVASCRIPT_CONTROLS": False, # 已弃用
"KV_STORE": False, # 已弃用
# 启用此功能时,Presto中的嵌套类型将被展开为额外的列和/或数组
# 这是实验性功能,不适用于所有嵌套类型
"PRESTO_EXPAND_DATA": False,
# 暴露API端点来计算缩略图
"THUMBNAILS": False,
# 启用通过webdriver缓存和检索仪表板截图的端点
# 需要配置Celery和使用THUMBNAIL_CACHE_CONFIG配置缓存
"ENABLE_DASHBOARD_SCREENSHOT_ENDPOINTS": False,
# 使用webdriver生成仪表板的截图(PDF或JPG)
# 禁用时,截图由浏览器即时生成
# 此功能开关用于仪表板视图中的下载功能
# 依赖于ENABLE_DASHBOARD_SCREENSHOT_ENDPOINT的启用
"ENABLE_DASHBOARD_DOWNLOAD_WEBDRIVER_SCREENSHOT": False,
"SHARE_QUERIES_VIA_KV_STORE": False,
"TAGGING_SYSTEM": False,
"SQLLAB_BACKEND_PERSISTENCE": True,
"LISTVIEWS_DEFAULT_CARD_VIEW": False,
# 当为True时,在Markdown组件中转义HTML(而不是渲染它)
"ESCAPE_MARKDOWN_HTML": False,
"DASHBOARD_CROSS_FILTERS": True, # 已弃用
"DASHBOARD_VIRTUALIZATION": True,
"GLOBAL_ASYNC_QUERIES": False,
"EMBEDDED_SUPERSET": False,
# 启用警报和报告的新实现
"ALERT_REPORTS": False,
"ALERT_REPORT_TABS": False,
"ALERT_REPORT_SLACK_V2": False,
"DASHBOARD_RBAC": False,
"ENABLE_ADVANCED_DATA_TYPES": False,
# 启用ALERTS_ATTACH_REPORTS时,系统会发送带有截图和链接的邮件和Slack消息
# 禁用ALERTS_ATTACH_REPORTS时,系统不会为'alert'类型的报告生成截图,
# 只发送带有链接的邮件和Slack消息;
# 对于'report'类型的报告仍会发送带有截图和链接的邮件和Slack消息
"ALERTS_ATTACH_REPORTS": True,
# 允许用户导出表格可视化类型的完整CSV
# 这可能导致服务器内存或计算资源耗尽
"ALLOW_FULL_CSV_EXPORT": False,
"ALLOW_ADHOC_SUBQUERY": False,
"USE_ANALAGOUS_COLORS": False,
# 将RLS规则应用于SQL Lab查询。这需要解析和操作查询,
# 可能会破坏查询和/或允许用户绕过RLS。请谨慎使用!
"RLS_IN_SQLLAB": False,
# 模拟用户时,使用电子邮件前缀而不是用户名
"IMPERSONATE_WITH_EMAIL_PREFIX": False,
# 在启用了用户模拟的数据源中,按模拟键(如用户名)启用缓存
"CACHE_IMPERSONATION": False,
# 为Superset缓存(非数据库缓存模拟)启用按用户键缓存
"CACHE_QUERY_BY_USER": False,
# 启用通过嵌入共享图表
"EMBEDDABLE_CHARTS": True,
"DRILL_TO_DETAIL": True,
"DRILL_BY": True,
"DATAPANEL_CLOSED_BY_DEFAULT": False,
"HORIZONTAL_FILTER_BAR": False,
# 此功能默认关闭,目前仅在Presto、Postgres和Bigquery中受支持
# 还需要在数据库级别启用,通过在数据库的extra属性中添加
# `cost_estimate_enabled: true`键值对
"ESTIMATE_QUERY_COST": False,
# 允许用户在创建数据库时启用SSH隧道
# 用户必须检查数据库引擎是否支持SSH隧道
# 否则启用此标志不会对数据库产生任何影响
"SSH_TUNNELING": False,
"AVOID_COLORS_COLLISION": True,
# 不在菜单中显示用户信息
"MENU_HIDE_USER_INFO": False,
# 允许用户添加可以跨数据库查询的``superset://``数据库
# 这是一个具有潜在安全和性能风险的实验性功能,请谨慎使用
# 如果启用了此功能,您还可以通过本文件中的``SUPERSET_META_DB_LIMIT``配置值
# 设置从每个数据库返回的数据量限制
"ENABLE_SUPERSET_META_DB": False,
# 设置为True以使用Playwright替代Selenium执行报告和缩略图
# 与Selenium不同,Playwright报告支持deck.gl可视化
# 启用此功能需要安装"playwright" pip包
"PLAYWRIGHT_REPORTS_AND_THUMBNAILS": False,
# 设置为True以启用实验性图表插件
"CHART_PLUGINS_EXPERIMENTAL": False,
# 无论数据库配置如何,强制SQLLAB使用Celery异步运行
"SQLLAB_FORCE_RUN_ASYNC": False,
# 设置为True以启用工厂重置CLI命令
"ENABLE_FACTORY_RESET_COMMAND": False,
# Superset是否应使用Slack头像作为用户头像
# 如果启用,您需要将"https://avatars.slack-edge.com"添加到
# TALISMAN_CONFIG的允许域名列表中
"SLACK_ENABLE_AVATARS": False,
}
# ------------------------------
# SSH隧道配置
# ------------------------------
# 允许用户设置连接SSH隧道时使用的主机地址
# 可以是localhost或其他别名(如0.0.0.0)
# ----------------------------------------------------------------------
# |
# -------------+ | +----------+
# 本地 | | | 远程 | :22 SSH端口
# 客户端 | <== SSH ========> | 服务器 | :8080 网络服务
# -------------+ | +----------+
# |
# 防火墙(仅开放22端口)
# ----------------------------------------------------------------------
SSH_TUNNEL_MANAGER_CLASS = "superset.extensions.ssh.SSHManager"
SSH_TUNNEL_LOCAL_BIND_ADDRESS = "127.0.0.1"
#: 隧道连接超时时间(秒)(open_channel超时)
SSH_TUNNEL_TIMEOUT_SEC = 10.0
#: 传输socket超时时间(秒)(``socket.settimeout``)
SSH_TUNNEL_PACKET_TIMEOUT_SEC = 1.0
# 功能开关也可以通过'SUPERSET_FEATURE_'前缀的环境变量设置
DEFAULT_FEATURE_FLAGS.update(
{
k[len("SUPERSET_FEATURE_") :]: parse_boolean_string(v)
for k, v in os.environ.items()
if re.search(r"^SUPERSET_FEATURE_\w+", k)
}
)
# 这只是一个默认配置
FEATURE_FLAGS: dict[str, bool] = {}
# 该函数接收所有功能开关的字典
# (DEFAULT_FEATURE_FLAGS与FEATURE_FLAGS合并后的结果)
# 可以修改它并返回类似的字典。注意传递给函数的
# 功能开关字典是配置字典的深拷贝,因此可以无副作用地修改
#
# GET_FEATURE_FLAGS_FUNC可用于实现渐进式发布、
# 基于角色的功能或完整的A/B测试框架
#
# from flask import g, request
# def GET_FEATURE_FLAGS_FUNC(feature_flags_dict: Dict[str, bool]) -> Dict[str, bool]:
# if hasattr(g, "user") and g.user.is_active:
# feature_flags_dict['some_feature'] = g.user and g.user.get_id() == 5
# return feature_flags_dict
GET_FEATURE_FLAGS_FUNC: Callable[[dict[str, bool]], dict[str, bool]] | None = None
# 该函数接收功能开关名称和可选的默认值
# 与GET_FEATURE_FLAGS_FUNC有类似用途,但在只需要评估单个功能开关时
# 可以避免评估所有功能开关
#
# 注意默认的`get_feature_flags`会在配置键设置时用此可调用对象
# 评估每个功能开关,因此不要同时使用GET_FEATURE_FLAGS_FUNC
# 和IS_FEATURE_ENABLED_FUNC
IS_FEATURE_ENABLED_FUNC: Callable[[str, bool | None], bool] | None = None
# 该函数用于扩展/覆盖前端`bootstrap_data.common`对象
# 可用于实现自定义前端功能,或动态更改某些配置
#
# `bootstrap_data.common`中的值应具有以下特征:
# - 不特定于用户正在访问的页面
# - 不包含敏感信息
#
# 接收转换前的通用bootstrap负载作为参数
# 返回应添加或覆盖到负载中的数据字典
COMMON_BOOTSTRAP_OVERRIDES_FUNC: Callable[ # noqa: E731
[dict[str, Any]], dict[str, Any]
] = lambda data: {}
# EXTRA_CATEGORICAL_COLOR_SCHEMES用于添加自定义分类颜色方案
# "我的自定义暖色到热色"颜色方案的示例代码:
# EXTRA_CATEGORICAL_COLOR_SCHEMES = [
# {
# "id": 'myVisualizationColors',
# "description": '',
# "label": '我的可视化颜色',
# "isDefault": True,
# "colors":
# ['#006699', '#009DD9', '#5AAA46', '#44AAAA', '#DDAA77', '#7799BB', '#88AA77',
# '#552288', '#5AAA46', '#CC7788', '#EEDD55', '#9977BB', '#BBAA44', '#DDCCDD']
# }]
# 这只是一个默认配置
EXTRA_CATEGORICAL_COLOR_SCHEMES: list[dict[str, Any]] = []
# THEME_OVERRIDES用于向Superset添加自定义主题
# "我的主题"自定义方案的示例代码:
# THEME_OVERRIDES = {
# "borderRadius": 4,
# "colors": {
# "primary": {
# "base": 'red',
# },
# "secondary": {
# "base": 'green',
# },
# "grayscale": {
# "base": 'orange',
# }
# }
# }
THEME_OVERRIDES: dict[str, Any] = {}
# EXTRA_SEQUENTIAL_COLOR_SCHEMES 用于添加自定义连续颜色方案
# EXTRA_SEQUENTIAL_COLOR_SCHEMES = [
# {
# "id": 'warmToHot',
# "description": '',
# "isDiverging": True,
# "label": '我的自定义暖色到热色',
# "isDefault": True,
# "colors":
# ['#552288', '#5AAA46', '#CC7788', '#EEDD55', '#9977BB', '#BBAA44', '#DDCCDD',
# '#006699', '#009DD9', '#5AAA46', '#44AAAA', '#DDAA77', '#7799BB', '#88AA77']
# }]
# 这只是一个默认配置
EXTRA_SEQUENTIAL_COLOR_SCHEMES: list[dict[str, Any]] = []
# ---------------------------------------------------
# 缩略图配置(需配合功能开关使用)
# ---------------------------------------------------
# 默认情况下,缩略图按用户渲染,匿名用户将回退到Selenium用户。
# 类似于警报和报告,缩略图可以配置为始终使用固定用户渲染。
# 完整执行器选项请参考 `superset.tasks.types.ExecutorType`。
# 要始终使用固定用户账户,请使用以下配置:
# THUMBNAIL_EXECUTE_AS = [ExecutorType.SELENIUM]
THUMBNAIL_SELENIUM_USER: str | None = "admin"
THUMBNAIL_EXECUTE_AS = [ExecutorType.CURRENT_USER, ExecutorType.SELENIUM]
# 默认情况下,缩略图摘要基于图表/仪表板元数据中的各种参数计算,
# 对于用户特定的缩略图,还会基于用户名计算。
# 要指定自定义摘要函数,请使用以下配置参数定义回调函数,接收:
# 1. 模型(仪表板或图表)
# 2. 执行器类型(如 ExecutorType.SELENIUM)
# 3. 执行器的用户名(注意,这是由 `THUMBNAIL_EXECUTE_AS` 定义的执行器;
# 只有当执行器类型为 `ExecutorType.CURRENT_USER` 时,
# 执行器才等于当前登录用户)
# 并返回最终的摘要字符串:
THUMBNAIL_DASHBOARD_DIGEST_FUNC: (
None | (Callable[[Dashboard, ExecutorType, str], str])
) = None
THUMBNAIL_CHART_DIGEST_FUNC: Callable[[Slice, ExecutorType, str], str] | None = None
THUMBNAIL_CACHE_CONFIG: CacheConfig = {
"CACHE_TYPE": "NullCache",
"CACHE_NO_NULL_WARNING": True,
}
# Selenium在尝试定位页面元素并等待该元素加载以进行截图时的超时时间
SCREENSHOT_LOCATE_WAIT = int(timedelta(seconds=10).total_seconds())
# Selenium等待所有名为"loading"的DOM类元素消失的超时时间
SCREENSHOT_LOAD_WAIT = int(timedelta(minutes=1).total_seconds())
# Selenium重试次数
SCREENSHOT_SELENIUM_RETRIES = 5
# Selenium启动准备时间(秒)
SCREENSHOT_SELENIUM_HEADSTART = 3
# 等待图表动画的时间(秒)
SCREENSHOT_SELENIUM_ANIMATION_WAIT = 5
# 将截图中的意外错误替换为真实的错误信息
SCREENSHOT_REPLACE_UNEXPECTED_ERRORS = False
# 等待错误信息模态框显示的最大时间(秒)
SCREENSHOT_WAIT_FOR_ERROR_MODAL_VISIBLE = 5
# 等待错误信息模态框关闭的最大时间(秒)
SCREENSHOT_WAIT_FOR_ERROR_MODAL_INVISIBLE = 5
# Playwright加载新页面时等待的事件
# 可选值:"load", "commit", "domcontentloaded", "networkidle"
# 文档:https://playwright.dev/python/docs/api/class-page#page-goto-option-wait-until
SCREENSHOT_PLAYWRIGHT_WAIT_EVENT = "load"
# Playwright浏览器上下文所有操作的默认超时时间(毫秒)
SCREENSHOT_PLAYWRIGHT_DEFAULT_TIMEOUT = int(
timedelta(seconds=30).total_seconds() * 1000
)
# ---------------------------------------------------
# 图片和文件配置
# ---------------------------------------------------
# 使用文件模型时的文件上传目录
UPLOAD_FOLDER = BASE_DIR + "/app/static/uploads/"
UPLOAD_CHUNK_SIZE = 4096
# 使用图片模型时的图片上传目录
IMG_UPLOAD_FOLDER = BASE_DIR + "/app/static/uploads/"
# 使用图片模型时的图片访问URL
IMG_UPLOAD_URL = "/static/uploads/"
# 图片尺寸默认设置为(300, 200, True)
# IMG_SIZE = (300, 200, True)
# 默认缓存超时时间,适用于所有缓存后端,
# 除非在每个缓存配置中特别覆盖
CACHE_DEFAULT_TIMEOUT = int(timedelta(days=1).total_seconds())
# Superset对象的默认缓存配置
CACHE_CONFIG: CacheConfig = {"CACHE_TYPE": "NullCache"}
# 数据源元数据和查询结果的缓存配置
DATA_CACHE_CONFIG: CacheConfig = {"CACHE_TYPE": "NullCache"}
# 仪表板过滤器状态缓存。`CACHE_TYPE`默认为`SupersetMetastoreCache`,
# 该类型将值存储在Superset元存储的键值表中,这是Superset正常运行所必需的,
# 但可以被任何`Flask-Caching`后端替换。
FILTER_STATE_CACHE_CONFIG: CacheConfig = {
"CACHE_TYPE": "SupersetMetastoreCache",
"CACHE_DEFAULT_TIMEOUT": int(timedelta(days=90).total_seconds()),
# 获取缓存值时是否重置超时时间?
"REFRESH_TIMEOUT_ON_RETRIEVAL": True,
# 以下参数仅适用于`MetastoreCache`:
# 条目应如何序列化/反序列化?
"CODEC": JsonKeyValueCodec(),
}
# 探索表单数据状态缓存。`CACHE_TYPE`默认为`SupersetMetastoreCache`,
# 该类型将值存储在Superset元存储的键值表中,这是Superset正常运行所必需的,
# 但可以被任何`Flask-Caching`后端替换。
EXPLORE_FORM_DATA_CACHE_CONFIG: CacheConfig = {
"CACHE_TYPE": "SupersetMetastoreCache",
"CACHE_DEFAULT_TIMEOUT": int(timedelta(days=7).total_seconds()),
# 获取缓存值时是否重置超时时间?
"REFRESH_TIMEOUT_ON_RETRIEVAL": True,
# 以下参数仅适用于`MetastoreCache`:
# 条目应如何序列化/反序列化?
"CODEC": JsonKeyValueCodec(),
}
# 按数据源UID存储缓存键(通过CacheKey)以进行自定义处理/失效
STORE_CACHE_KEYS_IN_METADATA_DB = False
# CORS选项
ENABLE_CORS = False
CORS_OPTIONS: dict[Any, Any] = {}
# 对markdown中使用的HTML内容进行消毒处理,以安全方式渲染。
# 出于安全考虑,不建议禁用此选项。如果您希望允许
# 默认消毒方案中未包含的有效安全元素,请使用
# HTML_SANITIZATION_SCHEMA_EXTENSIONS配置。
HTML_SANITIZATION = True
# 使用此配置扩展HTML消毒方案。
# 默认我们使用GitHub方案,定义在:
# https://github.com/syntax-tree/hast-util-sanitize/blob/main/lib/schema.js
# 例如,以下配置将允许渲染div元素的style属性和href中的ftp协议:
# HTML_SANITIZATION_SCHEMA_EXTENSIONS = {
# "attributes": {
# "div": ["style"],
# },
# "protocols": {
# "href": ["ftp"],
# }
# }
# 扩展默认方案时要小心,以避免XSS攻击。
HTML_SANITIZATION_SCHEMA_EXTENSIONS: dict[str, Any] = {}
# Chrome每个域名最多允许6个同时连接。当仪表板中有超过6个切片时,
# 许多获取请求会排队等待下一个可用套接字。PR #5039尝试为Superset实现域名分片,
# 此功能将仅通过配置启用(默认Superset不允许跨域请求)。
SUPERSET_WEBSERVER_DOMAINS = None
# 数据库视图中允许上传的文件格式类型
EXCEL_EXTENSIONS = {"xlsx", "xls"}
CSV_EXTENSIONS = {"csv", "tsv", "txt"}
COLUMNAR_EXTENSIONS = {"parquet", "zip"}
ALLOWED_EXTENSIONS = {*EXCEL_EXTENSIONS, *CSV_EXTENSIONS, *COLUMNAR_EXTENSIONS}
# 上传CSV时的可选最大文件大小(字节)
CSV_UPLOAD_MAX_SIZE = None
# CSV导出选项:将作为参数传递给DataFrame.to_csv方法的键值对。
# 注意:不应覆盖index选项
CSV_EXPORT = {"encoding": "utf-8"}
# Excel导出选项:将作为参数传递给DataFrame.to_excel方法的键值对。
# 注意:不应覆盖index选项
EXCEL_EXPORT: dict[str, Any] = {}
# ---------------------------------------------------
# 时间粒度配置
# ---------------------------------------------------
# 应用中禁用的时间粒度列表(内置时间粒度见superset/db_engine_specs/base.py)。
# 例如:要禁用1秒时间粒度:
# TIME_GRAIN_DENYLIST = ['PT1S']
TIME_GRAIN_DENYLIST: list[str] = []
# 要支持的额外时间粒度,使用与superset/db_engine_specs/base.py中类似的定义。
# 例如:添加一个新的2秒时间粒度:
# TIME_GRAIN_ADDONS = {'PT2S': '2 second'}
TIME_GRAIN_ADDONS: dict[str, str] = {}
# 每个引擎额外时间粒度的实现。
# 要截断的列在表达式中用`{col}`表示。
# 例如:在clickhouse引擎上实现2秒时间粒度:
# TIME_GRAIN_ADDON_EXPRESSIONS = {
# 'clickhouse': {
# 'PT2S': 'toDateTime(intDiv(toUInt32(toDateTime({col})), 2)*2)'
# }
# }
TIME_GRAIN_ADDON_EXPRESSIONS: dict[str, dict[str, str]] = {}
# 自定义时间粒度和人工连接列生成器的映射,
# 用于在生成结果和时间偏移之间的连接键时使用。
# 参见superset/common/query_context_processor.get_aggregated_join_column
#
# 按财年聚合的连接列生成器示例
# def join_producer(row: Series, column_index: int) -> str:
# return row[index].strftime("%F")
#
# TIME_GRAIN_JOIN_COLUMN_PRODUCERS = {"P1F": join_producer}
TIME_GRAIN_JOIN_COLUMN_PRODUCERS: dict[str, Callable[[Series, int], str]] = {}
# ---------------------------------------------------
# 环境中不允许的可视化类型列表
# 例如:禁用数据透视表和树状图:
# VIZ_TYPE_DENYLIST = ['pivot_table', 'treemap']
# ---------------------------------------------------
VIZ_TYPE_DENYLIST: list[str] = []
# --------------------------------------------------
# 需要注册的模块、数据源和中间件
# --------------------------------------------------
DEFAULT_MODULE_DS_MAP = OrderedDict(
[
("superset.connectors.sqla.models", ["SqlaTable"]),
]
)
ADDITIONAL_MODULE_DS_MAP: dict[str, list[str]] = {}
ADDITIONAL_MIDDLEWARE: list[Callable[..., Any]] = []
# 1) https://docs.python-guide.org/writing/logging/
# 2) https://docs.python.org/2/library/logging.config.html
# 默认配置器将使用下面定义的LOG_*设置
LOGGING_CONFIGURATOR = DefaultLoggingConfigurator()
# 控制台日志设置
LOG_FORMAT = "%(asctime)s:%(levelname)s:%(name)s:%(message)s"
LOG_LEVEL = logging.DEBUG if DEBUG else logging.INFO
# ---------------------------------------------------
# 启用时间轮转日志处理器
# ---------------------------------------------------
# LOG_LEVEL = DEBUG, INFO, WARNING, ERROR, CRITICAL
ENABLE_TIME_ROTATE = False
TIME_ROTATE_LOG_LEVEL = logging.DEBUG if DEBUG else logging.INFO
FILENAME = os.path.join(DATA_DIR, "superset.log")
ROLLOVER = "midnight" # 每天午夜轮转
INTERVAL = 1 # 轮转间隔(天)
BACKUP_COUNT = 30 # 保留的日志文件数量
# 用于审计查询的自定义日志记录器。可用于将运行的查询发送到
# 结构化不可变存储以进行审计。该函数会在SQL Lab和图表/仪表板中
# 运行的每个查询时被调用。
# def QUERY_LOGGER(
# database,
# query,
# schema=None,
# client=None,
# security_manager=None,
# log_params=None,
# ):
# pass
QUERY_LOGGER = None
# 设置此API密钥以启用Mapbox可视化
MAPBOX_API_KEY = os.environ.get("MAPBOX_API_KEY", "")
# 任何分析数据库查询返回的最大行数
SQL_MAX_ROW = 100000
# SQL Lab UI中显示的最大行数
# 为避免浏览器内存/本地存储问题而设置。不影响导出的CSV文件
DISPLAY_MAX_ROW = 10000
# SQL Lab查询的默认行数限制。可以通过SQL Lab UI设置新限制来覆盖
DEFAULT_SQLLAB_LIMIT = 1000
# 当功能标志ENABLE_SUPERSET_META_DB启用时,Superset元数据库的限制
SUPERSET_META_DB_LIMIT: int | None = 1000
# 在SQL Lab保存查询和计划查询模态框上添加警告消息
SQLLAB_SAVE_WARNING_MESSAGE = None
SQLLAB_SCHEDULE_WARNING_MESSAGE = None
# 仪表板自动刷新时的强制刷新模式
DASHBOARD_AUTO_REFRESH_MODE: Literal["fetch", "force"] = "force"
# 仪表板自动刷新间隔选项
DASHBOARD_AUTO_REFRESH_INTERVALS = [
[0, "不刷新"],
[10, "10秒"],
[30, "30秒"],
[60, "1分钟"],
[300, "5分钟"],
[1800, "30分钟"],
[3600, "1小时"],
[21600, "6小时"],
[43200, "12小时"],
[86400, "24小时"],
]
# 用于警报和报告调度任务的解决方法,获取celery beat触发时间
# 详情参见 https://github.com/celery/celery/issues/6974
CELERY_BEAT_SCHEDULER_EXPIRES = timedelta(weeks=1)
# 默认celery配置使用SQLA作为代理,在生产环境中
# 您应该使用适当的代理,如这里所述:
# https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/index.html
class CeleryConfig: # pylint: disable=too-few-public-methods
broker_url = "sqla+sqlite:///celerydb.sqlite"
imports = (
"superset.sql_lab",
"superset.tasks.scheduler",
"superset.tasks.thumbnails",
"superset.tasks.cache",
)
result_backend = "db+sqlite:///celery_results.sqlite"
worker_prefetch_multiplier = 1 # 工作线程预取乘数
task_acks_late = False # 任务确认延迟
task_annotations = {
"sql_lab.get_sql_results": {
"rate_limit": "100/s", # 速率限制
},
}
beat_schedule = {
"reports.scheduler": {
"task": "reports.scheduler",
"schedule": crontab(minute="*", hour="*"), # 每分钟执行
"options": {"expires": int(CELERY_BEAT_SCHEDULER_EXPIRES.total_seconds())},
},
"reports.prune_log": {
"task": "reports.prune_log",
"schedule": crontab(minute=0, hour=0), # 每天午夜执行
},
# 取消注释以启用查询表清理
# "prune_query": {
# "task": "prune_query",
# "schedule": crontab(minute=0, hour=0, day_of_month=1), # 每月1日执行
# "options": {"retention_period_days": 180}, # 保留180天
# },
}
CELERY_CONFIG: type[CeleryConfig] = CeleryConfig
# 将celery配置设为None可禁用上述所有配置
# CELERY_CONFIG = None
# 由Superset服务器提供的额外静态HTTP头。注意
# Flask-Talisman会应用相关的安全HTTP头。
# DEFAULT_HTTP_HEADERS: 设置HTTP头的默认值。这些值可能会在应用内被覆盖
# OVERRIDE_HTTP_HEADERS: 设置HTTP头的覆盖值。这些值将
# 覆盖应用内设置的任何值
DEFAULT_HTTP_HEADERS: dict[str, Any] = {}
OVERRIDE_HTTP_HEADERS: dict[str, Any] = {}
HTTP_HEADERS: dict[str, Any] = {}
# 此处设置的数据库ID将在SQL Lab中作为默认选项
DEFAULT_DB_ID = None
# SQL Lab同步查询的超时时间
SQLLAB_TIMEOUT = int(timedelta(seconds=30).total_seconds())
# SQL Lab查询验证的超时时间
SQLLAB_VALIDATION_TIMEOUT = int(timedelta(seconds=10).total_seconds())
# SQL Lab默认数据库ID
SQLLAB_DEFAULT_DBID = None
# 查询在被celery终止前可以运行的最长时间
SQLLAB_ASYNC_TIME_LIMIT_SEC = int(timedelta(hours=6).total_seconds())
# 某些数据库支持运行EXPLAIN查询,允许用户在运行前估计
# 查询成本。这些EXPLAIN查询应设置较短的超时时间
SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT = int(timedelta(seconds=10).total_seconds())
# SQL Lab通过resultsKey获取查询结果的超时时间
# 0表示无超时
SQLLAB_QUERY_RESULT_TIMEOUT = 0
# 数据库返回的成本是相对值;为了将成本映射到具体值
# 您需要定义一个考虑特定基础设施的自定义格式化程序。例如,您可以
# 通过运行EXPLAIN事后分析查询,并计算相对成本的直方图来
# 将成本表示为百分位数,此步骤是可选的,因为每个数据库引擎规范都有自己的
# 查询成本格式化程序,但如果您想自定义它,可以在配置中定义:
# def postgres_query_cost_formatter(
# result: List[Dict[str, Any]]
# ) -> List[Dict[str, str]]:
# # 25, 50, 75%百分位数
# percentile_costs = [100.0, 1000.0, 10000.0]
#
# out = []
# for row in result:
# relative_cost = row["Total cost"]
# percentile = bisect.bisect_left(percentile_costs, relative_cost) + 1
# out.append({
# "Relative cost": relative_cost,
# "Percentile": str(percentile * 25) + "%",
# })
#
# return out
#
# QUERY_COST_FORMATTERS_BY_ENGINE: {"postgresql": postgres_query_cost_formatter}
QUERY_COST_FORMATTERS_BY_ENGINE: dict[
str, Callable[[list[dict[str, Any]]], list[dict[str, Any]]]
] = {}
# 控制是否对CTA(create table as查询)强制执行限制的标志
SQLLAB_CTAS_NO_LIMIT = False
# 这允许您围绕SQL Lab中的"CREATE TABLE AS"或CTA功能定义自定义逻辑
# 确定给定用户的目标模式应该在哪里。
# 数据库`CTAS Schema`设置优先于此设置。
# 下面的示例返回用户名,CTA查询将把表写入模式名为`username`
# SQLLAB_CTAS_SCHEMA_NAME_FUNC = lambda database, user, schema, sql: user.username
# 这是一个更复杂的示例,根据数据库您可以利用可用数据
# 为CTA查询分配模式:
# def compute_schema_name(database: Database, user: User, schema: str, sql: str) -> str:
# if database.name == 'mysql_payments_slave':
# return 'tmp_superset_schema'
# if database.name == 'presto_gold':
# return user.username
# if database.name == 'analytics':
# if 'analytics' in [r.name for r in user.roles]:
# return 'analytics_cta'
# else:
# return f'tmp_{schema}'
# 函数接受数据库对象、用户对象、模式名称和将要运行的SQL
SQLLAB_CTAS_SCHEMA_NAME_FUNC: (
None | (Callable[[Database, models.User, str, str], str])
) = None
# 如果启用,可以通过使用"异步运行"按钮/功能来存储SQL Lab中长时间运行的查询结果
RESULTS_BACKEND: BaseCache | None = None
# 使用PyArrow和MessagePack进行异步查询结果的序列化,
# 而不是JSON。此功能需要社区进行额外测试才能完全采用,
# 因此提供此配置选项以便在发现问题时禁用。
RESULTS_BACKEND_USE_MSGPACK = True
# 用于存储从CSV文件创建的外部Hive表的S3存储桶。
# 例如:'companyname-superset'
CSV_TO_HIVE_UPLOAD_S3_BUCKET = None
# 上述指定存储桶中包含所有外部表的目录
CSV_TO_HIVE_UPLOAD_DIRECTORY = "EXTERNAL_HIVE_TABLES/"
# 根据使用的数据库、用户和提供的schema动态创建上传目录的函数
def CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC( # pylint: disable=invalid-name
database: Database,
user: models.User, # pylint: disable=unused-argument
schema: str | None,
) -> str:
# 注意最后的空路径强制以斜杠结尾
return os.path.join(
CSV_TO_HIVE_UPLOAD_DIRECTORY, str(database.id), schema or "", ""
)
# Hive中存储从上传的CSV创建的表的命名空间
UPLOADED_CSV_HIVE_NAMESPACE: str | None = None
# 计算允许用于CSV上传的schema的函数。
# 允许的schema将是schemas_allowed_for_file_upload数据库配置和此函数结果的并集
# mypy没有捕获到if case确保列表内容始终为str
ALLOWED_USER_CSV_SCHEMA_FUNC: Callable[[Database, models.User], list[str]] = ( # noqa: E731
lambda database, user: [UPLOADED_CSV_HIVE_NAMESPACE]
if UPLOADED_CSV_HIVE_NAMESPACE
else []
)
# 对于CSV上传应视为null的值
CSV_DEFAULT_NA_NAMES = list(STR_NA_VALUES)
# 合并到SQL Lab的Jinja上下文中的字典项。
# 现有上下文将使用此字典更新,意味着现有键的值将被此字典内容覆盖。
# 通过JINJA_CONTEXT_ADDONS暴露功能存在安全隐患,因为它为用户打开了执行不受信任代码的窗口。
# 重要的是确保暴露的对象(以及附加到这些对象的对象)是无害的。
# 我们建议仅暴露返回原生类型的简单/纯函数。
JINJA_CONTEXT_ADDONS: dict[str, Callable[..., Any]] = {}
# 按引擎合并到全局模板处理器中的宏模板处理器字典。
# 现有模板处理器将使用此字典更新,意味着现有键将被此字典内容覆盖。
# 自定义的addons不一定需要使用Jinja模板语言。
# 这允许您按引擎定义自定义逻辑来处理模板。
# 示例值 = `{"presto": CustomPrestoTemplateProcessor}`
CUSTOM_TEMPLATE_PROCESSORS: dict[str, type[BaseTemplateProcessor]] = {}
# 由API/Superset控制的角色,不应由人工更改
ROBOT_PERMISSION_ROLES = ["Public", "Gamma", "Alpha", "Admin", "sql_lab"]
CONFIG_PATH_ENV_VAR = "SUPERSET_CONFIG_PATH"
# 如果指定了可调用对象,它将在应用启动时被调用,同时传递Flask应用的引用。
# 这可以用于以任何方式修改Flask应用。
# 示例:FLASK_APP_MUTATOR = lambda x: x.before_request = f
FLASK_APP_MUTATOR = None
# SMTP服务器配置
EMAIL_NOTIFICATIONS = False # 所有邮件都使用dryrun模式发送
SMTP_HOST = "localhost"
SMTP_STARTTLS = True
SMTP_SSL = False
SMTP_USER = "superset"
SMTP_PORT = 25
SMTP_PASSWORD = "superset"
SMTP_MAIL_FROM = "superset@superset.com"
# 如果为True,使用ssl.Purpose.CLIENT_AUTH和默认系统根CA证书创建默认SSL上下文
SMTP_SSL_SERVER_AUTH = False
ENABLE_CHUNK_ENCODING = False
# 是否将flask_appbuilder包的日志级别提升为ERROR
# 在调试FAB相关问题时(如权限管理)设置为False
SILENCE_FAB = True
FAB_ADD_SECURITY_VIEWS = True
FAB_ADD_SECURITY_PERMISSION_VIEW = False
FAB_ADD_SECURITY_VIEW_MENU_VIEW = False
FAB_ADD_SECURITY_PERMISSION_VIEWS_VIEW = False
# 指向包含常见错误及其解决方案的页面链接
# 该链接将附加在SQL Lab错误信息的底部
TROUBLESHOOTING_LINK = ""
# CSRF令牌超时时间,设置为None表示永不过期
WTF_CSRF_TIME_LIMIT = int(timedelta(weeks=1).total_seconds())
# 该链接应指向有关如何获取数据源访问权限的说明页面
# 将显示在权限错误信息的底部
PERMISSION_INSTRUCTIONS_LINK = ""
# 通过配置将外部Blueprint集成到应用中
# 这些Blueprint将被集成到应用中
BLUEPRINTS: list[Blueprint] = []
# 提供一个可调用对象,接收tracking_url并返回另一个URL
# 用于将内部Hadoop作业跟踪器URL转换为代理URL
# 为Hive和Presto引擎转换SQL查询跟踪URL。您还可以
# 通过向转换函数添加第二个参数来访问查询本身的信息,例如:
# TRACKING_URL_TRANSFORMER = (
# lambda url, query: url if is_fresh(query) else None
# )
# pylint: disable-next=unnecessary-lambda-assignment
TRACKING_URL_TRANSFORMER = lambda url: url # noqa: E731
# 自定义每个引擎的轮询时间
DB_POLL_INTERVAL_SECONDS: dict[str, int] = {}
# 使用Presto引擎时的连续轮询间隔
# 参考:https://github.com/dropbox/PyHive/blob/8eb0aeab8ca300f3024655419b93dad926c1a351/pyhive/presto.py#L93 # pylint: disable=line-too-long,useless-suppression
PRESTO_POLL_INTERVAL = int(timedelta(seconds=1).total_seconds())
# 允许为每个数据库引擎自定义认证方式的白名单
# 示例:
# from your.module import AuthClass
# from another.extra import auth_method
#
# ALLOWED_EXTRA_AUTHENTICATIONS: Dict[str, Dict[str, Callable[..., Any]]] = {
# "trino": {
# "custom_auth": AuthClass,
# "another_auth_method": auth_method,
# },
# }
ALLOWED_EXTRA_AUTHENTICATIONS: dict[str, dict[str, Callable[..., Any]]] = {}
# 应复制给每个新用户的模板仪表板ID
DASHBOARD_TEMPLATE_ID = None
# 一个可调用对象,允许在运行时动态修改数据库连接URL和参数
# 这可用于实现模拟(impersonation)或任意逻辑。例如,您可以将不同用户
# 连接到使用不同的连接参数,或将他们的电子邮件地址作为用户名传递。
# 该函数接收连接uri对象、连接参数、用户名,并返回修改后的uri和params对象。
# 示例:
# def DB_CONNECTION_MUTATOR(uri, params, username, security_manager, source):
# user = security_manager.find_user(username=username)
# if user and user.email:
# uri.username = user.email
# return uri, params
#
# 注意返回的uri和params将直接传递给sqlalchemy的
# `create_engine(url, **params)`
DB_CONNECTION_MUTATOR = None
# 一个可调用对象,在每次调用DB Engine Specs时被调用,
# 用于对引擎URI进行自定义验证。
# 参见:superset.db_engine_specs.base.BaseEngineSpec.validate_database_uri
# 示例:
# def DB_ENGINE_URI_VALIDATOR(sqlalchemy_uri: URL):
# if not <some condition>:
# raise Exception("URI无效")
#
DB_SQLA_URI_VALIDATOR: Callable[[URL], None] | None = None
# 每个引擎不允许使用的SQL函数集合。用于限制在SQL Lab和图表中使用
# 不安全的SQL函数。字典的键是引擎名称,值是不允许的函数集合。
DISALLOWED_SQL_FUNCTIONS: dict[str, set[str]] = {
"postgresql": {
"database_to_xml",
"inet_client_addr",
"inet_server_addr",
"query_to_xml",
"query_to_xml_and_xmlschema",
"table_to_xml",
"table_to_xml_and_xmlschema",
"version",
},
"clickhouse": {"url"},
"mysql": {"version"},
}
# 一个拦截要执行的SQL并可修改它的函数。
# 常见用例是在SQL前添加某种注释头,
# 包含用户名和工作节点信息等信息
#
# def SQL_QUERY_MUTATOR(
# sql,
# security_manager=security_manager,
# database=database,
# ):
# dttm = datetime.now().isoformat()
# return f"-- [SQL LAB] {user_name} {dttm}\n{sql}"
#
# 注意:为了向后兼容,您可以在函数定义中解包上述任何参数,
# 但请将**kwargs作为最后一个参数,以允许以后添加新参数而不会出错。
# 注意:此函数中的任何操作都不会影响缓存键,因此理想情况下此函数
# 应该是"功能性的",即从其输入是确定性的。
def SQL_QUERY_MUTATOR( # pylint: disable=invalid-name,unused-argument
sql: str, **kwargs: Any
) -> str:
return sql
# 一个变量,选择是在拆分输入查询之前还是之后应用SQL_QUERY_MUTATOR
# 它允许使用SQL_QUERY_MUTATOR函数做更多事情而不仅仅是添加注释
# 用法:如果您想对给定查询的每个语句应用更改,请设置MUTATE_AFTER_SPLIT = True
# 一个示例用例是如果数据有基于角色的访问控制,并且您希望
# 在每个用户查询旁边应用SET ROLE语句。更改此变量可保持
# SQL_Lab和图表的功能。
MUTATE_AFTER_SPLIT = False
# 此函数允许用户为所有外发邮件添加头部数据。例如,
# 如果您需要在邮件头部包含元数据,或者想要修改
# 邮件标题、头部或发件人的规格。
def EMAIL_HEADER_MUTATOR( # pylint: disable=invalid-name,unused-argument
msg: MIMEMultipart, **kwargs: Any
) -> MIMEMultipart:
return msg
# 定义要从所有用户下拉列表中排除的用户名列表
# 包括所有者、创建者过滤器等。
# 也可以通过重写安全管理器中的get_exclude_users_from_lists方法
# 来排除这些用户
EXCLUDE_USERS_FROM_LISTS: list[str] | None = None
# 对于数据库连接,此字典将从可用列表/下拉菜单中移除
# 您不希望显示为可用的数据库引擎。
# 可用列表由已安装的驱动生成,某些引擎有多个驱动。
# 例如:DBS_AVAILABLE_DENYLIST: Dict[str, Set[str]] = {"databricks": {"pyhive", "pyodbc"}}
DBS_AVAILABLE_DENYLIST: dict[str, set[str]] = {}
# 此认证提供者用于需要访问受保护资源的后台(离线)任务。
# 终端用户可以重写它以支持自定义认证机制
MACHINE_AUTH_PROVIDER_CLASS = "superset.utils.machine_auth.MachineAuthProvider"
# ---------------------------------------------------
# 警报和报告
# ---------------------------------------------------
# 用于警报/报告(功能标志ALERT_REPORTS)设置滑动cron窗口大小,
# 应与celery beat配置同步(减去1秒)
ALERT_REPORTS_CRON_WINDOW_SIZE = 59
ALERT_REPORTS_WORKING_TIME_OUT_KILL = True
# 警报/报告尝试以哪个用户身份执行。默认情况下,
# 以警报/报告的主要所有者身份执行(优先考虑最后修改者,
# 如果创建者或最后修改者在所有者列表中,则使用他们,
# 否则使用第一个所有者)。
# 要首先尝试以所有者列表中的创建者身份执行(如果存在),然后回退到创建者,
# 然后是所有者列表中的最后修改者(如果存在),再到最后修改者,
# 再到所有者,最后是`THUMBNAIL_SELENIUM_USER`,设置如下:
# ALERT_REPORTS_EXECUTE_AS = [
# ExecutorType.CREATOR_OWNER,
# ExecutorType.CREATOR,
# ExecutorType.MODIFIER_OWNER,
# ExecutorType.MODIFIER,
# ExecutorType.OWNER,
# ExecutorType.SELENIUM,
# ]
ALERT_REPORTS_EXECUTE_AS: list[ExecutorType] = [ExecutorType.OWNER]
# 如果ALERT_REPORTS_WORKING_TIME_OUT_KILL为True,设置一个celery硬超时
# 等于工作超时 + ALERT_REPORTS_WORKING_TIME_OUT_LAG
ALERT_REPORTS_WORKING_TIME_OUT_LAG = int(timedelta(seconds=10).total_seconds())
# 如果ALERT_REPORTS_WORKING_TIME_OUT_KILL为True,设置一个celery硬超时
# 等于工作超时 + ALERT_REPORTS_WORKING_SOFT_TIME_OUT_LAG
ALERT_REPORTS_WORKING_SOFT_TIME_OUT_LAG = int(timedelta(seconds=1).total_seconds())
# 用户创建警报时使用的默认值
ALERT_REPORTS_DEFAULT_WORKING_TIMEOUT = 3600
ALERT_REPORTS_DEFAULT_RETENTION = 90
ALERT_REPORTS_DEFAULT_CRON_VALUE = "0 0 * * *" # 每天
# 如果设置为True,则不发送通知,工作线程仅记录消息。
# 对调试很有用
ALERT_REPORTS_NOTIFICATION_DRY_RUN = False
# 运行查询的最大尝试次数,防止因临时错误返回给用户导致的假错误。
# 设置大于1的值以启用重试。
ALERT_REPORTS_QUERY_EXECUTION_MAX_TRIES = 1
# 截图的自定义宽度
ALERT_REPORTS_MIN_CUSTOM_SCREENSHOT_WIDTH = 600
ALERT_REPORTS_MAX_CUSTOM_SCREENSHOT_WIDTH = 2400
# 设置执行之间的最小间隔阈值(针对每个警报/报告)
# 值应为整数,例如int(timedelta(minutes=5).total_seconds())
# 您也可以将一个返回预期整数的函数分配给配置
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=0).total_seconds())
REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=0).total_seconds())
# 在所有警报和报告邮件中使用自定义前缀
EMAIL_REPORTS_SUBJECT_PREFIX = "[Report] "
# 警报和报告邮件中行动号召链接的文本
EMAIL_REPORTS_CTA = "在Superset中探索"
# Superset报告使用的Slack API令牌,可以是字符串或可调用对象
SLACK_API_TOKEN: Callable[[], str] | str | None = None
SLACK_PROXY = None
# 用于生成报告的webdriver。使用以下之一:
# firefox
# 要求:安装geckodriver和firefox
# 限制:有时可能有bug
# chrome:
# 要求:无头chrome
# 限制:无法生成元素的截图
WEBDRIVER_TYPE = "firefox"
# 窗口大小 - 这将影响数据的渲染
WEBDRIVER_WINDOW = {
"dashboard": (1600, 2000),
"slice": (3000, 1200),
"pixel_density": 1,
}
# 可选覆盖默认的认证钩子,用于为离线webdriver(使用Selenium时)或浏览器上下文(使用Playwright时,
# 参见PLAYWRIGHT_REPORTS_AND_THUMBNAILS功能标志)提供认证
WEBDRIVER_AUTH_FUNC = None
# 直接传递给webdriver的任何配置选项
WEBDRIVER_CONFIGURATION: dict[Any, Any] = {"service_log_path": "/dev/null"}
# 作为参数传递给配置对象的额外参数
# 注意:如果使用Chrome,您需要添加"--marionette"参数
WEBDRIVER_OPTION_ARGS = ["--headless"]
# 用于访问用户界面的基础URL
WEBDRIVER_BASEURL = "http://0.0.0.0:8080/"
# 邮件报告中超链接使用的基础URL
WEBDRIVER_BASEURL_USER_FRIENDLY = WEBDRIVER_BASEURL
# Selenium等待邮件报告页面加载和渲染的时间
EMAIL_PAGE_RENDER_WAIT = int(timedelta(seconds=30).total_seconds())
# 将用户引导至可以报告bug的链接
BUG_REPORT_URL = None
BUG_REPORT_TEXT = "报告问题"
BUG_REPORT_ICON = None # 推荐尺寸:16x16
# 将用户引导至可以了解更多关于Superset的链接
DOCUMENTATION_URL = None
DOCUMENTATION_TEXT = "文档"
DOCUMENTATION_ICON = None # 推荐尺寸:16x16
# 时间选择器中"最近N天"相对于什么时间:
# 'today'表示本地时区的午夜(00:00:00)
# 'now'表示相对于查询发起时间
# 如果开始和结束时间都设置为now,这将使时间
# 过滤器成为一个移动窗口。如果仅将结束时间设置为now,
# 开始时间将被设置为午夜,而结束时间将相对于
# 查询发起时间。
DEFAULT_RELATIVE_START_TIME = "today"
DEFAULT_RELATIVE_END_TIME = "today"
# 配置每个引擎使用哪个SQL验证器
SQL_VALIDATORS_BY_ENGINE = {
"presto": "PrestoDBSQLValidator",
"postgresql": "PostgreSQLValidator",
}
# 首选数据库列表,按优先级排序。这些数据库将
# 在"添加数据库"对话框中突出显示。您应该使用
# `superset/db_engine_specs/`中相应DB引擎规范的"engine_name"属性
PREFERRED_DATABASES: list[str] = [
"PostgreSQL",
"Presto",
"MySQL",
"SQLite",
# 等等
]
# 添加新数据库时我们会尝试连接它。根据哪些参数不正确,
# 这可能需要几分钟时间,直到SQLAlchemy驱动程序ping数据库超时。
# 我们可以在这里指定一个更短的超时时间,而不是依赖驱动程序超时
TEST_DATABASE_CONNECTION_TIMEOUT = timedelta(seconds=30)
# 允许用户使用个人OAuth2令牌认证的数据库所需的详细信息。
# 更多信息参见https://github.com/apache/superset/issues/20300。
# scope和URI是可选的。
DATABASE_OAUTH2_CLIENTS: dict[str, dict[str, Any]] = {
# "Google Sheets": {
# "id": "XXX.apps.googleusercontent.com",
# "secret": "GOCSPX-YYY",
# "scope": " ".join(
# [
# "https://www.googleapis.com/auth/drive.readonly",
# "https://www.googleapis.com/auth/spreadsheets",
# "https://spreadsheets.google.com/feeds",
# ]
# ),
# "authorization_request_uri": "https://accounts.google.com/o/oauth2/v2/auth",
# "token_request_uri": "https://oauth2.googleapis.com/token",
# },
}
# OAuth2状态使用以下算法编码在JWT中
DATABASE_OAUTH2_JWT_ALGORITHM = "HS256"
# 默认情况下重定向URI指向/api/v1/database/oauth2/,不需要特别指定。
# 如果您运行多个Superset实例,您可能希望有一个代理处理重定向,
# 因为重定向URI需要在OAuth2应用中注册。在这种情况下,
# 代理可以通过查看OAuth2状态对象中的`default_redirect_uri`属性
# 将请求转发到正确的实例。
# DATABASE_OAUTH2_REDIRECT_URI = "http://localhost:8088/api/v1/database/oauth2/"
# 获取访问令牌和刷新令牌时的超时时间
DATABASE_OAUTH2_TIMEOUT = timedelta(seconds=30)
# 启用/禁用CSP警告
CONTENT_SECURITY_POLICY_WARNING = True
# 是否启用Talisman?
TALISMAN_ENABLED = utils.cast_to_boolean(os.environ.get("TALISMAN_ENABLED", True))
# 如果需要Talisman,您希望如何配置它?
TALISMAN_CONFIG = {
"content_security_policy": {
"base-uri": ["'self'"],
"default-src": ["'self'"],
"img-src": [
"'self'",
"blob:",
"data:",
"https://apachesuperset.gateway.scarf.sh",
"https://static.scarf.sh/",
# "https://avatars.slack-edge.com", # 当SLACK_ENABLE_AVATARS为True时取消注释
],
"worker-src": ["'self'", "blob:"],
"connect-src": [
"'self'",
"https://api.mapbox.com",
"https://events.mapbox.com",
],
"object-src": "'none'",
"style-src": [
"'self'",
"'unsafe-inline'",
],
"script-src": ["'self'", "'strict-dynamic'"],
},
"content_security_policy_nonce_in": ["script-src"],
"force_https": False,
"session_cookie_secure": False,
}
# React在开发模式下需要`eval`才能正常工作
TALISMAN_DEV_CONFIG = {
"content_security_policy": {
"base-uri": ["'self'"],
"default-src": ["'self'"],
"img-src": [
"'self'",
"blob:",
"data:",
"https://apachesuperset.gateway.scarf.sh",
"https://static.scarf.sh/",
"https://avatars.slack-edge.com",
],
"worker-src": ["'self'", "blob:"],
"connect-src": [
"'self'",
"https://api.mapbox.com",
"https://events.mapbox.com",
],
"object-src": "'none'",
"style-src": [
"'self'",
"'unsafe-inline'",
],
"script-src": ["'self'", "'unsafe-inline'", "'unsafe-eval'"],
},
"content_security_policy_nonce_in": ["script-src"],
"force_https": False,
"session_cookie_secure": False,
}
# Flask会话cookie选项
#
# 详情参见https://flask.palletsprojects.com/en/1.1.x/security/#set-cookie-options
#
SESSION_COOKIE_HTTPONLY = True # 防止前端JS读取cookie?
SESSION_COOKIE_SECURE = False # 防止cookie通过非TLS传输?
SESSION_COOKIE_SAMESITE: Literal["None", "Lax", "Strict"] | None = "Lax"
# 是否使用flask-session的服务器端会话或Flask安全cookie
SESSION_SERVER_SIDE = False
# 使用Redis作为服务器端会话后端的示例配置
# from flask_session import RedisSessionInterface
#
# SESSION_SERVER_SIDE = True
# SESSION_TYPE = "redis"
# SESSION_REDIS = Redis(host="localhost", port=6379, db=0)
#
# 其他可能的配置选项和后端:
# # https://flask-session.readthedocs.io/en/latest/config.html
# 缓存静态资源
SEND_FILE_MAX_AGE_DEFAULT = int(timedelta(days=365).total_seconds())
# 存储示例数据的数据库URI,如果设置为`None`则默认为SQLALCHEMY_DATABASE_URI
SQLALCHEMY_EXAMPLES_URI = "sqlite:///" + os.path.join(DATA_DIR, "examples.db")
# 可选前缀,在渲染UI时添加到所有静态资源路径
# 这对于在外部CDN托管资源非常有用
STATIC_ASSETS_PREFIX = ""
# 某些SQLAlchemy连接字符串可能会给Superset带来安全风险
# 通常这些应该被禁止
PREVENT_UNSAFE_DB_CONNECTIONS = True
# 如果为true,数据集上的所有默认URL在前端都将被视为相对URL
PREVENT_UNSAFE_DEFAULT_URLS_ON_DATASET = True
# 定义数据集数据导入(v1)允许的URL列表
# 简单示例,只允许属于特定域的URL:
# ALLOWED_IMPORT_URL_DOMAINS = [
# r"^https://.+\.domain1\.com\/?.*", r"^https://.+\.domain2\.com\/?.*"
# ]
DATASET_IMPORT_ALLOWED_DATA_URLS = [r".*"]
# 使用自定义证书时存储SSL证书的路径
# 默认为临时目录
# 示例:SSL_CERT_PATH = "/certs"
SSL_CERT_PATH: str | None = None
# SQLA表修改器,每次我们获取某个表的元数据
# (superset.connectors.sqla.models.SqlaTable)时,都会调用这个钩子
# 以允许使用此回调修改对象
# 这可以用于根据命名约定等设置对象的任何属性
# 您可以在测试中找到示例
# pylint: disable-next=unnecessary-lambda-assignment
SQLA_TABLE_MUTATOR = lambda table: table # noqa: E731
# 全局异步查询配置选项
# 需要启用GLOBAL_ASYNC_QUERIES功能标志
GLOBAL_ASYNC_QUERY_MANAGER_CLASS = (
"superset.async_events.async_query_manager.AsyncQueryManager"
)
GLOBAL_ASYNC_QUERIES_REDIS_CONFIG = {
"port": 6379,
"host": "127.0.0.1",
"password": "",
"db": 0,
"ssl": False,
}
GLOBAL_ASYNC_QUERIES_REDIS_STREAM_PREFIX = "async-events-"
GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT = 1000
GLOBAL_ASYNC_QUERIES_REDIS_STREAM_LIMIT_FIREHOSE = 1000000
GLOBAL_ASYNC_QUERIES_REGISTER_REQUEST_HANDLERS = True
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_NAME = "async-token"
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SECURE = False
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_SAMESITE: None | (Literal["None", "Lax", "Strict"]) = (
None
)
GLOBAL_ASYNC_QUERIES_JWT_COOKIE_DOMAIN = None
GLOBAL_ASYNC_QUERIES_JWT_SECRET = "test-secret-change-me"
GLOBAL_ASYNC_QUERIES_TRANSPORT: Literal["polling", "ws"] = "polling"
GLOBAL_ASYNC_QUERIES_POLLING_DELAY = int(
timedelta(milliseconds=500).total_seconds() * 1000
)
GLOBAL_ASYNC_QUERIES_WEBSOCKET_URL = "ws://127.0.0.1:8080/"
# 嵌入式配置选项
GUEST_ROLE_NAME = "Public"
GUEST_TOKEN_JWT_SECRET = "test-guest-secret-change-me"
GUEST_TOKEN_JWT_ALGO = "HS256"
GUEST_TOKEN_HEADER_NAME = "X-GuestToken"
GUEST_TOKEN_JWT_EXP_SECONDS = 300 # 5分钟
# 嵌入式superset的访客令牌受众,可以是字符串或可调用对象
GUEST_TOKEN_JWT_AUDIENCE: Callable[[], str] | str | None = None
# 可以提供一个可调用对象来对访客令牌配置进行额外验证
# 例如某些RLS参数:
# lambda x: len(x['rls']) == 1 and "tenant_id=" in x['rls'][0]['clause']
#
# 将GuestTokenUser字典作为参数
# 从可调用对象返回False将向用户返回HTTP 400
GUEST_TOKEN_VALIDATOR_HOOK = None
# SQL数据集健康检查。注意如果启用,强烈建议对可调用对象
# 进行记忆化(memoize)以提高性能,例如:
#
# @cache_manager.cache.memoize(timeout=0)
# def DATASET_HEALTH_CHECK(datasource: SqlaTable) -> Optional[str]:
# if (
# datasource.sql and
# len(sql_parse.ParsedQuery(datasource.sql, strip_comments=True).tables) == 1
# ):
# return (
# "此虚拟数据集仅查询一个表,因此可以直接查询该表来替代。"
# )
#
# return None
#
# 在FLASK_APP_MUTATOR可调用对象中,即应用和缓存初始化后,
# 还需要添加以下逻辑以在回调函数变更时清除所有数据源的缓存:
#
# def FLASK_APP_MUTATOR(app: Flask) -> None:
# name = "DATASET_HEALTH_CHECK"
# func = app.config[name]
# code = func.uncached.__code__.co_code
#
# if cache_manager.cache.get(name) != code:
# cache_manager.cache.delete_memoized(func)
# cache_manager.cache.set(name, code, timeout=0)
#
DATASET_HEALTH_CHECK: Callable[[SqlaTable], str] | None = None
# 高级数据类型键应与列元数据中设置的键对应
ADVANCED_DATA_TYPES: dict[str, AdvancedDataType] = {
"internet_address": internet_address,
"port": internet_port,
}
# 默认情况下,欢迎页面显示用户有权访问的所有图表和仪表板。
# 可以通过提供标题和FAB过滤器来更改为仅显示示例或自定义视图:
# WELCOME_PAGE_LAST_TAB = (
# "Xyz",
# [{"col": 'created_by', "opr": 'rel_o_m', "value": 10}],
# )
WELCOME_PAGE_LAST_TAB: Literal["examples", "all"] | tuple[str, list[dict[str, Any]]] = (
"all"
)
# 压缩文件允许的最大大小
ZIPPED_FILE_MAX_SIZE = 100 * 1024 * 1024 # 100MB
# 压缩文件允许的最大压缩比
ZIP_FILE_MAX_COMPRESS_RATIO = 200.0
# 导航栏环境标签的配置。将'text'设置为''将隐藏标签。
# 'color'可以是十六进制颜色代码,也可以是点索引的主题颜色(例如error.base)
ENVIRONMENT_TAG_CONFIG = {
"variable": "SUPERSET_ENV",
"values": {
"debug": {
"color": "error.base",
"text": "flask-debug",
},
"development": {
"color": "error.base",
"text": "开发环境",
},
"production": {
"color": "",
"text": "",
},
},
}
# 额外的关联查询过滤器可以限制UI中显示的对象。
# 例如,要在"所有者"下拉列表中仅显示"admin"或以字母"b"开头的用户,
# 可以在配置中添加以下内容:
# def user_filter(query: Query, *args, *kwargs):
# from superset import security_manager
#
# user_model = security_manager.user_model
# filters = [
# user_model.username == "admin",
# user_model.username.ilike("b%"),
# ]
# return query.filter(or_(*filters))
#
# EXTRA_RELATED_QUERY_FILTERS = {"user": user_filter}
#
# 类似地,要限制"角色"下拉列表中的角色,可以为"role"键提供自定义过滤器回调。
class ExtraRelatedQueryFilters(TypedDict, total=False):
role: Callable[[Query], Query]
user: Callable[[Query], Query]
EXTRA_RELATED_QUERY_FILTERS: ExtraRelatedQueryFilters = {}
# 额外的动态查询过滤器可以在应用任何其他过滤之前限制UI中显示的对象。
# 当考虑将功能标志与常规角色过滤器结合使用时非常有用,
# 这些过滤器默认在我们的base_filters中应用。
# 例如,要在"数据库连接"列表中仅显示以字母"b"开头的数据库,
# 可以在配置中添加以下内容:
# def initial_database_filter(query: Query, *args, *kwargs):
# from superset.models.core import Database
#
# filter = Database.database_name.startswith('b')
# return query.filter(filter)
#
# EXTRA_DYNAMIC_QUERY_FILTERS = {"database": initial_database_filter}
class ExtraDynamicQueryFilters(TypedDict, total=False):
databases: Callable[[Query], Query]
EXTRA_DYNAMIC_QUERY_FILTERS: ExtraDynamicQueryFilters = {}
# -------------------------------------------------------------------
# * 警告: 停止在此处编辑配置值 *
# -------------------------------------------------------------------
# 不要在此行下方添加配置值,因为本地配置将无法覆盖它们
if CONFIG_PATH_ENV_VAR in os.environ:
# 显式导入不在pythonpath中的配置模块;
# 对于通过pex执行应用程序的情况非常有用
cfg_path = os.environ[CONFIG_PATH_ENV_VAR]
try:
module = sys.modules[__name__]
override_conf = imp.load_source("superset_config", cfg_path)
for key in dir(override_conf):
if key.isupper():
setattr(module, key, getattr(override_conf, key))
click.secho(f"已加载您的本地配置文件于 [{cfg_path}]", fg="cyan")
except Exception:
logger.exception(
"导入配置失败 %s=%s", CONFIG_PATH_ENV_VAR, cfg_path
)
raise
elif importlib.util.find_spec("superset_config") and not is_test():
try:
# pylint: disable=import-error,wildcard-import,unused-wildcard-import
import superset_config
from superset_config import * # noqa: F403, F401
click.secho(
f"已加载您的本地配置文件于 [{superset_config.__file__}]",
fg="cyan",
)
except Exception:
logger.exception("找到但导入本地superset_config失败")
raise