Skip to content

Commit 4895ce0

Browse files
Add wasm32-wasip1 test job (#5729)
* wasi ci job * disable failing tests * mark test as conditional on `panic = "unwind"`
1 parent 9a8eb96 commit 4895ce0

File tree

11 files changed

+98
-9
lines changed

11 files changed

+98
-9
lines changed

.github/workflows/ci.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,82 @@ jobs:
487487
.nox/emscripten
488488
key: emscripten-${{ hashFiles('emscripten/*') }}-${{ hashFiles('noxfile.py') }}-${{ steps.setup-python.outputs.python-path }}
489489

490+
wasm32-wasip1:
491+
name: wasm32-wasip1
492+
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
493+
needs: [fmt]
494+
runs-on: ubuntu-latest
495+
env:
496+
WASI_SDK_PATH: "/opt/wasi-sdk"
497+
CPYTHON_PATH: "${{ github.workspace }}/wasi/cpython"
498+
steps:
499+
- uses: actions/[email protected]
500+
- uses: actions/setup-python@v6
501+
with:
502+
python-version: 3.14
503+
id: setup-python
504+
- name: Install Rust toolchain
505+
uses: dtolnay/rust-toolchain@stable
506+
with:
507+
targets: wasm32-wasip1
508+
components: rust-src
509+
- name: "Install wasmtime"
510+
uses: bytecodealliance/actions/wasmtime/setup@v1
511+
- name: "Install WASI SDK"
512+
run: |
513+
mkdir ${{ env.WASI_SDK_PATH }} && \
514+
curl -s -S --location https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-24/wasi-sdk-24.0-x86_64-linux.tar.gz | \
515+
tar --strip-components 1 --directory ${{ env.WASI_SDK_PATH }} --extract --gunzip
516+
$WASI_SDK_PATH/bin/clang --version
517+
- uses: actions/cache/restore@v5
518+
id: cache-wasip1-python
519+
with:
520+
path: ${{ env.CPYTHON_PATH }}/cross-build/
521+
key: wasm32-wasip1-python
522+
- uses: actions/[email protected]
523+
with:
524+
repository: python/cpython
525+
ref: 3.14
526+
path: ${{ env.CPYTHON_PATH }}
527+
fetch-depth: 1
528+
- name: Build
529+
run: |
530+
cd ${{ env.CPYTHON_PATH }}
531+
cat >> Tools/wasm/wasi/config.site-wasm32-wasi <<'EOF'
532+
533+
# Force-disable POSIX dynamic loading for WASI
534+
ac_cv_func_dlopen=no
535+
ac_cv_lib_dl_dlopen=no
536+
EOF
537+
python Tools/wasm/wasi build --quiet -- --config-cache
538+
cp cross-build/wasm32-wasip1/libpython3.14.a \
539+
cross-build/wasm32-wasip1/Modules/_hacl/libHacl_HMAC.a \
540+
cross-build/wasm32-wasip1/Modules/_decimal/libmpdec/libmpdec.a \
541+
cross-build/wasm32-wasip1/Modules/expat/libexpat.a \
542+
cross-build/wasm32-wasip1/build/lib.wasi-wasm32-3.14/
543+
- uses: Swatinem/rust-cache@v2
544+
with:
545+
save-if: ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'CI-save-pr-cache') }}
546+
- name: Test
547+
env:
548+
PYO3_CROSS_LIB_DIR: ${{ env.CPYTHON_PATH }}/cross-build/wasm32-wasip1/build/lib.wasi-wasm32-3.14/
549+
CARGO_BUILD_TARGET: wasm32-wasip1
550+
CARGO_TARGET_WASM32_WASIP1_RUNNER: wasmtime run --dir ${{ env.CPYTHON_PATH }}::/ --env PYTHONPATH=/lib
551+
RUSTFLAGS: >
552+
-C link-arg=-L${{ env.WASI_SDK_PATH }}/share/wasi-sysroot/lib/wasm32-wasi
553+
-C link-arg=-lwasi-emulated-signal
554+
-C link-arg=-lwasi-emulated-process-clocks
555+
-C link-arg=-lwasi-emulated-getpid
556+
-C link-arg=-lmpdec
557+
-C link-arg=-lHacl_HMAC
558+
-C link-arg=-lexpat
559+
run: RUSTDOCFLAGS=$RUSTFLAGS cargo test
560+
- uses: actions/cache/save@v5
561+
if: ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'CI-save-pr-cache') }}
562+
with:
563+
path: ${{ env.CPYTHON_PATH }}/cross-build/
564+
key: ${{ steps.cache-wasip1-python.outputs.cache-primary-key }}
565+
490566
test-debug:
491567
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
492568
needs: [fmt]

