From 64c0a215f12bdfcd1eceeb3788c69a16983d4602 Mon Sep 17 00:00:00 2001 From: Zach Vorhies Date: Mon, 21 Sep 2026 14:15:32 -0700 Subject: [PATCH] fix(python): lock tooling to py310 baseline --- .github/actions/setup/README.md | 2 +- .github/actions/setup/action.yml | 4 +-- .github/workflows/audit-ignored-tests.yml | 2 +- .github/workflows/template_native_build.yml | 5 ++- .github/workflows/validate-boards.yml | 2 +- crates/fbuild-python/tests/pyo3_policy.rs | 38 +++++++++++++++++++++ install | 2 +- uv.lock | 2 +- 8 files changed, 49 insertions(+), 8 deletions(-) diff --git a/.github/actions/setup/README.md b/.github/actions/setup/README.md index befa52092..a468746de 100644 --- a/.github/actions/setup/README.md +++ b/.github/actions/setup/README.md @@ -114,7 +114,7 @@ Use `steps..outputs.zccache-store-path` inside workflow expressions. The sam | Input | Default | Description | |---|---|---| | `fbuild-version` | `latest` | PyPI version spec. Pin to an exact version (`2.1.16`) for reproducible CI. | -| `python-version` | `3.12` | Python used to install fbuild. Must be >= 3.9. | +| `python-version` | `3.10` | Python used to install fbuild. Must be >= 3.10. | | `cache` | `true` | Set to `false` to install fbuild without wiring `actions/cache`. | | `cache-mode` | `combined` | `combined` keeps one `FBUILD_CACHE_DIR` entry per key. `split` restores a packages cache shared per platform family and a per-board build-payload cache, and runs `fbuild install` as its own step. | | `save` | `true` | `false` restores caches without saving; use it on pull requests. | diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b592668ef..189196785 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -11,9 +11,9 @@ inputs: required: false default: "latest" python-version: - description: "Python version used to install fbuild. Must be >= 3.9." + description: "Python version used to install fbuild. Must be >= 3.10." required: false - default: "3.12" + default: "3.10" cache: description: "Whether to save/restore the fbuild cache via actions/cache. Set to 'false' to skip caching (install only)." required: false diff --git a/.github/workflows/audit-ignored-tests.yml b/.github/workflows/audit-ignored-tests.yml index caeec417e..0425b4414 100644 --- a/.github/workflows/audit-ignored-tests.yml +++ b/.github/workflows/audit-ignored-tests.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: - python-version: "3.12" + python-version: "3.10" - name: Install uv run: pip install --timeout 60 uv - name: Generate inventory (markdown) diff --git a/.github/workflows/template_native_build.yml b/.github/workflows/template_native_build.yml index dce231840..6ab23e5b6 100644 --- a/.github/workflows/template_native_build.yml +++ b/.github/workflows/template_native_build.yml @@ -118,7 +118,10 @@ jobs: - uses: actions/setup-python@v6 with: - python-version: "3.13" + # The extension's public ABI baseline is abi3-py310. Keep release + # tooling on that version so a newer interpreter cannot constrain + # the repository's dependency lock (FastLED/fbuild#1451). + python-version: "3.10" # rust-toolchain.toml pins 1.95.0 which overrides the above; # ensure the target stdlib is installed for the pinned toolchain too. diff --git a/.github/workflows/validate-boards.yml b/.github/workflows/validate-boards.yml index 2efc6705f..504574472 100644 --- a/.github/workflows/validate-boards.yml +++ b/.github/workflows/validate-boards.yml @@ -33,7 +33,7 @@ jobs: - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: - python-version: "3.12" + python-version: "3.10" - name: Install PlatformIO timeout-minutes: 5 run: pip install --timeout 60 "platformio==${PLATFORMIO_CORE_VERSION}" diff --git a/crates/fbuild-python/tests/pyo3_policy.rs b/crates/fbuild-python/tests/pyo3_policy.rs index d0f5f66dc..10b7d28fb 100644 --- a/crates/fbuild-python/tests/pyo3_policy.rs +++ b/crates/fbuild-python/tests/pyo3_policy.rs @@ -204,6 +204,44 @@ fn pyo3_029_policy_stays_target_python_independent() { } } +#[test] +fn python_api_and_fixed_ci_interpreters_use_py310() { + // FastLED/fbuild#1451: the public extension is abi3-py310. Lock and run + // repository-owned Python tooling against that API floor; do not make a + // newer interpreter an accidental resolver requirement. + let root = repo_root(); + let manifest = fs::read_to_string(root.join("pyproject.toml")).unwrap(); + let lockfile = fs::read_to_string(root.join("uv.lock")).unwrap(); + let install = fs::read_to_string(root.join("install")).unwrap(); + let setup_action = fs::read_to_string(root.join(".github/actions/setup/action.yml")).unwrap(); + let setup_readme = fs::read_to_string(root.join(".github/actions/setup/README.md")).unwrap(); + + for (name, contents) in [ + ("pyproject.toml", manifest.as_str()), + ("uv.lock", lockfile.as_str()), + ("install", install.as_str()), + ] { + assert!( + contents.contains("requires-python = \">=3.10\""), + "{name} must retain Python 3.10 as its supported floor" + ); + } + assert!(setup_action.contains("default: \"3.10\"")); + assert!(setup_readme.contains("| `python-version` | `3.10` |")); + + for workflow in [ + ".github/workflows/template_native_build.yml", + ".github/workflows/audit-ignored-tests.yml", + ".github/workflows/validate-boards.yml", + ] { + let contents = fs::read_to_string(root.join(workflow)).unwrap(); + assert!( + contents.contains("python-version: \"3.10\""), + "{workflow} must use the Python 3.10 API baseline" + ); + } +} + #[test] fn native_release_workflow_uses_current_cross_toolchains() { let root = repo_root(); diff --git a/install b/install index 47ec8ff88..befa44a47 100644 --- a/install +++ b/install @@ -1,6 +1,6 @@ #!/usr/bin/env -S uv run --script # /// script -# requires-python = ">=3.9" +# requires-python = ">=3.10" # /// """Install uv and the pinned Rust toolchain for fbuild development. diff --git a/uv.lock b/uv.lock index 71cc6ddac..cae1e5ef0 100644 --- a/uv.lock +++ b/uv.lock @@ -4,7 +4,7 @@ requires-python = ">=3.10" [[package]] name = "fbuild" -version = "2.5.24" +version = "2.5.25" source = { editable = "." } [package.dev-dependencies]