Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/scripts/stubs/check-stubs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# .github/scripts/stubs/check-stubs.sh <stub-dir> [venv-dir]
#
# <stub-dir> is what `generatePythonStubs` wrote, e.g.
# ksp-fixtures/compose/build/generated/pythonStubs/desktopMain
# python-multiplatform-compose/fixtures/compose/build/generated/pythonStubs/desktopMain
# The venv defaults to <repo>/.tmp/stubs-venv (git-ignored) and is created on first use.
set -euo pipefail

Expand Down
18 changes: 9 additions & 9 deletions .github/workflows/stubs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
branches: [ "develop" ]
paths:
- "python-multiplatform-gradle-plugin/**"
- "ksp-fixtures/compose/**"
- "python-multiplatform-compose/fixtures/compose/**"
- ".github/scripts/stubs/**"
- "gradle/libs.versions.toml"
- ".github/workflows/stubs.yml"
Expand Down Expand Up @@ -52,10 +52,10 @@ jobs:
python-version: '3.13'

- name: Generate the stubs over the Compose jars
run: ./gradlew :ksp-fixtures:compose:generatePythonStubs --console=plain
run: ./gradlew :python-multiplatform-compose:fixtures:compose:generatePythonStubs --console=plain

- name: Type-check a consumer against them (mypy)
run: .github/scripts/stubs/check-stubs.sh ksp-fixtures/compose/build/generated/pythonStubs/desktopMain
run: .github/scripts/stubs/check-stubs.sh python-multiplatform-compose/fixtures/compose/build/generated/pythonStubs/desktopMain

- name: Assemble the artifact
run: |
Expand All @@ -65,7 +65,7 @@ jobs:
out=build/kotlin-stubs
rm -rf "$out"
mkdir -p "$out"
cp -R ksp-fixtures/compose/build/generated/pythonStubs/desktopMain/. "$out/"
cp -R python-multiplatform-compose/fixtures/compose/build/generated/pythonStubs/desktopMain/. "$out/"
cat > "$out/README.md" <<README
# Kotlin-name stubs for Compose ${compose_version}

