Add Pyodide support (#12731)

This includes some initial work on adding Pyodide support (issue
#12729). It is enough to get
```
uv pip compile -p /path/to/pyodide --extra-index-url file:/path/to/simple-index
```
to work which should already be quite useful.

## Test Plan

* added a unit test for `pyodide_platform`
* integration tested manually with:
```
cargo run pip install \
-p /home/rchatham/Documents/programming/tmp/pyodide-venv-test/.pyodide-xbuildenv-0.29.3/0.27.4/xbuildenv/pyodide-root/dist/python \
--extra-index-url file:/home/rchatham/Documents/programming/tmp/pyodide-venv-test/.pyodide-xbuildenv-0.29.3/0.27.4/xbuildenv/pyodide-root/package_index \
--index-strategy unsafe-best-match --target blah --no-build \
numpy pydantic
```

---------

Co-authored-by: konsti <konstin@mailbox.org>
Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Hood Chatham 2025-06-03 10:01:26 -07:00 committed by GitHub
parent 37e22e4da6
commit f9d3f24728
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 168 additions and 2 deletions

View file

@ -1294,6 +1294,45 @@ jobs:
run: | run: |
.\uv.exe pip install anyio .\uv.exe pip install anyio
integration-test-pyodide-linux:
timeout-minutes: 10
needs: build-binary-linux-libc
name: "integration test | pyodide on ubuntu"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: "Download binary"
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: uv-linux-libc-${{ github.sha }}
- name: "Prepare binary"
run: chmod +x ./uv
- name: "Create a native virtual environment"
run: |
./uv venv venv-native -p 3.12
# We use features added in 0.30.3 but there is no known breakage in
# newer versions.
./uv pip install -p venv-native/bin/python pyodide-build==0.30.3 pip
- name: "Install pyodide interpreter"
run: |
source ./venv-native/bin/activate
pyodide xbuildenv install 0.27.5
PYODIDE_PYTHON=$(pyodide config get interpreter)
PYODIDE_INDEX=$(pyodide config get package_index)
echo "PYODIDE_PYTHON=$PYODIDE_PYTHON" >> $GITHUB_ENV
echo "PYODIDE_INDEX=$PYODIDE_INDEX" >> $GITHUB_ENV
- name: "Create pyodide virtual environment"
run: |
./uv venv -p $PYODIDE_PYTHON venv-pyodide
source ./venv-pyodide/bin/activate
./uv pip install --extra-index-url=$PYODIDE_INDEX --no-build numpy
python -c 'import numpy'
integration-test-github-actions: integration-test-github-actions:
timeout-minutes: 10 timeout-minutes: 10
needs: build-binary-linux-libc needs: build-binary-linux-libc

View file

@ -226,6 +226,10 @@ pub enum TargetTriple {
#[serde(rename = "aarch64-manylinux_2_40")] #[serde(rename = "aarch64-manylinux_2_40")]
#[serde(alias = "aarch64-manylinux240")] #[serde(alias = "aarch64-manylinux240")]
Aarch64Manylinux240, Aarch64Manylinux240,
/// A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12.
#[cfg_attr(feature = "clap", value(name = "wasm32-pyodide2024"))]
Wasm32Pyodide2024,
} }
impl TargetTriple { impl TargetTriple {
@ -450,6 +454,13 @@ impl TargetTriple {
}, },
Arch::Aarch64, Arch::Aarch64,
), ),
Self::Wasm32Pyodide2024 => Platform::new(
Os::Pyodide {
major: 2024,
minor: 0,
},
Arch::Wasm32,
),
} }
} }
@ -490,6 +501,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "aarch64", Self::Aarch64Manylinux238 => "aarch64",
Self::Aarch64Manylinux239 => "aarch64", Self::Aarch64Manylinux239 => "aarch64",
Self::Aarch64Manylinux240 => "aarch64", Self::Aarch64Manylinux240 => "aarch64",
Self::Wasm32Pyodide2024 => "wasm32",
} }
} }
@ -530,6 +542,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "Linux", Self::Aarch64Manylinux238 => "Linux",
Self::Aarch64Manylinux239 => "Linux", Self::Aarch64Manylinux239 => "Linux",
Self::Aarch64Manylinux240 => "Linux", Self::Aarch64Manylinux240 => "Linux",
Self::Wasm32Pyodide2024 => "Emscripten",
} }
} }
@ -570,6 +583,10 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "", Self::Aarch64Manylinux238 => "",
Self::Aarch64Manylinux239 => "", Self::Aarch64Manylinux239 => "",
Self::Aarch64Manylinux240 => "", Self::Aarch64Manylinux240 => "",
// This is the value Emscripten gives for its version:
// https://github.com/emscripten-core/emscripten/blob/4.0.8/system/lib/libc/emscripten_syscall_stubs.c#L63
// It doesn't really seem to mean anything? But for completeness we include it here.
Self::Wasm32Pyodide2024 => "#1",
} }
} }
@ -610,6 +627,9 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "", Self::Aarch64Manylinux238 => "",
Self::Aarch64Manylinux239 => "", Self::Aarch64Manylinux239 => "",
Self::Aarch64Manylinux240 => "", Self::Aarch64Manylinux240 => "",
// This is the Emscripten compiler version for Pyodide 2024.
// See https://pyodide.org/en/stable/development/abi.html#pyodide-2024-0
Self::Wasm32Pyodide2024 => "3.1.58",
} }
} }
@ -650,6 +670,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "posix", Self::Aarch64Manylinux238 => "posix",
Self::Aarch64Manylinux239 => "posix", Self::Aarch64Manylinux239 => "posix",
Self::Aarch64Manylinux240 => "posix", Self::Aarch64Manylinux240 => "posix",
Self::Wasm32Pyodide2024 => "posix",
} }
} }
@ -690,6 +711,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => "linux", Self::Aarch64Manylinux238 => "linux",
Self::Aarch64Manylinux239 => "linux", Self::Aarch64Manylinux239 => "linux",
Self::Aarch64Manylinux240 => "linux", Self::Aarch64Manylinux240 => "linux",
Self::Wasm32Pyodide2024 => "emscripten",
} }
} }
@ -730,6 +752,7 @@ impl TargetTriple {
Self::Aarch64Manylinux238 => true, Self::Aarch64Manylinux238 => true,
Self::Aarch64Manylinux239 => true, Self::Aarch64Manylinux239 => true,
Self::Aarch64Manylinux240 => true, Self::Aarch64Manylinux240 => true,
Self::Wasm32Pyodide2024 => false,
} }
} }

