Skip to content

Python bindings: cross-platform wheel matrix + PyPI publishing (+ cp314t) #132

Closed

Description

@dean0x

Follow-up to #59 / #131. The native Python bindings (crates/mds-python, to be published as markdown-script — ADR-012 selected this name; mdscript on PyPI is third-party owned and cannot be shared) landed in #131 as a dev/test-only crate — the extension builds and the pytest suite runs in CI, but no wheels are published. This issue tracks turning that into a real PyPI distribution as part of the single coordinated release.

Note: v0.4.0 shipped 2026-09-02 with no Python build or publish job in release.yml. This work is now active. PyPI name registration is tracked separately in #292; only a first upload claims the markdown-script name (the pending publisher filed 2026-08-25 reserves nothing and expires unused).

Scope

  • Cross-platform wheel matrix. Build cp311-abi3 wheels for the release
    target platforms (mirror the napi 7-target set where a Python ABI exists):
    manylinux/musllinux x86_64 + aarch64, macOS x86_64 + arm64, Windows x86_64.
    Use maturin build --release (via maturin-action or the pinned maturin) with an
    sdist.
  • PyPI publishing via OIDC trusted publisher for release.yml (preferred; no
    long-lived token), mirroring the npm provenance setup. Publish wheels + sdist.
  • Wire into the coordinated release. Extend:
    • release.yml — a build-python matrix + publish-python job, gated on the
      version check, ordered with the crates.io/npm publishes.
    • scripts/verify-versions.mjs — assert the markdown-script wheel version equals the
      workspace version (it currently checks crates + npm only; markdown-script gets its
      version from the Cargo workspace via maturin dynamic, so this is an added
      assertion, not a new source of truth).
    • scripts/bump-version.mjs — no manifest edit needed (version is dynamic), but
      confirm the CHANGELOG/coordination covers the Python package.
  • cp314t free-threaded wheels. The extension is already free-threading ready
    (frozen result classes, #[pymodule(gil_used = false)], GIL released per compile);
    the cp314t ABI is a separate build. Add it once the toolchain/runner support is
    stable and soaked.
  • Post-publish smoke: pip install markdown-script on a clean machine + provenance
    attestation check.

Notes

Activity

  1. added this to the v0.4.0 milestone on Aug 9, 2026
  2. dean0x commented on Aug 9, 2026

    @dean0x
    OwnerAuthor

    Milestoned v0.4.0 for one sub-item only (2026-08-09 sweep)

    To be explicit about scope, because the bulk of this issue is not pre-tag:

    Pre-tag (v0.4.0): PyPI \mdscript` name registration— the one-time maintainer action. Rationale:crates/mds-python/README.mdand the repo docs already advertisepip install mdscript`, but the name is unregistered on PyPI. That is a squatting window that opens wider the moment v0.4.0 is announced. Registration costs minutes and does not require the wheel matrix, the release-workflow changes, or OIDC to exist yet.

    Not pre-tag (post-v0.4.0): everything else here — the cross-platform wheel matrix, release.yml build-python/publish-python jobs, verify-versions.mjs assertion, OIDC trusted publishing, and cp314t. Nothing Python ships in the v0.4.0 release and the docs are honest about that (crates/mds-python is dev/test-only; CI builds and tests it but publishes nothing).

    If it is preferable to track these separately, split the name-registration bullet into its own issue and bump this one back off the milestone.

  3. removed this from the v0.4.0 milestone on Aug 9, 2026
  4. dean0x commented on Aug 18, 2026

    @dean0x
    OwnerAuthor

    Name decision blocking this issue: see #292

    #292 has been re-scoped and now carries the Python package name decision that this
    issue's PyPI publishing work depends on. Summary of what changed:

    • mdscript on PyPI is not available — it is a genuine project (5 releases, April
      2021, real code, dormant ~5 years) in the same problem space, and PEP 541 offers no
      route to it because the owner is reachable.
    • Their top_level.txt is exactly mdscript, so keeping import mdscript under a
      different distribution name would silently clobber site-packages for whichever
      package installs second. Both names must change.
    • Decision (ADR-012): the Python distribution ships as markdown-script with
      import name markdown_script.

    Impact on the scope in this issue

    The scope items above that say mdscript need to read markdown-script /
    markdown_script:

    The rename itself is tracked in #292 and should land before the publishing job here goes
    live.

    Verified PyPI Trusted Publisher values for the publish-python job

    Field Value
    Owner dean0x
    Repository mdscript
    Workflow filename release.yml
    Environment name (blank)

    If this issue's implementation adds environment: pypi to the publish job, the
    trusted-publisher record on PyPI must be updated to match the environment name, or the
    OIDC exchange will be rejected.

  5. dean0x commented on Aug 20, 2026

    @dean0x
    OwnerAuthor

    Deferred from v0.4.0 code review

    Finding: python-04 from wave-v0.4.0-wave1 review (2026-08-19_1216)

    File:Line: crates/mds-python/tests/test_parity.py:349

    Issue: Byte-level differentials across 3 helpers × 4 surfaces; nothing Python ships in v0.4.0.

    Reason for deferral: This belongs with the cross-platform wheel matrix and PyPI publishing decision in this issue.

    Related: PR #308 (wave/v0.4.0-wave1), issue #292

  6. dean0x commented on Sep 1, 2026

    @dean0x
    OwnerAuthor

    Note for the aarch64-musl wheel leg: maturin 1.13.3 (the version pinned in CLAUDE.md/CI) bundles cargo-zigbuild 0.22.2, which does not filter -Wl,--fix-cortex-a53-843419 (rust-lang/rust#155453, emitted by rustc >= 1.98.0 for both aarch64 linux targets); zig cc rejects the flag. maturin 1.14.1 bundles cargo-zigbuild 0.23.0 which filters it (cargo-zigbuild#452). Any zig-based aarch64-musl wheel build needs maturin >= 1.14.1. Publisher matching rules verified on 2026-09-02: workflow is the bare filename release.yml (reusable/called workflows do not match); a blank publisher environment means the environment claim is not checked, so adding environment: to the job later needs no publisher change; the publish job needs job-level permissions: id-token: write with pypa/gh-action-pypi-publish; the PyPI user who created the pending publisher becomes the project owner on first upload. See also the expiry note on #292.

  7. modified the milestones: v0.4.1, v0.4.2 on Sep 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions