跳至主要内容
在 GitHub 上编辑此页面

开发指南

为文档做贡献

最新的文档和教程可在 https://superset.org.cn/ 获取。

文档网站使用 Docusaurus 2 构建,这是一个现代静态网站生成器,其源代码位于 ./docs 目录中。

本地开发

要设置一个带有热重载功能的文档网站本地开发环境

cd docs
yarn install # Installs NPM dependencies
yarn start # Starts development server at https://127.0.0.1:3000

构建

要创建并提供文档网站的生产构建

yarn build
yarn serve

部署

master 的提交会触发文档网站的重建和重新部署。提交修改文档的拉取请求,并使用 docs: 前缀。

创建可视化插件

Superset 中的可视化效果在 JavaScript 或 TypeScript 中实现。Superset 预装了多种可视化类型(以下简称“可视化插件”),可以在 superset-frontend/plugins 目录下找到。可视化插件在 superset-frontend/src/visualizations/presets/MainPreset.js 中添加到应用程序中。Superset 项目始终乐于审查高质量可视化插件的新提案。但是,对于高度定制的可视化类型,建议维护 Superset 的分支,并手动添加自定义构建的可视化插件。

注意:有关创建和部署自定义可视化插件的更多社区资源,请访问 Superset Wiki

先决条件

要创建新的可视化插件,您需要以下条件

  • 运行 MacOS 或 Linux(Windows 未正式支持,但可能有效)
  • Node.js 16
  • npm 7 或 8

还建议您对 React 和 npm/Node 系统有所了解。

创建简单的 Hello World 可视化插件

要开始,您需要 Superset Yeoman 生成器。建议使用与您正在使用的 Superset 版本捆绑在一起的模板版本。可以通过以下步骤进行安装

npm i -g yo
cd superset-frontend/packages/generator-superset
npm i
npm link

之后,您可以继续创建可视化插件。为可视化插件创建一个新目录,并使用 superset-plugin-chart 前缀,然后运行 Yeoman 生成器

mkdir /tmp/superset-plugin-chart-hello-world
cd /tmp/superset-plugin-chart-hello-world

初始化可视化插件

yo @superset-ui/superset

之后,生成器会问一些问题(默认值应该没问题)

$ yo @superset-ui/superset
_-----_ ╭──────────────────────────╮
| | │ Welcome to the │
|--(o)--| │ generator-superset │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
? Package name: superset-plugin-chart-hello-world
? Description: Hello World
? What type of chart would you like? Time-series chart
create package.json
create .gitignore
create babel.config.js
create jest.config.js
create README.md
create tsconfig.json
create src/index.ts
create src/plugin/buildQuery.ts
create src/plugin/controlPanel.ts
create src/plugin/index.ts
create src/plugin/transformProps.ts
create src/types.ts
create src/SupersetPluginChartHelloWorld.tsx
create test/index.test.ts
create test/__mocks__/mockExportString.js
create test/plugin/buildQuery.test.ts
create test/plugin/transformProps.test.ts
create types/external.d.ts
create src/images/thumbnail.png

要构建可视化插件,请运行以下命令

npm i --force
npm run build

或者,要在开发模式下运行可视化插件(=在进行更改时重建),请使用以下命令启动开发服务器

npm run dev

要将包添加到 Superset,请转到 Superset 源文件夹中的 superset-frontend 子目录,然后运行

npm i -S /tmp/superset-plugin-chart-hello-world

如果您将包发布到 npm,自然也可以直接从那里安装。之后,编辑 superset-frontend/src/visualizations/presets/MainPreset.js 并进行以下更改

import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';

导入可视化插件,然后将以下内容添加到传递给 plugins 属性的数组中

new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),

之后,可视化插件应该在您运行 Superset 时显示出来,例如开发服务器

npm run dev-server

测试

Python 测试

所有 Python 测试都在 tox 中进行,这是一个标准化的测试框架。所有 Python 测试可以通过任何 tox 环境 运行,方法是:

tox -e <environment>

例如:

tox -e py38

或者,您可以通过以下方式运行单个文件中的所有测试:

tox -e <environment> -- tests/test_file.py

或者,对于特定的测试,您可以通过以下方式运行:

tox -e <environment> -- tests/test_file.py::TestClassName::test_method_name

请注意,测试环境使用临时目录来定义 SQLite 数据库,这些数据库将在每次调用测试命令组之前清除。

Superset 代码库中还包含一个实用程序脚本用于运行 Python 集成测试。可以在 此处找到自述文件

要运行所有集成测试,例如,从根目录运行此脚本

scripts/tests/run.sh

您可以使用 pytest 运行位于 './tests/unit_tests' 中的单元测试。这是一种简单的方法,可以运行不需要任何数据库设置的隔离测试

pytest ./link_to_test.py

使用本地 Presto 连接进行测试

如果您碰巧更改了 Presto/Trino 的数据库引擎规范,可以使用 Docker 运行本地 Presto 集群

docker run -p 15433:15433 starburstdata/presto:350-e.6

然后更新 SUPERSET__SQLALCHEMY_EXAMPLES_URI 以指向本地 Presto 集群

