diff --git a/.github/actions/setup-pyodide-build/action.yml b/.github/actions/setup-pyodide-build/action.yml new file mode 100644 index 00000000..fc414e7c --- /dev/null +++ b/.github/actions/setup-pyodide-build/action.yml @@ -0,0 +1,95 @@ +name: 'Setup Pyodide Build' +description: 'Install pyodide-build tooling, cross-build environment, and validate wheel platform tag compatibility.' + +inputs: + pyodide-version: + description: 'Pyodide version (e.g. 0.29.3). Used for both pyodide-build and xbuildenv.' + required: true + python-version: + description: 'Python version for setup-python step' + required: false + default: '3.13' + +outputs: + emscripten-version: + description: 'Emscripten SDK version required by this Pyodide build' + value: ${{ steps.validate.outputs.emscripten_version }} + pyodide-root: + description: 'Path to the Pyodide cross-build root directory' + value: ${{ steps.validate.outputs.pyodide_root }} + wheel-platform-tag: + description: 'Wheel platform tag (e.g. pyodide_2025_0_wasm32)' + value: ${{ steps.validate.outputs.wheel_platform_tag }} + +runs: + using: 'composite' + steps: + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ inputs.python-version }} + + - name: Install pyodide-build and validate tooling + id: validate + shell: bash + run: | + PYODIDE_VERSION="${{ inputs.pyodide-version }}" + + python -m pip install --upgrade pip + pip install "pyodide-build==${PYODIDE_VERSION}" "wheel<0.44" + + # Verify pyodide CLI works (catches import errors like wheel.cli removal) + pyodide --help > /dev/null + + # Install the matching cross-build environment explicitly. + # Without this, `pyodide build` would auto-install the latest xbuildenv, + # which may have an incompatible lockfile format (e.g. 0.29.4 lockfile + # missing `info.version` causes pydantic ValidationError in 0.29.3). + pyodide xbuildenv install "${PYODIDE_VERSION}" + + # Derive PYODIDE_ROOT — the xbuildenv install prints its path, + # and `pyodide config` requires a full Pyodide checkout Makefile. + XBUILD_DIR="$(pwd)/.pyodide-xbuildenv-${PYODIDE_VERSION}/${PYODIDE_VERSION}/xbuildenv" + if [ ! -d "$XBUILD_DIR/pyodide-root" ]; then + XBUILD_DIR="$HOME/.pyodide-xbuildenv-${PYODIDE_VERSION}/${PYODIDE_VERSION}/xbuildenv" + fi + PYODIDE_ROOT="$XBUILD_DIR/pyodide-root" + + if [ ! -d "$PYODIDE_ROOT" ]; then + echo "ERROR: PYODIDE_ROOT not found at $PYODIDE_ROOT" + exit 1 + fi + + echo "PYODIDE_ROOT=$PYODIDE_ROOT" >> $GITHUB_ENV + echo "pyodide_root=$PYODIDE_ROOT" >> $GITHUB_OUTPUT + + # Get Emscripten version (needed for emsdk setup in release workflow) + EMSCRIPTEN_VERSION=$(python3 -c " + import os + os.environ['PYODIDE_ROOT'] = '$PYODIDE_ROOT' + from pyodide_build.build_env import get_build_environment_vars + from pathlib import Path + print(get_build_environment_vars(Path(os.environ['PYODIDE_ROOT']))['PYODIDE_EMSCRIPTEN_VERSION']) + ") + echo "emscripten_version=${EMSCRIPTEN_VERSION}" >> $GITHUB_OUTPUT + echo "Emscripten version: ${EMSCRIPTEN_VERSION}" + + # Verify wheel platform tag — this is the tag used in the .whl filename. + # wheel_platform() returns the build platform tag (e.g. pyodide_2025_0_wasm32) + # NOT the install-compatibility tags from pyodide_tags() where emscripten comes first. + TAG=$(python3 -c " + import os + os.environ['PYODIDE_ROOT'] = '$PYODIDE_ROOT' + from pyodide_build.build_env import wheel_platform + print(wheel_platform()) + ") + echo "wheel_platform_tag=$TAG" >> $GITHUB_OUTPUT + echo "Pyodide wheel platform tag: $TAG" + + if echo "$TAG" | grep -q "pyodide_"; then + echo "Wheel platform tag is pyodide_* — OK (compatible with Pyodide ${PYODIDE_VERSION} runtime)" + else + echo "ERROR: Wheel platform tag is '$TAG', expected pyodide_*" + echo "This means the built wheel will NOT be compatible with the Pyodide ${PYODIDE_VERSION} runtime." + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 6f346701..e4117257 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -226,39 +226,9 @@ jobs: - name: Validate Pyodide build tooling if: needs.release-check.outputs.ducpy == 'true' - run: | - python -m pip install --upgrade pip - pip install "pyodide-build==0.29.3" "wheel<0.44" - - # Verify pyodide CLI works (catches import errors like the wheel.cli removal) - pyodide --help > /dev/null - - # Install cross-build environment - pyodide xbuildenv install 0.29.3 - XBUILD_DIR="$(pwd)/.pyodide-xbuildenv-0.29.3/0.29.3/xbuildenv" - if [ ! -d "$XBUILD_DIR/pyodide-root" ]; then - XBUILD_DIR="$HOME/.pyodide-xbuildenv-0.29.3/0.29.3/xbuildenv" - fi - export PYODIDE_ROOT="$XBUILD_DIR/pyodide-root" - echo "PYODIDE_ROOT=$PYODIDE_ROOT" - - # Check wheel platform tag — this is the tag used in the .whl filename. - # pyodide_tags() returns install-compatibility tags (emscripten first), but - # wheel_platform() returns the actual build platform tag (e.g. pyodide_2025_0_wasm32). - TAG=$(python3 -c " - import os - os.environ['PYODIDE_ROOT'] = '$PYODIDE_ROOT' - from pyodide_build.build_env import wheel_platform - print(wheel_platform()) - ") - echo "Pyodide wheel platform tag: $TAG" - if echo "$TAG" | grep -q "pyodide_"; then - echo "Wheel platform tag is pyodide_* — OK (compatible with Pyodide 0.29.3 runtime)" - else - echo "ERROR: Wheel platform tag is '$TAG', expected pyodide_*" - echo "This means the built wheel will NOT be compatible with the Pyodide 0.29.3 runtime." - exit 1 - fi + uses: ./.github/actions/setup-pyodide-build + with: + pyodide-version: '0.29.3' # ────────────────────────────────────────────────────────────────────── # Phase 3: Summary & gate check diff --git a/.github/workflows/release-ducpy.yml b/.github/workflows/release-ducpy.yml index 8148156b..b6e59cdc 100644 --- a/.github/workflows/release-ducpy.yml +++ b/.github/workflows/release-ducpy.yml @@ -14,6 +14,7 @@ jobs: runs-on: ubuntu-latest env: UV_PYTHON: "3.13" + PYODIDE_VERSION: "0.29.3" concurrency: group: release-ducpy cancel-in-progress: false @@ -69,49 +70,18 @@ jobs: fi working-directory: ./packages/ducpy - - name: Install Pyodide build tooling + - name: Setup Pyodide build tooling id: pyodide_tooling if: steps.release.outputs.status == 'success' - run: | - python -m pip install --upgrade pip - pip install "pyodide-build==0.29.3" "wheel<0.44" - pyodide xbuildenv install 0.29.3 - XBUILD_DIR="$(pwd)/.pyodide-xbuildenv-0.29.3/0.29.3/xbuildenv" - if [ ! -d "$XBUILD_DIR/pyodide-root" ]; then - XBUILD_DIR="$HOME/.pyodide-xbuildenv-0.29.3/0.29.3/xbuildenv" - fi - export PYODIDE_ROOT="$XBUILD_DIR/pyodide-root" - - # Get Emscripten version (needed for emsdk setup) - EMSCRIPTEN_VERSION=$(python3 -c " - import os - os.environ['PYODIDE_ROOT'] = '$PYODIDE_ROOT' - from pyodide_build.build_env import get_build_environment_vars - from pathlib import Path - print(get_build_environment_vars(Path(os.environ['PYODIDE_ROOT']))['PYODIDE_EMSCRIPTEN_VERSION']) - ") - echo "emscripten_version=${EMSCRIPTEN_VERSION}" >> $GITHUB_OUTPUT - - # Verify wheel platform tag is pyodide_* (not pyemscripten_*) - TAG=$(python3 -c " - import os - os.environ['PYODIDE_ROOT'] = '$PYODIDE_ROOT' - from pyodide_build.build_env import wheel_platform - print(wheel_platform()) - ") - echo "Pyodide wheel platform tag: $TAG" - if echo "$TAG" | grep -q "pyodide_"; then - echo "Wheel platform tag is pyodide_* — OK" - else - echo "ERROR: Wheel platform tag is '$TAG', expected pyodide_*" - exit 1 - fi + uses: ./.github/actions/setup-pyodide-build + with: + pyodide-version: ${{ env.PYODIDE_VERSION }} - name: Setup Emscripten SDK if: steps.release.outputs.status == 'success' uses: mymindstorm/setup-emsdk@v14 with: - version: ${{ steps.pyodide_tooling.outputs.emscripten_version }} + version: ${{ steps.pyodide_tooling.outputs.emscripten-version }} - name: Setup Rust nightly for Pyodide if: steps.release.outputs.status == 'success' @@ -122,6 +92,8 @@ jobs: - name: Build Pyodide wheel if: steps.release.outputs.status == 'success' working-directory: ./packages/ducpy + env: + PYODIDE_ROOT: ${{ steps.pyodide_tooling.outputs.pyodide-root }} run: | TAG=$(git describe --tags --abbrev=0 --match 'ducpy@*') VERSION="${TAG#ducpy@}" @@ -129,6 +101,25 @@ jobs: uv run python scripts/sync_schema.py RUSTUP_TOOLCHAIN=nightly SETUPTOOLS_SCM_PRETEND_VERSION="${VERSION}" pyodide build --outdir dist + - name: Verify wheel platform tag + if: steps.release.outputs.status == 'success' + working-directory: ./packages/ducpy + run: | + WHEEL=$(find dist -name '*.whl' | head -1) + if [ -z "$WHEEL" ]; then + echo "ERROR: No wheel found in dist/" + exit 1 + fi + echo "Built wheel: $WHEEL" + EXPECTED_TAG="${{ steps.pyodide_tooling.outputs.wheel-platform-tag }}" + if echo "$WHEEL" | grep -q "$EXPECTED_TAG"; then + echo "Wheel filename contains expected tag '$EXPECTED_TAG' — OK" + else + echo "ERROR: Wheel filename does not contain expected tag '$EXPECTED_TAG'" + echo "This means the built wheel is incompatible with the Pyodide ${{ env.PYODIDE_VERSION }} runtime." + exit 1 + fi + - name: Upload wheels to GitHub release if: steps.release.outputs.status == 'success' env: @@ -158,4 +149,4 @@ jobs: event-type: trigger-web-deployment token: ${{ secrets.GITHUB_TOKEN }} client-payload: | - {"source": "release-ducpy", "web_changed": "false", "success": "true"} + {"source": "release-ducpy", "web_changed": "false", "success": "true"} \ No newline at end of file diff --git a/packages/ducpy/src/ducpy/__init__.py b/packages/ducpy/src/ducpy/__init__.py index 70c1bf7f..2b64c276 100644 --- a/packages/ducpy/src/ducpy/__init__.py +++ b/packages/ducpy/src/ducpy/__init__.py @@ -27,6 +27,6 @@ from .enums import * from .parse import (DucData, get_external_file, list_external_files, parse_duc, parse_duc_lazy) -from .search import * from .serialize import DUC_SCHEMA_VERSION, serialize_duc +from .search import * from .utils import *