Expand All @@ -79,9 +79,9 @@ jobs:
| python-multiplatform commit | ${GITHUB_SHA} |
| ref | ${GITHUB_REF} |
| workflow run | ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} |
| generator | \`:ksp-fixtures:compose:generatePythonStubs\` |
| generator | \`:python-multiplatform-compose:fixtures:compose:generatePythonStubs\` |

Packages stubbed: the \`artifactIncludePackages\` of \`ksp-fixtures/compose/build.gradle.kts\` at
Packages stubbed: the \`artifactIncludePackages\` of \`python-multiplatform-compose/fixtures/compose/build.gradle.kts\` at
that commit.

Use: put this directory on the type checker's path (\`MYPYPATH=<this directory>\`, or the
Expand Down Expand Up @@ -129,11 +129,11 @@ jobs:
python-version: '3.13'

- name: Generate the stubs over the Compose jars
run: ./gradlew :ksp-fixtures:compose:generatePythonStubs --console=plain
run: ./gradlew :python-multiplatform-compose:fixtures:compose:generatePythonStubs --console=plain

- name: No two stub paths are equal under case folding
run: |
python3 - ksp-fixtures/compose/build/generated/pythonStubs/desktopMain <<'PY'
python3 - python-multiplatform-compose/fixtures/compose/build/generated/pythonStubs/desktopMain <<'PY'
import os, sys
seen = {}
for root, dirs, files in os.walk(sys.argv[1]):
Expand All @@ -146,4 +146,4 @@ jobs:
PY

- name: Type-check a consumer against them (mypy)
run: .github/scripts/stubs/check-stubs.sh ksp-fixtures/compose/build/generated/pythonStubs/desktopMain
run: .github/scripts/stubs/check-stubs.sh python-multiplatform-compose/fixtures/compose/build/generated/pythonStubs/desktopMain
12 changes: 6 additions & 6 deletions .github/workflows/typedpython.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ name: TypedPython CI
on:
push:
branches: [ "develop", "main" ]
paths: [ "python-multiplatform-ksp/**", "ksp-fixtures/app/**", ".github/workflows/typedpython.yml" ]
paths: [ "python-multiplatform-ksp/**", "python-multiplatform-ksp/fixtures/app/**", ".github/workflows/typedpython.yml" ]
pull_request:
branches: [ "develop", "main" ]
paths: [ "python-multiplatform-ksp/**", "ksp-fixtures/app/**", ".github/workflows/typedpython.yml" ]
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.
Expand Down Expand Up @@ -86,7 +86,7 @@ jobs:
# 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 (ksp-fixtures/app/build.gradle.kts).
# 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:
Expand All @@ -108,15 +108,15 @@ jobs:

- name: App fixture tests
run: |
rm -rf ksp-fixtures/app/build/test-results/desktopTest
./gradlew :ksp-fixtures:app:desktopTest --rerun --console=plain \
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("ksp-fixtures/app/build/test-results/desktopTest/*.xml")
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]
Expand Down
16 changes: 11 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ interoperability in both directions:
| `python-multiplatform/` | The library: FFI layer, object model, upcall runtime |
| `python-multiplatform-ksp/` | KSP processor that generates the upcall table from Kotlin sources |
| `python-multiplatform-gradle-plugin/` | Gradle plugin: `PYTHONHOME` staging, artifact walker (binds prebuilt jars/klibs), `.pyi` stub generation |
| `ksp-fixtures/` | Consumer modules that exercise what the generators produce |
| `<module>/fixtures/` | Consumer modules that exercise what the generators produce, each inside the module whose output it checks (`python-multiplatform-ksp`, `python-multiplatform-gradle-plugin`, `python-multiplatform-compose`) |
| `sample/` | Compose Multiplatform demo app (desktop, Android, iOS, wasmJs, GraalVM native image) |
| `binary/` | Source archives of per-platform CPython distributions |
| `python_for_kotlin_binding.mermaid` | User-authored sketch of the object model (see rule 14) |
Expand Down Expand Up @@ -296,16 +296,22 @@ Rule 5 applies. In addition:
checking only iOS lets androidNative break unnoticed (an `actual` placed only in `iosMain` once did,
for days).

### The generator consumers: `ksp-fixtures`
### The generator consumers: `<module>/fixtures`

`:python-multiplatform-gradle-plugin:test` alone does not verify the code that **uses** what the
generators emit. Run each fixture module as a **separate** Gradle invocation (rule 8):

| Task | Catches |
|---|---|
| `:ksp-fixtures:app:desktopTest` | Upcall and proxy runtime |
| `:ksp-fixtures:compose:desktopTest` | Compose bindings and render proofs |
| `:ksp-fixtures:artifact:desktopTest` | Artifact walker and `.pyi` stubs |
| `:python-multiplatform-ksp:fixtures:app:desktopTest` | Upcall and proxy runtime |
| `:python-multiplatform-compose:fixtures:compose:desktopTest` | Compose bindings and render proofs |
| `:python-multiplatform-gradle-plugin-fixtures:artifact:desktopTest` | Artifact walker and `.pyi` stubs |

Where each lives: `python-multiplatform-ksp/fixtures/{library,app,android}` (KSP processor),
`python-multiplatform-gradle-plugin/fixtures/{artifact,artifact-valueclass,klib-artifact}` (artifact
walker; the plugin is an included build, so their Gradle path is
`:python-multiplatform-gradle-plugin-fixtures:<name>`) and
`python-multiplatform-compose/fixtures/{compose,notebook-e2e}` (Compose host).

Forgetting `artifact` has put red tests on `develop` twice; plugin unit tests cannot see them.
Running the three in one invocation once hid 24 failures caused by an ordering dependency.
Expand Down
6 changes: 3 additions & 3 deletions PROJECT.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Kotlin Multiplatform 에 CPython 을 임베딩해 **Kotlin 과 Python 이 서로
| `python-multiplatform/` | 라이브러리, FFI 계층(`python/native/ffi/`), 객체 모델(`python/multiplatform/ffi/`), 업콜 런타임 |
| `python-multiplatform-ksp/` | 업콜 테이블을 생성하는 KSP 프로세서 |
| `python-multiplatform-gradle-plugin/` | `stagePythonHome`, 아티팩트 워커(빌드된 jar/klib 바인딩), `.pyi` 스텁 생성 |
| `ksp-fixtures/` | 생성기 산출물을 실제로 쓰는 소비자 모듈 (`app`, `compose`, `artifact`, …) |
| `python-multiplatform-ksp/fixtures/`, `python-multiplatform-gradle-plugin/fixtures/`, `python-multiplatform-compose/fixtures/` | 생성기 산출물을 실제로 쓰는 소비자 모듈, 검증 대상 모듈 안에 둔다 (`app`, `compose`, `artifact`, ...) |
| `sample/` | Compose Multiplatform 데모 앱 (데스크톱·Android·iOS·wasmJs·GraalVM 네이티브 이미지) |
| `python_for_kotlin_binding.mermaid` | 사용자가 그린 객체 모델 스케치 (확정 스펙 아님) |
| `docs/` | `INTENT.md`, `SPEC.md`, `design/`, `platforms/`, `investigations/`, `roadmap/`, `guide/`, `locale/` |
Expand All @@ -68,8 +68,8 @@ Kotlin Multiplatform 에 CPython 을 임베딩해 **Kotlin 과 Python 이 서로

- 컴파일 확인은 세 타깃: `compileKotlinAndroidNativeArm64`(기본 루프), `compileKotlinIosSimulatorArm64`,
`compileKotlinDesktop`. **androidNative 를 빼먹지 않는다**, `nativeMain` 을 iOS 와 공유한다.
- 생성기 소비자 검증은 **모듈마다 따로**: `:ksp-fixtures:app:desktopTest`,
`:ksp-fixtures:compose:desktopTest`, `:ksp-fixtures:artifact:desktopTest`.
- 생성기 소비자 검증은 **모듈마다 따로**: `:python-multiplatform-ksp:fixtures:app:desktopTest`,
`:python-multiplatform-compose:fixtures:compose:desktopTest`, `:python-multiplatform-gradle-plugin-fixtures:artifact:desktopTest`.
- 결과는 `build/test-results/<target>/*.xml` 을 지우고 `--rerun` 으로 다시 돌려 센다.
- 종료 코드는 파이프로 읽지 않는다. 상세 규정은 `AGENTS.md` §15.
- CPython 은 저장소에 벤더링하지 않는다. Gradle 이 플랫폼별로 내려받아 검증·추출한다
Expand Down
Loading
Loading