WeavePy is an experimental high-performance Python interpreter written in Rust, designed to be a 100% compatible, drop-in replacement for CPython. The goal is simple but ambitious: run existing Python code, packages, tools, and workflows unchanged while dramatically improving execution speed, startup time, memory usage, and runtime scalability. WeavePy treats CPython compatibility as the baseline, not a stretch goal — using CPython's own test suite as a guiding standard while exploring a modern Rust-based runtime architecture built for aggressive optimization, native interoperability, and long-term performance work.
Status: drop-in replacement for the documented CPython 3.13 surface, with a measured conformance baseline and a live C-extension entry point. The bundled regression suite at
tests/regrtest/covers the seven semantic groups exercised byRFC 0027(object model, iterators/ generators/coroutines, numerics/strings/format, containers, exceptions/ context, serialization/compression/codecs, and IO/OS/argparse/inspect/ typing) and is green onmain.RFC 0028adds the PEP 3118 buffer protocol, PEP 590 vectorcall, the fullPyType_FromSpec[WithBases]slot surface, and a_ndarray.cC-extension fixture exercising the stack end-to-end.RFC 0029closes the loop: thedatetimeC-API, the fullPyCapsulesurface, keyword-awarePyArg_ParseTupleAndKeywords, property-aware descriptor dispatch intp_getset, a numpy-shaped_numpylike.cfixture exercisingdtype/ufuncs/buffer-protocol/ reshape/mask_select/PyDateTime, a PEP 425 wheel-tag matcher in_minipip(so binary wheels resolve), and an end-to-end regression test that installs a binary wheel under a private prefix and imports the bundled extension through the regularExtensionFileLoaderpath — proving thenumpyinstall-and-run story works mechanically.RFC 0030ships the pure-Python drop-in surface: a real PyPI-compatiblepip(PEP 440/503/508/425, dependency resolver, PEP 517 sdist builds, full CLI), anumpyfacade with pure-Python fallback soimport numpyworks without compiling_numpylike, a bundledpytest+pluggy+iniconfig+exceptiongroupstack, andsys.settrace/sys.setprofile/sys.monitoring(PEP 669) +tracemallocobservability so debuggers, coverage tools, and profilers boot.RFC 0031closes the observability loop: the VM dispatcher actually fires the registered hooks (call / line / return / yield / exception forsettrace+setprofile; the PEP 669 event table forsys.monitoring;record_allocfrom container- construction opcodes fortracemalloc; PEP 578 audit dispatch at open / compile / exec / eval / import / marshal sites). The same commit lands PEP 684 sub-interpreters (_xxsubinterpreters
- a high-level
interpretersfrontend with cross-interpreter channels), wirespdb/bdbon top of the now-firingsettrace, and grows_pytestto handle@pytest.mark.parametrizeCartesian matrices, indirect fixtures,request.addfinalizerLIFO ordering, and per-scope (function / class / module / session) fixture caching.RFC 0036wires a real CPython 3.13Lib/test/checkout into theregrtestharness (--cpython-dir, crash-isolated--mode subprocess,--jobs) and rewrites the touched rows oftests/regrtest/expectations.tomlfrom guesses to a measured baseline (unexpected 0on a fresh sweep).RFC 0049(wave 5) retires the curated allowlist as a scope mechanism: discovery now schedules every vendoredtest_*.pyfile andtest_*/package (504 labels, up from 227), andexpectations.tomlis a measured whole-suite baseline — 226 of the 427 vendored-CPython labels pass under the sweep budget (plus all 77 bundled fixtures), and every red row carries a measured first-failure reason. The same wave landed theSETUP_ANNOTATIONSopcode (block-entry__annotations__, lazy type/module getsets), CPython-strictbool()/__bool__/__len__semantics,strargument-clinic arity across ~30 native methods, full-mapping-protocolstr.format_map, saturating int shift semantics, code-object value equality (code_richcompare),Py_ReprEnter-style recursive-repr guards on dict views and the io stack (fixing two native stack overflows), a CPython-shapedcodeop, verbatimconfigparser, and the six built-incodecserror-handler callables. Expect small breaking changes around the edges as the long tail catches up.
RFC 0033makes WeavePy introspectable like CPython. It ships a CPython-faithful code-object surface (co_code,co_linetable(PEP 626),co_exceptiontable,co_positions()(PEP 657),co_stacksize,co_qualname,co_lines(),replace(), …) backed by a newcpython_codecodec that re-encodes WeavePy's instruction stream into CPython 3.13's 16-bit_Py_CODEUNITform (EXTENDED_ARG+ inlineCACHEentries). On top of that it lands the four introspection modules every serious tool reaches for —import ast,import dis,import opcode,import symtable— as frozen Python over thin Rust cores (_ast,_symtable), amarshalthat serialises code objects byte-compatibly with CPython 3.13 (TYPE_CODE+FLAG_REFshared refs
- exact 15-bit bigint digits), and real
.pycread/write under__pycache__using CPython'sb"\xf3\r\r\n"magic + PEP 552 header (kept collision-safe by a distinctweavepy-3.13cache tag). Six bundled regrtests cross-check the whole surface against CPython 3.13.
RFC 0054lands the async wave: a native_asyncioC-accelerator (the realFuture/Taskstate machines,current_task/all_tasks, eager task factories, cancellation bookkeeping) that CPython's frozenasyncioadopts via its normal import hook, plus an OpenSSL-shaped_sslover rustls — fullgetpeercert()X.509→dict parsing, SNI servername callbacks via a two-phaserustls::server::Acceptorhandshake, server-side ALPN, session stats, options/verify_flags bitmasks (VERIFY_X509_STRICT, CRL checks), dual RSA/ECC certificate slots, encrypted PKCS#8 keys with password callbacks, per-message handshake callbacks, and TLS 1.3 post-handshake-auth emulation. The vendoredtest_asynciopackage now grades as 31 per-submodule rows — all 31 pass over real loopback sockets, real subprocess transports, and rustls TLS — and the network tail graduates to measuredpassrows:test_ssl(191 tests),test_urllib2,test_poplib, joining the already-green httplib/imaplib/ftplib/smtplib/socketserver family.
RFC 0055is the daily-driver wave: the acceptance bar moves from "passes CPython's tests" to "runs real installed packages". A newecosystemconformance lane (tests/ecosystem/) creates a scratch venv per manifest row with the WeavePy binary under test, installs real PyPI packages through the in-tree pip (online or fully offline via a wheel cache), runs a behaviour-asserting probe, and grades against a checked-in baseline — all nine launch rows pass: six, attrs, click, jinja2, requests, python-dateutil, typing_extensions, packaging, and real pytest (8.4). Getting there landed the mypyc C-API tail (charset_normalizer's compiled.soloads and runs), dependency-closure resolution inpip install --no-index --find-links, the 3.11+importlib.resourcespackage layout (.abc,.readers,NamespaceLoader), int-subclassSystemExitpayloads (sys.exit(pytest.ExitCode.OK)), and site-packages precedence over the bundled third-party facades —pip install packaging(or pytest, numpy, …) now actually changes whatimport packagingreturns. The same wave finished the CLI/REPL residuals (test_cmd_line,test_repl,test_cmd_line_scriptall pass).
RFC 0056is the modern-stack wave: a faithful_sqlite3over rusqlite + verbatimLib/sqlite3, real vendored expat behindpyexpat, the ctypes/mock/warnings residual burns, an abi3/PyO3 surface audit (_abi3check), and an ecosystem matrix grown from 9 to 27 rows — all pass, offline from the wheel cache. Capstone: Django migrates against the new sqlite3 backend, runs ORM CRUD +atomic()rollback, and serves a request throughdjango.test.Client. Net regrtest flips includetest_sqlite3,test_dbm_sqlite3, the XML family (test_pyexpat/test_sax/test_minidom/test_pulldom/test_plistlib/test_xml_etree*),test_htmlparser,test_unittest/test_doctest/test_warnings, andtest_compileall.
RFC 0057is the long-tail wave: the measured whole-suite baseline moves from 418 to 496 of 543Lib/testfiles passing (+78 net flips, zero timeout rows,unexpected 0), with the ecosystem lane still 27/27 offline. The wave lands the comprehension-scope root-cause fix (thetest_listcomps/test_dictcomps/test_setcomps/test_named_expressionsquartet flips), exceptionargsas a real slot, the slot-descriptor error taxonomy,compile()from AST with thePyCF_*flags (test_astresidual: 169F/80E → 1F), frozen module specs +AppleFrameworkLoader(test_import/test_typesnow run end-to-end), a_decimalthat passes the decTest corpus (test_decimalis a measured pass row), pickle protocol 5 with out-of-bandPickleBufferround-trips (test_pickle/test_picklebuffer/test_pickletoolsall pass), CPython-faithful pattern-match codegen + jump threading for trace-event exactness, and the retirement of everytimeoutrow (test_deque/test_mmap/test_weakrefpass under measured budgets). The re-baseline itself caught two engine bugs: a greedy TLS shutdown drain that could eat post-close_notifyplaintext under load (intermittenttest_sslSTARTTLS deadlock), and adatetime_CAPIstand-in shadowing the real capsule (segfaulting any extension doingPyDateTime_IMPORT, e.g. orjson) — both fixed and re-measured.
RFC 0060is the conformance endgame wave: the measured whole-suite baseline moves to 515 of 548 files passing (fail 27, error 0, skip 6, timeout 0,unexpected 0; +14 net flips), and the ecosystem lane grows to 29/29 with two capstones — pandas (binary wheel, real numpy underneath) and FastAPI (pydantic v2 routes throughTestClient). The wave lands the_testcapi/_testinternalcapifixture surface (vectorcall fixture types un-gatetest_call's matrix, dict watchers, rare-event counters, frame probes,normalize_path, and an instruction-sequence assemble stage —test_compiler_assembleruns CPython-3.13 pseudo-op streams through to executable code objects), a Python-constructibletypes.CodeType, the full blake2/sha3/shake constructor surface,sys.orig_argvover the WTF-8 argv bridge, PEP 578 audit-hook blocking semantics, and retires thetest.libregrtestshim for the verbatim package. The capstones caught real engine bugs — aPyType_FromMetaclassNULL-tp_allocsegfault, Cython'sPyType_CheckExactrejecting the_ImmutableTypeMetametaclass (retired for a truthfulPy_TPFLAGS_IMMUTABLETYPE),zoneinforestructured as a real package,str-subclass__slots__, and aCALL_FUNCTION_EXkwargs clone that defeated prompt reaping (anSSLContextleak under asyncio timeouts). Flips includetest_call,test_hashlib,test_re,test_ast,test_builtin,test_frame,test_zoneinfo, and the fixture-gated introspection rows; the honestly-enumerated remainder (thetest_compile/test_peepholercodegen-stage cluster,test_capi's fixture fractal, and the unboxed-value identity legs oftest_marshal) carries measured reasons inexpectations.toml.
RFC 0067(performance wave 5) makes the tier-2 Cranelift JIT the default execution mode:cargo build -p weavepy-clinow ships it,WEAVEPY_JIT=0restores the pure interpreter, and the bench gate measures the shipped configuration. The wave lands native-to-native calls — a compiled callee is entered directly with marshaled scalars (no interpreter frame, no argument binding, no guard re-resolution), with deopt/raise materializing the exact interpreter frame mid-flight — and the native eval breaker: a countdown poll at loop back edges and call sites that hands off the GIL, services signals/finalizers promptly, and revalidates burned-in globals so a cross-thread rebind (the spin-on-a-flag idiom) is observed within one stride. Measured on the committed macOS-aarch64 baseline: suite geomean 3.33× CPython (from wave 4's 8.04×), withfibunder the default JIT 6.2× faster than interpreted (retiring wave 4's JIT call regression) and the loop kernels (sumvm/nested_loops/jitloop) at 0.05× — 20× faster than CPython.
RFC 0068is conformance zero — the final red-row burn: the whole-suite sweep now grades fail 0, error 0, timeout 0, unexpected 0 across all 550 labels (546 pass, the three principled skips —test_embed,test_getpath,test_multiprocessing_fork-on-macOS — and onedivergencerow:test_marshal's two enumerated subtests assert marshal-loaded ints/floats are new objects byid(), unsatisfiable under the unboxed numeric model). The wave lands the codegen-stage surface —_testinternalcapi.compiler_codegen+optimize_cfgover the same flowgraph IR the production compiler emits through (test_compiler_codegen,test_peepholer,test_compile,test_code,test_disflip) — tracing exactness (test_sys_settrace,test_monitoring,test_trace), the importlib machinery burn (CPython's real_bootstrap/_bootstrap_externalfrozen verbatim over the native_imp), real multi-processweavepy -m test -j2workers over the libregrtest JSON protocol (test_regrtestflips), thetest_socketlong tail (sendmsg/recvmsg/SCM_RIGHTS), and PEP 734 sub-interpreters end-to-end (test_interpretersand thetest__interpreters/test__interpchannels/test__interpqueuestrio, C-API-created interpreters included), while the skip-row audit graduatestest_locale/test_pdb/test_socketto measured rows. The re-baseline caught real engine bugs, notably exhaustedFOR_ITERtemporaries skipping finalizers — CPython frees a temporary list's elements by refcount the instant the loop ends, and WeavePy's plain drop leftChannelID.__del__(and any__del__on a loop-consumed temporary) waiting for the next cyclic collection — and the sub-interpreter extension-compatibility ImportError being swallowed by the PyInit blanket retype.
RFC 0069(performance wave 6) attacks the call-shaped remainder and burns the numpy crash census. Tier-2 lands method-call lanes (class-version-guardedrecv.method(args)with a pinned receiver and native method entry), float completion (math.sqrt/sin/cos/fabsintrinsics with CPython's domain errors, float floor-div/mod, cross-block operand values for ternaries), and tier-1 gains call-shape inline caches (exact-positional, defaults, kwnames, bound-method) plus a zero-allocation generator park/unpark that holds the frame in the generator box across yields. Committed baseline: suite geomean 3.16× CPython (3.05× measured on the dev host; from wave 5's 3.33×, 3.60× re-measured pre-wave on the same host), withspectral_norm2.3× faster,richards1.7×,generators1.6×, andcall_overhead1.5× — the boxed-object fixtures (float_math,deltablue) carry to wave 7. The crash burn fixes seven C-API crash classes (C-recursion accounting with stack headroom guards, self-referential list crossing,tp_mro/tp_basicsizepublication for VM subclasses of C types, borrowed instance-pointer pinning, foreignlen()grounding, optional-probe error discipline, container-ownedPySequence_GetItemreferences): all 12 previously-crashingnumpy._coreselftest modules now run zero-crash, withtest_hashtableandtest_protocolspassing outright. The sweep stays at unexpected 0, catching two real WS4 regressions in-wave (generator frame identity acrossawaitfor pdb, and the send dance's line-event discipline forsys.settrace).
RFC 0070(performance wave 7) generalizes tier-2's single pinned receiver into a nullable object lane: any number of object-typed locals and stack values ride pin slots,-1encodes theNonesingleton, andis None/is not Nonefences lower to one integer compare — with object-valued attribute loads and stores (runtime pins, displaced-value prompt-reap discipline) and__slots__attribute lanes on top. Native generator activations (v1) land deopt-shaped: a yield writes the frame back and lets the interpreter execute the suspension (JitStatus::Yielded, never charged to the deopt budget), resumes re-enter natively at the next loop back edge's OSR entry, and a profitability gate admits only generator bodies with a yield-free inner loop — real work between suspensions — so yield-dense pipelines never pay the round trip. Committed baseline: suite geomean 3.11× CPython (3.06× measured on the dev host), withdeltablue1.2× faster andattr_access1.16×; the deferred object-lane consumers (class-call construction, object arguments/returns, iterator pipelines) carry to the next wave.
This is a Cargo workspace organized along the classical interpreter pipeline. Each crate owns one phase of execution and depends only on the phases before it, so implementation work in any layer can proceed mostly in isolation.
weavepy/
├── Cargo.toml # workspace root (shared metadata, deps, lints)
├── rust-toolchain.toml # pinned to stable + rustfmt + clippy
├── rustfmt.toml # formatting rules
├── .cargo/config.toml # workspace cargo aliases
├── crates/
│ ├── weavepy-lexer/ # Python source -> tokens
│ ├── weavepy-parser/ # tokens -> AST (re-exports the AST module)
│ ├── weavepy-compiler/ # AST -> bytecode (CodeObject + opcodes)
│ ├── weavepy-vm/ # bytecode interpreter + object model
│ ├── weavepy/ # umbrella library: public Rust embedding API
│ ├── weavepy-cli/ # the `weavepy` binary, argv-compatible with `python`
│ └── weavepy-conformance/ # CPython-as-oracle harness (dev-only, not on crates.io)
├── conformance/
│ └── corpus/ # in-tree Python fixtures graded against CPython
├── docs/
│ ├── ARCHITECTURE.md # design overview + open questions
│ ├── CONFORMANCE.md # how WeavePy is graded against CPython
│ └── rfcs/ # design documents
└── .github/workflows/ci.yml # fmt + clippy + tests on Linux/macOS/Windows + conformance
WeavePy targets stable Rust. The toolchain is pinned via rust-toolchain.toml,
so a fresh rustup install will pick up the right channel automatically.
# Build everything.
cargo build --workspace
# Run the test suite.
cargo test --workspace
# Lint and format checks (matches CI).
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
# Convenience aliases (defined in .cargo/config.toml).
cargo xtest
cargo xclippyThe CLI binary is named weavepy and aims to be argv-compatible with python.
# Inline source (mirrors `python -c`).
cargo run -p weavepy-cli -- -c "print('hello, weavepy')"
# Run a script file.
cargo run -p weavepy-cli -- path/to/script.py
# Print the version (mirrors `python -V`).
cargo run -p weavepy-cli -- --versionCompatibility is graded automatically. The weavepy-conformance crate
runs the host's python3 as an oracle (tokenize, ast.parse + ast.dump,
compile + dis.dis) and reports per-phase agreement on a corpus of
Python fixtures. CI runs the harness on every PR and uploads the
report as an artifact.
cargo run -p weavepy-conformance -- run # all phases
cargo run -p weavepy-conformance -- diff tokens # one phase
# End-to-end: run CPython's own Lib/test/ files under WeavePy and grade
# against the measured baseline (RFC 0036).
cargo run -p weavepy-conformance -- regrtest \
--cpython-dir vendor/cpython/Lib/test --mode subprocess --jobs 8
# Ecosystem lane: venv + pip install + probe per real PyPI package,
# graded against tests/ecosystem/expectations.toml (RFC 0055).
cargo run -p weavepy-conformance -- ecosystem # online
python3 tools/ecosystem_fetch.py --dest target/ecosystem-wheels
cargo run -p weavepy-conformance -- ecosystem \
--wheels target/ecosystem-wheels # offlineSee docs/CONFORMANCE.md for the model, the
corpus layout, and the now-live CPython regrtest-style runner (RFC
0034 built it; RFC 0036 wired a real CPython 3.13 checkout into the CLI).
- Compatibility first. CPython's behavior — including dark corners, PEP 8 grammar minutiae, and the reference C-API — is the spec. The CPython test suite is the acceptance harness. Performance work that breaks compatibility is rejected.
- Performance second, but seriously. Once a feature is correct, the
architecture should make it fast: tiered execution, inline caches,
specialization, and — since RFC 0067 — a Cranelift-backed tier-2 JIT
that ships on by default (
WEAVEPY_JIT=0opts out at runtime). - Modern, safe foundation. Written in safe Rust where possible, with
unsafeconfined to small, well-audited boundaries (object header layout, FFI to native extensions, etc.). - Embeddable. The
weavepycrate is a library first; theweavepyCLI is just one consumer.
See CONTRIBUTING.md for development setup, coding
standards, and how to propose larger changes via the RFC process in
docs/rfcs/.
WeavePy is dual-licensed under either of:
- Apache License, Version 2.0 (
LICENSE-APACHE) - MIT License (
LICENSE-MIT)
at your option. This matches the rest of the Rust ecosystem, so contributions to and from common Rust crates remain straightforward.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in WeavePy by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.