diff --git a/.asf.yaml b/.asf.yaml
index 0b7ec5a5b85bb..9fdad3908c074 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -72,6 +72,7 @@ github:
- cypress-matrix (3, chrome)
- cypress-matrix (4, chrome)
- cypress-matrix (5, chrome)
+ - dependency-review
- frontend-build
- pre-commit (current)
- pre-commit (next)
diff --git a/.dockerignore b/.dockerignore
index 33b76412b60cb..31c873f0073f9 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -42,6 +42,7 @@ docs/
install/
superset-frontend/cypress-base/
superset-frontend/coverage/
+superset-frontend/.temp_cache/
superset/static/assets/
superset-websocket/dist/
venv
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index f1b0fea5b7e5a..520bad78189c1 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -16,17 +16,17 @@
# Notify E2E test maintainers of changes
-/superset-frontend/cypress-base/ @jinghua-qa @geido @eschutho @rusackas @betodealmeida
+/superset-frontend/cypress-base/ @sadpandajoe @geido @eschutho @rusackas @betodealmeida
# Notify PMC members of changes to GitHub Actions
-/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @john-bodley @kgabryje @dpgaspar
+/.github/ @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar
# Notify PMC members of changes to required GitHub Actions
-/.asf.yaml @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @john-bodley @kgabryje @dpgaspar
+/.asf.yaml @villebro @geido @eschutho @rusackas @betodealmeida @nytai @mistercrunch @craig-rueda @kgabryje @dpgaspar
-# Maps are a finnicky contribution process we care about
+# Maps are a finicky contribution process we care about
**/*.geojson @villebro @rusackas
/superset-frontend/plugins/legacy-plugin-chart-country-map/ @villebro @rusackas
diff --git a/.github/actions/setup-backend/action.yml b/.github/actions/setup-backend/action.yml
index 1910f48514580..2d2f993ffb20e 100644
--- a/.github/actions/setup-backend/action.yml
+++ b/.github/actions/setup-backend/action.yml
@@ -44,10 +44,13 @@ runs:
if [ "${{ inputs.install-superset }}" = "true" ]; then
sudo apt-get update && sudo apt-get -y install libldap2-dev libsasl2-dev
pip install --upgrade pip setuptools wheel uv
+
if [ "${{ inputs.requirements-type }}" = "dev" ]; then
uv pip install --system -r requirements/development.txt
elif [ "${{ inputs.requirements-type }}" = "base" ]; then
uv pip install --system -r requirements/base.txt
fi
+
+ uv pip install --system -e .
fi
shell: bash
diff --git a/.github/actions/setup-docker/action.yml b/.github/actions/setup-docker/action.yml
new file mode 100644
index 0000000000000..71a559829f673
--- /dev/null
+++ b/.github/actions/setup-docker/action.yml
@@ -0,0 +1,69 @@
+name: "Setup Docker Environment"
+description: "Reusable steps for setting up QEMU, Docker Buildx, DockerHub login, Supersetbot, and optionally Docker Compose"
+inputs:
+ build:
+ description: "Used for building?"
+ required: false
+ default: "false"
+ dockerhub-user:
+ description: "DockerHub username"
+ required: false
+ dockerhub-token:
+ description: "DockerHub token"
+ required: false
+ install-docker-compose:
+ description: "Flag to install Docker Compose"
+ required: false
+ default: "true"
+ login-to-dockerhub:
+ description: "Whether you want to log into dockerhub"
+ required: false
+ default: "true"
+outputs: {}
+runs:
+ using: "composite"
+ steps:
+
+ - name: Set up QEMU
+ if: ${{ inputs.build == 'true' }}
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ if: ${{ inputs.build == 'true' }}
+ uses: docker/setup-buildx-action@v3
+
+ - name: Try to login to DockerHub
+ if: ${{ inputs.login-to-dockerhub == 'true' }}
+ continue-on-error: true
+ uses: docker/login-action@v3
+ with:
+ username: ${{ inputs.dockerhub-user }}
+ password: ${{ inputs.dockerhub-token }}
+
+ - name: Install Docker Compose
+ if: ${{ inputs.install-docker-compose == 'true' }}
+ shell: bash
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y ca-certificates curl
+ sudo install -m 0755 -d /etc/apt/keyrings
+
+ # Download and save the Docker GPG key in the correct format
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
+
+ # Ensure the key file is readable
+ sudo chmod a+r /etc/apt/keyrings/docker.gpg
+
+ # Add the Docker repository using the correct key
+ echo \
+ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
+ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
+ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
+
+ # Update package lists and install Docker Compose plugin
+ sudo apt update
+ sudo apt install -y docker-compose-plugin
+
+ - name: Docker Version Info
+ shell: bash
+ run: docker info
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 286749a78cea2..089473a3a3f8c 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -22,8 +22,7 @@ updates:
# - package-ecosystem: "pip"
- # NOTE: as dependabot isn't compatible with our python
- # dependency setup (pip-compile-multi), we'll be using
+ # NOTE: as dependabot isn't compatible with our usage of `uv pip compile` we're using
# `supersetbot` instead
- package-ecosystem: "npm"
diff --git a/.github/workflows/bump-python-package.yml b/.github/workflows/bump-python-package.yml
index 9f3fff5cee55f..6a57d20f1b5c5 100644
--- a/.github/workflows/bump-python-package.yml
+++ b/.github/workflows/bump-python-package.yml
@@ -45,8 +45,8 @@ jobs:
with:
python-version: "3.10"
- - name: Install pip-compile-multi
- run: pip install pip-compile-multi
+ - name: Install uv
+ run: pip install uv
- name: supersetbot bump-python -p "${{ github.event.inputs.package }}"
env:
diff --git a/.github/workflows/check-python-deps.yml b/.github/workflows/check-python-deps.yml
new file mode 100644
index 0000000000000..749c41b75f89a
--- /dev/null
+++ b/.github/workflows/check-python-deps.yml
@@ -0,0 +1,44 @@
+name: Check python dependencies
+
+on:
+ push:
+ branches:
+ - "master"
+ - "[0-9].[0-9]*"
+ pull_request:
+ types: [synchronize, opened, reopened, ready_for_review]
+
+# cancel previous workflow jobs for PRs
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ check-python-deps:
+ runs-on: ubuntu-22.04
+ steps:
+
+ - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+ submodules: recursive
+ depth: 1
+
+ - name: Setup Python
+ if: steps.check.outputs.python
+ uses: ./.github/actions/setup-backend/
+
+ - name: Run uv
+ if: steps.check.outputs.python
+ run: ./scripts/uv-pip-compile.sh
+
+ - name: Check for uncommitted changes
+ run: |
+ if [[ -n "$(git diff)" ]]; then
+ echo "ERROR: The pinned dependencies are not up-to-date."
+ echo "Please run './scripts/uv-pip-compile.sh' and commit the changes."
+ exit 1
+ else
+ echo "Pinned dependencies are up-to-date."
+ fi
diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml
index 08771876bfd68..0b98678bb1fb6 100644
--- a/.github/workflows/dependency-review.yml
+++ b/.github/workflows/dependency-review.yml
@@ -5,13 +5,25 @@
# Source repository: https://github.com/actions/dependency-review-action
# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
name: "Dependency Review"
-on: [pull_request]
+on:
+ push:
+ branches:
+ - "master"
+ - "[0-9].[0-9]*"
+ pull_request:
+ types: [synchronize, opened, reopened, ready_for_review]
+
+# cancel previous workflow jobs for PRs
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
+ cancel-in-progress: true
permissions:
contents: read
jobs:
dependency-review:
+ if: github.event_name == 'pull_request'
runs-on: ubuntu-22.04
steps:
- name: "Checkout Repository"
@@ -33,3 +45,24 @@ jobs:
# pkg:npm/node-forge@1.3.1
# selecting BSD-3-Clause licensing terms for node-forge to ensure compatibility with Apache
allow-dependencies-licenses: pkg:npm/store2@2.14.2, pkg:npm/applitools/core, pkg:npm/applitools/core-base, pkg:npm/applitools/css-tree, pkg:npm/applitools/ec-client, pkg:npm/applitools/eg-socks5-proxy-server, pkg:npm/applitools/eyes, pkg:npm/applitools/eyes-cypress, pkg:npm/applitools/nml-client, pkg:npm/applitools/tunnel-client, pkg:npm/applitools/utils, pkg:npm/node-forge@1.3.1, pkg:npm/rgbcolor, pkg:npm/jszip@3.10.1
+
+ python-dependency-liccheck:
+ runs-on: ubuntu-22.04
+ steps:
+ - name: "Checkout Repository"
+ uses: actions/checkout@v4
+
+ - name: Setup Python
+ uses: ./.github/actions/setup-backend/
+ with:
+ requirements-type: base
+
+ - name: "Set up liccheck"
+ run: |
+ uv pip install --system liccheck
+ - name: "Run liccheck"
+ run: |
+ # run the checks
+ liccheck -R output.txt
+ # Print the report
+ cat output.txt
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 287026c084412..91256651f1a5a 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -15,20 +15,20 @@ concurrency:
jobs:
setup_matrix:
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
outputs:
matrix_config: ${{ steps.set_matrix.outputs.matrix_config }}
steps:
- id: set_matrix
run: |
- MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311"]'; fi)
+ MATRIX_CONFIG=$(if [ "${{ github.event_name }}" == "pull_request" ]; then echo '["dev", "lean"]'; else echo '["dev", "lean", "py310", "websocket", "dockerize", "py311"]'; fi)
echo "matrix_config=${MATRIX_CONFIG}" >> $GITHUB_OUTPUT
echo $GITHUB_OUTPUT
docker-build:
name: docker-build
needs: setup_matrix
- runs-on: ubuntu-22.04
+ runs-on: ubuntu-24.04
strategy:
matrix:
build_preset: ${{fromJson(needs.setup_matrix.outputs.matrix_config)}}
@@ -50,21 +50,13 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
- - name: Set up QEMU
+ - name: Setup Docker Environment
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
- uses: docker/setup-qemu-action@v3
-
- - name: Set up Docker Buildx
- if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
- uses: docker/setup-buildx-action@v3
-
- - name: Try to login to DockerHub
- if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
- continue-on-error: true
- uses: docker/login-action@v3
+ uses: ./.github/actions/setup-docker
with:
- username: ${{ secrets.DOCKERHUB_USER }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
+ dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
+ dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
+ build: "true"
- name: Setup supersetbot
if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
@@ -84,7 +76,30 @@ jobs:
fi
supersetbot docker \
+ --push \
--preset ${{ matrix.build_preset }} \
--context "$EVENT" \
--context-ref "$RELEASE" $FORCE_LATEST \
+ --extra-flags "--build-arg INCLUDE_CHROMIUM=false" \
$PLATFORM_ARG
+
+ - name: Docker pull
+ if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
+ run: docker pull apache/superset:GHA-${GITHUB_RUN_ID}
+
+ - name: Print docker stats
+ if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
+ run: |
+ IMAGE_ID=$(docker images --filter "label=sha=${{ github.sha }}" --format "{{.ID}}" | head -n 1)
+ echo "SHA: ${{ github.sha }}"
+ echo "IMAGE: $IMAGE_ID"
+ docker images $IMAGE_ID
+ docker history $IMAGE_ID
+
+ - name: docker-compose sanity check
+ if: (steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker) && (matrix.build_preset == 'dev' || matrix.build_preset == 'lean')
+ shell: bash
+ run: |
+ export SUPERSET_BUILD_TARGET=${{ matrix.build_preset }}
+ docker compose build superset-init --build-arg DEV_MODE=false --build-arg INCLUDE_CHROMIUM=false
+ docker compose up superset-init --exit-code-from superset-init
diff --git a/.github/workflows/ephemeral-env.yml b/.github/workflows/ephemeral-env.yml
index acf3b0cc72124..92a0512b0bd75 100644
--- a/.github/workflows/ephemeral-env.yml
+++ b/.github/workflows/ephemeral-env.yml
@@ -27,6 +27,9 @@ jobs:
outputs:
slash-command: ${{ steps.eval-body.outputs.result }}
feature-flags: ${{ steps.eval-feature-flags.outputs.result }}
+ env:
+ DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
+ DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
steps:
- name: Debug
@@ -139,31 +142,24 @@ jobs:
ref: ${{ steps.get-sha.outputs.sha }}
persist-credentials: false
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
+ - name: Setup Docker Environment
+ uses: ./.github/actions/setup-docker
+ with:
+ dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
+ dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
+ build: "true"
+ install-docker-compose: "false"
- name: Setup supersetbot
uses: ./.github/actions/setup-supersetbot/
- - name: Try to login to DockerHub
- if: steps.check.outputs.python || steps.check.outputs.frontend || steps.check.outputs.docker
- continue-on-error: true
- uses: docker/login-action@v3
- with:
- username: ${{ secrets.DOCKERHUB_USER }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- name: Build ephemeral env image
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- username: ${{ secrets.DOCKERHUB_USER }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
run: |
supersetbot docker \
+ --push \
+ --load \
--preset ci \
--platform linux/amd64 \
--context-ref "$RELEASE" \
diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml
index ec06bc8e1cf63..096b1dfa1cbaa 100644
--- a/.github/workflows/tag-release.yml
+++ b/.github/workflows/tag-release.yml
@@ -45,17 +45,20 @@ jobs:
build_preset: ["dev", "lean", "py310", "websocket", "dockerize", "py311"]
fail-fast: false
steps:
- - name: Set up QEMU
- uses: docker/setup-qemu-action@v3
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
uses: actions/checkout@v4
with:
fetch-depth: 0
+ - name: Setup Docker Environment
+ uses: ./.github/actions/setup-docker
+ with:
+ dockerhub-user: ${{ secrets.DOCKERHUB_USER }}
+ dockerhub-token: ${{ secrets.DOCKERHUB_TOKEN }}
+ install-docker-compose: "false"
+ build: "true"
+
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
@@ -64,13 +67,6 @@ jobs:
- name: Setup supersetbot
uses: ./.github/actions/setup-supersetbot/
- - name: Try to login to DockerHub
- continue-on-error: true
- uses: docker/login-action@v3
- with:
- username: ${{ secrets.DOCKERHUB_USER }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
-
- name: Execute custom Node.js script
env:
DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }}
@@ -91,6 +87,7 @@ jobs:
fi
supersetbot docker \
+ --push \
--preset ${{ matrix.build_preset }} \
--context "$EVENT" \
--context-ref "$RELEASE" $FORCE_LATEST \
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 60107de11c0f2..f4361616527e1 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -38,10 +38,6 @@ repos:
types-paramiko,
types-Markdown,
]
- - repo: https://github.com/peterdemin/pip-compile-multi
- rev: v2.6.4
- hooks:
- - id: pip-compile-multi-verify
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
diff --git a/Dockerfile b/Dockerfile
index 4ee30930898d3..4f24360988101 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -52,12 +52,11 @@ WORKDIR /app/superset-frontend
RUN mkdir -p /app/superset/static/assets \
/app/superset/translations
-# Copy translation files
-COPY superset/translations /app/superset/translations
-
# Mount package files and install dependencies if not in dev mode
RUN --mount=type=bind,source=./superset-frontend/package.json,target=./package.json \
--mount=type=bind,source=./superset-frontend/package-lock.json,target=./package-lock.json \
+ --mount=type=cache,target=/root/.cache \
+ --mount=type=cache,target=/root/.npm \
if [ "$DEV_MODE" = "false" ]; then \
npm ci; \
else \
@@ -68,16 +67,24 @@ RUN --mount=type=bind,source=./superset-frontend/package.json,target=./package.j
COPY superset-frontend /app/superset-frontend
# Build the frontend if not in dev mode
-RUN if [ "$DEV_MODE" = "false" ]; then \
+RUN --mount=type=cache,target=/app/superset-frontend/.temp_cache \
+ --mount=type=cache,target=/root/.npm \
+ if [ "$DEV_MODE" = "false" ]; then \
echo "Running 'npm run ${BUILD_CMD}'"; \
- if [ "$BUILD_TRANSLATIONS" = "true" ]; then \
- npm run build-translation; \
- fi; \
npm run ${BUILD_CMD}; \
else \
echo "Skipping 'npm run ${BUILD_CMD}' in dev mode"; \
- fi && \
- rm -rf /app/superset/translations/*/*/*.po
+ fi;
+
+# Copy translation files
+COPY superset/translations /app/superset/translations
+
+# Build the frontend if not in dev mode
+RUN if [ "$BUILD_TRANSLATIONS" = "true" ]; then \
+ npm run build-translation; \
+ fi; \
+ rm -rf /app/superset/translations/*/*/*.po; \
+ rm -rf /app/superset/translations/*/*/*.mo;
######################################################################
@@ -103,7 +110,7 @@ RUN useradd --user-group -d ${SUPERSET_HOME} -m --no-log-init --shell /bin/bash
# Some bash scripts needed throughout the layers
COPY --chmod=755 docker/*.sh /app/docker/
-RUN pip install --no-cache-dir --upgrade setuptools pip uv
+RUN pip install --no-cache-dir --upgrade uv
# Using uv as it's faster/simpler than pip
RUN uv venv /app/.venv
@@ -112,9 +119,9 @@ ENV PATH="/app/.venv/bin:${PATH}"
# Install Playwright and optionally setup headless browsers
ARG INCLUDE_CHROMIUM="true"
ARG INCLUDE_FIREFOX="false"
-RUN --mount=type=cache,target=/root/.cache/pip \
+RUN --mount=type=cache,target=/root/.cache/uv\
if [ "$INCLUDE_CHROMIUM" = "true" ] || [ "$INCLUDE_FIREFOX" = "true" ]; then \
- pip install playwright && \
+ uv pip install playwright && \
playwright install-deps && \
if [ "$INCLUDE_CHROMIUM" = "true" ]; then playwright install chromium; fi && \
if [ "$INCLUDE_FIREFOX" = "true" ]; then playwright install firefox; fi; \
@@ -129,12 +136,15 @@ FROM python-base AS python-translation-compiler
# Install Python dependencies using docker/pip-install.sh
COPY requirements/translations.txt requirements/
-RUN --mount=type=cache,target=/root/.cache/pip \
- /app/docker/pip-install.sh -r requirements/translations.txt
+RUN --mount=type=cache,target=/root/.cache/uv \
+ /app/docker/pip-install.sh --requires-build-essential -r requirements/translations.txt
COPY superset/translations/ /app/translations_mo/
-RUN pybabel compile -d /app/translations_mo | true && \
- rm -f /app/translations_mo/*/*/*.po
+RUN if [ "$BUILD_TRANSLATIONS" = "true" ]; then \
+ pybabel compile -d /app/translations_mo | true; \
+ fi; \
+ rm -f /app/translations_mo/*/*/*.po; \
+ rm -f /app/translations_mo/*/*/*.json;
######################################################################
# Python APP common layer
@@ -175,6 +185,11 @@ RUN /app/docker/apt-install.sh \
# Copy compiled things from previous stages
COPY --from=superset-node /app/superset/static/assets superset/static/assets
+# TODO, when the next version comes out, use --exclude superset/translations
+COPY superset superset
+# TODO in the meantime, remove the .po files
+RUN rm superset/translations/*/*/*.po
+
# Merging translations from backend and frontend stages
COPY --from=superset-node /app/superset/translations superset/translations
COPY --from=python-translation-compiler /app/translations_mo superset/translations
@@ -187,12 +202,13 @@ EXPOSE ${SUPERSET_PORT}
# Final lean image...
######################################################################
FROM python-common AS lean
-COPY superset superset
# Install Python dependencies using docker/pip-install.sh
COPY requirements/base.txt requirements/
-RUN --mount=type=cache,target=/root/.cache/pip \
- /app/docker/pip-install.sh --requires-build-essential -r requirements/base.txt && \
+RUN --mount=type=cache,target=/root/.cache/uv \
+ /app/docker/pip-install.sh --requires-build-essential -r requirements/base.txt
+# Install the superset package
+RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install .
RUN python -m compileall /app/superset
@@ -203,7 +219,6 @@ USER superset
# Dev image...
######################################################################
FROM python-common AS dev
-COPY superset superset
# Debian libs needed for dev
RUN /app/docker/apt-install.sh \
@@ -214,8 +229,10 @@ RUN /app/docker/apt-install.sh \
# Copy development requirements and install them
COPY requirements/*.txt requirements/
# Install Python dependencies using docker/pip-install.sh
-RUN --mount=type=cache,target=/root/.cache/pip \
- /app/docker/pip-install.sh --requires-build-essential -r requirements/development.txt && \
+RUN --mount=type=cache,target=/root/.cache/uv \
+ /app/docker/pip-install.sh --requires-build-essential -r requirements/development.txt
+# Install the superset package
+RUN --mount=type=cache,target=/root/.cache/uv \
uv pip install .
RUN python -m compileall /app/superset
diff --git a/RELEASING/changelog.py b/RELEASING/changelog.py
index 80ff98cba6953..c33a9b03c3ac2 100644
--- a/RELEASING/changelog.py
+++ b/RELEASING/changelog.py
@@ -272,14 +272,14 @@ def __repr__(self) -> str:
@staticmethod
def _git_get_current_head() -> str:
- output = os.popen("git status | head -1").read()
+ output = os.popen("git status | head -1").read() # noqa: S605, S607
match = re.match("(?:HEAD detached at|On branch) (.*)", output)
if not match:
return ""
return match.group(1)
def _git_checkout(self, git_ref: str) -> None:
- os.popen(f"git checkout {git_ref}").read()
+ os.popen(f"git checkout {git_ref}").read() # noqa: S605
current_head = self._git_get_current_head()
if current_head != git_ref:
print(f"Could not checkout {git_ref}")
@@ -290,7 +290,7 @@ def _git_logs(self) -> list[str]:
current_git_ref = self._git_get_current_head()
self._git_checkout(self._git_ref)
output = (
- os.popen('git --no-pager log --pretty=format:"%h|%an|%ae|%ad|%s|"')
+ os.popen('git --no-pager log --pretty=format:"%h|%an|%ae|%ad|%s|"') # noqa: S605, S607
.read()
.split("\n")
)
diff --git a/RELEASING/generate_email.py b/RELEASING/generate_email.py
index ac9ca4a27ccef..2936635cfea05 100755
--- a/RELEASING/generate_email.py
+++ b/RELEASING/generate_email.py
@@ -31,7 +31,7 @@
RECEIVER_EMAIL = "dev@superset.apache.org"
PROJECT_NAME = "Superset"
PROJECT_MODULE = "superset"
-PROJECT_DESCRIPTION = "Apache Superset is a modern, enterprise-ready business intelligence web application."
+PROJECT_DESCRIPTION = "Apache Superset is a modern, enterprise-ready business intelligence web application." # noqa: E501
def string_comma_to_list(message: str) -> list[str]:
diff --git a/RELEASING/verify_release.py b/RELEASING/verify_release.py
index 3502636100572..61bbf073ab059 100755
--- a/RELEASING/verify_release.py
+++ b/RELEASING/verify_release.py
@@ -23,12 +23,12 @@
import requests
-# Part 1: Verify SHA512 hash - this is the same as running `shasum -a 512 {release}` and comparing it against `{release}.sha512`
+# Part 1: Verify SHA512 hash - this is the same as running `shasum -a 512 {release}` and comparing it against `{release}.sha512` # noqa: E501
def get_sha512_hash(filename: str) -> str:
"""Run the shasum command on the file and return the SHA512 hash."""
- result = subprocess.run(["shasum", "-a", "512", filename], stdout=subprocess.PIPE)
+ result = subprocess.run(["shasum", "-a", "512", filename], stdout=subprocess.PIPE) # noqa: S603, S607
sha512_hash = result.stdout.decode().split()[0]
return sha512_hash
@@ -43,7 +43,7 @@ def read_sha512_file(filename: str) -> str:
def verify_sha512(filename: str) -> str:
- """Verify if the SHA512 hash of the file matches with the hash in the .sha512 file."""
+ """Verify if the SHA512 hash of the file matches with the hash in the .sha512 file.""" # noqa: E501
sha512_hash = get_sha512_hash(filename)
sha512_file_content = read_sha512_file(filename)
@@ -53,14 +53,15 @@ def verify_sha512(filename: str) -> str:
return "SHA failed"
-# Part 2: Verify RSA key - this is the same as running `gpg --verify {release}.asc {release}` and comparing the RSA key and email address against the KEYS file
+# Part 2: Verify RSA key - this is the same as running `gpg --verify {release}.asc {release}` and comparing the RSA key and email address against the KEYS file # noqa: E501
def get_gpg_info(filename: str) -> tuple[Optional[str], Optional[str]]:
"""Run the GPG verify command and extract RSA key and email address."""
asc_filename = filename + ".asc"
- result = subprocess.run(
- ["gpg", "--verify", asc_filename, filename], capture_output=True
+ result = subprocess.run( # noqa: S603
+ ["gpg", "--verify", asc_filename, filename], # noqa: S607
+ capture_output=True, # noqa: S607
)
output = result.stderr.decode()
@@ -90,7 +91,7 @@ def get_gpg_info(filename: str) -> tuple[Optional[str], Optional[str]]:
def verify_key(key: str, email: Optional[str]) -> str:
"""Fetch the KEYS file and verify if the RSA/EDDSA key and email match."""
url = "https://downloads.apache.org/superset/KEYS"
- response = requests.get(url)
+ response = requests.get(url) # noqa: S113
if response.status_code == 200:
if key not in response.text:
return "RSA/EDDSA key not found on KEYS page"
diff --git a/RESOURCES/INTHEWILD.md b/RESOURCES/INTHEWILD.md
index 26ea8a1597e5d..2006bd34a1c8e 100644
--- a/RESOURCES/INTHEWILD.md
+++ b/RESOURCES/INTHEWILD.md
@@ -79,7 +79,7 @@ Join our growing community!
- [Astronomer](https://www.astronomer.io) [@ryw]
- [Avesta Technologies](https://avestatechnologies.com/) [@TheRum]
- [Caizin](https://caizin.com/) [@tejaskatariya]
-- [Careem](https://www.careem.com/) [@SamraHanifCareem]
+- [Careem](https://www.careem.com/) [@samraHanif0340]
- [Cloudsmith](https://cloudsmith.io) [@alancarson]
- [Cyberhaven](https://www.cyberhaven.com/) [@toliver-ch]
- [Deepomatic](https://deepomatic.com/) [@Zanoellia]
diff --git a/docker-compose.yml b/docker-compose.yml
index 32355dbad2daa..e248e973e6355 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -35,11 +35,14 @@ x-superset-volumes: &superset-volumes
x-common-build: &common-build
context: .
- target: dev
+ target: ${SUPERSET_BUILD_TARGET:-dev} # can use `dev` (default) or `lean`
cache_from:
- apache/superset-cache:3.10-slim-bookworm
args:
DEV_MODE: "true"
+ INCLUDE_CHROMIUM: ${INCLUDE_CHROMIUM:-false}
+ INCLUDE_FIREFOX: ${INCLUDE_FIREFOX:-false}
+ BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
services:
nginx:
@@ -157,6 +160,7 @@ services:
# and build it on startup while firing docker-frontend.sh in dev mode, where
# it'll mount and watch local files and rebuild as you update them
DEV_MODE: "true"
+ BUILD_TRANSLATIONS: ${BUILD_TRANSLATIONS:-false}
environment:
# set this to false if you have perf issues running the npm i; npm run dev in-docker
# if you do so, you have to run this manually on the host, which should perform better!
diff --git a/docker/docker-bootstrap.sh b/docker/docker-bootstrap.sh
index 1a4e04be94e7a..1338e0cea5dd7 100755
--- a/docker/docker-bootstrap.sh
+++ b/docker/docker-bootstrap.sh
@@ -30,12 +30,16 @@ if [ "$CYPRESS_CONFIG" == "true" ]; then
export SUPERSET_TESTENV=true
export SUPERSET__SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://superset:superset@db:5432/superset
fi
+if [[ "$DATABASE_DIALECT" == postgres* ]] ; then
+ echo "Installing postgres requirements"
+ uv pip install -e .[postgres]
+fi
#
# Make sure we have dev requirements installed
#
if [ -f "${REQUIREMENTS_LOCAL}" ]; then
echo "Installing local overrides at ${REQUIREMENTS_LOCAL}"
- pip install --no-cache-dir -r "${REQUIREMENTS_LOCAL}"
+ uv pip install --no-cache-dir -r "${REQUIREMENTS_LOCAL}"
else
echo "Skipping local overrides"
fi
diff --git a/docker/docker-frontend.sh b/docker/docker-frontend.sh
index b80e12a0ca79a..f851576730fce 100755
--- a/docker/docker-frontend.sh
+++ b/docker/docker-frontend.sh
@@ -35,7 +35,7 @@ if [ "$BUILD_SUPERSET_FRONTEND_IN_DOCKER" = "true" ]; then
echo "Running `npm install`"
npm install
- echo "Running frontend"
+ echo "Start webpack dev server"
npm run dev
else
diff --git a/docker/pythonpath_dev/superset_config.py b/docker/pythonpath_dev/superset_config.py
index e8223e53584bc..5b14e6b1849e1 100644
--- a/docker/pythonpath_dev/superset_config.py
+++ b/docker/pythonpath_dev/superset_config.py
@@ -99,7 +99,7 @@ class CeleryConfig:
FEATURE_FLAGS = {"ALERT_REPORTS": True}
ALERT_REPORTS_NOTIFICATION_DRY_RUN = True
-WEBDRIVER_BASEURL = "http://superset:8088/" # When using docker compose baseurl should be http://superset_app:8088/
+WEBDRIVER_BASEURL = "http://superset:8088/" # When using docker compose baseurl should be http://superset_app:8088/ # noqa: E501
# The base URL for the email report hyperlinks.
WEBDRIVER_BASEURL_USER_FRIENDLY = WEBDRIVER_BASEURL
SQLLAB_CTAS_NO_LIMIT = True
diff --git a/docs/data/countries.json b/docs/data/countries.json
index dc5319b8743d7..34e505b2e3263 100644
--- a/docs/data/countries.json
+++ b/docs/data/countries.json
@@ -63,6 +63,7 @@
"Fiji",
"Finland",
"France",
+ "France (with overseas)",
"France (regions)",
"French Polynesia",
"Gabon",
diff --git a/docs/docs/contributing/development.mdx b/docs/docs/contributing/development.mdx
index a20e1e246fd6c..ac58f92e8dfda 100644
--- a/docs/docs/contributing/development.mdx
+++ b/docs/docs/contributing/development.mdx
@@ -72,6 +72,19 @@ documentation.
configured to be secure.
:::
+### Supported environment variables
+
+Affecting the Docker build process:
+- **SUPERSET_BUILD_TARGET (default=dev):** which --target to build, either `lean` or `dev` are commonly used
+- **INCLUDE_FIREFOX (default=false):** whether to include the Firefox headless browser in the build
+- **INCLUDE_CHROMIUM (default=false):** whether to include the Firefox headless browser in the build
+- **BUILD_TRANSLATIONS(default=false):** whether to compile the translations from the .po files available
+
+For more env vars that affect your configuration, see this
+[superset_config.py](https://github.com/apache/superset/blob/master/docker/pythonpath_dev/superset_config.py)
+used in the `docker compose` context to assign env vars to the superset configuration.
+
+
### Nuking the postgres database
At times, it's possible to end up with your development database in a bad state, it's
@@ -242,19 +255,19 @@ If you add a new requirement or update an existing requirement (per the `install
$ python3 -m venv venv
$ source venv/bin/activate
$ python3 -m pip install -r requirements/development.txt
-$ pip-compile-multi --no-upgrade
+$ ./scripts/uv-pip-compile.sh
```
-When upgrading the version number of a single package, you should run `pip-compile-multi` with the `-P` flag:
+When upgrading the version number of a single package, you should run `./scripts/uv-pip-compile.sh` with the `-P` flag:
```bash
-$ pip-compile-multi -P my-package
+$ ./scripts/uv-pip-compile.sh -P some-package-to-upgrade
```
-To bring all dependencies up to date as per the restrictions defined in `setup.py` and `requirements/*.in`, run pip-compile-multi` without any flags:
+To bring all dependencies up to date as per the restrictions defined in `setup.py` and `requirements/*.in`, run `./scripts/uv-pip-compile.sh --upgrade`
```bash
-$ pip-compile-multi
+$ ./scripts/uv-pip-compile.sh --upgrade
```
This should be done periodically, but it is recommended to do thorough manual testing of the application to ensure no breaking changes have been introduced that aren't caught by the unit and integration tests.
diff --git a/pyproject.toml b/pyproject.toml
index b1412ccaaa29b..b9cf62c4b793f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -24,7 +24,7 @@ name = "apache-superset"
description = "A modern, enterprise-ready business intelligence web application"
readme = "README.md"
dynamic = ["version", "scripts", "entry-points"]
-requires-python = "~=3.9"
+requires-python = ">=3.9"
license = { file="LICENSE.txt" }
authors = [
{ name = "Apache Software Foundation", email = "dev@superset.apache.org" },
@@ -191,7 +191,6 @@ development = [
"grpcio>=1.55.3",
"openapi-spec-validator",
"parameterized",
- "pip-compile-multi",
"pre-commit",
"progress>=1.5,<2",
"psutil",
@@ -216,7 +215,7 @@ combine_as_imports = true
include_trailing_comma = true
line_length = 88
known_first_party = "superset"
-known_third_party = "alembic, apispec, backoff, celery, click, colorama, cron_descriptor, croniter, cryptography, dateutil, deprecation, flask, flask_appbuilder, flask_babel, flask_caching, flask_compress, flask_jwt_extended, flask_login, flask_migrate, flask_sqlalchemy, flask_talisman, flask_testing, flask_wtf, freezegun, geohash, geopy, holidays, humanize, isodate, jinja2, jwt, markdown, markupsafe, marshmallow, msgpack, nh3, numpy, pandas, parameterized, parsedatetime, pgsanity, pkg_resources, polyline, prison, progress, pyarrow, sqlalchemy_bigquery, pyhive, pyparsing, pytest, pytest_mock, pytz, redis, requests, selenium, setuptools, shillelagh, simplejson, slack, sqlalchemy, sqlalchemy_utils, sqlparse, typing_extensions, urllib3, werkzeug, wtforms, wtforms_json, yaml"
+known_third_party = "alembic, apispec, backoff, celery, click, colorama, cron_descriptor, croniter, cryptography, dateutil, deprecation, flask, flask_appbuilder, flask_babel, flask_caching, flask_compress, flask_jwt_extended, flask_login, flask_migrate, flask_sqlalchemy, flask_talisman, flask_testing, flask_wtf, freezegun, geohash, geopy, holidays, humanize, isodate, jinja2, jwt, markdown, markupsafe, marshmallow, msgpack, nh3, numpy, pandas, parameterized, parsedatetime, pgsanity, polyline, prison, progress, pyarrow, sqlalchemy_bigquery, pyhive, pyparsing, pytest, pytest_mock, pytz, redis, requests, selenium, setuptools, shillelagh, simplejson, slack, sqlalchemy, sqlalchemy_utils, sqlparse, typing_extensions, urllib3, werkzeug, wtforms, wtforms_json, yaml"
multi_line_output = 3
order_by_type = false
@@ -277,8 +276,8 @@ exclude = [
line-length = 88
indent-width = 4
-# Assume Python 3.8
-target-version = "py310"
+# Assume Python 3.9
+target-version = "py39"
[tool.ruff.lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
@@ -291,22 +290,24 @@ select = [
"E9",
"PT009",
"TRY201",
- # TODO add these rules in follow up PR
- # "B",
- # "C",
- # "E",
- # "F",
- #"F",
- # "I",
- # "N",
- # "PT",
- # "Q",
- # "S",
- # "T",
- #"W",
+ "B",
+ "C",
+ "E",
+ "F",
+ "F",
+ "I",
+ "N",
+ "PT",
+ "Q",
+ "S",
+ "T",
+ "W",
]
ignore = [
"S101",
+ "PT006",
+ "T201",
+ "N999",
]
extend-select = ["I"]
@@ -360,3 +361,36 @@ docstring-code-format = false
# This only has an effect when the `docstring-code-format` setting is
# enabled.
docstring-code-line-length = "dynamic"
+
+[tool.liccheck]
+requirement_txt_file = "requirements/base.txt"
+authorized_licenses = [
+ "academic free license (afl)",
+ "apache license 2.0",
+ "apache software",
+ "apache software, bsd",
+ "bsd",
+ "isc license (iscl)",
+ "isc license",
+ "mit",
+ "mozilla public license 2.0 (mpl 2.0)",
+ "osi approved",
+ "osi approved",
+ "python software foundation",
+ "the unlicense (unlicense)",
+ "the unlicense",
+]
+[tool.liccheck.authorized_packages]
+# --------------------------------------------------------------
+# These are ok, checked manually
+# Seems ok, might need legal review
+# https://github.com/urschrei/pypolyline/blob/master/LICENSE.md
+polyline = "2"
+# Apache 2.0 https://github.com/hkwi/python-geohash
+python-geohash = "0"
+# --------------------------------------------------------------
+
+# TODO REMOVE THESE DEPS FROM CODEBASE
+func-timeout = "4" # AGPL
+paramiko = "3" # GPL
+pyxlsb = "1" # GPL
diff --git a/requirements/base.in b/requirements/base.in
index ca3a260a0eeea..17f5379cc837f 100644
--- a/requirements/base.in
+++ b/requirements/base.in
@@ -16,7 +16,6 @@
# specific language governing permissions and limitations
# under the License.
#
--e file:.
urllib3>=1.26.18
werkzeug>=3.0.1
numexpr>=2.9.0
diff --git a/requirements/base.txt b/requirements/base.txt
index 3ee2be0bf51dc..b2979900f7603 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -1,17 +1,10 @@
-# SHA1:04f7e0860829f18926ea238354e6d4a6ab823d50
-#
-# This file is autogenerated by pip-compile-multi
-# To update, run:
-#
-# pip-compile-multi
-#
--e file:.
- # via -r requirements/base.in
+# This file was autogenerated by uv via the following command:
+# uv pip compile pyproject.toml requirements/base.in -o requirements/base.txt
alembic==1.14.0
# via flask-migrate
amqp==5.3.1
# via kombu
-apispec[yaml]==6.3.0
+apispec==6.3.0
# via flask-appbuilder
apsw==3.46.0.0
# via shillelagh
@@ -27,7 +20,7 @@ attrs==24.2.0
babel==2.16.0
# via flask-babel
backoff==2.2.1
- # via apache-superset
+ # via apache-superset (pyproject.toml)
bcrypt==4.2.1
# via paramiko
billiard==4.2.1
@@ -35,7 +28,7 @@ billiard==4.2.1
blinker==1.9.0
# via flask
bottleneck==1.4.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
brotli==1.1.0
# via flask-compress
cachelib==0.9.0
@@ -47,7 +40,7 @@ cachetools==5.5.0
cattrs==24.1.2
# via requests-cache
celery==5.4.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
certifi==2024.8.30
# via requests
cffi==1.17.1
@@ -58,7 +51,7 @@ charset-normalizer==3.4.0
# via requests
click==8.1.7
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# celery
# click-didyoumean
# click-option-group
@@ -69,22 +62,22 @@ click==8.1.7
click-didyoumean==0.3.1
# via celery
click-option-group==0.5.6
- # via apache-superset
+ # via apache-superset (pyproject.toml)
click-plugins==1.1.1
# via celery
click-repl==0.3.0
# via celery
colorama==0.4.6
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
cron-descriptor==1.4.5
- # via apache-superset
+ # via apache-superset (pyproject.toml)
croniter==5.0.1
- # via apache-superset
+ # via apache-superset (pyproject.toml)
cryptography==43.0.3
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# paramiko
# pyopenssl
defusedxml==0.7.1
@@ -92,7 +85,7 @@ defusedxml==0.7.1
deprecated==1.2.15
# via limits
deprecation==2.1.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
dnspython==2.7.0
# via email-validator
email-validator==2.2.0
@@ -103,7 +96,7 @@ exceptiongroup==1.2.2
# via cattrs
flask==2.3.3
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
# flask-babel
# flask-caching
@@ -116,66 +109,66 @@ flask==2.3.3
# flask-sqlalchemy
# flask-wtf
flask-appbuilder==4.5.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-babel==2.0.0
# via flask-appbuilder
flask-caching==2.3.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-compress==1.17
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-jwt-extended==4.7.1
# via flask-appbuilder
flask-limiter==3.8.0
# via flask-appbuilder
flask-login==0.6.3
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
flask-migrate==3.1.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-session==0.8.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-sqlalchemy==2.5.1
# via
# flask-appbuilder
# flask-migrate
flask-talisman==1.1.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
flask-wtf==1.2.2
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
func-timeout==4.3.5
- # via apache-superset
+ # via apache-superset (pyproject.toml)
geographiclib==2.0
# via geopy
geopy==2.4.1
- # via apache-superset
+ # via apache-superset (pyproject.toml)
google-auth==2.36.0
# via shillelagh
greenlet==3.0.3
# via
# -r requirements/base.in
- # apache-superset
+ # apache-superset (pyproject.toml)
# shillelagh
gunicorn==23.0.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
hashids==1.3.1
- # via apache-superset
+ # via apache-superset (pyproject.toml)
holidays==0.25
- # via apache-superset
+ # via apache-superset (pyproject.toml)
humanize==4.11.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
idna==3.10
# via
# email-validator
# requests
importlib-metadata==8.5.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
importlib-resources==6.4.5
# via limits
isodate==0.7.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
itsdangerous==2.2.0
# via
# flask
@@ -185,7 +178,7 @@ jinja2==3.1.4
# flask
# flask-babel
jsonpath-ng==1.7.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
jsonschema==4.17.3
# via flask-appbuilder
kombu==5.4.2
@@ -196,10 +189,10 @@ limits==3.13.0
# via flask-limiter
mako==1.3.6
# via
+ # apache-superset (pyproject.toml)
# alembic
- # apache-superset
markdown==3.7
- # via apache-superset
+ # via apache-superset (pyproject.toml)
markdown-it-py==3.0.0
# via rich
markupsafe==3.0.2
@@ -217,16 +210,16 @@ marshmallow-sqlalchemy==0.28.2
mdurl==0.1.2
# via markdown-it-py
msgpack==1.0.8
- # via apache-superset
+ # via apache-superset (pyproject.toml)
msgspec==0.18.6
# via flask-session
nh3==0.2.19
- # via apache-superset
+ # via apache-superset (pyproject.toml)
numexpr==2.10.2
# via -r requirements/base.in
numpy==1.23.5
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# bottleneck
# numexpr
# pandas
@@ -239,7 +232,7 @@ ordered-set==4.1.0
# via flask-limiter
packaging==24.2
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# apispec
# deprecation
# gunicorn
@@ -247,28 +240,28 @@ packaging==24.2
# marshmallow
# marshmallow-sqlalchemy
# shillelagh
-pandas[excel]==2.0.3
- # via apache-superset
+pandas==2.0.3
+ # via apache-superset (pyproject.toml)
paramiko==3.5.0
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# sshtunnel
parsedatetime==2.6
- # via apache-superset
+ # via apache-superset (pyproject.toml)
pgsanity==0.2.9
- # via apache-superset
+ # via apache-superset (pyproject.toml)
platformdirs==3.8.1
# via requests-cache
ply==3.11
# via jsonpath-ng
polyline==2.0.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
prison==0.2.1
# via flask-appbuilder
prompt-toolkit==3.0.48
- # via click-repl
+ # via click-
pyarrow==18.1.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
pyasn1==0.6.1
# via
# pyasn1-modules
@@ -281,7 +274,7 @@ pygments==2.18.0
# via rich
pyjwt==2.10.1
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
# flask-jwt-extended
pynacl==1.5.0
@@ -289,12 +282,12 @@ pynacl==1.5.0
pyopenssl==24.2.1
# via shillelagh
pyparsing==3.2.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
pyrsistent==0.20.0
# via jsonschema
python-dateutil==2.9.0.post0
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# celery
# croniter
# flask-appbuilder
@@ -302,9 +295,9 @@ python-dateutil==2.9.0.post0
# pandas
# shillelagh
python-dotenv==1.0.1
- # via apache-superset
+ # via apache-superset (pyproject.toml)
python-geohash==0.8.5
- # via apache-superset
+ # via apache-superset (pyproject.toml)
pytz==2024.2
# via
# croniter
@@ -314,10 +307,10 @@ pyxlsb==1.0.10
# via pandas
pyyaml==6.0.2
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# apispec
redis==4.6.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
requests==2.32.2
# via
# requests-cache
@@ -329,13 +322,13 @@ rich==13.9.4
rsa==4.9
# via google-auth
selenium==3.141.0
- # via apache-superset
-shillelagh[gsheetsapi]==1.2.18
- # via apache-superset
+ # via apache-superset (pyproject.toml)
+shillelagh==1.2.18
+ # via apache-superset (pyproject.toml)
shortid==0.1.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
simplejson==3.19.3
- # via apache-superset
+ # via apache-superset (pyproject.toml)
six==1.16.0
# via
# prison
@@ -343,11 +336,11 @@ six==1.16.0
# url-normalize
# wtforms-json
slack-sdk==3.33.4
- # via apache-superset
+ # via apache-superset (pyproject.toml)
sqlalchemy==1.4.54
# via
+ # apache-superset (pyproject.toml)
# alembic
- # apache-superset
# flask-appbuilder
# flask-sqlalchemy
# marshmallow-sqlalchemy
@@ -355,20 +348,20 @@ sqlalchemy==1.4.54
# sqlalchemy-utils
sqlalchemy-utils==0.38.3
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
sqlglot==25.24.5
- # via apache-superset
+ # via apache-superset (pyproject.toml)
sqlparse==0.5.2
- # via apache-superset
+ # via apache-superset (pyproject.toml)
sshtunnel==0.4.0
- # via apache-superset
+ # via apache-superset (pyproject.toml)
tabulate==0.8.10
- # via apache-superset
+ # via apache-superset (pyproject.toml)
typing-extensions==4.12.2
# via
+ # apache-superset (pyproject.toml)
# alembic
- # apache-superset
# cattrs
# flask-limiter
# limits
@@ -405,17 +398,17 @@ wrapt==1.17.0
# via deprecated
wtforms==3.2.1
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# flask-appbuilder
# flask-wtf
# wtforms-json
wtforms-json==0.3.5
- # via apache-superset
+ # via apache-superset (pyproject.toml)
xlrd==2.0.1
# via pandas
xlsxwriter==3.0.9
# via
- # apache-superset
+ # apache-superset (pyproject.toml)
# pandas
zipp==3.21.0
# via importlib-metadata
diff --git a/requirements/development.in b/requirements/development.in
index e48d78f1d37ea..99584560e58bb 100644
--- a/requirements/development.in
+++ b/requirements/development.in
@@ -16,5 +16,4 @@
# specific language governing permissions and limitations
# under the License.
#
--r base.in
--e .[development,bigquery,cors,druid,gevent,gsheets,mysql,playwright,postgres,presto,prophet,trino,thumbnails]
+-e .[development,bigquery,cors,druid,gevent,gsheets,mysql,postgres,presto,prophet,trino,thumbnails]
diff --git a/requirements/development.txt b/requirements/development.txt
index 1afbd47d0c213..a4b9ec2b6588f 100644
--- a/requirements/development.txt
+++ b/requirements/development.txt
@@ -1,54 +1,294 @@
-# SHA1:dc767a7288b56c785b0cd3c38e95e7b5e66be1ac
-#
-# This file is autogenerated by pip-compile-multi
-# To update, run:
-#
-# pip-compile-multi
-#
--r base.txt
--e file:.
- # via
- # -r /Users/max/code/superset/requirements/base.in
- # -r requirements/development.in
-build==1.2.1
- # via pip-tools
+# This file was autogenerated by uv via the following command:
+# uv pip compile requirements/development.in -c requirements/base.txt -o requirements/development.txt
+-e .
+ # via -r requirements/development.in
+alembic==1.14.0
+ # via
+ # -c requirements/base.txt
+ # flask-migrate
+amqp==5.3.1
+ # via
+ # -c requirements/base.txt
+ # kombu
+apispec==6.3.0
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+apsw==3.46.0.0
+ # via
+ # -c requirements/base.txt
+ # shillelagh
+async-timeout==4.0.3
+ # via
+ # -c requirements/base.txt
+ # redis
+attrs==24.2.0
+ # via
+ # -c requirements/base.txt
+ # cattrs
+ # jsonschema
+ # requests-cache
+babel==2.16.0
+ # via
+ # -c requirements/base.txt
+ # flask-babel
+backoff==2.2.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+bcrypt==4.2.1
+ # via
+ # -c requirements/base.txt
+ # paramiko
+billiard==4.2.1
+ # via
+ # -c requirements/base.txt
+ # celery
+blinker==1.9.0
+ # via
+ # -c requirements/base.txt
+ # flask
+bottleneck==1.4.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+brotli==1.1.0
+ # via
+ # -c requirements/base.txt
+ # flask-compress
+cachelib==0.9.0
+ # via
+ # -c requirements/base.txt
+ # flask-caching
+ # flask-session
+cachetools==5.5.0
+ # via
+ # -c requirements/base.txt
+ # google-auth
+cattrs==24.1.2
+ # via
+ # -c requirements/base.txt
+ # requests-cache
+celery==5.4.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+certifi==2024.8.30
+ # via
+ # -c requirements/base.txt
+ # requests
+cffi==1.17.1
+ # via
+ # -c requirements/base.txt
+ # cryptography
+ # pynacl
cfgv==3.4.0
# via pre-commit
+charset-normalizer==3.4.0
+ # via
+ # -c requirements/base.txt
+ # requests
+click==8.1.7
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # celery
+ # click-didyoumean
+ # click-option-group
+ # click-plugins
+ # click-repl
+ # flask
+ # flask-appbuilder
+click-didyoumean==0.3.1
+ # via
+ # -c requirements/base.txt
+ # celery
+click-option-group==0.5.6
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+click-plugins==1.1.1
+ # via
+ # -c requirements/base.txt
+ # celery
+click-repl==0.3.0
+ # via
+ # -c requirements/base.txt
+ # celery
cmdstanpy==1.1.0
# via prophet
+colorama==0.4.6
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
contourpy==1.0.7
# via matplotlib
-coverage[toml]==7.6.8
+coverage==7.6.8
# via pytest-cov
+cron-descriptor==1.4.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+croniter==5.0.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+cryptography==43.0.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # paramiko
+ # pyopenssl
cycler==0.12.1
# via matplotlib
db-dtypes==1.3.1
# via pandas-gbq
+defusedxml==0.7.1
+ # via
+ # -c requirements/base.txt
+ # odfpy
+deprecated==1.2.15
+ # via
+ # -c requirements/base.txt
+ # limits
+deprecation==2.1.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
distlib==0.3.8
# via virtualenv
+dnspython==2.7.0
+ # via
+ # -c requirements/base.txt
+ # email-validator
docker==7.0.0
# via apache-superset
+email-validator==2.2.0
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+et-xmlfile==2.0.0
+ # via
+ # -c requirements/base.txt
+ # openpyxl
+exceptiongroup==1.2.2
+ # via
+ # -c requirements/base.txt
+ # cattrs
+ # pytest
filelock==3.12.2
# via virtualenv
+flask==2.3.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
+ # flask-babel
+ # flask-caching
+ # flask-compress
+ # flask-cors
+ # flask-jwt-extended
+ # flask-limiter
+ # flask-login
+ # flask-migrate
+ # flask-session
+ # flask-sqlalchemy
+ # flask-testing
+ # flask-wtf
+flask-appbuilder==4.5.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+flask-babel==2.0.0
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+flask-caching==2.3.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+flask-compress==1.17
+ # via
+ # -c requirements/base.txt
+ # apache-superset
flask-cors==4.0.0
# via apache-superset
+flask-jwt-extended==4.7.1
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+flask-limiter==3.8.0
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+flask-login==0.6.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
+flask-migrate==3.1.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+flask-session==0.8.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+flask-sqlalchemy==2.5.1
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+ # flask-migrate
+flask-talisman==1.1.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
flask-testing==0.8.1
# via apache-superset
+flask-wtf==1.2.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
fonttools==4.55.0
# via matplotlib
freezegun==1.5.1
# via apache-superset
+func-timeout==4.3.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
future==1.0.0
# via pyhive
+geographiclib==2.0
+ # via
+ # -c requirements/base.txt
+ # geopy
+geopy==2.4.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
gevent==24.2.1
# via apache-superset
-google-api-core[grpc]==2.23.0
+google-api-core==2.23.0
# via
# google-cloud-bigquery
# google-cloud-bigquery-storage
# google-cloud-core
# pandas-gbq
# sqlalchemy-bigquery
+google-auth==2.36.0
+ # via
+ # -c requirements/base.txt
+ # google-api-core
+ # google-auth-oauthlib
+ # google-cloud-bigquery
+ # google-cloud-core
+ # pandas-gbq
+ # pydata-google-auth
+ # shillelagh
+ # sqlalchemy-bigquery
google-auth-oauthlib==1.2.1
# via
# pandas-gbq
@@ -70,6 +310,12 @@ googleapis-common-protos==1.66.0
# via
# google-api-core
# grpcio-status
+greenlet==3.0.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # gevent
+ # shillelagh
grpcio==1.68.0
# via
# apache-superset
@@ -77,50 +323,241 @@ grpcio==1.68.0
# grpcio-status
grpcio-status==1.60.1
# via google-api-core
+gunicorn==23.0.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+hashids==1.3.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+holidays==0.25
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # prophet
+humanize==4.11.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
identify==2.5.36
# via pre-commit
+idna==3.10
+ # via
+ # -c requirements/base.txt
+ # email-validator
+ # requests
+importlib-metadata==8.5.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+importlib-resources==6.4.5
+ # via
+ # -c requirements/base.txt
+ # limits
+ # prophet
iniconfig==2.0.0
# via pytest
+isodate==0.7.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+itsdangerous==2.2.0
+ # via
+ # -c requirements/base.txt
+ # flask
+ # flask-wtf
+jinja2==3.1.4
+ # via
+ # -c requirements/base.txt
+ # flask
+ # flask-babel
+jsonpath-ng==1.7.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+jsonschema==4.17.3
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+ # jsonschema-spec
+ # openapi-schema-validator
+ # openapi-spec-validator
jsonschema-spec==0.1.6
# via openapi-spec-validator
kiwisolver==1.4.7
# via matplotlib
+kombu==5.4.2
+ # via
+ # -c requirements/base.txt
+ # celery
+korean-lunar-calendar==0.3.1
+ # via
+ # -c requirements/base.txt
+ # holidays
lazy-object-proxy==1.10.0
# via openapi-spec-validator
+limits==3.13.0
+ # via
+ # -c requirements/base.txt
+ # flask-limiter
+mako==1.3.6
+ # via
+ # -c requirements/base.txt
+ # alembic
+ # apache-superset
+markdown==3.7
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+markdown-it-py==3.0.0
+ # via
+ # -c requirements/base.txt
+ # rich
+markupsafe==3.0.2
+ # via
+ # -c requirements/base.txt
+ # jinja2
+ # mako
+ # werkzeug
+ # wtforms
+marshmallow==3.23.1
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
+ # marshmallow-sqlalchemy
+marshmallow-sqlalchemy==0.28.2
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
matplotlib==3.9.0
# via prophet
+mdurl==0.1.2
+ # via
+ # -c requirements/base.txt
+ # markdown-it-py
+msgpack==1.0.8
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+msgspec==0.18.6
+ # via
+ # -c requirements/base.txt
+ # flask-session
mysqlclient==2.2.6
# via apache-superset
+nh3==0.2.19
+ # via
+ # -c requirements/base.txt
+ # apache-superset
nodeenv==1.8.0
# via pre-commit
+numpy==1.23.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # bottleneck
+ # cmdstanpy
+ # contourpy
+ # db-dtypes
+ # matplotlib
+ # pandas
+ # pandas-gbq
+ # prophet
+ # pyarrow
oauthlib==3.2.2
# via requests-oauthlib
+odfpy==1.4.1
+ # via
+ # -c requirements/base.txt
+ # pandas
openapi-schema-validator==0.4.4
# via openapi-spec-validator
openapi-spec-validator==0.5.6
# via apache-superset
+openpyxl==3.1.5
+ # via
+ # -c requirements/base.txt
+ # pandas
+ordered-set==4.1.0
+ # via
+ # -c requirements/base.txt
+ # flask-limiter
+packaging==24.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # apispec
+ # db-dtypes
+ # deprecation
+ # docker
+ # google-cloud-bigquery
+ # gunicorn
+ # limits
+ # marshmallow
+ # marshmallow-sqlalchemy
+ # matplotlib
+ # pytest
+ # shillelagh
+ # sqlalchemy-bigquery
+pandas==2.0.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # cmdstanpy
+ # db-dtypes
+ # pandas-gbq
+ # prophet
pandas-gbq==0.19.1
# via apache-superset
parameterized==0.9.0
# via apache-superset
+paramiko==3.5.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # sshtunnel
+parsedatetime==2.6
+ # via
+ # -c requirements/base.txt
+ # apache-superset
pathable==0.4.3
# via jsonschema-spec
+pgsanity==0.2.9
+ # via
+ # -c requirements/base.txt
+ # apache-superset
pillow==10.3.0
# via
# apache-superset
# matplotlib
-pip-compile-multi==2.6.3
- # via apache-superset
-pip-tools==7.4.1
- # via pip-compile-multi
-playwright==1.42.0
- # via apache-superset
+platformdirs==3.8.1
+ # via
+ # -c requirements/base.txt
+ # requests-cache
+ # virtualenv
pluggy==1.5.0
# via pytest
+ply==3.11
+ # via
+ # -c requirements/base.txt
+ # jsonpath-ng
+polyline==2.0.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
pre-commit==4.0.1
# via apache-superset
+prison==0.2.1
+ # via
+ # -c requirements/base.txt
+ # flask-appbuilder
progress==1.6
# via apache-superset
+prompt-toolkit==3.0.48
+ # via
+ # -c requirements/base.txt
+ # click-repl
prophet==1.1.5
# via apache-superset
proto-plus==1.25.0
@@ -138,22 +575,64 @@ psutil==6.1.0
# via apache-superset
psycopg2-binary==2.9.6
# via apache-superset
+pyarrow==14.0.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # db-dtypes
+ # pandas-gbq
+pyasn1==0.6.1
+ # via
+ # -c requirements/base.txt
+ # pyasn1-modules
+ # python-ldap
+ # rsa
+pyasn1-modules==0.4.1
+ # via
+ # -c requirements/base.txt
+ # google-auth
+ # python-ldap
+pycparser==2.22
+ # via
+ # -c requirements/base.txt
+ # cffi
pydata-google-auth==1.9.0
# via pandas-gbq
pydruid==0.6.9
# via apache-superset
-pyee==11.0.1
- # via playwright
pyfakefs==5.3.5
# via apache-superset
-pyhive[presto]==0.7.0
+pygments==2.18.0
+ # via
+ # -c requirements/base.txt
+ # rich
+pyhive==0.7.0
# via apache-superset
pyinstrument==4.4.0
# via apache-superset
-pyproject-hooks==1.2.0
+pyjwt==2.10.1
# via
- # build
- # pip-tools
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
+ # flask-jwt-extended
+pynacl==1.5.0
+ # via
+ # -c requirements/base.txt
+ # paramiko
+pyopenssl==24.2.1
+ # via
+ # -c requirements/base.txt
+ # shillelagh
+pyparsing==3.2.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # matplotlib
+pyrsistent==0.20.0
+ # via
+ # -c requirements/base.txt
+ # jsonschema
pytest==7.4.4
# via
# apache-superset
@@ -163,45 +642,248 @@ pytest-cov==6.0.0
# via apache-superset
pytest-mock==3.10.0
# via apache-superset
+python-dateutil==2.9.0.post0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # celery
+ # croniter
+ # flask-appbuilder
+ # freezegun
+ # google-cloud-bigquery
+ # holidays
+ # matplotlib
+ # pandas
+ # pyhive
+ # shillelagh
+ # trino
+python-dotenv==1.0.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+python-geohash==0.8.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
python-ldap==3.4.4
# via apache-superset
+pytz==2024.2
+ # via
+ # -c requirements/base.txt
+ # croniter
+ # flask-babel
+ # pandas
+ # trino
+pyxlsb==1.0.10
+ # via
+ # -c requirements/base.txt
+ # pandas
+pyyaml==6.0.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # apispec
+ # jsonschema-spec
+ # pre-commit
+redis==4.6.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+requests==2.32.2
+ # via
+ # -c requirements/base.txt
+ # docker
+ # google-api-core
+ # google-cloud-bigquery
+ # jsonschema-spec
+ # pydruid
+ # pyhive
+ # requests-cache
+ # requests-oauthlib
+ # shillelagh
+ # trino
+requests-cache==1.2.0
+ # via
+ # -c requirements/base.txt
+ # shillelagh
requests-oauthlib==2.0.0
# via google-auth-oauthlib
rfc3339-validator==0.1.4
# via openapi-schema-validator
+rich==13.9.4
+ # via
+ # -c requirements/base.txt
+ # flask-limiter
+rsa==4.9
+ # via
+ # -c requirements/base.txt
+ # google-auth
ruff==0.8.0
# via apache-superset
+selenium==3.141.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+setuptools==75.6.0
+ # via
+ # nodeenv
+ # pandas-gbq
+ # pydata-google-auth
+ # zope-event
+ # zope-interface
+shillelagh==1.2.18
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+shortid==0.1.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+simplejson==3.19.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+six==1.16.0
+ # via
+ # -c requirements/base.txt
+ # prison
+ # python-dateutil
+ # rfc3339-validator
+ # url-normalize
+ # wtforms-json
+slack-sdk==3.33.4
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+sqlalchemy==1.4.54
+ # via
+ # -c requirements/base.txt
+ # alembic
+ # apache-superset
+ # flask-appbuilder
+ # flask-sqlalchemy
+ # marshmallow-sqlalchemy
+ # shillelagh
+ # sqlalchemy-bigquery
+ # sqlalchemy-utils
sqlalchemy-bigquery==1.12.0
# via apache-superset
+sqlalchemy-utils==0.38.3
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
+sqlglot==25.24.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
sqloxide==0.1.51
# via apache-superset
+sqlparse==0.5.2
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+sshtunnel==0.4.0
+ # via
+ # -c requirements/base.txt
+ # apache-superset
statsd==4.0.1
# via apache-superset
-tomli==2.1.0
+tabulate==0.8.10
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+tomli==2.2.1
# via
- # build
# coverage
- # pip-tools
# pytest
-toposort==1.10
- # via pip-compile-multi
tqdm==4.67.1
# via
# cmdstanpy
# prophet
trino==0.330.0
# via apache-superset
+typing-extensions==4.12.2
+ # via
+ # -c requirements/base.txt
+ # alembic
+ # apache-superset
+ # cattrs
+ # flask-limiter
+ # limits
+ # rich
+ # shillelagh
+tzdata==2024.2
+ # via
+ # -c requirements/base.txt
+ # celery
+ # kombu
+ # pandas
tzlocal==5.2
# via trino
+url-normalize==1.4.3
+ # via
+ # -c requirements/base.txt
+ # requests-cache
+urllib3==1.26.18
+ # via
+ # -c requirements/base.txt
+ # docker
+ # requests
+ # requests-cache
+ # selenium
+vine==5.1.0
+ # via
+ # -c requirements/base.txt
+ # amqp
+ # celery
+ # kombu
virtualenv==20.23.1
# via pre-commit
-wheel==0.45.1
- # via pip-tools
+wcwidth==0.2.13
+ # via
+ # -c requirements/base.txt
+ # prompt-toolkit
+werkzeug==3.1.3
+ # via
+ # -c requirements/base.txt
+ # flask
+ # flask-appbuilder
+ # flask-jwt-extended
+ # flask-login
+wrapt==1.17.0
+ # via
+ # -c requirements/base.txt
+ # deprecated
+wtforms==3.2.1
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # flask-appbuilder
+ # flask-wtf
+ # wtforms-json
+wtforms-json==0.3.5
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+xlrd==2.0.1
+ # via
+ # -c requirements/base.txt
+ # pandas
+xlsxwriter==3.0.9
+ # via
+ # -c requirements/base.txt
+ # apache-superset
+ # pandas
+zipp==3.21.0
+ # via
+ # -c requirements/base.txt
+ # importlib-metadata
zope-event==5.0
# via gevent
zope-interface==5.4.0
# via gevent
-
-# The following packages are considered to be unsafe in a requirements file:
-# pip
-# setuptools
+zstandard==0.23.0
+ # via
+ # -c requirements/base.txt
+ # flask-compress
diff --git a/requirements/translations.txt b/requirements/translations.txt
index 4eab2d21f4f08..cc863d50fc0b7 100644
--- a/requirements/translations.txt
+++ b/requirements/translations.txt
@@ -1,9 +1,4 @@
-# SHA1:cad160f3d4cd7c33896f42a479eeaa1b5bedc5fb
-#
-# This file is autogenerated by pip-compile-multi
-# To update, run:
-#
-# pip-compile-multi
-#
+# This file was autogenerated by uv via the following command:
+# uv pip compile requirements/translations.in -o requirements/translations.txt
babel==2.16.0
# via -r requirements/translations.in
diff --git a/scripts/benchmark_migration.py b/scripts/benchmark_migration.py
index 90d94853dccb8..8da9a68609eb3 100644
--- a/scripts/benchmark_migration.py
+++ b/scripts/benchmark_migration.py
@@ -70,7 +70,7 @@ def extract_modified_tables(module: ModuleType) -> set[str]:
return tables
-def find_models(module: ModuleType) -> list[type[Model]]:
+def find_models(module: ModuleType) -> list[type[Model]]: # noqa: C901
"""
Find all models in a migration script.
"""
@@ -94,7 +94,7 @@ def find_models(module: ModuleType) -> list[type[Model]]:
# downgrade
sqlalchemy_uri = current_app.config["SQLALCHEMY_DATABASE_URI"]
engine = create_engine(sqlalchemy_uri)
- Base = automap_base()
+ Base = automap_base() # noqa: N806
Base.prepare(engine, reflect=True)
seen = set()
while tables:
@@ -138,7 +138,7 @@ def find_models(module: ModuleType) -> list[type[Model]]:
@click.option("--limit", default=1000, help="Maximum number of entities.")
@click.option("--force", is_flag=True, help="Do not prompt for confirmation.")
@click.option("--no-auto-cleanup", is_flag=True, help="Do not remove created models.")
-def main(
+def main( # noqa: C901
filepath: str, limit: int = 1000, force: bool = False, no_auto_cleanup: bool = False
) -> None:
auto_cleanup = not no_auto_cleanup
diff --git a/scripts/cancel_github_workflows.py b/scripts/cancel_github_workflows.py
index fcf3bc49427d7..b8ae06541e5b0 100755
--- a/scripts/cancel_github_workflows.py
+++ b/scripts/cancel_github_workflows.py
@@ -49,7 +49,7 @@
def request(
method: Literal["GET", "POST", "DELETE", "PUT"], endpoint: str, **kwargs: Any
) -> dict[str, Any]:
- resp = requests.request(
+ resp = requests.request( # noqa: S113
method,
f"https://api.github.com/{endpoint.lstrip('/')}",
headers={"Authorization": f"Bearer {github_token}"},
@@ -152,7 +152,7 @@ def print_commit(commit: dict[str, Any], branch: str) -> None:
help="Whether to also cancel running workflows.",
)
@click.argument("branch_or_pull", required=False)
-def cancel_github_workflows(
+def cancel_github_workflows( # noqa: C901
branch_or_pull: Optional[str],
repo: str,
event: list[str],
diff --git a/scripts/change_detector.py b/scripts/change_detector.py
index df46538f1ee99..7394936d3b388 100755
--- a/scripts/change_detector.py
+++ b/scripts/change_detector.py
@@ -51,12 +51,12 @@
def fetch_files_github_api(url: str): # type: ignore
"""Fetches data using GitHub API."""
- req = Request(url)
+ req = Request(url) # noqa: S310
req.add_header("Authorization", f"Bearer {GITHUB_TOKEN}")
req.add_header("Accept", "application/vnd.github.v3+json")
print(f"Fetching from {url}")
- with urlopen(req) as response:
+ with urlopen(req) as response: # noqa: S310
body = response.read()
return json.loads(body)
@@ -130,7 +130,7 @@ def main(event_type: str, sha: str, repo: str) -> None:
)
# Output results
- output_path = os.getenv("GITHUB_OUTPUT") or "/tmp/GITHUB_OUTPUT.txt"
+ output_path = os.getenv("GITHUB_OUTPUT") or "/tmp/GITHUB_OUTPUT.txt" # noqa: S108
with open(output_path, "a") as f:
for check, changed in changes_detected.items():
if changed:
@@ -139,8 +139,8 @@ def main(event_type: str, sha: str, repo: str) -> None:
def get_git_sha() -> str:
- return os.getenv("GITHUB_SHA") or subprocess.check_output(
- ["git", "rev-parse", "HEAD"]
+ return os.getenv("GITHUB_SHA") or subprocess.check_output( # noqa: S603
+ ["git", "rev-parse", "HEAD"] # noqa: S607
).strip().decode("utf-8")
diff --git a/scripts/check-env.py b/scripts/check-env.py
index 647aa11421bd0..e7816fb585d24 100755
--- a/scripts/check-env.py
+++ b/scripts/check-env.py
@@ -47,7 +47,7 @@ def __init__(
def get_version(self) -> Optional[str]:
try:
- version = subprocess.check_output(self.command, shell=True).decode().strip()
+ version = subprocess.check_output(self.command, shell=True).decode().strip() # noqa: S602
if self.version_post_process:
version = self.version_post_process(version)
return version.split()[-1]
@@ -76,7 +76,7 @@ def check_version(self) -> str:
def format_result(self) -> str:
ideal_range_str = f"{self.ideal_range[0]} - {self.ideal_range[1]}"
supported_range_str = f"{self.supported_range[0]} - {self.supported_range[1]}"
- return f"{self.status.split()[0]} {self.name:<25} {self.version or 'N/A':<25} {ideal_range_str:<25} {supported_range_str:<25}"
+ return f"{self.status.split()[0]} {self.name:<25} {self.version or 'N/A':<25} {ideal_range_str:<25} {supported_range_str:<25}" # noqa: E501
def check_memory(min_gb: int) -> str:
@@ -101,8 +101,9 @@ def get_cpu_info() -> str:
def get_docker_platform() -> str:
try:
output = (
- subprocess.check_output(
- "docker info --format '{{.OperatingSystem}}'", shell=True
+ subprocess.check_output( # noqa: S602
+ "docker info --format '{{.OperatingSystem}}'", # noqa: S607
+ shell=True, # noqa: S607
)
.decode()
.strip()
@@ -117,7 +118,7 @@ def get_docker_platform() -> str:
@click.command(
help="""
This script checks the local environment for various software versions and other requirements, providing feedback on whether they are ideal, supported, or unsupported.
-"""
+""" # noqa: E501
)
@click.option(
"--docker", is_flag=True, help="Check Docker and Docker Compose requirements"
@@ -128,7 +129,7 @@ def get_docker_platform() -> str:
help="Check frontend requirements (npm, Node.js, memory)",
)
@click.option("--backend", is_flag=True, help="Check backend requirements (Python)")
-def main(docker: bool, frontend: bool, backend: bool) -> None:
+def main(docker: bool, frontend: bool, backend: bool) -> None: # noqa: C901
requirements = [
Requirement(
"python",
diff --git a/scripts/cypress_run.py b/scripts/cypress_run.py
index 4b9e00febfb25..ca8b68cd35a69 100644
--- a/scripts/cypress_run.py
+++ b/scripts/cypress_run.py
@@ -74,7 +74,7 @@ def run_cypress_for_test_file(
print(f"DRY RUN: {cmd}")
return 0
- process = subprocess.Popen(
+ process = subprocess.Popen( # noqa: S602
cmd,
shell=True,
stdout=subprocess.PIPE,
diff --git a/scripts/erd/erd.py b/scripts/erd/erd.py
index d49940feb5fc0..84f7fee29c58a 100644
--- a/scripts/erd/erd.py
+++ b/scripts/erd/erd.py
@@ -171,7 +171,7 @@ def generate_erd(file_path: str) -> None:
"""
data = introspect_models()
templates_path = os.path.dirname(__file__)
- env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
+ env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path)) # noqa: S701
# Load the template
template = env.get_template("erd.template.puml")
diff --git a/scripts/uv-pip-compile.sh b/scripts/uv-pip-compile.sh
new file mode 100755
index 0000000000000..dd1208ec26777
--- /dev/null
+++ b/scripts/uv-pip-compile.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+set -e
+
+ADDITIONAL_ARGS="$@"
+
+# Generate the requirements/base.txt file
+uv pip compile pyproject.toml requirements/base.in -o requirements/base.txt $ADDITIONAL_ARGS
+
+# Generate the requirements/development.txt file, making sure requirements/base.txt is a constraint to keep the versions in sync
+uv pip compile requirements/development.in -c requirements/base.txt -o requirements/development.txt $ADDITIONAL_ARGS
+
+uv pip compile requirements/translations.in -o requirements/translations.txt $ADDITIONAL_ARGS
diff --git a/setup.py b/setup.py
index 00b8d22e2a4f6..b89288f760511 100644
--- a/setup.py
+++ b/setup.py
@@ -30,7 +30,7 @@
def get_git_sha() -> str:
try:
- output = subprocess.check_output(["git", "rev-parse", "HEAD"])
+ output = subprocess.check_output(["git", "rev-parse", "HEAD"]) # noqa: S603, S607
return output.decode().strip()
except Exception: # pylint: disable=broad-except
return ""
@@ -58,7 +58,7 @@ def get_git_sha() -> str:
zip_safe=False,
entry_points={
"console_scripts": ["superset=superset.cli.main:superset"],
- # the `postgres` and `postgres+psycopg2://` schemes were removed in SQLAlchemy 1.4
+ # the `postgres` and `postgres+psycopg2://` schemes were removed in SQLAlchemy 1.4 # noqa: E501
# add an alias here to prevent breaking existing databases
"sqlalchemy.dialects": [
"postgres.psycopg2 = sqlalchemy.dialects.postgresql:dialect",
diff --git a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb
index 2969a7f96e43e..793c618791ae8 100644
--- a/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb
+++ b/superset-frontend/plugins/legacy-plugin-chart-country-map/scripts/Country Map GeoJSON Generator.ipynb
@@ -561,9 +561,532 @@
"metadata": {
"id": "k-KuZ8L4t1LU"
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " featurecla | \n",
+ " scalerank | \n",
+ " adm1_code | \n",
+ " diss_me | \n",
+ " iso_3166_2 | \n",
+ " wikipedia | \n",
+ " iso_a2 | \n",
+ " adm0_sr | \n",
+ " name | \n",
+ " name_alt | \n",
+ " name_local | \n",
+ " type | \n",
+ " type_en | \n",
+ " code_local | \n",
+ " code_hasc | \n",
+ " note | \n",
+ " hasc_maybe | \n",
+ " region | \n",
+ " region_cod | \n",
+ " provnum_ne | \n",
+ " gadm_level | \n",
+ " check_me | \n",
+ " datarank | \n",
+ " abbrev | \n",
+ " postal | \n",
+ " area_sqkm | \n",
+ " sameascity | \n",
+ " labelrank | \n",
+ " name_len | \n",
+ " mapcolor9 | \n",
+ " mapcolor13 | \n",
+ " fips | \n",
+ " fips_alt | \n",
+ " woe_id | \n",
+ " woe_label | \n",
+ " woe_name | \n",
+ " latitude | \n",
+ " longitude | \n",
+ " sov_a3 | \n",
+ " adm0_a3 | \n",
+ " adm0_label | \n",
+ " admin | \n",
+ " geonunit | \n",
+ " gu_a3 | \n",
+ " gn_id | \n",
+ " gn_name | \n",
+ " gns_id | \n",
+ " gns_name | \n",
+ " gn_level | \n",
+ " gn_region | \n",
+ " gn_a1_code | \n",
+ " region_sub | \n",
+ " sub_code | \n",
+ " gns_level | \n",
+ " gns_lang | \n",
+ " gns_adm1 | \n",
+ " gns_region | \n",
+ " min_label | \n",
+ " max_label | \n",
+ " min_zoom | \n",
+ " wikidataid | \n",
+ " name_ar | \n",
+ " name_bn | \n",
+ " name_de | \n",
+ " name_en | \n",
+ " name_es | \n",
+ " name_fr | \n",
+ " name_el | \n",
+ " name_hi | \n",
+ " name_hu | \n",
+ " name_id | \n",
+ " name_it | \n",
+ " name_ja | \n",
+ " name_ko | \n",
+ " name_nl | \n",
+ " name_pl | \n",
+ " name_pt | \n",
+ " name_ru | \n",
+ " name_sv | \n",
+ " name_tr | \n",
+ " name_vi | \n",
+ " name_zh | \n",
+ " ne_id | \n",
+ " name_he | \n",
+ " name_uk | \n",
+ " name_ur | \n",
+ " name_fa | \n",
+ " name_zht | \n",
+ " FCLASS_ISO | \n",
+ " FCLASS_US | \n",
+ " FCLASS_FR | \n",
+ " FCLASS_RU | \n",
+ " FCLASS_ES | \n",
+ " FCLASS_CN | \n",
+ " FCLASS_TW | \n",
+ " FCLASS_IN | \n",
+ " FCLASS_NP | \n",
+ " FCLASS_PK | \n",
+ " FCLASS_DE | \n",
+ " FCLASS_GB | \n",
+ " FCLASS_BR | \n",
+ " FCLASS_IL | \n",
+ " FCLASS_PS | \n",
+ " FCLASS_SA | \n",
+ " FCLASS_EG | \n",
+ " FCLASS_MA | \n",
+ " FCLASS_PT | \n",
+ " FCLASS_AR | \n",
+ " FCLASS_JP | \n",
+ " FCLASS_KO | \n",
+ " FCLASS_VN | \n",
+ " FCLASS_TR | \n",
+ " FCLASS_ID | \n",
+ " FCLASS_PL | \n",
+ " FCLASS_GR | \n",
+ " FCLASS_IT | \n",
+ " FCLASS_NL | \n",
+ " FCLASS_SE | \n",
+ " FCLASS_BD | \n",
+ " FCLASS_UA | \n",
+ " FCLASS_TLC | \n",
+ " geometry | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 2176 | \n",
+ " Admin-1 states provinces | \n",
+ " 10 | \n",
+ " SPM-4866 | \n",
+ " 4866 | \n",
+ " PM-X01~ | \n",
+ " http://en.wikipedia.org/wiki/Saint-Pierre,_Sai... | \n",
+ " PM | \n",
+ " 4 | \n",
+ " Saint-Pierre | \n",
+ " None | \n",
+ " None | \n",
+ " Commune | \n",
+ " Commune | \n",
+ " 97502 | \n",
+ " PM.SP | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " 0.0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 10 | \n",
+ " None | \n",
+ " None | \n",
+ " 0.0 | \n",
+ " 1 | \n",
+ " 20 | \n",
+ " 12 | \n",
+ " 9 | \n",
+ " 11 | \n",
+ " None | \n",
+ " None | \n",
+ " 24549865.0 | \n",
+ " St.-Pierre, PM, Saint Pierre and Miquelon | \n",
+ " St.-Pierre | \n",
+ " 46.7795 | \n",
+ " -56.1918 | \n",
+ " FR1 | \n",
+ " SPM | \n",
+ " 3 | \n",
+ " Saint Pierre and Miquelon | \n",
+ " Saint Pierre and Miquelon | \n",
+ " SPM | \n",
+ " 3424935.0 | \n",
+ " Commune de Saint-Pierre | \n",
+ " 0.0 | \n",
+ " None | \n",
+ " 1.0 | \n",
+ " None | \n",
+ " PM.97502 | \n",
+ " None | \n",
+ " None | \n",
+ " 0.0 | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " 11.0 | \n",
+ " 11.0 | \n",
+ " 11.0 | \n",
+ " Q34617 | \n",
+ " سان بيير وميكلون | \n",
+ " সাঁ পিয়ের ও মিকলোঁ | \n",
+ " Saint-Pierre und Miquelon | \n",
+ " Saint Pierre and Miquelon | \n",
+ " San Pedro y Miquelón | \n",
+ " Saint-Pierre-et-Miquelon | \n",
+ " Σαιν-Πιερ και Μικελόν | \n",
+ " सन्त पियर और मिकलान | \n",
+ " Saint-Pierre és Miquelon | \n",
+ " Saint Pierre dan Miquelon | \n",
+ " Saint-Pierre e Miquelon | \n",
+ " サンピエール島・ミクロン島 | \n",
+ " 생피에르 미클롱 | \n",
+ " Saint-Pierre en Miquelon | \n",
+ " Saint-Pierre i Miquelon | \n",
+ " Saint-Pierre e Miquelon | \n",
+ " Сен-Пьер и Микелон | \n",
+ " Saint-Pierre och Miquelon | \n",
+ " Saint Pierre ve Miquelon | \n",
+ " Saint-Pierre và Miquelon | \n",
+ " 圣皮埃尔和密克隆 | \n",
+ " 1159315673 | \n",
+ " סן-פייר ומיקלון | \n",
+ " Сен-П'єр і Мікелон | \n",
+ " سینٹ پیئر و میکیلون | \n",
+ " سن پیر و میکلن | \n",
+ " 聖皮埃與密克隆群島 | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " POLYGON ((-56.15095 46.79365, -56.15648 46.789... | \n",
+ "
\n",
+ " \n",
+ " 2177 | \n",
+ " Admin-1 states provinces | \n",
+ " 10 | \n",
+ " SPM-4867 | \n",
+ " 4867 | \n",
+ " PM-X02~ | \n",
+ " http://en.wikipedia.org/wiki/Miquelon-Langlade | \n",
+ " PM | \n",
+ " 4 | \n",
+ " Miquelon-Langlade | \n",
+ " None | \n",
+ " None | \n",
+ " Commune | \n",
+ " Commune | \n",
+ " 97501 | \n",
+ " PM.ML | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " 0.0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " 10 | \n",
+ " None | \n",
+ " None | \n",
+ " 0.0 | \n",
+ " -99 | \n",
+ " 20 | \n",
+ " 17 | \n",
+ " 9 | \n",
+ " 11 | \n",
+ " None | \n",
+ " None | \n",
+ " 24549864.0 | \n",
+ " Miquelon-Langlade, PM, Saint Pierre and Miquelon | \n",
+ " Miquelon-Langlade | \n",
+ " 47.0461 | \n",
+ " -56.3418 | \n",
+ " FR1 | \n",
+ " SPM | \n",
+ " 3 | \n",
+ " Saint Pierre and Miquelon | \n",
+ " Saint Pierre and Miquelon | \n",
+ " SPM | \n",
+ " 3424938.0 | \n",
+ " Commune de Miquelon-Langlade | \n",
+ " -1187330.0 | \n",
+ " Saint-Pierre et Miquelon, Collectivite Territo... | \n",
+ " 1.0 | \n",
+ " None | \n",
+ " PM.97501 | \n",
+ " None | \n",
+ " None | \n",
+ " 1.0 | \n",
+ " fra | \n",
+ " SB00 | \n",
+ " None | \n",
+ " 11.0 | \n",
+ " 11.0 | \n",
+ " 11.0 | \n",
+ " None | \n",
+ " ميكلون ولانغليد | \n",
+ " মিকুইলন-ল্যাংলেড | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelón-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " Μικελόν-Λαγκλέιντ | \n",
+ " मिकेलॉन-लैंगलेड | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " ミクロン=ラングラード | \n",
+ " 미클롱-랭글레이드 | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelão-Langlade | \n",
+ " Микелон-Ланглад | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " Miquelon-Langlade | \n",
+ " 密克隆-朗格拉德 | \n",
+ " 1159315961 | \n",
+ " מירה | \n",
+ " Міквелон-Лангладе | \n",
+ " میکیولون لینگلاڈے | \n",
+ " میکوئلون-لانگلید | \n",
+ " 密克隆-朗格拉德 | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " None | \n",
+ " POLYGON ((-56.27379 46.89545, -56.2355 46.8720... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " featurecla scalerank adm1_code diss_me iso_3166_2 \\\n",
+ "2176 Admin-1 states provinces 10 SPM-4866 4866 PM-X01~ \n",
+ "2177 Admin-1 states provinces 10 SPM-4867 4867 PM-X02~ \n",
+ "\n",
+ " wikipedia iso_a2 adm0_sr \\\n",
+ "2176 http://en.wikipedia.org/wiki/Saint-Pierre,_Sai... PM 4 \n",
+ "2177 http://en.wikipedia.org/wiki/Miquelon-Langlade PM 4 \n",
+ "\n",
+ " name name_alt name_local type type_en code_local \\\n",
+ "2176 Saint-Pierre None None Commune Commune 97502 \n",
+ "2177 Miquelon-Langlade None None Commune Commune 97501 \n",
+ "\n",
+ " code_hasc note hasc_maybe region region_cod provnum_ne gadm_level \\\n",
+ "2176 PM.SP None None None None 0.0 0 \n",
+ "2177 PM.ML None None None None 0.0 0 \n",
+ "\n",
+ " check_me datarank abbrev postal area_sqkm sameascity labelrank \\\n",
+ "2176 0 10 None None 0.0 1 20 \n",
+ "2177 0 10 None None 0.0 -99 20 \n",
+ "\n",
+ " name_len mapcolor9 mapcolor13 fips fips_alt woe_id \\\n",
+ "2176 12 9 11 None None 24549865.0 \n",
+ "2177 17 9 11 None None 24549864.0 \n",
+ "\n",
+ " woe_label woe_name \\\n",
+ "2176 St.-Pierre, PM, Saint Pierre and Miquelon St.-Pierre \n",
+ "2177 Miquelon-Langlade, PM, Saint Pierre and Miquelon Miquelon-Langlade \n",
+ "\n",
+ " latitude longitude sov_a3 adm0_a3 adm0_label \\\n",
+ "2176 46.7795 -56.1918 FR1 SPM 3 \n",
+ "2177 47.0461 -56.3418 FR1 SPM 3 \n",
+ "\n",
+ " admin geonunit gu_a3 gn_id \\\n",
+ "2176 Saint Pierre and Miquelon Saint Pierre and Miquelon SPM 3424935.0 \n",
+ "2177 Saint Pierre and Miquelon Saint Pierre and Miquelon SPM 3424938.0 \n",
+ "\n",
+ " gn_name gns_id \\\n",
+ "2176 Commune de Saint-Pierre 0.0 \n",
+ "2177 Commune de Miquelon-Langlade -1187330.0 \n",
+ "\n",
+ " gns_name gn_level gn_region \\\n",
+ "2176 None 1.0 None \n",
+ "2177 Saint-Pierre et Miquelon, Collectivite Territo... 1.0 None \n",
+ "\n",
+ " gn_a1_code region_sub sub_code gns_level gns_lang gns_adm1 gns_region \\\n",
+ "2176 PM.97502 None None 0.0 None None None \n",
+ "2177 PM.97501 None None 1.0 fra SB00 None \n",
+ "\n",
+ " min_label max_label min_zoom wikidataid name_ar \\\n",
+ "2176 11.0 11.0 11.0 Q34617 سان بيير وميكلون \n",
+ "2177 11.0 11.0 11.0 None ميكلون ولانغليد \n",
+ "\n",
+ " name_bn name_de \\\n",
+ "2176 সাঁ পিয়ের ও মিকলোঁ Saint-Pierre und Miquelon \n",
+ "2177 মিকুইলন-ল্যাংলেড Miquelon-Langlade \n",
+ "\n",
+ " name_en name_es \\\n",
+ "2176 Saint Pierre and Miquelon San Pedro y Miquelón \n",
+ "2177 Miquelon-Langlade Miquelón-Langlade \n",
+ "\n",
+ " name_fr name_el name_hi \\\n",
+ "2176 Saint-Pierre-et-Miquelon Σαιν-Πιερ και Μικελόν सन्त पियर और मिकलान \n",
+ "2177 Miquelon-Langlade Μικελόν-Λαγκλέιντ मिकेलॉन-लैंगलेड \n",
+ "\n",
+ " name_hu name_id \\\n",
+ "2176 Saint-Pierre és Miquelon Saint Pierre dan Miquelon \n",
+ "2177 Miquelon-Langlade Miquelon-Langlade \n",
+ "\n",
+ " name_it name_ja name_ko \\\n",
+ "2176 Saint-Pierre e Miquelon サンピエール島・ミクロン島 생피에르 미클롱 \n",
+ "2177 Miquelon-Langlade ミクロン=ラングラード 미클롱-랭글레이드 \n",
+ "\n",
+ " name_nl name_pl \\\n",
+ "2176 Saint-Pierre en Miquelon Saint-Pierre i Miquelon \n",
+ "2177 Miquelon-Langlade Miquelon-Langlade \n",
+ "\n",
+ " name_pt name_ru name_sv \\\n",
+ "2176 Saint-Pierre e Miquelon Сен-Пьер и Микелон Saint-Pierre och Miquelon \n",
+ "2177 Miquelão-Langlade Микелон-Ланглад Miquelon-Langlade \n",
+ "\n",
+ " name_tr name_vi name_zh \\\n",
+ "2176 Saint Pierre ve Miquelon Saint-Pierre và Miquelon 圣皮埃尔和密克隆 \n",
+ "2177 Miquelon-Langlade Miquelon-Langlade 密克隆-朗格拉德 \n",
+ "\n",
+ " ne_id name_he name_uk name_ur \\\n",
+ "2176 1159315673 סן-פייר ומיקלון Сен-П'єр і Мікелон سینٹ پیئر و میکیلون \n",
+ "2177 1159315961 מירה Міквелон-Лангладе میکیولون لینگلاڈے \n",
+ "\n",
+ " name_fa name_zht FCLASS_ISO FCLASS_US FCLASS_FR FCLASS_RU \\\n",
+ "2176 سن پیر و میکلن 聖皮埃與密克隆群島 None None None None \n",
+ "2177 میکوئلون-لانگلید 密克隆-朗格拉德 None None None None \n",
+ "\n",
+ " FCLASS_ES FCLASS_CN FCLASS_TW FCLASS_IN FCLASS_NP FCLASS_PK FCLASS_DE \\\n",
+ "2176 None None None None None None None \n",
+ "2177 None None None None None None None \n",
+ "\n",
+ " FCLASS_GB FCLASS_BR FCLASS_IL FCLASS_PS FCLASS_SA FCLASS_EG FCLASS_MA \\\n",
+ "2176 None None None None None None None \n",
+ "2177 None None None None None None None \n",
+ "\n",
+ " FCLASS_PT FCLASS_AR FCLASS_JP FCLASS_KO FCLASS_VN FCLASS_TR FCLASS_ID \\\n",
+ "2176 None None None None None None None \n",
+ "2177 None None None None None None None \n",
+ "\n",
+ " FCLASS_PL FCLASS_GR FCLASS_IT FCLASS_NL FCLASS_SE FCLASS_BD FCLASS_UA \\\n",
+ "2176 None None None None None None None \n",
+ "2177 None None None None None None None \n",
+ "\n",
+ " FCLASS_TLC geometry \n",
+ "2176 None POLYGON ((-56.15095 46.79365, -56.15648 46.789... \n",
+ "2177 None POLYGON ((-56.27379 46.89545, -56.2355 46.8720... "
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
- "df = pd.concat([df_10m[~df_10m['admin'].isin(df_50m['admin'].unique())], df_50m])"
+ "df = pd.concat([df_10m[~df_10m['admin'].isin(df_50m['admin'].unique())], df_50m])\n",
+ "rdf = df[(df['admin'] == 'Saint Pierre and Miquelon')]\n",
+ "pd.set_option('display.max_rows', None)\n",
+ "pd.set_option('display.max_columns', None)\n",
+ "rdf"
]
},
{
@@ -665,7 +1188,7 @@
" 'france',\n",
" # 'french guiana',\n",
" 'french polynesia',\n",
- " # 'french southern territories (the)',\n",
+ " #'french southern and antarctic lands',\n",
" 'gabon', \n",
" 'gambia',\n",
" 'germany',\n",
@@ -763,7 +1286,7 @@
" # 'saint helena, ascension and tristan da cunha', # part of UK, in Natural Earth data\n",
" 'saint lucia',\n",
" 'saint martin',\n",
- " # 'saint martin (french part)', part of Saint Martin, in Natural Earth data\n",
+ " #'saint martin (french part)', part of Saint Martin, in Natural Earth data\n",
" 'saint pierre and miquelon',\n",
" 'saint vincent and the grenadines',\n",
" 'samoa',\n",
@@ -836,6 +1359,7 @@
"# CSV files that are defined later in the notebook:\n",
"region_maps = [\n",
" 'france_regions',\n",
+ " 'france_overseas',\n",
" 'italy_regions',\n",
" 'philippines_regions',\n",
" 'turkey_regions'\n",
@@ -986,12 +1510,14 @@
},
{
"data": {
- "image/png": "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",
+ "image/png": "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\n",
"text/plain": [
- "