View file

@ -43,6 +43,7 @@ pub enum Os {
Manylinux { major: u16, minor: u16 }, Manylinux { major: u16, minor: u16 },
Musllinux { major: u16, minor: u16 }, Musllinux { major: u16, minor: u16 },
Windows, Windows,
Pyodide { major: u16, minor: u16 },
Macos { major: u16, minor: u16 }, Macos { major: u16, minor: u16 },
FreeBsd { release: String }, FreeBsd { release: String },
NetBsd { release: String }, NetBsd { release: String },
@ -67,6 +68,7 @@ impl fmt::Display for Os {
Self::Illumos { .. } => write!(f, "illumos"), Self::Illumos { .. } => write!(f, "illumos"),
Self::Haiku { .. } => write!(f, "haiku"), Self::Haiku { .. } => write!(f, "haiku"),
Self::Android { .. } => write!(f, "android"), Self::Android { .. } => write!(f, "android"),
Self::Pyodide { .. } => write!(f, "pyodide"),
} }
} }
} }
@ -109,6 +111,7 @@ pub enum Arch {
S390X, S390X,
LoongArch64, LoongArch64,
Riscv64, Riscv64,
Wasm32,
} }
impl fmt::Display for Arch { impl fmt::Display for Arch {
@ -126,6 +129,7 @@ impl fmt::Display for Arch {
Self::S390X => write!(f, "s390x"), Self::S390X => write!(f, "s390x"),
Self::LoongArch64 => write!(f, "loongarch64"), Self::LoongArch64 => write!(f, "loongarch64"),
Self::Riscv64 => write!(f, "riscv64"), Self::Riscv64 => write!(f, "riscv64"),
Self::Wasm32 => write!(f, "wasm32"),
} }
} }
} }
@ -168,7 +172,7 @@ impl Arch {
// manylinux_2_36 // manylinux_2_36
Self::LoongArch64 => Some(36), Self::LoongArch64 => Some(36),
// unsupported // unsupported
Self::Powerpc | Self::Armv5TEL | Self::Armv6L => None, Self::Powerpc | Self::Armv5TEL | Self::Armv6L | Self::Wasm32 => None,
} }
} }
@ -187,6 +191,7 @@ impl Arch {
Self::S390X => "s390x", Self::S390X => "s390x",
Self::LoongArch64 => "loongarch64", Self::LoongArch64 => "loongarch64",
Self::Riscv64 => "riscv64", Self::Riscv64 => "riscv64",
Self::Wasm32 => "wasm32",
} }
} }

