Skip to content

Release: merge release into main #73

Release: merge release into main

Release: merge release into main #73

Workflow file for this run

name: TypedPython CI
# The TypedPython gate and compiler are Python (python-multiplatform-ksp/src/{main,test}/python).
# Gradle does not run them; this workflow does.
on:
push:
branches: [ "develop", "main" ]
paths: [ "python-multiplatform-ksp/**", "python-multiplatform-ksp/fixtures/app/**", ".github/workflows/typedpython.yml" ]
pull_request:
branches: [ "develop", "main" ]
paths: [ "python-multiplatform-ksp/**", "python-multiplatform-ksp/fixtures/app/**", ".github/workflows/typedpython.yml" ]
concurrency:
# A newer push to the same ref supersedes this run; frees the shared macOS runners.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
name: TypedPython tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
defaults:
run:
working-directory: python-multiplatform-ksp
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- name: Create the environment
# pyrefly is pinned exactly: the gate reads its versioned type-report format.
run: |
uv venv .venv --python 3.13
uv pip install --python .venv/bin/python "pyrefly==1.3.2" pytest
- name: Behaviour tests
run: .venv/bin/python -m pytest -q -m "not measurement"
- name: Measurements (recorded, sanity bounds only)
# A shared runner is not an idle machine (AGENTS.md §8): read ratios, not absolute times.
run: .venv/bin/python -m pytest -q -s -m measurement
sanitizers:
# SPEC N-8: ASan/UBSan runs are the safety net outside the proof. Every extension TypedPython
# builds in these tests is compiled with -fsanitize=address,undefined (TP_SANITIZE=1, see
# conftest.py) and the interpreter runs with the ASan runtime preloaded; any report fails the run.
# Linux only: macOS refuses to load the ASan runtime into the framework Python (the cgen
# sanitizer test has a launcher-based macOS path of its own).
name: TypedPython tests under ASan + UBSan (ubuntu-latest)
runs-on: ubuntu-latest
defaults:
run:
working-directory: python-multiplatform-ksp
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v5
- name: Create the environment
run: |
uv venv .venv --python 3.13
uv pip install --python .venv/bin/python "pyrefly==1.3.2" pytest
- name: Relax ASLR entropy (ASan shadow mapping on newer kernels)
run: sudo sysctl -w vm.mmap_rnd_bits=28 || true
- name: Self-check, the sanitizers must catch planted faults
# Builds a deliberately faulty extension (heap out-of-bounds read, signed overflow) and
# REQUIRES both reports. If this step passes, the setup below can detect faults.
run: .venv/bin/python tools/sanitizers.py selfcheck
- name: cgen, runtime and pipeline tests, sanitized
# detect_leaks=0: CPython itself leaks at exit. LD_PRELOAD is applied to this one command
# only (tools/sanitizers.py env prints it); the gate's pyrefly runs without it.
run: |
env $(.venv/bin/python tools/sanitizers.py env) \
.venv/bin/python -m pytest -q -m "not measurement" \
src/test/python/test_cgen.py src/test/python/test_runtime.py src/test/python/test_pipeline.py
app-fixture:
# #45: a TypedPython-compiled module calling Kotlin through the upcall table, in the app
# fixture's desktop JVM. buildTypedPythonBridge needs a host Python with pyrefly; without one the
# four TypedPythonKotlinCallTest tests skip. Locally that is allowed; here a skip fails the job.
# macOS only: elsewhere the JVM does not load libpython with global symbols, so the
# dynamic_lookup extension cannot resolve the C API (python-multiplatform-ksp/fixtures/app/build.gradle.kts).
name: TypedPython from Kotlin, app fixture (macos-latest)
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'zulu'
cache: 'gradle'
- uses: astral-sh/setup-uv@v5
- name: Create the TypedPython host environment
working-directory: python-multiplatform-ksp
run: |
uv venv .venv --python 3.13
uv pip install --python .venv/bin/python "pyrefly==1.3.2" pytest
- name: App fixture tests
run: |
rm -rf python-multiplatform-ksp/fixtures/app/build/test-results/desktopTest
./gradlew :python-multiplatform-ksp:fixtures:app:desktopTest --rerun --console=plain \
-PtypedpythonPython="$PWD/python-multiplatform-ksp/.venv/bin/python"
- name: The TypedPython tests ran (none skipped)
run: |
python3 - <<'PY'
import glob, sys, xml.etree.ElementTree as ET
cases = [c for p in glob.glob("python-multiplatform-ksp/fixtures/app/build/test-results/desktopTest/*.xml")
for c in ET.parse(p).getroot().iter("testcase")
if c.get("classname") == "fixture.app.TypedPythonKotlinCallTest"]
skipped = [c.get("name") for c in cases if c.find("skipped") is not None]
print(f"TypedPythonKotlinCallTest: {len(cases)} test(s), {len(skipped)} skipped")
if not cases or skipped:
print("skipped: " + ", ".join(skipped) if skipped else "no TypedPythonKotlinCallTest results")
sys.exit(1)
PY