PEP 783: Emscripten Packaging

Well wheels tagged as linux cannot be uploaded to pypyi for precisely the reason that it’s vague. Instead, they need to be tagged manylinux which is a separate standard with an explicit definition. I think we need something analogous here.

1 Like

manyemscripten doesn’t really sound right, if it’s really a problem to use pyodide maybe stdemscripten or commonenscripten or pyemscripten?

2 Likes

many-emscripten looks good to me. (We could get inventive with a condensed version of that word if we think it does not sound right).

I think many-emscripten isn’t great because it actually only works for one emscripten not many. If we can’t name it pyodide then I think pyemscripten would be okay.

that’s a good point. happy with pyemscripten.

1 Like

Sorry for the delay in all of this, I’ve had a busy couple of months and I’ve just gotten around to taking a look at this.

On the tin, I don’t see anything particularly problematic with adding a platform tag for emscripten, so I expect I’ll end up accepting it (or something close to it), but I have a few questions.

The last few messages on this thread are questions about what the actual name is going to be, are we still expecting it to be pyodide_${PYTHON_MAJOR_MINOR}_${PATCH}_wasm32 or are we expecting it to be something like pyemscripten or something?

The biggest sticking point to me is that I’m not sure that pyodide is a platform? I’ve been doing a fair amount of reading to try and disambiguate, but let me just make sure my understanding is correct.

  • wasm is a basically just like regular assembly, except that instead of your CPU running it “directly” [1], you have a virtual machine running on top of a host machine that executes the ISA instead, allowing it to be portable [2]. This also has the interesting property that all access to interesting things is required to be mediated through some sort of host process, so that sandboxing is built in by default.
  • emscripten is a compiler that can turn C/C++ code into wasm that specifically is targeting the browser (although you can run it locally too inside of node), but what makes them interesting here in terms of platform tags is that they’ve had to make a lot of decisions on how to expose certain things like filesystems, etc that means they’re also kind of like an OS in the traditional sense.
  • wasi is basically another option for “platform” that a wasm program can target, where it’s a defined set of APIs that a runtime has to provide, and then there are a number of runtimes that provide those (and sometimes extra things on top). This is like wasmtime, wasmer, etc.
  • pyodide is a Python interpreter that is intended to target the wasm virtual machine on top of the runtime provided by emscripten.

Is that all correct?

Where I’m getting stuck is that it feels like the platform tag as specified is mixing together multiple distinct pieces of compatibility. The tag is pyodide_${PYTHON_MAJOR_MINOR}_${PATCH}_wasm32, but none of our other platform tags include the Python major version in them, or really anything about the Python version at all.

Wheels have 3 parts of the filename that makes up the entire compatibility tag:

  • Python Version
  • Python ABI
  • Platform Tag

The Python Version and Python ABI are intended for Python to declare compatibility with a particular Python, while the platform tag is intended to declare compatibility with the system that Python is running on.

One thing that may not be obvious is that the Python Version / Python ABI isn’t tied to CPython, and different interpreters can have their own values there. For the Python Version, the pyN value is a special case that says the wheel is compatible with any Python interpreter that supports Python N, but CPython has cpXY that says its only compatible with CPython X.Y, and not another interpreter.

PEP 425 gives these examples for the Python interpreter tag:

The Python tag indicates the implementation and version required by a distribution. Major implementations have abbreviated codes, initially:

  • py: Generic Python (does not require implementation-specific features)

  • cp: CPython

  • ip: IronPython

  • pp: PyPy

  • jy: Jython

Other Python implementations should use sys.implementation.name.

Likewise the ABI isn’t specific to CPython, it lets individual implementations define their own ABI using a similarly, for cases where the ABI may differ based on compiler flags or what have you. This also has interpreter specific meaning and we see things like cp314t here. The abi3 is a special case, that probably should have been cp3 or something, because abi3 is also specific to CPython, it just didn’t match the existing rules.

Reading through some of the earlier examples, the wheel filenames you’re using just seem wrong to me?