View file

@ -71,6 +71,8 @@ pub enum PlatformTag {
Illumos { release_arch: SmallString }, Illumos { release_arch: SmallString },
/// Ex) `solaris_11_4_x86_64` /// Ex) `solaris_11_4_x86_64`
Solaris { release_arch: SmallString }, Solaris { release_arch: SmallString },
/// Ex) `pyodide_2024_0_wasm32`
Pyodide { major: u16, minor: u16 },
} }
impl PlatformTag { impl PlatformTag {
@ -97,6 +99,7 @@ impl PlatformTag {
PlatformTag::Haiku { .. } => Some("Haiku"), PlatformTag::Haiku { .. } => Some("Haiku"),
PlatformTag::Illumos { .. } => Some("Illumos"), PlatformTag::Illumos { .. } => Some("Illumos"),
PlatformTag::Solaris { .. } => Some("Solaris"), PlatformTag::Solaris { .. } => Some("Solaris"),
PlatformTag::Pyodide { .. } => Some("Pyodide"),
} }
} }
} }
@ -262,6 +265,7 @@ impl std::fmt::Display for PlatformTag {
Self::Haiku { release_arch } => write!(f, "haiku_{release_arch}"), Self::Haiku { release_arch } => write!(f, "haiku_{release_arch}"),
Self::Illumos { release_arch } => write!(f, "illumos_{release_arch}"), Self::Illumos { release_arch } => write!(f, "illumos_{release_arch}"),
Self::Solaris { release_arch } => write!(f, "solaris_{release_arch}_64bit"), Self::Solaris { release_arch } => write!(f, "solaris_{release_arch}_64bit"),
Self::Pyodide { major, minor } => write!(f, "pyodide_{major}_{minor}_wasm32"),
} }
} }
} }
@ -616,6 +620,35 @@ impl FromStr for PlatformTag {
}); });
} }
if let Some(rest) = s.strip_prefix("pyodide_") {
let mid =
rest.strip_suffix("_wasm32")
.ok_or_else(|| ParsePlatformTagError::InvalidArch {
platform: "pyodide",
tag: s.to_string(),
})?;
let underscore = memchr::memchr(b'_', mid.as_bytes()).ok_or_else(|| {
ParsePlatformTagError::InvalidFormat {
platform: "pyodide",
tag: s.to_string(),
}
})?;
let major: u16 = mid[..underscore].parse().map_err(|_| {
ParsePlatformTagError::InvalidMajorVersion {
platform: "pyodide",
tag: s.to_string(),
}
})?;
let minor: u16 = mid[underscore + 1..].parse().map_err(|_| {
ParsePlatformTagError::InvalidMinorVersion {
platform: "pyodide",
tag: s.to_string(),
}
})?;
return Ok(Self::Pyodide { major, minor });
}
Err(ParsePlatformTagError::UnknownFormat(s.to_string())) Err(ParsePlatformTagError::UnknownFormat(s.to_string()))
} }
} }
@ -900,6 +933,27 @@ mod tests {
); );
} }
#[test]
fn pyodide_platform() {
let tag = PlatformTag::Pyodide {
major: 2024,
minor: 0,
};
assert_eq!(
PlatformTag::from_str("pyodide_2024_0_wasm32").as_ref(),
Ok(&tag)
);
assert_eq!(tag.to_string(), "pyodide_2024_0_wasm32");
assert_eq!(
PlatformTag::from_str("pyodide_2024_0_wasm64"),
Err(ParsePlatformTagError::InvalidArch {
platform: "pyodide",
tag: "pyodide_2024_0_wasm64".to_string()
})
);
}
#[test] #[test]
fn unknown_platform() { fn unknown_platform() {
assert_eq!( assert_eq!(

View file

@ -617,6 +617,12 @@ fn compatible_tags(platform: &Platform) -> Result<Vec<PlatformTag>, PlatformErro
arch, arch,
}] }]
} }
(Os::Pyodide { major, minor }, Arch::Wasm32) => {
vec![PlatformTag::Pyodide {
major: *major,
minor: *minor,
}]
}
_ => { _ => {
return Err(PlatformError::OsVersionDetectionError(format!( return Err(PlatformError::OsVersionDetectionError(format!(
"Unsupported operating system and architecture combination: {os} {arch}" "Unsupported operating system and architecture combination: {os} {arch}"

View file

@ -510,6 +510,24 @@ def get_operating_system_and_architecture():
"major": int(version[0]), "major": int(version[0]),
"minor": int(version[1]), "minor": int(version[1]),
} }
elif operating_system == "emscripten":
pyodide_abi_version = sysconfig.get_config_var("PYODIDE_ABI_VERSION")
if not pyodide_abi_version:
print(
json.dumps(
{
"result": "error",
"kind": "emscripten_not_pyodide",
}
)
)
sys.exit(0)
version = pyodide_abi_version.split("_")
operating_system = {
"name": "pyodide",
"major": int(version[0]),
"minor": int(version[1]),
}
elif operating_system in [ elif operating_system in [
"freebsd", "freebsd",
"netbsd", "netbsd",

View file

@ -757,6 +757,8 @@ pub enum InterpreterInfoError {
python_major: usize, python_major: usize,
python_minor: usize, python_minor: usize,
}, },
#[error("Only Pyodide is support for Emscripten Python")]
EmscriptenNotPyodide,
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]

View file

@ -348,6 +348,10 @@ impl From<&uv_platform_tags::Arch> for Arch {
), ),
variant: None, variant: None,
}, },
uv_platform_tags::Arch::Wasm32 => Self {
family: target_lexicon::Architecture::Wasm32,
variant: None,
},
} }
} }
} }
@ -380,6 +384,9 @@ impl From<&uv_platform_tags::Os> for Os {
uv_platform_tags::Os::NetBsd { .. } => Self(target_lexicon::OperatingSystem::Netbsd), uv_platform_tags::Os::NetBsd { .. } => Self(target_lexicon::OperatingSystem::Netbsd),
uv_platform_tags::Os::OpenBsd { .. } => Self(target_lexicon::OperatingSystem::Openbsd), uv_platform_tags::Os::OpenBsd { .. } => Self(target_lexicon::OperatingSystem::Openbsd),
uv_platform_tags::Os::Windows => Self(target_lexicon::OperatingSystem::Windows), uv_platform_tags::Os::Windows => Self(target_lexicon::OperatingSystem::Windows),
uv_platform_tags::Os::Pyodide { .. } => {
Self(target_lexicon::OperatingSystem::Emscripten)
}
} }
} }
} }