export SUPERSET__SQLALCHEMY_EXAMPLES_URI=presto://127.0.0.1:15433/memory/default

前端测试

我们使用 JestEnzyme 测试 TypeScript/JavaScript。可以使用以下命令运行测试:

cd superset-frontend
npm run test

要运行单个测试文件

npm run test -- path/to/file.js

e2e 集成测试

我们使用 Cypress 进行端到端集成测试。快速入门的一种简单方法是利用 tox 在隔离环境中运行整个套件。

tox -e cypress

或者,您可以按照以下步骤在开发环境中进行更低级的设置

首先设置 python/flask 后端

export SUPERSET_CONFIG=tests.integration_tests.superset_test_config
export SUPERSET_TESTENV=true
export CYPRESS_BASE_URL="https://127.0.0.1:8081"
superset db upgrade
superset load_test_users
superset init
superset load-examples --load-test-data
superset run --port 8081

在另一个终端中,准备前端并运行 Cypress 测试

cd superset-frontend
npm run build-instrumented

cd cypress-base
npm install

# run tests via headless Chrome browser (requires Chrome 64+)
npm run cypress-run-chrome

# run tests from a specific file
npm run cypress-run-chrome -- --spec cypress/e2e/explore/link.test.ts

# run specific file with video capture
npm run cypress-run-chrome -- --spec cypress/e2e/dashboard/index.test.js --config video=true

# to open the cypress ui
npm run cypress-debug

# to point cypress to a url other than the default (https://127.0.0.1:8088) set the environment variable before running the script
# e.g., CYPRESS_BASE_URL="https://127.0.0.1:9000"
CYPRESS_BASE_URL=<your url> npm run cypress open

请参见 superset-frontend/cypress_build.sh

或者,您可以使用 docker compose 环境进行测试

确保您已将以下行添加到 /etc/hosts 文件中:127.0.0.1 db

如果您已经启动了 Docker 环境,请使用以下命令确保新的数据库实例:docker compose down -v

启动环境

CYPRESS_CONFIG=true docker compose up

它将在端口 8088 上提供后端和前端。

运行 Cypress 测试

cd cypress-base
npm install
npm run cypress open

调试服务器应用程序

请按照这些说明调试在 docker 容器中运行的 Flask 应用程序。

首先将以下内容添加到 ./docker-compose.yaml 文件中

superset:
env_file: docker/.env
image: *superset-image
container_name: superset_app
command: ["/app/docker/docker-bootstrap.sh", "app"]
restart: unless-stopped
+ cap_add:
+ - SYS_PTRACE
ports:
- 8088:8088
+ - 5678:5678
user: "root"
depends_on: *superset-depends-on
volumes: *superset-volumes
environment:
CYPRESS_CONFIG: "${CYPRESS_CONFIG}"

像往常一样启动 Superset

docker compose up

将所需的库和包安装到 docker 容器中

进入 superset_app 容器

docker exec -it superset_app /bin/bash
root@39ce8cf9d6ab:/app#

在容器中运行以下命令

apt update
apt install -y gdb
apt install -y net-tools
pip install debugpy

查找 Flask 进程的 PID。确保使用第一个 PID。每次更改任何 Python 代码时,Flask 应用程序都会重新生成一个子进程。因此,使用第一个 PID 很重要。

ps -ef

UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:09 ? 00:00:00 bash /app/docker/docker-bootstrap.sh app
root 6 1 4 14:09 ? 00:00:04 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0
root 10 6 7 14:09 ? 00:00:07 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0

将 debugpy 注入正在运行的 Flask 进程中。在本例中,PID 为 6。

python3 -m debugpy --listen 0.0.0.0:5678 --pid 6

验证 debugpy 是否正在监听端口 5678

netstat -tunap

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5678 0.0.0.0:* LISTEN 462/python
tcp 0 0 0.0.0.0:8088 0.0.0.0:* LISTEN 6/python

您现在可以将调试器附加到该进程。使用 VSCode,您可以配置一个类似于以下内容的启动配置文件 .vscode/launch.json。

{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Superset App in Docker Container",
"type": "python",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app"
}
]
},
]
}

VSCode 不会立即在断点处停止。我们已附加到 PID 6,但它尚未识别任何子进程。为了“唤醒”调试器,您需要修改一个 Python 文件。这将触发 Flask 重新加载代码并创建一个新的子进程。VSCode 将检测到这个新的子进程,断点将被激活。

在 Kubernetes 环境中调试服务器应用程序

要调试在 Kubernetes 集群内的 POD 中运行的 Flask,您需要确保该 POD 作为 root 运行,并被授予 SYS_TRACE 功能。这些设置不应在生产环境中使用。

  securityContext:
capabilities:
add: ["SYS_PTRACE"]

有关更多详细信息,请参见 为容器设置功能

一旦 POD 作为 root 运行并具有 SYS_PTRACE 功能,它将能够调试 Flask 应用程序。

您可以按照与 docker compose 中相同的说明进行操作。进入 POD 并安装所需的库和包;gdb、netstat 和 debugpy。

