Skip to content

feat(embed): stage license texts into share/licenses of bundle outputs - #718

Open
espetro wants to merge 1 commit into
work/emb659from
work/lic709
Open

espetro wants to merge 1 commit into
work/emb659from
work/lic709

Conversation

@espetro

@espetro espetro commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Closes #709

What changed

A --embed-python=bundle output now carries its license texts in name/share/licenses/, so the redistribution obligation of shipping a compiled CPython is met by the bundle step itself.

  • src/pyscriptc/licenses.py (new): stage_bundle writes name/share/licenses/ with
    • LICENSE.cpython.txt, the bundled runtime's own text, copied from the pack (lib/pythonX.Y/LICENSE.txt of the pinned asset),
    • one LICENSE.<component>.txt per third-party component compiled into libpython (expat, libffi, mpdecimal, OpenSSL, SQLite, zlib, zstd, ncurses and the rest of the packaging/third-party.toml inventory),
    • NOTICE, the third-party notice rollup for the bundled stdlib and libraries, and
    • one directory per bundled third-party distribution, holding the licenses/ tree of its *.dist-info metadata (the site-packages the embed: bundle pure-Python dependencies into site-packages, refuse native wheels #660 slice stages).
  • The third-party texts ship as pyscriptc.pbs_licenses package data, so an installed compiler stages them without a repository checkout. The pinned python-build-standalone install_only asset the pack is cut from carries no licenses/ directory, so the texts are vendored from the same release's pgo+lto-full archive (the macos-arm64 and linux-x86_64 archives carry byte-identical texts, checked) with their sha256 pinned in packaging/pbs_licenses.toml. scripts/sync_pbs_licenses.py refreshes them (--fetch) and verifies them by default (drift exits 1). packaging/build.sh includes the directory in the onefile binary.
  • scripts/gen_third_party_notices.py writes NOTICE and the packaged copy together, and --check covers both.
  • .github/workflows/embed.yml: the acceptance step asserts OUT-moved/prog/share/licenses/LICENSE.cpython.txt, LICENSE.expat.txt and NOTICE again (the check dropped in feat(embed): the pinned CPython runtime pack and the --embed-python seam (#657, #658) #707 is restored).
  • Docs: docs/reference/runtime-pack.md, docs/getting-started/install.md, .agents/docs/release/embed-runtime.md.

Tests

uv run pytest -n 2 tests/test_licenses.py tests/test_sync_pbs_licenses.py tests/test_embed.py \
  tests/test_third_party_notices.py tests/test_sitedeps.py tests/test_runtime_bump_check.py \
  tests/test_stdlibzip.py -q
70 passed, 0 failed, 1 skipped
uv run ruff check          # Ruff: No issues found
uv run ruff format --check # 821 files already formatted
uv run python -m benchmarks.baseline.run --check
scripting geomean  time 9.8x CPython  rss inf x CPython
island geomean  time 1.6x CPython  rss inf x CPython
within reference

End to end on this host (macOS arm64, the pinned PBS 20261021 pack), the acceptance program compiled and relocated:

$ pyscriptc compile --island island_fractions.py --emit bin --embed-python=bundle -o OUT/prog
$ cp -R OUT OUT-moved && rm -rf OUT
$ env -i HOME=... OUT-moved/prog/bin/prog
11/12
$ ls OUT-moved/prog/share/licenses | wc -l
21

The 21 files are the 20 component texts plus NOTICE; LICENSE.cpython.txt is the pack's own lib/python3.14/LICENSE.txt (13.5 KB).

A wheel install was checked separately: the built wheel carries pyscriptc/pbs_licenses/ (21 entries) and a fresh venv with only that wheel stages the same set from package data (staged 20 notice True). scripts/wheel_smoke.sh passes (hello).

Not done

  • The licenses/ texts of a bundled distribution are staged only when its *.dist-info carries a licenses/ directory. A distribution that ships no license directory contributes nothing, and the wheel's metadata license expression is not turned into a text.
  • The python-build-standalone full archive is not part of the runtime pack; the texts are vendored into the wheel at build time instead. A runtime bump has to refresh the vendored texts, the inventory and NOTICE (documented in .agents/docs/release/embed-runtime.md).
  • The docker-based acceptance run was not executed here; the embed CI job on the PR is the acceptance test.

Closes #709, stacked on the #659/#660 bundle work (PR #716).

- src/pyscriptc/licenses.py: stage_bundle now writes name/share/licenses/
  with three sources: the bundled runtime's own CPython license text copied
  from the pack (lib/pythonX.Y/LICENSE.txt), the license texts of the
  third-party components compiled into libpython, the NOTICE rollup, and the
  licenses/ tree of every *.dist-info the bundle's site-packages carries
  (#660).
- the third-party texts ship as pyscriptc.pbs_licenses package data because
  the pinned install_only asset carries no licenses/ directory; the texts
  are vendored from the same PBS release's pgo+lto-full archive (verified
  identical across the macos-arm64 and linux-x86_64 archives) with their
  sha256 pinned in packaging/pbs_licenses.toml and refreshed by
  scripts/sync_pbs_licenses.py (--fetch re-vendors, default mode verifies;
  drift exit 1). An installed compiler stages from package data, no repo
  checkout needed; packaging/build.sh includes the directory in the onefile.
- scripts/gen_third_party_notices.py now writes NOTICE and the packaged
  copy together (--check covers both), and the footer describes what an
  output actually carries.
- .github/workflows/embed.yml: the acceptance step asserts
  OUT-moved/prog/share/licenses/{LICENSE.cpython.txt,LICENSE.expat.txt,
  NOTICE} again.
- docs/reference/runtime-pack.md, docs/getting-started/install.md and
  .agents/docs/release/embed-runtime.md describe the staged tree, the
  vendoring and the bump procedure.

Verified end to end on this host (macOS arm64, PBS 20261021 pack):
env -i relocation of the acceptance bundle prints 11/12 and carries all 21
license files; a wheel install stages the same set from package data.
@espetro espetro added this to the v0.7.0 milestone Oct 26, 2026
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying pyscriptc with  Cloudflare Pages  Cloudflare Pages

Latest commit: fb164e2
Status:🚫  Build failed.

View logs

This branch has not been deployed

No deployments
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