You mentioned an example like this cryptography-44.0.2-cp37-abi3-pyodide_2025_0_wasm32.whl, but that wheel shouldn’t be installed on Pyodide at all as far as Wheel’s compatibility tags go, because it’s specifically targeting CPython version 3.7 (cp37 ) with CPython’s abi3 ABI (there’s a special case for the cpXY tags paired with abi3 that makes them >= instead of ==.

My naive (as far as emscripten / wasm goes) expectation is that a wheel targeting pyodide would have a filename that looks something like cryptography-44.0.2-po029-2025_0-wasm32_emscripten.whl.

That feels like it fits into how these tags work everywhere else better? Platform tags are independent of the Python running, if I made my own Python interpreter that was targeting wasm+emscripten, but I used a different version of Python than pyodide, say I’m old school and I decide to build a retro Python 2.7 for Emscripten, what would it mean for my Python to be runnable on pyodide_2025_0_wasm32?

What if you get subprocess working and I ship a subprocess that isn’t related to, or linked against, Python at all. In the current system I could ship that in a py3-none-manylinuxwhatever wheel because it’s not linked against Python so the details of the Python interpreter don’t matter, just the system that it’s running on.

If you look at the various manylinux PEP, what they provide over the generic x86_64_linux tag has nothing to do with the Python version and almost nothing to do with the compiler or compiler flags, and it’s basically entirely about what capabilities you’re allowed to assume the system has (via the shared libraries you’re allowed to link against).

There’s actually nothing conceptually wrong with the generic linux tag, it just would mean that your wheel can’t assume anything about the platform other than “linux”, so no dynamic linking against anything. We only really disallowed it because that wasn’t practical and it was built “by default” so the likelihood is that all of the wheels uploaded using that tag were going to be dynamic linking to random things and be broken.

My understanding is the capabilities of the platform is tied to what emscripten supports, not what Pyodide supports, so it feels like the platform tag here should be focused on Emscripten (it’s not clear to me if it needs to be versioned like Manylinux or macOS is or whether it can be unversioned like windows is). It sounds like maybe versioning might be useful as the PEP talks about how emscripten is constantly adding new features?

Most of the docs on the Pyodide ABI tag feels like it should just be part of the Pyodide interpreter tag and interpreter ABI (and by default it’s going to get a tag based on sys.implementation.name , so a PEP adding support for a short name seems reasonable to me if needed or wanted).

It’s not clear to me whether stuff like stack unwinding and such are things that belong in the definition of an “emscripten” platform or whether those are part of pyodide, but I’m happy either way.

Anyways, I’m not opposed (and I’m generally for) adding a tag for emscripten, the tl;dr of what I’d like to understand/see before making a decision here:

  1. I’d like the naming thread resolved, either by the PEP authors saying they don’t want to change the name or by coming to an agreement on what the name should be and updating the PEP.
  2. The PEP appears to be inconsistent with itself, it says the platform tag is pyodide_${PYTHON_MAJOR_MINOR}_${PATCH}_wasm32, but then the Python code (and this thread) seems to suggest that the platforms ag will be something like pyodide_2025_0_wasm32, so the PEP needs to be fixed to be self consistent with what is actually being proposed.
  3. I’d like to either understand (and include it in the PEP) why this platform tag needs to be different than the rest and include stuff that is specific to a given Python interpreter in it OR I’d like the platform tag limited to just be about emscripten itself and have the Pyodide specific ABI stuff get moved into the Python Tag and Python ABI.

Hopefully that all makes sense?


  1. To the extent ASM is run directly, and not by a vendor specific microcode :wink: ↩︎

  2. I guess some compilers let you compile it down to native code still though? ↩︎

3 Likes

Correct: Wasm is a virtual ISA. And your question in your footnote is also correct: Wasm can be compiled to native code (and it was actually designed to make that happen fast).

That’s a reasonable summary.

Correct, and my next WASI-related PEP will be defining a platform tag for WASI, so heads-up. :wink:

My guess is @hoodmane would call Emscripten more like a Python platform since it includes stuff like tooling around building projects on top of providing a Python interpreter.

pyodide is a third-party build of CPython, it’s not another interpreter. AFAIU that explains things like cryptography-44.0.2-cp37-abi3-pyodide_2025_0_wasm32.whl.

Thanks for the response @dstufft!

emscripten is a compiler that can turn C/C++ code into wasm that specifically is targeting the browser … they’ve had to make a lot of decisions on how to expose certain things like filesystems, etc that means they’re also kind of like an OS in the traditional sense

Yes, Emscripten is a compiler, operating system, and collection of system libraries for running C/C++ code in JavaScript runtimes. But it’s not just one ABI/operating system it is a bunch of them depending on a bunch of linker “settings” flags. They also provide no guarantees of ABI compatibility between Emscripten patch releases so in principle Emscripten 5.0.1 is a completely unrelated platform from Emscripten 5.0.2.

So emscripten is comparable in some ways to the linux tag. But unlike the manylinux situation, the different ABIs are not forwards compatible, so a program compiled to target an old one will not work with a new one or even with the same version but with different ABI-sensitive flags. Thus, there is no possibility of manyemscripten.

pyodide is a Python interpreter that is intended to target the wasm virtual machine on top of the runtime provided by emscripten.

pyodide consists of the following components:

  1. CPython with a few patches (on the order of 45 lines of diff)
  2. A JS/Python ffi like ctypes for JS runtimes (upstreaming this is the subject of pep 818)
  3. A choice of Emscripten version + ABI-sensitive flags + static libraries to link
  4. A toolchain for cross compiling and testing packages for this platform

So in some sense it is a Python interpreter but it is not a distinct intepreter from CPython.

The tag is pyodide_{PYTHON_MAJOR_MINOR}_{PATCH}_wasm32, but none of our other platform tags include the Python major version in them, or really anything about the Python version at all.

Until last week I had pyodide_{YEAR}_{PATCH}_wasm32 as the platform tag. I’m thinking we should switch back to using the year since it is a bit confusing to use the Python version. The platform is component 3 above. Since Emscripten is not a well-defined platform, someone has to choose a specific Emscripten. Whether we call it pyodide or pyemscripten I don’t care. We have the following two constraints:

  • We want to benefit from improvements in functionality, code size, and performance that come with newer Emscripten versions and newer ABIs.

  • We want to avoid a combinatorial explosion of wheels.

So the idea is that we pick one platform per Python version. So it’s possible to build Python 3.13 or indeed a completely unrelated C program with the pyodide_2026_0 platform (or whatever we decide to call it). We’ve just decided by convention to use it with Python 3.14.

This makes abi3 wheels no better than dedicated wheels because the cp37-abi3-pyodide_2026_0 wheel works with Python interpreters >= 3.7 built for the pyodide_2026_0 platform but we’re only ever planning to build Python 3.14 for the pyodide_2026_0 platform. But there is nothing stopping anyone from building other Python interpreters for that platform.

cryptography-44.0.2-po029-2025_0-wasm32_emscripten.whl

Well:

  1. Pyodide is CPython so we should use cp for the interpreter tag. There are minor differences but our goal is to make them go away in the next few years. In particular, sys.implementation.name in Pyodide is cpython.
  2. 2025_0-wasm32_emscripten seems a bit too vague. How do we know where to go for the platform definition? It’s not defined by Emscripten. I like either pyodide or pyemscripten in the platform better. I suppose we could say that our platform is 2025_0-wasm32_emscripten but it seems to me that some other ecosystem could define a conflicting notion of what that means.

say I decide to build a retro Python 2.7 for Emscripten, what would it mean for my Python to be runnable on pyodide_2025_0_wasm32?

It’s documented here: Pyodide Platform ABI

My understanding is the capabilities of the platform is tied to what emscripten supports, not what Pyodide supports, so it feels like the platform tag here should be focused on Emscripten (it’s not clear to me if it needs to be versioned like Manylinux or macOS is or whether it can be unversioned like windows is).

This is right. We can’t call it manyemscripten since it won’t even work with all binaries compiled and linked with Emscripten 5.0.1, only those that also pass specific additional flags. I think pyemscripten works well with this. But we can’t just use the Emscripten version since as I said 5.0.1 is too vague. Either the year or the Python version could go here but I think the year is better since the Python version is conceptually confusing.

Most of the docs on the Pyodide ABI tag feels like it should just be part of the Pyodide interpreter tag and interpreter ABI

Did you look here? None of that is related to Python at all.

tl;dr

1. I’ll go ahead and change it to pyemscripten.

2. I was using the year until a couple of weeks ago when @thomas suggested switching to the Python version. But from what you said it seems that using the Python version is more confusing than helpful so I’m thinking we should go back to the year.

3. Explained above.

I’d like the platform tag limited to just be about emscripten itself

In the ideal case Emscripten would solve this for us by providing periodic named ABIs that everyone could standardize on. Or at least tell us when they break ABI. I know several other ecosystems like the Godot game engine that are having exactly the same problem as us. (Also, Rust is quite troublesome since they are only willing to support one stable Emscripten platform. Luckily, I am the maintainer of the Rust Emscripten target so I can keep us in sync.)

Since Emscripten has not shown interest thus far in solving this problem for the ecosystem, we have to do it ourselves one way or another. The plan of one platform per Python minor version allows us to gradually bring in improvements while also still being a stable enough platform that people can target.

It feels to me that modulo bikeshedding the platform name we are basically forced into this solution because of Emscripten’s posture.

I will add more detail about this situation to the pep.

Opened PEP 783: pyemscripten_YEAR_PATCH as platform tag, more rejected ideas & context by hoodmane · Pull Request #4841 · python/peps · GitHub updating the PEP based on the discussion here.

This sounds like a very practical solution to a difficult issue, but it feels to me like it would be less confusing if the tags were designed in a way that wasn’t tied to that approach. Not because we’re expecting to need that flexibility, but simply because no other platform has that constraint, so by avoiding it, we ensure that people new to emscripten packaging don’t have to re-learn their assumptions to understand how emscripten tags work.

I’m still struggling to understand what emscripten is, in terms that relate to other platforms. If emscripten is a compiler, then it shouldn’t matter in tag terms (just like Windows tags don’t care whether the compiler was MSVC or something else). It sounds more like it’s a platform like “Win32”, but with each version being (in effect) a completely new platform. In that case, the platform tag should be something like emscripten_5_0_1. You say that’s “too vague”, but I couldn’t find an explanation of why that’s so - could you repost the reason, please?

If pyodide is essentially a build of CPython that runs on a particular emscripten version, then I feel that it should not need to be reflected in the tags - a tag set of cp*-*-emscripten* implicitly states that the wheel is for pyodide, because that’s the only implementation of CPython on emscripten. So there’s no need to repeat that information.

Sorry if I’m asking dumb questions here. One reason I think it matters is that at least part of the point of having emscripten packaging standards is to make it easier for people to build wheels for emscripten/pyodide, and that means that we’ll have an influx of people building emscripten wheels who have less expertise than is currently needed to do so. Making things more understandable for such people is crucial to making that a success. IMO it’s telling that the PEP currently has nothing in the “How to Teach This” section beyond pointers to the existing pyodide documentation. I think that the section should cover more than that - how do people who are not interested in building packages on pyodide, but just want to know “is this wheel here compatible with the version of pyodide I’m running in my webapp” by looking at the tags, going to get that information, for example?

2 Likes

I’m not sure how that would be possible.

I’m still struggling to understand what emscripten is

I think a large aspect of what’s confusing here is that Emscripten applications are analogous to freestanding bare metal programs. When Emscripten produces the application, it will inject an entire operating system into it. As a result of this, there are flags that change the system libraries or the ABI that wouldn’t make sense if the target were something like Windows since the system libraries are part of the operating system and changing the ABI would just break your program.

You say that’s “too vague”, but I couldn’t find an explanation of why that’s so - could you repost the reason, please?

The reason is that there are flags like -sWASM_BIGINT or -fwasm-exceptions that change the ABI. Also, there are a number of libraries that must be statically linked due to platform limitations and which versions of which libraries are present also affects what dynamic libraries work. We could of course call it emscripten_5_0_1_wasm32 and leave these choices implicit, but I think it is easier to understand if the platform reflects that there are additional choices to be made.

the point of having emscripten packaging standards is to make it easier for people to build wheels for emscripten/pyodide, and that means that we’ll have an influx of people building emscripten wheels who have less expertise than is currently needed to do so

Well my hope is that people will use cibuildwheel or pyodide-build to build Emscripten wheels. Of course there are a lot of different problems that come up when building these things but honestly we don’t have general solutions for a lot of these problems. The best tips I have are in those Pyodide docs. As far as building wheels directly without the tooling we’ve built, in the case of Rust extensions it is quite easy. If it’s a C/C++ extension built with setuptools, it’s quite complicated. @freakboy3742 and @mhsmith and I have talked about trying to improve the situation around cross-builds but it is a long term project.

it’s telling that the PEP currently has nothing in the “How to Teach This” section beyond pointers to the existing pyodide documentation

I’m happy to expand that, but it’s worth noting that my reference in writing this was the manylinux peps and as far as I can tell none of them even have a “How to Teach This” section.

how do people who […] just want to know “is this wheel here compatible with the version of pyodide I’m running in my webapp” by looking at the tags, going to get that information, for example?

We will put a table in the Pyodide docs.

Thanks, this is actually super helpful to understand the pieces, with this context I agree that considering the interpreter part of Pyodide to be “just” CPython makes sense.

This also makes sense to me. I mostly agree that (3) is the “platform” (more on that in a minute).

I think a year makes a lot more sense than Python version, entirely because platform tags are wholly independent of Python (e.g. it’s possible to ship a single file rust binary with 0 ties to a specific Python version) and the question of which platforms any individual project (including CPython, with or without the Pyodide patches) supports is up to them.

In other words, it shouldn’t be confusing for someone to make their own Python interpreter that targets emscripten that targets a different version of Python than the one CPython/Pyodide is supporting on the emscripten platform (but they would obviously use something different than cpXY for their interpreter tag, unless they’re also just a Pyodide style build that happens to target a different version).

Using a year means that the fact that Pyodide only supports a given CPython version for a given version of the platform is an implementation of Pyodide, not of the platform, which I think is a cleaner separation of concerns.

Using the emscripten version like @pf_moore suggested also seems like it might be a reasonable choice? Instead of maintaining a mapping of “Year Based ABI to emscripten version”, you’d just maintain a mapping of what emscripten versions a given pyodide supported. The risk I suppose is proliferation of platform targets where people build against the “wrong” emscripten and their wheel can’t be installed, but I feel like that can happen with the year based ABI too, but at least the emscripten version tag makes it more obvious what they actually built against?

I don’t feel super strongly about that though, I think a year based versus a version based is just different sets of trade offs.

Yea, I don’t think whether they’re forwards or backwards compatible or not affects much other than the question of whether the platform needs to be versioned, and if so how do we version it. Windows isn’t versioned because they’re (afaik) very good about ABI compatibility, macOS is versioned because they’re less good about it.

The bare linux tag is actually pretty close to emscripten I think, in that you can’t assume anything about the ABI compatibility of any given system. The manylinux tag was able to find a common set of libraries that did maintain good forward compatibility so it’s versioning scheme was able to be forwards compatible, but it sounds like emscripten is not, so versioning sounds required, and that version has to be == not >=, so that’s fine.

Perfect, this matches my intuition of what this “should” be as well now that I understand better :slight_smile:

I think where I got confused was things under the “General” section felt to be more about decisions pyodide itself made than questions about the platform (particularly things about what libraries are linked into the interpreter).

I understand better now what I’m looking at now so I think I’d soften my original message, but I do think that the documentation for the platform feels somewhat entangled with Pyodide. Ideally the definition of a platform should be completely distinct from the interpreter (even CPython itself, none of our existing platforms care at all about anything about CPython).

I think it’s natural that it’s currently documented as entangled with pyodide given it’s something that pyodide is documenting about itself currently.

From what I can tell, currently the actual definition of the platform itself (not of Pyodide/CPython’s build on top of that) is basically mapping an identifier (YEAR_N) to:

  • A specific version of Emscripten.
  • The compiler flag -sWASM_BIGINT.
    • This appears to be a default under newer versions of Emscripten?
  • The requirement to not use the compiler flag -pthread.
  • Maybe the compiler flag -fexceptions?
    • I’m not actually sure if that’s a required flag for the ABI or if that’s just documenting that if you want to use those things you have to pass that flag?
    • It appears like this isn’t needed anymore and some WASM native thing is used now? Or it was blocked on Rust support?
  • The patch to the dynamic loader so that /lib/python3.12/site-packages/{wheel_name}.libs is added to the library load path to mimic RPATH support.
    • Oh, this appears to only be required on older versions of Emscripten, and it appears that newer versions natively supports RPATH? Or maybe both is required now? I’m not sure from reading it.
  • Some stuff about what compiler flags you have to pass to rust to not get linker errors when building?
    • This doesn’t feel like it’s part of the platform tbh, this just feels like it’s part of a guide on how to get rust to actually build for this platform?

Everything else seems to be either describing how to build or talking about Pyodide specific choices?

I think the platform defining a specific version of emscripten is pretty uncontroversial and an obvious requirement (whether that’s done by mapping a YEAR_N to emscripten version, or whether the platform tag is just emscripten_5_0_1 either one works I think, just different trade offs).

I know I’ve been poking at the compiler flag portions (both here and in discord) and I don’t want to keep going over it in circles, but I’ve been reading and trying to understand a bit more, and I do have one more question on them.

I know that you don’t currently have subprocess support, but assuming that you add it, would I be able to do something like subprocess.run([“foo”]), where foo is an binary compiled by the same emscripten version but isn’t a Python tool, it’s just some random C thing, that used a different set of flags?

My intuition (which is entirely based on “regular” platforms, not WASM based ones) is that ABI issues are typically entirely around dynamic linking into the same process, and subprocess.run() is spawning a new, distinct, process, and thus the ABI between them does not matter. However I have no idea if emscripten breaks that where even the process boundary is no longer a true boundary?

I don’t want to keep going over it in circles

So far seems like this discussion feels quite productive to me, doesn’t hurt to go over the details a few times until we reach convergence. In particular, I will try to improve our ABI docs based on your feedback.

I think a year makes a lot more sense than Python version

+1

Using the emscripten version like @pf_moore suggested also seems like it might be a reasonable choice?

I think the year is better for a practical reason that the we want to add an “ABI patch” version. It’s easier to say 2025_0 than 5_0_2_0. Since the Emscripten version has three digits already, and it’s a little unclear which part is our ABI version and which part is the Emscripten version. Since it’s more details than the Emscripten version, you’ll have to look up in a table what it is anyways so I think like using the Python version, using the Emscripten version introduces more potential confusion compared to just a year.

The bare linux tag is actually pretty close to emscripten I think

Agreed.

particularly things about what libraries are linked into the interpreter

This could use further clarification: these libraries are not used for anything in the core interpreter. They are a collection of libraries that can only be linked statically due to platform limitations and that we link because they are required for one or more packages. In this sense I view this as pretty directly comparable to the list of system dynamic libraries that can be linked against in PEP 559: peps/peps/pep-0599.rst at main · python/peps · GitHub. And whereas PEP 600 removed this list because Python specs have no actual control over Linux platforms, we do have direct control over this. Of course if it were possible to dynamically link these then we’d take the approach of vendoring them into the wheels that need them.

Anyways, this is necessary information for figuring out whether some package can or cannot work, so IMO this means it is part of the platform from a packaging perspective.

-sWASM_BIGINT … This appears to be a default under newer versions of Emscripten?

Yes.

Maybe the compiler flag -fexceptions?

  • I’m not actually sure if that’s a required flag for the ABI or if that’s just documenting that if you want to use those things you have to pass that flag?

  • It appears like this isn’t needed anymore and some WASM native thing is used now? Or it was blocked on Rust support?

We’re using -fwasm-exceptions now since Rust now fully supports it. There are three distinct unwinding ABIs. If the shared library does not use unwinding at all, it will work without any unwinding flag. If it does use unwinding it has to use the right unwinding ABI. The main interpreter application does not use unwinding except in a couple of places needed to support shared library unwinding use.

and it appears that newer versions natively supports RPATH? Or maybe both is required now?

Newer versions since Emscripten 4.0.9 used with 3.13 natively support RPATH.

compiler flags you have to pass to rust …

This doesn’t feel like it’s part of the platform tbh, this just feels like it’s part of a guide on how to get rust to actually build for this platform?

Yes that is correct. Probably we should add a more clearly delineated boundary between how to build and what the platform is. It’s a bit muddied for the Emscripten compiler and linker itself since it is both shorter and more useful to document how they should be used rather than the technical details of what the binary needs to look like. But then we really end up giving emscripten build instructions. From there to also giving Rust build instructions doesn’t seem like a crazy step to me. shrug

Everything else seems to be either describing how to build or talking about Pyodide specific choices?

I’m not sure what you mean by Pyodide-specific choices but there is a lot about how to build.

would I be able to do something like subprocess.run([“foo”]), where foo is an binary compiled by the same emscripten version but isn’t a Python tool, it’s just some random C thing, that used a different set of flags?

Emscripten has no notion of processes nor any concept of an “executable” that lives at a file path. I don’t ever expect subprocess.run() to work in web browsers because it is not clear to me what it could possibly mean or usefully do there. However, in our node python executable, ideally we could make subprocesses run native processes. But then you’d run native executables because those are things that actually live in your file system.

This would be useful for testing but not for much else. It’s niche enough and hypothetical enough that I don’t think it’s worth trying to come up with a way to tag “Emscripten wheel that includes a linux binary used as a subprocess”. If people make Emscripten Python testing utilities like this, they don’t need to be distributed as wheels.