通常,在 Kubernetes 环境中,节点无法从集群外部访问。因此,VSCode 将无法远程连接到 Kubernetes 节点上的端口 5678。要做到这一点,您需要创建一个将 5678 端口转发到本地计算机的隧道。

kubectl port-forward  pod/superset-<some random id> 5678:5678

您现在可以使用与上述相同的配置启动 VSCode 调试器。VSCode 将连接到 127.0.0.1:5678,该端口由 kubectl 转发到您的远程 Kubernetes POD。

Storybook

Superset 包含一个 Storybook,用于预览各种 Superset 组件的布局/样式,以及它们的变体。要打开并查看 Storybook

cd superset-frontend
npm run storybook

为 Superset 贡献新的 React 组件时,请尝试在该组件的 jsx/tsx 文件旁边添加一个 Story。

贡献翻译

我们使用 Flask-Babel 翻译 Superset。在 Python 文件中,我们使用以下 翻译函数 来自 Flask-Babel

  • gettextlazy_gettext(通常缩写为 _):用于翻译单个字符串。
  • ngettext:用于翻译可能变为复数的字符串。
from flask_babel import lazy_gettext as _

然后用它包装可翻译的字符串,例如 _('Translate me')。在提取过程中,传递给 _ 的字符串文字将被添加到为每种语言生成的 .po 文件中,以便以后进行翻译。

在运行时,_ 函数将返回当前语言给定字符串的翻译,如果不存在翻译,则返回给定字符串本身。

在 TypeScript/JavaScript 中,技术类似:我们导入 t(简单翻译)、tn(包含数字的翻译)。

import { t, tn } from "@superset-ui/translation";

启用语言选择

LANGUAGES 变量添加到您的 superset_config.py 中。在其中包含多个选项将向导航栏右侧的 UI 添加一个语言选择下拉菜单。

LANGUAGES = {
'en': {'flag': 'us', 'name': 'English'},
'fr': {'flag': 'fr', 'name': 'French'},
'zh': {'flag': 'cn', 'name': 'Chinese'},
}

创建新的语言字典

首先检查您的目标语言的语言代码是否已存在。检查您的目标语言的 两位字母的 ISO 639-1 代码 是否已存在于 superset/translations 目录中

ls superset/translations | grep -E "^[a-z]{2}\/"

如果您的语言已有预先存在的翻译,请跳过下一节

以下语言已由 Flask AppBuilder 支持,这将使将应用程序翻译成您的目标语言变得更加容易:Flask AppBuilder i18n 文档

要为新语言创建字典,首先确保已安装必要的依赖项

pip install -r superset/translations/requirements.txt

然后运行以下命令,将 LANGUAGE_CODE 替换为您的目标语言的语言代码

pybabel init -i superset/translations/messages.pot -d superset/translations -l LANGUAGE_CODE

例如,要添加芬兰语(语言代码 fi)的翻译,请运行以下命令

pybabel init -i superset/translations/messages.pot -d superset/translations -l fi

提取新的翻译字符串

在进行翻译时,我们需要定期从后端和前端提取字符串,以编译所有要翻译的字符串的列表。它不会自动发生,而是收集字符串并将它们放到 .po 文件中以供翻译的必要步骤,这样才能编译它们。

此脚本就是这样做的

./scripts/translations/babel_update.sh

更新语言文件

运行以下命令使用新提取的字符串更新语言文件。

 pybabel update -i superset/translations/messages.pot -d superset/translations --ignore-obsolete

然后,您可以翻译收集在 superset/translation 下面的文件中的字符串,每个语言对应一个文件夹。您可以使用 Poedit 更方便地翻译 po 文件。以下是一个 教程

要在 MacOS 上执行翻译,可以通过 Homebrew 安装 poedit

brew install poedit

之后,只需启动 poedit 应用程序并打开 messages.po 文件即可。在芬兰语翻译的情况下,这将是 superset/translations/fi/LC_MESSAGES/messages.po

应用翻译

要使翻译在前端可用,我们需要将 PO 文件转换为 JSON 文件集合。要将所有 PO 文件转换为格式化的 JSON 文件,可以使用 build-translation 脚本

# Install dependencies if you haven't already
cd superset-frontend/ && npm ci
# Compile translations for the frontend
npm run build-translation

最后,为了使翻译生效,我们需要使用pybabel将翻译目录编译成后端使用的二进制 MO 文件。

# inside the project root
pybabel compile -d superset/translations

代码风格检查

Python

我们使用 Pylint 进行代码风格检查,可以通过以下方式调用:

# for python
tox -e pylint

在最佳实践方面,请避免全局(通过.pylintrc)或文件头部的顶级级别禁用 Pylint 消息,尽管有一些例外。禁用应该在内联进行,因为它可以防止掩盖问题并提供有关禁用该消息的原因的上下文。

此外,Python 代码使用 Black 自动格式化,它被配置为 pre-commit 钩子。还有许多 编辑器集成

TypeScript

cd superset-frontend
npm ci
# run eslint checks
npm run eslint -- .
# run tsc (typescript) checks
npm run type

如果使用带有 vscode 的 eslint 扩展,请将以下内容放在您的工作区settings.json文件中

"eslint.workingDirectories": [
"superset-frontend"
]