The morphir-python Morphir extension
The morphir-python extension lets a Morphir host, such as the Rust morphir
CLI, compile Python with morphir compile --language python and generate Python
with morphir generate --target python. It is the
morphir-python-binding
compiler built as a WebAssembly guest or a standalone process speaking the
Morphir extension protocol (MEP). It is the same compiler that the Python package runs
natively, so both give the same IR and the same diagnostic codes.
This repository builds and releases the extension. Bundles up to
extension/python/v0.4.0 were released from
finos/morphir-rust and remain
available there.
| Identity | Value |
|---|---|
| Extension ID | morphir-python |
| Short ID and release tag | python, extension/python/v<version> |
| Language | python (.py) |
| Target | python |
| IR versions | 3, 4 |
| Published 0.5.0 MEP versions | 0.2.0-draft.1, 0.1 |
| Multiple source documents | multiDocument: true, from 0.4.2 |
Extension 0.5.0 pairs with morphir-python==0.1.2 and
morphir-python-native==0.1.2, using published Rust SDK 0.4.0.
The bridge API remains revision 1; core morphir==0.1.1 includes the updated
documentation metadata.
Historical extension 0.4.2 pairs with morphir-python==0.1.0,
morphir-python-native==0.1.1 and morphir==0.1.0; its compiler version is
0.4.2. Use 0.4.2 or later with hosts that require an explicit multi-document
claim; 0.4.1 omits that claim.
Model protocol in release 0.5.0
Package, protocol, envelope, claims and IR versions identify different contracts:
| Contract | Value |
|---|---|
| Compiler / extension package | 0.5.0 |
| Rust extension SDK dependency | exactly 0.4.0 from crates.io |
| MEP offers | exact 0.2.0-draft.1 and legacy 0.1 |
| Model envelope | exact 0.1.0-draft.1 |
| Claim set | 0.1.0-draft.2 |
| Model profile / codec | morphir-ir / morphir-json |
| Semantic IR | 3.0.0 or 4.0.0, Library distributions |
The host must offer complete operation/profile/codec/envelope/IR tuples through
modelTransport during initialization. The guest selects only their intersection
and the lower value of each limit. Both morphir.frontend.compileModel and
morphir.backend.generateModel support each stated IR version. The static limits
are 12 MiB encoded content, 8 MiB decoded content, depth 128 and 100,000 nodes.
Session capabilities remain fixed after initialization. Legacy sessions use
compile/generate and cannot call model methods. Other MEP drafts do not match.
Numeric and string request IDs retain their type and value. Unsupported Ion profiles or evidence, required guarantees, and Specs/Application generation are refused explicitly. No rich-model preservation or automatic codec fallback is advertised.
The shared executable MCK's separate python-json-library-v1 profile qualifies
the supported JSON subset. Its fixed expectations and existing MoonBit rich-Ion
profile remain independent. WASM qualification uses the pinned Rust Extism host
adapter; raw request and response bodies pass unchanged to the guest. This ABI
handles requests only, so notification silence and exit describe the adapter and
guest route, not notification delivery inside the WASM guest.
The declaration is in rust/extension.toml.
The released host recipe below uses legacy MEP 0.1. For new-draft protocol
checks, use the source-pinned MCK
recorded in the release evidence.
Install the qualified release bundle
This recipe uses finos/morphir 0.4.0-beta.10 and Python extension 0.5.0. Use the Rust product CLI, not the MoonBit executable of the same name. The compatibility guide explains the difference. CPython is not needed to run the installed WASM guest.
For a reproducible setup from this checkout, python3 scripts/docs_hosts.py prepare downloads the pinned CLI and bundle, verifies the release archive and
both bundle file SHA-256 digests, renames the descriptor to release.json, and
prints the absolute MORPHIR_HOST and PYTHON_BUNDLE paths. Pins live in
site/integrations.json
and rust/extension.toml.
Run the printed --version command and check it reports 0.4.0-beta.10.
For manual acquisition, download the 0.5.0 .wasm, .wasm.sha256 and .release.json assets
from the extension release.
Verify the SHA-256 values in the pin file before using them, then rename the
.release.json descriptor to release.json in the same bundle directory.
The WASM digest is
791d6cc60f442b1088b291e9aed4f2740a38b0f0cc920f5f7418735c2b88aeb6.
The descriptor digest is
a78df591623388a95f3f7f8f7465422cee3dd4f6d86a64224d2a02291d8a81b3.
The host release has platform-specific archives; use the declared target and
hash rather than an unversioned executable from PATH.
Install, discover and invoke
Use a fresh project directory with the src/acme/ model files from the
quickstart, then set MORPHIR_HOST and PYTHON_BUNDLE to those
verified absolute paths. This POSIX-shell recipe creates an isolated Morphir
home, publishes to a local index, installs the bundle and checks discovery
before compiling. It is the exact recipe run by documentation qualification.
#!/usr/bin/env bash
set -euo pipefail
# MORPHIR_HOST is the verified finos/morphir 0.4.0-beta.10 executable.
# PYTHON_BUNDLE is the verified 0.5.0 bundle directory containing release.json.
: "${MORPHIR_HOST:?Set the verified Rust-host executable path}"
: "${PYTHON_BUNDLE:?Set the verified bundle directory}"
"$MORPHIR_HOST" --version
export MORPHIR_HOME="$PWD/.morphir-home"
"$MORPHIR_HOST" extension repository init .morphir/python-index
"$MORPHIR_HOST" extension repository add python-local --directory .morphir/python-index
"$MORPHIR_HOST" extension repository publish python-local --bundle "$PYTHON_BUNDLE"
"$MORPHIR_HOST" extension repository verify python-local
"$MORPHIR_HOST" extension install --repository python-local morphir-python
"$MORPHIR_HOST" extension list
cat > morphir.toml <<'TOML'
[project]
name = "acme/example"
version = "0.1.0"
source_directory = "src"
[frontend]
language = "python"
emit_parse_stage = false
TOML
"$MORPHIR_HOST" compile --language python --input src --ir-version 3.0.0 --output compiled
"$MORPHIR_HOST" generate --target python --input compiled/morphir-ir.json --output host-generated
"$MORPHIR_HOST" compile --language python --input host-generated --ir-version 3.0.0 --output host-rebuilt
The installed extension supplies the python frontend and target. Compilation
writes compiled/morphir-ir.json; generation writes the two modules beneath
host-generated/acme/. Recompilation checks equivalent IR. For this CLI,
omitting --ir-version, or selecting 4, requests draft v4. The Python CLI
instead defaults to v3, so recipes state the version explicitly.
Installation records capability claims as unchecked; the runtime compile and
generate checks provide execution evidence. The existing bundle qualifier also
removes the local index, blocks network access and repeats v3/v4 round trips.
Use python3 scripts/docs_hosts.py qualify to repeat the displayed workflow and
offline checks. Receipts record pins, file hashes, host identity, checker and
input digest. Download failure never counts as a passing qualification.
Download and choose a runtime
Release 0.5.0 provides both WASM and process bundles on
GitHub Releases.
The process executable is a MEP guest for the finos/morphir host. The
morphir-python CLI continues to use its pinned native Python wheel through the
mise/pipx installation; choosing an extension runtime does
not configure that CLI.
Use two separate canonical bundle directories and named local repositories.
The WASM bundle contains its .wasm, checksum and release.json. The process
bundle contains the raw executables, their checksums and its own release.json.
The canonical repository writer refuses a bundle mixing both runtimes.
The process bundle includes Linux x86_64/ARM64, macOS x86_64/ARM64 and Windows
x86_64. Installation chooses the matching platform and refuses an absent one.
The release includes five raw executables and checksums, a separately named
process descriptor, morphir-python-extension-VERSION.tar.gz, source-bound
qualification receipts and SHA256SUMS. The archive contains the complete
canonical process bundle, with release.json and executable permissions. Its
payloads match the raw assets. Raw MCK reports, their saved rechecks, runtime
switching evidence and host timing samples are retained alongside the bundles.
With the GitHub CLI installed, run this in a fresh
directory using Bash, shasum and tar. Download all assets before checking
SHA256SUMS; it covers the qualification evidence as well as the bundles.
#!/usr/bin/env bash
set -euo pipefail
VERSION=0.5.0
gh release download "extension/python/v$VERSION" \
--repo finos/morphir-python --dir python-extension-assets
(cd python-extension-assets && shasum -a 256 -c SHA256SUMS)
mkdir python-wasm python-process
cp "python-extension-assets/morphir-python-binding-$VERSION.wasm" \
"python-extension-assets/morphir-python-binding-$VERSION.wasm.sha256" python-wasm/
cp "python-extension-assets/morphir-python-binding-$VERSION.release.json" \
python-wasm/release.json
tar -xzf "python-extension-assets/morphir-python-extension-$VERSION.tar.gz" \
-C python-process
export WASM_BUNDLE="$(cd python-wasm && pwd)"
export PROCESS_BUNDLE="$(cd python-process && pwd)"
The qualification workflow runs installation and runtime-switching checks
against this extracted archive. Both directories above contain version 0.5.0.
Historical 0.4.2 bundles remain available from their original release.
Set WASM_BUNDLE and PROCESS_BUNDLE to those unmodified directories. With
MORPHIR_HOST pointing at the pinned host described above, an isolated trial is:
export MORPHIR_HOME="$(mktemp -d)"
VERSION=0.5.0
"$MORPHIR_HOST" extension repository init ./wasm-repository
"$MORPHIR_HOST" extension repository init ./process-repository
"$MORPHIR_HOST" extension repository add python-wasm --directory ./wasm-repository
"$MORPHIR_HOST" extension repository add python-process --directory ./process-repository
"$MORPHIR_HOST" extension repository publish python-wasm --bundle "$WASM_BUNDLE"
"$MORPHIR_HOST" extension repository publish python-process --bundle "$PROCESS_BUNDLE"
"$MORPHIR_HOST" extension install morphir-python --repository python-wasm --version "$VERSION"
# Switch the active provider in this isolated Morphir home.
"$MORPHIR_HOST" extension uninstall morphir-python
"$MORPHIR_HOST" extension install morphir-python --repository python-process --version "$VERSION"
The repository selects the runtime; this host has no --runtime installation
flag. It permits one active morphir-python provider per home. Uninstall it
before installing the other runtime from its explicit repository. Compile and
generate commands remain the same. The process guest starts in stdio mode with
no arguments; --stdio is also accepted by hosts configured to pass it.
Installation restores executable permissions, so the Morphir host can launch a
downloaded raw executable without a user Rust toolchain or Python interpreter.
A process has ordinary OS rights; WASM uses the host's Extism isolation.
The developer Rust host checker pins the upstream host source and tests actual WASM/process bytes independently of the installation recipe. It verifies legacy v3/v4 operations, diagnostic parity, orderly shutdown and process timeout cleanup. Its timing runner retains fresh-guest startup and compile/generate samples for small and larger inputs, including the machine, build profile, input and artifact identities. These observations do not establish newer-draft conformance or a general speed claim.
The release-assembly check runs this switch in both directions with fresh project caches, compares v3/v4 IR and generated-file digests, rejects an actual foreign-only bundle, and checks that changing installed bytes causes a digest refusal before compilation. Each platform's own bundle qualifier also checks installed-byte integrity. These are legacy-route checks. The separate executable MCK qualification covers the new MEP draft and its model operations. Promotion must retain and verify both kinds of evidence for the candidate being released.
To verify already built candidates without rebuilding them:
python -m scripts.qualify_runtime --wasm "$WASM_BUNDLE" \
--process "$PROCESS_BUNDLE" --report .dev/qualification/runtime-choice.json
Build a development bundle
From the repository root:
mise install
mise run install
mise run extension:bundle
This task:
- builds the release WASM guest and validates it with
wasm-tools; - packages it with finos/morphir-rust's canonical WASM packager
(
scripts/package_extension.py), run unchanged at the revision pinned inrust/extension.toml, so the bundle has the same descriptor format as earlier releases. The finos/morphirmorphir extension bundlecommand packages native process extensions only; - downloads the Morphir CLI version pinned in
rust/extension.toml, checks its SHA-256 digest, publishes and installs the bundle into a new Morphir home, deletes the repository, blocks network access, and compiles, generates and recompiles a two-module model in IR v3 and v4; - checks that the IR from the extension equals the IR from the Python API for the same sources;
- requires digest refusal when installed bytes are changed in a fresh project, then restores the original artifact.
The bundle is written to .morphir/build/extensions/python/, and JSON receipts
with every digest are written to .dev/qualification/. A bundle built from a
clean checkout records its commit as gitCommit; a bundle from a modified
checkout does not.
CI runs this task when the compiler, the declaration or the bundle tooling
changes, and uploads the bundle as morphir-python-extension-bundle.