View file

@ -220,7 +220,8 @@ impl TorchStrategy {
| Os::Dragonfly { .. } | Os::Dragonfly { .. }
| Os::Illumos { .. } | Os::Illumos { .. }
| Os::Haiku { .. } | Os::Haiku { .. }
| Os::Android { .. } => { | Os::Android { .. }
| Os::Pyodide { .. } => {
Either::Right(std::iter::once(TorchBackend::Cpu.index_url())) Either::Right(std::iter::once(TorchBackend::Cpu.index_url()))
} }
} }

View file

@ -1702,6 +1702,7 @@ interpreter. Use <code>--universal</code> to display the tree for all platforms,
<li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li> <li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li>
<li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li> <li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li>
<li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li> <li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li>
<li><code>wasm32-pyodide2024</code>: A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12</li>
</ul></dd><dt id="uv-tree--python-version"><a href="#uv-tree--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The Python version to use when filtering the tree.</p> </ul></dd><dt id="uv-tree--python-version"><a href="#uv-tree--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The Python version to use when filtering the tree.</p>
<p>For example, pass <code>--python-version 3.10</code> to display the dependencies that would be included when installing on Python 3.10.</p> <p>For example, pass <code>--python-version 3.10</code> to display the dependencies that would be included when installing on Python 3.10.</p>
<p>Defaults to the version of the discovered Python interpreter.</p> <p>Defaults to the version of the discovered Python interpreter.</p>
@ -3295,6 +3296,7 @@ by <code>--python-version</code>.</p>
<li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li> <li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li>
<li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li> <li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li>
<li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li> <li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li>
<li><code>wasm32-pyodide2024</code>: A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12</li>
</ul></dd><dt id="uv-pip-compile--python-version"><a href="#uv-pip-compile--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The Python version to use for resolution.</p> </ul></dd><dt id="uv-pip-compile--python-version"><a href="#uv-pip-compile--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The Python version to use for resolution.</p>
<p>For example, <code>3.8</code> or <code>3.8.17</code>.</p> <p>For example, <code>3.8</code> or <code>3.8.17</code>.</p>
<p>Defaults to the version of the Python interpreter used for resolution.</p> <p>Defaults to the version of the Python interpreter used for resolution.</p>
@ -3533,6 +3535,7 @@ be used with caution, as it can modify the system Python installation.</p>
<li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li> <li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li>
<li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li> <li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li>
<li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li> <li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li>
<li><code>wasm32-pyodide2024</code>: A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12</li>
</ul></dd><dt id="uv-pip-sync--python-version"><a href="#uv-pip-sync--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The minimum Python version that should be supported by the requirements (e.g., <code>3.7</code> or <code>3.7.9</code>).</p> </ul></dd><dt id="uv-pip-sync--python-version"><a href="#uv-pip-sync--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The minimum Python version that should be supported by the requirements (e.g., <code>3.7</code> or <code>3.7.9</code>).</p>
<p>If a patch version is omitted, the minimum patch version is assumed. For example, <code>3.7</code> is mapped to <code>3.7.0</code>.</p> <p>If a patch version is omitted, the minimum patch version is assumed. For example, <code>3.7</code> is mapped to <code>3.7.0</code>.</p>
</dd><dt id="uv-pip-sync--quiet"><a href="#uv-pip-sync--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p> </dd><dt id="uv-pip-sync--quiet"><a href="#uv-pip-sync--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
@ -3796,6 +3799,7 @@ should be used with caution, as it can modify the system Python installation.</p
<li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li> <li><code>aarch64-manylinux_2_38</code>: An ARM64 target for the <code>manylinux_2_38</code> platform</li>
<li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li> <li><code>aarch64-manylinux_2_39</code>: An ARM64 target for the <code>manylinux_2_39</code> platform</li>
<li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li> <li><code>aarch64-manylinux_2_40</code>: An ARM64 target for the <code>manylinux_2_40</code> platform</li>
<li><code>wasm32-pyodide2024</code>: A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12</li>
</ul></dd><dt id="uv-pip-install--python-version"><a href="#uv-pip-install--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The minimum Python version that should be supported by the requirements (e.g., <code>3.7</code> or <code>3.7.9</code>).</p> </ul></dd><dt id="uv-pip-install--python-version"><a href="#uv-pip-install--python-version"><code>--python-version</code></a> <i>python-version</i></dt><dd><p>The minimum Python version that should be supported by the requirements (e.g., <code>3.7</code> or <code>3.7.9</code>).</p>
<p>If a patch version is omitted, the minimum patch version is assumed. For example, <code>3.7</code> is mapped to <code>3.7.0</code>.</p> <p>If a patch version is omitted, the minimum patch version is assumed. For example, <code>3.7</code> is mapped to <code>3.7.0</code>.</p>
</dd><dt id="uv-pip-install--quiet"><a href="#uv-pip-install--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p> </dd><dt id="uv-pip-install--quiet"><a href="#uv-pip-install--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>

7
uv.schema.json generated
View file

@ -2338,6 +2338,13 @@
"enum": [ "enum": [
"aarch64-manylinux_2_40" "aarch64-manylinux_2_40"
] ]
},
{
"description": "A wasm32 target using the the Pyodide 2024 platform. Meant for use with Python 3.12.",
"type": "string",
"enum": [
"wasm32-pyodide2024"
]
} }
] ]
}, },