src/conversions/std/array.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ pub(crate) fn invalid_sequence_length(expected: usize, actual: usize) -> PyErr {
135135

136136
#[cfg(test)]
137137
mod tests {
138+
#[cfg(panic = "unwind")]
138139
use std::{
139140
panic,
140141
sync::atomic::{AtomicUsize, Ordering},
@@ -147,6 +148,7 @@ mod tests {
147148
use crate::{types::PyList, PyResult, Python};
148149

149150
#[test]
151+
#[cfg(panic = "unwind")]
150152
fn array_try_from_fn() {
151153
static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0);
152154
struct CountDrop;
@@ -303,6 +305,7 @@ mod tests {
303305
}
304306

305307
// https://stackoverflow.com/a/59211505
308+
#[cfg(panic = "unwind")]
306309
fn catch_unwind_silent<F, R>(f: F) -> std::thread::Result<R>
307310
where
308311
F: FnOnce() -> R + panic::UnwindSafe,

src/conversions/std/osstr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ mod tests {
230230
};
231231

232232
#[test]
233-
#[cfg(not(windows))]
233+
#[cfg(not(any(windows, target_os = "wasi")))]
234234
fn test_non_utf8_conversion() {
235235
Python::attach(|py| {
236236
#[cfg(not(target_os = "wasi"))]

src/conversions/std/path.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ mod tests {
135135
types::{PyAnyMethods, PyString},
136136
IntoPyObjectExt,
137137
};
138+
#[cfg(not(target_os = "wasi"))]
138139
use std::ffi::OsStr;
139140
use std::fmt::Debug;
140141
#[cfg(unix)]
@@ -143,7 +144,7 @@ mod tests {
143144
use std::os::windows::ffi::OsStringExt;
144145

145146
#[test]
146-
#[cfg(not(windows))]
147+
#[cfg(not(any(windows, target_os = "wasi")))]
147148
fn test_non_utf8_conversion() {
148149
Python::attach(|py| {
149150
#[cfg(not(target_os = "wasi"))]

src/instance.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2454,10 +2454,10 @@ fn panic_on_null(py: Python<'_>) -> ! {
24542454
#[cfg(test)]
24552455
mod tests {
24562456
use super::{Bound, IntoPyObject, Py};
2457-
#[cfg(all(feature = "macros", Py_3_8))]
2457+
#[cfg(all(feature = "macros", Py_3_8, panic = "unwind"))]
24582458
use crate::exceptions::PyValueError;
24592459
use crate::test_utils::generate_unique_module_name;
2460-
#[cfg(all(feature = "macros", Py_3_8))]
2460+
#[cfg(all(feature = "macros", Py_3_8, panic = "unwind"))]
24612461
use crate::test_utils::UnraisableCapture;
24622462
use crate::types::{dict::IntoPyDict, PyAnyMethods, PyCapsule, PyDict, PyString};
24632463
use crate::{ffi, Borrowed, IntoPyObjectExt, PyAny, PyResult, Python};
@@ -2815,7 +2815,7 @@ a = A()
28152815
});
28162816
}
28172817

2818-
#[cfg(all(feature = "macros", Py_3_8))]
2818+
#[cfg(all(feature = "macros", Py_3_8, panic = "unwind"))]
28192819
#[test]
28202820
fn test_constructors_panic_on_null() {
28212821
Python::attach(|py| {

src/marker.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,7 @@ mod tests {
910910
}
911911

912912
#[test]
913+
#[cfg(panic = "unwind")]
913914
fn test_detach_panics_safely() {
914915
Python::attach(|py| {
915916
let result = std::panic::catch_unwind(|| unsafe {

src/types/list.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,6 +1544,7 @@ mod tests {
15441544
}
15451545

15461546
#[test]
1547+
#[cfg(panic = "unwind")]
15471548
fn bad_intopyobject_doesnt_cause_leaks() {
15481549
use crate::types::PyInt;
15491550
use std::convert::Infallible;

src/types/tuple.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,7 @@ mod tests {
14421442
}
14431443

14441444
#[test]
1445+
#[cfg(panic = "unwind")]
14451446
fn bad_intopyobject_doesnt_cause_leaks() {
14461447
use crate::types::PyInt;
14471448
use std::convert::Infallible;
@@ -1504,6 +1505,7 @@ mod tests {
15041505
}
15051506

15061507
#[test]
1508+
#[cfg(panic = "unwind")]
15071509
fn bad_intopyobject_doesnt_cause_leaks_2() {
15081510
use crate::types::PyInt;
15091511
use std::convert::Infallible;

tests/test_class_attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ fn recursive_class_attributes() {
151151
}
152152

153153
#[test]
154-
#[cfg(Py_3_8)] // sys.unraisablehook not available until Python 3.8
154+
#[cfg(all(Py_3_8, panic = "unwind"))] // sys.unraisablehook not available until Python 3.8
155155
fn test_fallible_class_attribute() {
156156
use pyo3::exceptions::PyValueError;
157157
use test_utils::UnraisableCapture;

tests/test_class_basics.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
#![cfg(feature = "macros")]
22

33
use pyo3::prelude::*;
4+
use pyo3::py_run;
45
use pyo3::types::PyType;
5-
use pyo3::{py_run, PyClass};
6+
#[cfg(not(target_arch = "wasm32"))]
7+
use pyo3::PyClass;
68

79
mod test_utils;
810

@@ -285,6 +287,7 @@ impl UnsendableChild {
285287
}
286288
}
287289

290+
#[cfg(not(target_arch = "wasm32"))]
288291
fn test_unsendable<T: PyClass + 'static>() -> PyResult<()> {
289292
let (keep_obj_here, obj) = Python::attach(|py| -> PyResult<_> {
290293
let obj: Py<T> = PyType::new::<T>(py).call1((5,))?.extract()?;
@@ -323,7 +326,7 @@ fn test_unsendable<T: PyClass + 'static>() -> PyResult<()> {
323326

324327
/// If a class is marked as `unsendable`, it panics when accessed by another thread.
325328
#[test]
326-
#[cfg_attr(target_arch = "wasm32", ignore)]
329+
#[cfg(not(target_arch = "wasm32"))]
327330
#[should_panic(
328331
expected = "test_class_basics::UnsendableBase is unsendable, but sent to another thread"
329332
)]
@@ -332,7 +335,7 @@ fn panic_unsendable_base() {
332335
}
333336

334337
#[test]
335-
#[cfg_attr(target_arch = "wasm32", ignore)]
338+
#[cfg(not(target_arch = "wasm32"))]
336339
#[should_panic(
337340
expected = "test_class_basics::UnsendableBase is unsendable, but sent to another thread"
338341
)]

0 commit comments

Comments
 (0)