mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 21:35:00 +00:00
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:
parent
37e22e4da6
commit
f9d3f24728
11 changed files with 168 additions and 2 deletions
39
.github/workflows/ci.yml
vendored
39
.github/workflows/ci.yml
vendored
|
@ -1294,6 +1294,45 @@ jobs:
|
|||
run: |
|
||||
.\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:
|
||||
timeout-minutes: 10
|
||||
needs: build-binary-linux-libc
|
||||
|
|
|
@ -226,6 +226,10 @@ pub enum TargetTriple {
|
|||
#[serde(rename = "aarch64-manylinux_2_40")]
|
||||
#[serde(alias = "aarch64-manylinux240")]
|
||||
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 {
|
||||
|
@ -450,6 +454,13 @@ impl TargetTriple {
|
|||
},
|
||||
Arch::Aarch64,
|
||||
),
|
||||
Self::Wasm32Pyodide2024 => Platform::new(
|
||||
Os::Pyodide {
|
||||
major: 2024,
|
||||
minor: 0,
|
||||
},
|
||||
Arch::Wasm32,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -490,6 +501,7 @@ impl TargetTriple {
|
|||
Self::Aarch64Manylinux238 => "aarch64",
|
||||
Self::Aarch64Manylinux239 => "aarch64",
|
||||
Self::Aarch64Manylinux240 => "aarch64",
|
||||
Self::Wasm32Pyodide2024 => "wasm32",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -530,6 +542,7 @@ impl TargetTriple {
|
|||
Self::Aarch64Manylinux238 => "Linux",
|
||||
Self::Aarch64Manylinux239 => "Linux",
|
||||
Self::Aarch64Manylinux240 => "Linux",
|
||||
Self::Wasm32Pyodide2024 => "Emscripten",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,6 +583,10 @@ impl TargetTriple {
|
|||
Self::Aarch64Manylinux238 => "",
|
||||
Self::Aarch64Manylinux239 => "",
|
||||
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::Aarch64Manylinux239 => "",
|
||||
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::Aarch64Manylinux239 => "posix",
|
||||
Self::Aarch64Manylinux240 => "posix",
|
||||
Self::Wasm32Pyodide2024 => "posix",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,6 +711,7 @@ impl TargetTriple {
|
|||
Self::Aarch64Manylinux238 => "linux",
|
||||
Self::Aarch64Manylinux239 => "linux",
|
||||
Self::Aarch64Manylinux240 => "linux",
|
||||
Self::Wasm32Pyodide2024 => "emscripten",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -730,6 +752,7 @@ impl TargetTriple {
|
|||
Self::Aarch64Manylinux238 => true,
|
||||
Self::Aarch64Manylinux239 => true,
|
||||
Self::Aarch64Manylinux240 => true,
|
||||
Self::Wasm32Pyodide2024 => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ pub enum Os {
|
|||
Manylinux { major: u16, minor: u16 },
|
||||
Musllinux { major: u16, minor: u16 },
|
||||
Windows,
|
||||
Pyodide { major: u16, minor: u16 },
|
||||
Macos { major: u16, minor: u16 },
|
||||
FreeBsd { release: String },
|
||||
NetBsd { release: String },
|
||||
|
@ -67,6 +68,7 @@ impl fmt::Display for Os {
|
|||
Self::Illumos { .. } => write!(f, "illumos"),
|
||||
Self::Haiku { .. } => write!(f, "haiku"),
|
||||
Self::Android { .. } => write!(f, "android"),
|
||||
Self::Pyodide { .. } => write!(f, "pyodide"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +111,7 @@ pub enum Arch {
|
|||
S390X,
|
||||
LoongArch64,
|
||||
Riscv64,
|
||||
Wasm32,
|
||||
}
|
||||
|
||||
impl fmt::Display for Arch {
|
||||
|
@ -126,6 +129,7 @@ impl fmt::Display for Arch {
|
|||
Self::S390X => write!(f, "s390x"),
|
||||
Self::LoongArch64 => write!(f, "loongarch64"),
|
||||
Self::Riscv64 => write!(f, "riscv64"),
|
||||
Self::Wasm32 => write!(f, "wasm32"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +172,7 @@ impl Arch {
|
|||
// manylinux_2_36
|
||||
Self::LoongArch64 => Some(36),
|
||||
// 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::LoongArch64 => "loongarch64",
|
||||
Self::Riscv64 => "riscv64",
|
||||
Self::Wasm32 => "wasm32",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ pub enum PlatformTag {
|
|||
Illumos { release_arch: SmallString },
|
||||
/// Ex) `solaris_11_4_x86_64`
|
||||
Solaris { release_arch: SmallString },
|
||||
/// Ex) `pyodide_2024_0_wasm32`
|
||||
Pyodide { major: u16, minor: u16 },
|
||||
}
|
||||
|
||||
impl PlatformTag {
|
||||
|
@ -97,6 +99,7 @@ impl PlatformTag {
|
|||
PlatformTag::Haiku { .. } => Some("Haiku"),
|
||||
PlatformTag::Illumos { .. } => Some("Illumos"),
|
||||
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::Illumos { release_arch } => write!(f, "illumos_{release_arch}"),
|
||||
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()))
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
fn unknown_platform() {
|
||||
assert_eq!(
|
||||
|
|
|
@ -617,6 +617,12 @@ fn compatible_tags(platform: &Platform) -> Result<Vec<PlatformTag>, PlatformErro
|
|||
arch,
|
||||
}]
|
||||
}
|
||||
(Os::Pyodide { major, minor }, Arch::Wasm32) => {
|
||||
vec![PlatformTag::Pyodide {
|
||||
major: *major,
|
||||
minor: *minor,
|
||||
}]
|
||||
}
|
||||
_ => {
|
||||
return Err(PlatformError::OsVersionDetectionError(format!(
|
||||
"Unsupported operating system and architecture combination: {os} {arch}"
|
||||
|
|
|
@ -510,6 +510,24 @@ def get_operating_system_and_architecture():
|
|||
"major": int(version[0]),
|
||||
"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 [
|
||||
"freebsd",
|
||||
"netbsd",
|
||||
|
|
|
@ -757,6 +757,8 @@ pub enum InterpreterInfoError {
|
|||
python_major: usize,
|
||||
python_minor: usize,
|
||||
},
|
||||
#[error("Only Pyodide is support for Emscripten Python")]
|
||||
EmscriptenNotPyodide,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
|
|
|
@ -348,6 +348,10 @@ impl From<&uv_platform_tags::Arch> for Arch {
|
|||
),
|
||||
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::OpenBsd { .. } => Self(target_lexicon::OperatingSystem::Openbsd),
|
||||
uv_platform_tags::Os::Windows => Self(target_lexicon::OperatingSystem::Windows),
|
||||
uv_platform_tags::Os::Pyodide { .. } => {
|
||||
Self(target_lexicon::OperatingSystem::Emscripten)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,8 @@ impl TorchStrategy {
|
|||
| Os::Dragonfly { .. }
|
||||
| Os::Illumos { .. }
|
||||
| Os::Haiku { .. }
|
||||
| Os::Android { .. } => {
|
||||
| Os::Android { .. }
|
||||
| Os::Pyodide { .. } => {
|
||||
Either::Right(std::iter::once(TorchBackend::Cpu.index_url()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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_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>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>
|
||||
<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>
|
||||
|
@ -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_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>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>
|
||||
<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>
|
||||
|
@ -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_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>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>
|
||||
<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>
|
||||
|
@ -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_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>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>
|
||||
<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>
|
||||
|
|
7
uv.schema.json
generated
7
uv.schema.json
generated
|
@ -2338,6 +2338,13 @@
|
|||
"enum": [
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue