Skip to content

Feat: Ship Pythonic stubs for Compose 1.11.1, generated by the runtime's own rule - #40

Merged
b-re-w merged 2 commits into
developfrom
work/real-stubs
Oct 3, 2026
Merged

b-re-w merged 2 commits into
developfrom
work/real-stubs

Conversation

@b-re-w

@b-re-w b-re-w commented Oct 3, 2026

Copy link
Copy Markdown
Member

Closes #12

tools/gen_stubs.py reads python-multiplatform's kotlin-stubs artifact (run 37077627980, Compose 1.11.1). It reads the zip in place, because two paths in it differ only in case (python-multiplatform #44). It writes pythonx/compose/**/__init__.pyi for every manifest module, plus py.typed.

Conversion rules

  • Names and parameters follow the runtime rule.
  • Class extension members are renamed, but method keywords stay Kotlin's, which the header says (python-multiplatform Docs: Bring the guide up to the Pythonic surface that now exists #34).
  • References into mapped Kotlin packages become pythonx modules; references into unmapped ones become Any.
  • Kotlin objects become classes in the parent stub. Sub-package folders would shadow the runtime KotlinObject.
  • A second package mapping re-exports the first, and material3 re-exports Column/Row/Spacer.
  • Objects shadowed by a same-named function are left out, as at run time.

Feature added: 10 stub files (385 kB) and py.typed.
Test added:

  • 24 stub tests, including a regeneration check that skips without the zip;
  • 7 mypy tests (correct code passes; a Kotlin-spelled keyword or name fails);
  • 2 wheel tests.

Red before the generator change: 28 failed. Disabling each step fails 1–11 tests.
CI: both jobs install mypy.
Documentation corrected: SPEC S1.1/S1.2, PROJECT.md, guide, both READMEs.

Upstream problems found (reported to the binder, not fixed here):

  • 14 upstream stubs have a None: constant syntax error;
  • colors: …ItemColors is typed bool;
  • object stubs lack functions such as Arrangement.spacedBy;
  • object constants are typed Any.
Environment Before After
python-multiplatform ba4c6f49 110 passed, 1 skipped 143 passed, 1 skipped
no checkout (worktree) 54 passed, 57 skipped 84 passed, 60 skipped

The PR was drafted by a subagent in a worktree, then reviewed and re-run here.

b-re-w added 2 commits October 3, 2026 09:02
…e's own rule

python-multiplatform now publishes Kotlin-named stubs for real Compose as a
CI artifact (kotlin-stubs, run 37077627980). tools/gen_stubs.py reads that zip
in place -- it holds two paths that differ only in case, which macOS cannot
extract (python-multiplatform #44) -- and writes pythonx/compose/**/__init__.pyi
for every manifest module, plus py.typed:

- names and parameters follow _reexport.python_name / snake_case, so an
  editor completes what the interpreter resolves;
- stub classes keep their names and their extension members are renamed, but
  a method's Protocol __call__ keeps Kotlin keyword names, because the runtime
  does not translate a method's keywords yet (python-multiplatform #34); the
  header says so;
- references into mapped Kotlin packages name the pythonx module; references
  into unmapped ones become Any;
- a Kotlin object is a class in its parent stub (constants as ClassVar,
  functions as snake_case staticmethods) -- not a sub-package directory, which
  would be a namespace package at run time and shadow the object the
  re-export serves; both upstream layouts are read;
- the second mapping of a package re-exports the first, so mypy sees one
  RowScope; material3 re-exports Column, Row and Spacer per [aliases];
- an object shadowed by a same-named function (Color, TextStyle,
  PaddingValues, TextUnit, ...) is left out, as at run time; constants named
  None are left out.

tests/test_typing.py runs mypy against the committed stubs: correct code
passes, a Kotlin-spelled keyword or name on a module function or method name
fails, and importing every manifest module checks every stub. CI installs
mypy.

Drafted by a subagent in a worktree; reviewed here and re-run.

feature added: generated stubs for 10 modules (385 kB) and py.typed.
test added: 24 in test_stubs.py (including a regeneration check that skips
without the zip), 7 in test_typing.py, 2 in test_wheel.py. Red before the
generator change: 28 failed, 20 passed. Disabling each generator step fails
between 1 and 11 tests.
documentation corrected: SPEC S1.1/S1.2 and baseline, PROJECT.md, guide
status/getting-started/index/concepts, README and README_ko.
Suite against python-multiplatform ba4c6f49: 110 passed, 1 skipped -> 143
passed, 1 skipped. Without a checkout (worktree, no notebook): 54 passed, 57
skipped -> 84 passed, 60 skipped. check_guide.py: 0.

Refs #12
test_typing.py made its temporary directory under .tmp/, which exists in a
working checkout but not in a fresh one, so CI failed with FileNotFoundError.
Both tests that use .tmp/ now create it first.

defect fixed: tests assumed .tmp/ existed.
Checked by running both modules with .tmp/ moved away: they pass.

Refs #12
@b-re-w
b-re-w merged commit 3aecfea into develop Oct 3, 2026
4 checks passed
@b-re-w
b-re-w deleted the work/real-stubs branch October 3, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant