Pyodide 314.0: Python packages can now publish WebAssembly wheels to PyPI
Posted by agriyakhetarpal 7 days ago
Comments
Comment by simonw 3 days ago
This means we can now take any C/Rust/whatever extension for Python, compile that as a `.wasm` extension, and then load it directly in browser Pyodide projects using:
await micropip.install("package-on-pypi")
import package_name
Here's how to try the new feature out. Visit https://pyodide.org/en/stable/console.html and type: import micropip
await micropip.install("pydantic_core")
import pydantic_core
That gets you this WASM wheel: https://pypi.org/project/pydantic_core/#pydantic_core-2.47.0...You can tell that it's got compiled code in (and not just Python) by running:
pydantic_core._pydantic_core
I get this: <module 'pydantic_core._pydantic_core' from '/lib/python3.14/site-packages/pydantic_core/_pydantic_core.cpython-314-wasm32-emscripten.so'>Comment by simonw 3 days ago
Here's the package: https://pypi.org/project/luau-wasm/
import micropip
await micropip.install("luau-wasm")
import luau_wasm
print(luau_wasm.execute(r'''
local animals = {"fox", "owl", "frog", "rabbit"}
table.sort(animals, function(a, b) return #a < #b end)
for i, name in animals do print(i .. ". " .. name .. " (" .. #name .. ")") end
'''))
And an interactive demo page where you can try it out: https://simonw.github.io/luau-wasm/Wrote about this in more detail on my blog: https://simonwillison.net/2026/Jun/13/publishing-wasm-wheels...
Comment by westurner 2 days ago
From https://news.ycombinator.com/item?id=43201706 :
> jupyterlite-xeus supports environment.yml with jupyterlite with packages from emscripten-forge: https://jupyterlite-xeus.readthedocs.io/en/latest/environmen...
emscripten-forge was a Quetz repo built with but is now hosted on prefix.dev.
From https://emscripten-forge.org/blog/ :
pixi run setup
pixi run build-emscripten-wasm32-pkg recipes/recipes_emscripten/regex
Pixi doesn't yet support building wheels though, just conda recipes.Does cibuildwheel already have this new support for building WASM pyodide packages?
Does jupyterlite's `micropip install` install these new WASM packages from PyPI?
Comment by rtpg 3 days ago
Tbh I don't feel great about people just writing up a bunch of scripts pulling things just on every run.
Comment by simonw 3 days ago
Comment by willXare 3 days ago
Comment by 12_throw_away 3 days ago
Comment by apitman 3 days ago
Comment by hoodchatham 3 days ago
Comment by rvz 3 days ago
Something as little as the runtime can just get exploited (which that as happened.) and cause a sandbox escape on the client side. There was a Chrome 0day at the runtime level which allowed untrusted code to run and escape the sandbox in the WASM runtime.
This complete worship of WASM (and their runtimes) as this magical silver bullet reminds me of the days and failures of Native Client (NaCL), Java Applets and Flash all over again.
Comment by simonw 3 days ago
I dunno, one sandbox escape in nine years is a pretty solid track record IMO.
Any reason WASM is more dangerous than regular JavaScript?
Comment by rvz 3 days ago
Even before that, there are several other sandbox escapes that predated the one you posted. [1] [2] and this one [3] can be used to trivially escape its sandbox with either of these vulnerabilities.
So it is not the magical silver bullet one may easily think it is.
[0] https://nvd.nist.gov/vuln/detail/CVE-2026-11645
[1] https://blog.ret2.io/2021/06/02/pwn2own-2021-jsc-exploit/
Comment by nextaccountic 3 days ago
Sandbox escapes could happen in Javascript too, right? But I don't see people avoiding browsing the web because of that
Comment by shevy-java 3 days ago
Comment by willXare 3 days ago
Comment by njoyablpnting 3 days ago
They haven't made anything too crazy, but performance is surprisingly good, even wiring in Pymunk for some physics stuff. If they get to the point where it's ever an issue they probably know enough to be working in a real game engine anyway.
Comment by IshKebab 3 days ago
Comment by zek 3 days ago
Comment by posborne 3 days ago
[1] https://github.com/bytecodealliance/componentize-py [2] https://peps.python.org/pep-0816/
Comment by zek 3 days ago
Comment by tancop 3 days ago
Comment by DarkUranium 3 days ago
It feels like nobody actually consulted actual compiler writers when designing this. I'm sure that isn't true, but it definitely feels that way. (I suspect the truth is that they were consulted, but ignored.)
It means codegen needs to resort to all sorts of hacks (like the relooper) in order to target WASM, a property not shared by any other target.
And apparently, the way they handle variables also results in deoptimization, though I don't recall the details of that.
Add the fact that interacting with the browser on the web still has to go via JavaScript to this day (for the most part, at least), and, well.
---
TL;DR a combination of poor IR design that has a massive impedance mismatch with pre-existing compilers (and most new ones, because it turns out there's a reason the WASM approach isn't standard) plus WASM still being a second-class citizen in its supposed primary environment (the 'W' in WASM) --- the former ensures targeting it consumes a lot of resources/time, the latter ensures the bar for that to be worth it is much higher.
You can target most architectures with little trouble (at least a a baseline --- optimization's a hard problem regardless of target, except maybe SPIR-V due to the recommendation that pre-optimization is limited in scope). But WASM is completely out there, it's closer to trying to target e.g. Java (not JVM!) at the backend instead of machine code or some other IR.
You don't make an IR intended to be targeted by existing/native compilers by making it completely different to anything they had to target before and completely different to their own IRs and representations ... unless you're the guys behind WASM.
Comment by ameliaquining 3 days ago
Most low-level IRs don't do structured control flow because most low-level IRs don't need to be translatable to verified-safe machine code in a single fast pass, whereas for WebAssembly that's a core design requirement.
Comment by csande17 3 days ago
The author alleges that the real reason WebAssembly uses loop/block is because that's how V8 worked internally at the time and Google didn't want to go to the trouble of implementing something different. But more recently V8 has started moving towards CFGs ( https://v8.dev/blog/leaving-the-sea-of-nodes ) so maybe there's hope in the future.
Comment by ameliaquining 2 days ago
More to the point, none of this has anything to do with ABI.
Comment by hmry 3 days ago
So the choice was made to put the burden of regularizing the control flow on the compilers at compile time, rather than the browser engine at website load time. Which seems rational to me.
Comment by wolfgangK 3 days ago
Comment by simonw 3 days ago
Comment by fzumstein 3 days ago
Comment by shevy-java 3 days ago
Now Python's versioning scheme is officially worse than PHP's or Perl's. Not just skipping one version here - they are skipping 314 versions!
Comment by foresterre 2 days ago
It tried amonst others to improve isolation and long compile times in a fairly foundational Rust library which can be found in many dependency trees. I found it a cool proof of concept at the time.
Having a WebAssembly binary embedded in a library was relatively unpopular in the Rust community (3). serde_derive 1.0.184 restored the uncompiled source version, but the release notes mention they hope that crates.io (Rust equivalent of PyPi) will add WebAssembly support in the future.
One of the reasons why this wasn't very popular was that WebAssembly is much harder to inspect than Rust source code (4).
I'm not a PyPi expert. The PEP itself seems to permit adding WebAssembly to a wheel (a python package). The PEP literally mentions "There are no security implications in this PEP" (security for whom?). In 2022 the supply chain attack surface was notably smaller since powerful enough LLM's didn't exist yet, yet it was for many a concern to include WebAssembly to package s in another ecosystem back then.
I do think other forms of binaries were already permitted, such as precompiled C/C++ libraries, so if that's true, then this is indeed relatively not that big of a security concern, but _no_ security implications seems to be a bit much.
I do see the added advantage to reduce friction of loading pre-compiled webassembly from PyPi directly instead of going through alternative packaging registries though.
(1) https://crates.io/crates/watt
(2) https://github.com/serde-rs/serde/commit/1afae183b06ffe47d05...
(3) https://github.com/serde-rs/serde/issues/2538
(4) https://old.reddit.com/r/rust/comments/15wx2xe/precompiled_b...
Comment by hoodchatham 2 days ago
Comment by efromvt 3 days ago
Comment by runningmike 3 days ago
Comment by sgammon 3 days ago
Comment by willXare 3 days ago
Comment by IshKebab 3 days ago
Comment by sspoisk 3 days ago
Comment by agrijakhetarpal 3 days ago