Skip to content

Commit 31bc87e

Browse files
authored
Merge pull request #121 from thisisthepy/feat/docs-baselines-118
Docs: Record the CI baselines and the TypedPython gate after #119
2 parents 7e83cc8 + a725736 commit 31bc87e

3 files changed

Lines changed: 14 additions & 13 deletions

File tree

‎PROJECT.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ Compose(`androidx.compose.*`)를 파이썬에서 쓰기 위한 pip 패키지 **`
2727

2828
| 상태 | 항목 |
2929
|---|---|
30-
| 구현 | 매핑 매니페스트 `pythonx-map.toml`, `@Composable` 항등 데코레이터, 실제 디스크 패키지 `pythonx` 와 모듈 수준 규칙 기반 재노출(snake_case 이름·키워드·시그니처, 오버로드 디스패치, 값 클래스 허용 목록), 실제 Compose 1.11.1 에서 생성한 `.pyi` 스텁과 `py.typed`(wheel 포함, mypy 로 검사), `Alignment`/`Arrangement` 상수(평면 `Alignment.End` 와 묶음 `Alignment.Horizontal.End` 모두, #9), proxy 메서드의 snake_case 이름과 키워드 인자(`m.padding(padding_values=...)`; python-multiplatform #131 이 바인더 쪽에서 제공하므로 #131 이상 필요; Kotlin 이름도 실행 시 그대로 통하고 스텁은 snake_case 만), 함수이기도 한 Kotlin object 의 호출(`Color(0xFFFFFFFF)` 과 `Color.Red` 둘 다; #88, 설치한 wheel 에서도 테스트됨. Int/Long 오버로드 선택은 python-multiplatform #146) |
30+
| 구현 | 매핑 매니페스트 `pythonx-map.toml`, `@Composable` 항등 데코레이터, 실제 디스크 패키지 `pythonx` 와 모듈 수준 규칙 기반 재노출(snake_case 이름·키워드·시그니처, 오버로드 디스패치, 값 클래스 허용 목록), 실제 Compose 1.11.1 에서 생성한 `.pyi` 스텁과 `py.typed`(wheel 포함, mypy 로 검사), `Alignment`/`Arrangement` 상수(평면 `Alignment.End` 와 묶음 `Alignment.Horizontal.End` 모두, #9), proxy 메서드의 snake_case 이름과 키워드 인자(`m.padding(padding_values=...)`; python-multiplatform #131 이 바인더 쪽에서 제공하므로 #131 이상 필요; Kotlin 이름도 실행 시 그대로 통하고 스텁은 snake_case 만), 함수이기도 한 Kotlin object 의 호출(`Color(0xFFFFFFFF)` 과 `Color.Red` 둘 다; #88, 설치한 wheel 에서도 테스트됨. Int/Long 오버로드 선택은 python-multiplatform #146), TypedPython 게이트 통과(`pythonx/` 에 오류 0, 경고 5: `_reexport.py` 의 재노출 자체인 `dynamic-attr`; #118, CI 의 with-binder 에서 검사) |
3131
| 부분 | 노트북 표기 그대로의 `remember_saveable`(`getValue()`/`setValue()`, `.value` 별칭; #102, 가짜 호스트로 테스트됨, 저장·복원 증거는 python-multiplatform #174), 선언형 앱 루트 `@app`·`app_root`(#11; 로직은 테스트됨, 바인더 경로는 #38 모양의 가짜 호스트로 테스트됨, 실제 Compose 증거는 python-multiplatform 노트북 E2E #26 에서 통과; 숫자·문자열 상태는 python-multiplatform #69 부터 왕복됨), 배포 설정, Material 3 위젯(렌더 증거는 python-multiplatform 노트북 E2E 에만, 설치한 wheel 에서 Kotlin 과 픽셀 일치), `Icon`(import 만 됨)·`DefaultIcons`(`Icons.Default` alias, 가짜 호스트로만 테스트됨, 스텁에서는 `DefaultIcons.Add` 가 `ImageVector`; `DefaultIcons.Add` 로 쓴다; 노트북의 `DefaultIcons.Add()` 가 아님), `TextField(state=...)`·`TextFieldState`(#10; `pythonx.compose.foundation.text.input`, 가짜 호스트로 테스트됨, 노트북의 `text_state=`/`padding=` 는 `state=`/`modifier=Modifier.padding(8)`; IME 조합 증거는 python-multiplatform 노트북 E2E #26 에서 통과) |
3232
| 계획 | 색 스킴, 코루틴 스코프(pythonx-concurrent 이후) |
3333

3434
### 테스트 기준선
3535

3636
```
37-
uv run --with pytest --with mypy pytest tests -q
38-
PythonMultiplatform 체크아웃 없음 152 passed, 123 skipped
39-
python-multiplatform develop 31c092f0+ 274 passed, 1 skipped
37+
GitHub Actions, develop 7e83cc8 (2026-10-17, #119; with-binder 는 pyrefly==1.3.2 포함)
38+
PythonMultiplatform 체크아웃 없음 155 passed, 129 skipped
39+
python-multiplatform develop 31c092f0+ 282 passed, 2 skipped (UI.ipynb, .tmp/kotlin-stubs.zip 없음)
4040
describe_member 없는 체크아웃 같은 수, 그중 7 개 건너뜀 (python-multiplatform #54 이전)
4141
describe(module, name) 없는 체크아웃 같은 수, 그중 13 개 건너뜀 (python-multiplatform #36 이전)
4242
그보다 오래된 체크아웃 거기에 5 개 더 건너뜀 (#131 이전, snake_case 이름 없음)

‎docs/SPEC.md‎

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,23 @@ Each item carries a status:
1414

1515
A behaviour change starts here, then becomes a failing test, then code (`AGENTS.md` §5).
1616

17-
## 0. Test baseline (2026-10-03, after the a5028618 stubs)
17+
## 0. Test baseline (2026-10-17, develop `7e83cc8`, after #119)
1818

19-
Run from a worktree with `uv run --with pytest --with mypy pytest tests -q -rs` (pytest 8, mypy 2.4, CPython 3.13), where
20-
`UI.ipynb` is absent and its one test skips:
19+
The GitHub Actions run on `develop` (`.github/workflows/test.yml`, run 39017245145; `python -m pytest
20+
tests -q -rs`, with pytest, mypy and, in the `with-binder` job, `pyrefly==1.3.2`). CI has neither
21+
`UI.ipynb` nor `.tmp/kotlin-stubs.zip`, so the notebook test and the committed-stubs check skip:
2122

2223
| Environment | Result |
2324
|---|---|
24-
| No `PythonMultiplatform` checkout found | **152 passed, 123 skipped**, 186 subtests passed |
25-
| python-multiplatform `develop` at `31c092f0` or later (property rows, #38; `describe_member`, #54; besides `add_member_resolver` and `describe(module, name)`) | **274 passed, 1 skipped**, 232 subtests passed |
25+
| No `PythonMultiplatform` checkout found (`no-binder`, CPython 3.13 and 3.15) | **155 passed, 129 skipped**, 269 subtests passed |
26+
| python-multiplatform `develop` at `31c092f0` or later (property rows, #38; `describe_member`, #54; besides `add_member_resolver` and `describe(module, name)`) (`with-binder`, CPython 3.15) | **282 passed, 2 skipped**, 326 subtests passed |
2627
| an older checkout, before python-multiplatform #131 (no binder-side snake_case names) | the same, with the snake_case method tests skipped |
2728
| an older one, without `describe(module, name)` (python-multiplatform #36) | with 13 more skipped again |
2829
| an older one still, without `add_member_resolver` | with 5 more skipped again |
2930

30-
Measured in a worktree, which has `.tmp/kotlin-stubs.zip` but no `UI.ipynb`. Without a checkout, the
31-
122 tests that install the binder's layers through `tests/adapter.py` skip (one of them against the
32-
installed wheel, #88), plus the notebook test.
31+
Without a checkout, the 122 tests that install the binder's layers through `tests/adapter.py` skip
32+
(one of them against the installed wheel, #88), and so do the 5 TypedPython gate tests (S1.3), the
33+
notebook test and the committed-stubs check.
3334
Against a binder without `describe(module, name)`, the 13 that check grouped constants (§7, S7.1)
3435
skip. Against a binder before python-multiplatform #131, the tests that call a snake_case method or
3536
pass a snake_case keyword on a proxy the binder returned skip, because those names are the binder's. The skip against a current checkout is `UI.ipynb`'s (§2). A binder older than #38 skips the 5

‎docs/guide/status.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<thead><tr><th><span data-lang="en">State</span><span data-lang="ko">상태</span></th><th><span data-lang="en">Item</span><span data-lang="ko">항목</span></th></tr></thead>
3737
<tbody><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en">Mapping manifest <code>pythonx/compose/pythonx-map.toml</code>: inside the package, ships in the wheel</span><span data-lang="ko">매핑 매니페스트 <code>pythonx/compose/pythonx-map.toml</code>: 패키지 안에 있으며 wheel 에 포함</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en"><code>@Composable</code> identity decorator</span><span data-lang="ko"><code>@Composable</code> 항등 데코레이터</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en"><code>pythonx</code> as a real on-disk package re-exporting <code>androidx.compose.*</code> by one rule: names, keywords, signatures, <code>Dp</code> allowlist</span><span data-lang="ko"><code>androidx.compose.*</code> 를 규칙 하나로 재노출하는 실제 디스크 패키지 <code>pythonx</code>: 이름, 키워드, 시그니처, <code>Dp</code> 허용 목록</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en"><code>Modifier</code> chains with snake_case methods, overload dispatch, <code>Dp</code> as a number</span><span data-lang="ko">snake_case 메서드를 쓰는 <code>Modifier</code> 체인, 오버로드 디스패치, 숫자 <code>Dp</code></span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en"><code>Column</code>, <code>Row</code>, <code>Spacer</code> importable from <code>material3</code> as well as <code>layout</code> (manifest <code>[aliases]</code>)</span><span data-lang="ko"><code>layout</code> 뿐 아니라 <code>material3</code> 에서도 import 되는 <code>Column</code>, <code>Row</code>, <code>Spacer</code> (매니페스트 <code>[aliases]</code>)</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en">Type stubs (<code>.pyi</code>) generated from real Compose 1.11.1 by the runtime's naming rule, with <code>py.typed</code>, checked with mypy (#12); many types are still <code>Any</code></span><span data-lang="ko">런타임과 같은 이름 규칙으로 실제 Compose 1.11.1 에서 생성한 타입 스텁(<code>.pyi</code>)과 <code>py.typed</code>, mypy 로 검사(#12); 아직 많은 타입이 <code>Any</code> 입니다</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en">Snake-case names, keywords and signatures: modules and methods; the names and keywords on a proxy are the binder's since python-multiplatform #131 (an older binder spells them in Kotlin), and Kotlin's own spelling still works at run time</span><span data-lang="ko">snake_case 이름·키워드·시그니처: 모듈과 메서드; 프록시의 이름과 키워드는 python-multiplatform #131 부터 바인더가 제공하고(오래된 바인더는 Kotlin 이름으로 씁니다), Kotlin 이름도 실행 시에는 그대로 통합니다</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en">The empty <code>Modifier</code>: <code>Modifier.padding(16)</code> from the class needs an app-supplied factory against real Compose</span><span data-lang="ko">빈 <code>Modifier</code>: 클래스에서 시작하는 <code>Modifier.padding(16)</code> 은 실제 Compose 에서 앱이 제공하는 팩토리가 필요</span></td></tr><tr><td><span class="chip ok"><span data-lang="en">implemented</span><span data-lang="ko">구현</span></span></td><td><span data-lang="en"><code>Alignment</code> / <code>Arrangement</code>: <code>Alignment.Center</code>, <code>Arrangement.End</code>, <code>Arrangement.spaced_by(8)</code>, and the grouped <code>Alignment.Horizontal.End</code> beside <code>Alignment.End</code></span><span data-lang="ko"><code>Alignment</code> / <code>Arrangement</code>: <code>Alignment.Center</code>, <code>Arrangement.End</code>, <code>Arrangement.spaced_by(8)</code>, 그리고 <code>Alignment.End</code> 와 나란히 묶음 표기 <code>Alignment.Horizontal.End</code></span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en">Material 3 widgets: re-exported by rule; render proofs per widget pending (#9)</span><span data-lang="ko">Material 3 위젯: 규칙으로 재노출됨; 위젯별 렌더 증거 대기(#9)</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en">Distribution as <code>pythonx-compose</code>: the wheel carries the manifest, the re-export rule, the type stubs and <code>py.typed</code></span><span data-lang="ko"><code>pythonx-compose</code> 배포: wheel 에 매니페스트, 재노출 규칙, 타입 스텁, <code>py.typed</code> 포함</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en">A declared app root (<code>@app</code>) and Pythonic state (<code>state</code>), with no update call: binder path tested against a fake host shaped after python-multiplatform #38; real Compose is the E2E module (#11, #19)</span><span data-lang="ko">갱신 호출 없는 선언형 앱 루트(<code>@app</code>)와 파이썬다운 상태(<code>state</code>): 바인더 경로는 python-multiplatform #38 모양의 가짜 호스트로 테스트됨, 실제 Compose 는 E2E 모듈(#11, #19)</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en"><code>DefaultIcons</code> is <code>Icons.Default</code>, written <code>DefaultIcons.Add</code>, tested against a fake host shaped after python-multiplatform #37/#38; the real draw is in python-multiplatform's render test</span><span data-lang="ko"><code>DefaultIcons</code> 는 <code>Icons.Default</code> 이며 <code>DefaultIcons.Add</code> 로 씁니다. python-multiplatform #37/#38 모양의 가짜 호스트로 테스트됨; 실제 그리기는 python-multiplatform 의 렌더 테스트에 있음</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en"><code>TextField(state=…)</code> with <code>TextFieldState</code> from <code>pythonx.compose.foundation.text.input</code>: tested against a fake host shaped after python-multiplatform #73; the input-method (IME) composing proof is python-multiplatform E2E #26 (#10)</span><span data-lang="ko"><code>pythonx.compose.foundation.text.input</code> 의 <code>TextFieldState</code> 를 쓰는 <code>TextField(state=…)</code>: python-multiplatform #73 모양의 가짜 호스트로 테스트됨; 입력기(IME) 조합 증거는 python-multiplatform E2E #26 (#10)</span></td></tr><tr><td><span class="chip planned"><span data-lang="en">planned</span><span data-lang="ko">계획</span></span></td><td><span data-lang="en">Colour schemes (36 colour parameters)</span><span data-lang="ko">색 스킴 (색 매개변수 36 개)</span></td></tr><tr><td><span class="chip partial"><span data-lang="en">partial</span><span data-lang="ko">부분</span></span></td><td><span data-lang="en"><code>remember_saveable</code> with the notebook's <code>getValue()</code> / <code>setValue()</code>: tested here against a fake host; saving and restoring is python-multiplatform's test (#174)</span><span data-lang="ko">노트북의 <code>getValue()</code> / <code>setValue()</code> 를 쓰는 <code>remember_saveable</code>: 여기서는 가짜 호스트로 테스트, 저장과 복원은 python-multiplatform 의 테스트(#174)</span></td></tr><tr><td><span class="chip planned"><span data-lang="en">planned</span><span data-lang="ko">계획</span></span></td><td><span data-lang="en">Coroutine scopes (after pythonx-concurrent)</span><span data-lang="ko">코루틴 스코프 (pythonx-concurrent 이후)</span></td></tr></tbody>
3838
</table></div>
39-
<p data-lang="en" class="muted">Test baseline: <code>152 passed, 123 skipped</code> without a python-multiplatform checkout; <code>274 passed, 1 skipped</code> with a current one. The one skip with a current checkout reads the maintainer's <code>UI.ipynb</code>.</p><p data-lang="ko" class="muted">테스트 기준선: python-multiplatform 체크아웃이 없으면 <code>152 passed, 123 skipped</code>, 최신 체크아웃이면 <code>274 passed, 1 skipped</code>. 최신 체크아웃에서 건너뛰는 1 개는 메인테이너의 <code>UI.ipynb</code> 를 읽는 테스트입니다.</p>
39+
<p data-lang="en" class="muted">Test baseline on CI: <code>155 passed, 129 skipped</code> without a python-multiplatform checkout; <code>282 passed, 2 skipped</code> with a current one. The two skips with a current checkout read the maintainer's <code>UI.ipynb</code> and a downloaded stubs artefact, which CI does not have.</p><p data-lang="ko" class="muted">CI 의 테스트 기준선: python-multiplatform 체크아웃이 없으면 <code>155 passed, 129 skipped</code>, 최신 체크아웃이면 <code>282 passed, 2 skipped</code>. 최신 체크아웃에서 건너뛰는 2 개는 메인테이너의 <code>UI.ipynb</code> 와 내려받은 스텁 아티팩트를 읽는 테스트이고, CI 에는 둘 다 없습니다.</p>
4040
</section>
4141
<section>
4242
<h2>FAQ</h2>

0 commit comments

Comments
 (0)