Skip to content

feat(update): add app-notification delivery and main yaml version reader #93

feat(update): add app-notification delivery and main yaml version reader

feat(update): add app-notification delivery and main yaml version reader #93

name: CI - Python Bindings
on:
push:
branches: [main, classic-next, develop, classic-9.1]
pull_request:
branches: [main, classic-next, develop, classic-9.1]
env:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
jobs:
parity-gates:
name: Python Parity Gates
runs-on: windows-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: python-bindings/uv.lock
# The parity-gates job only needs the drift-guard tooling (ruamel.yaml);
# everything else in check_parity_gate.py / validate_stubs.py is stdlib.
# `--inexact` is a safety net if a prior step ever seeded the venv with
# maturin-built wheels; it keeps extraneous packages untouched.
# `--locked` fails if committed uv.lock drifts from pyproject.toml.
- name: Install Python parity-gate tooling
run: uv sync --project python-bindings --inexact --group drift-guards --locked
- name: Run Tier-1 Python parity and runtime coverage gate
run: uv run --project python-bindings python tools/python_api_parity/check_parity_gate.py --repo-root .
- name: Run Python stub validation gate
run: uv run --project python-bindings python validate_stubs.py --rust-dir . --parity-contract docs/implementation/python_api_parity/baseline/parity_contract.json --json-out python-bindings/parity-artifacts/stub_validation_report.json --fail-on-warnings
# Drift guard: checked-in YAML `schema_version` headers vs the
# `client_schemas::*` constants in classic-config-core. Fails when a
# shippable YAML file's header would be refused at load time by the
# current client binary — i.e., the two sides of the contract drifted.
- name: Run YAML schema-version drift guard
run: uv run --project python-bindings python tools/schema_version_gate.py --repo-root .
- name: Upload parity and runtime coverage diagnostics
if: failure()
uses: actions/upload-artifact@v6
with:
name: python-parity-diagnostics
path: python-bindings/parity-artifacts/
if-no-files-found: warn
retention-days: 7
build-and-test:
name: Python Bindings Build + Smoke Tests
needs: [parity-gates]
runs-on: windows-latest
timeout-minutes: 90
steps:
- uses: actions/checkout@v6
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
cache-dependency-glob: python-bindings/uv.lock
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache cargo index
uses: actions/cache@v5
with:
path: ~/.cargo/git
key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-index-
- name: Cache cargo build
uses: actions/cache@v5
with:
path: target
key: ${{ runner.os }}-cargo-python-${{ hashFiles('**/Cargo.lock') }}-${{ hashFiles('foundation/**/*.rs', 'business-logic/**/*.rs', 'cpp-bindings/**/*.rs', 'node-bindings/**/*.rs', 'python-bindings/**/*.rs', 'ui-applications/**/*.rs') }}
restore-keys: |
${{ runner.os }}-cargo-python-${{ hashFiles('**/Cargo.lock') }}-
${{ runner.os }}-cargo-python-
# `uv sync` creates `python-bindings/.venv` and installs the locked
# tooling set (`maturin`, `pytest`). `--inexact` guards against the
# maturin-built `classic-*-py` wheels being pruned on any re-sync.
# `--locked` fails the job if the committed uv.lock drifts from
# pyproject.toml — catches silent lock/manifest divergence.
- name: Install Python bindings tooling
run: uv sync --project python-bindings --inexact --locked
# `maturin` is intentionally installed into `python-bindings/.venv` by
# the step above. `rebuild_rust.ps1` targets that interpreter explicitly
# for Python binding builds. Smoke-test collection imports promoted
# modules at import time, so CI must install the full Python binding
# set instead of a hand-maintained subset.
- name: Build and install Python bindings
shell: pwsh
run: pwsh -ExecutionPolicy Bypass -File rebuild_rust.ps1 -Target python
# Must invoke pytest through `python -m pytest`, not the `pytest.exe`
# entrypoint. `classic_config.ClassicConfig.get_config_path()` anchors
# settings discovery to `sys.argv[0]`'s parent directory (see
# test_config_import_anchors_settings_to_script_directory). When pytest
# runs as a console-script .exe, sys.argv[0] becomes `.venv\Scripts\pytest.exe`,
# which `get_config_path()` treats as a script path and derives a bogus
# settings parent from. `-m pytest` keeps sys.argv[0] pointed at the
# pytest package file, preserving the expected script-directory shape.
- name: Run Python bindings smoke tests
run: uv run --project python-bindings python -m pytest python-bindings/tests -q