Skip to content

Commit ad6b6ad

Browse files
hoodmanedavidhewitt
authored andcommitted
Add CI tests in Pyodide
1 parent 637ee8f commit ad6b6ad

File tree

8 files changed

+200
-0
lines changed

8 files changed

+200
-0
lines changed

.github/workflows/ci.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ on:
33
push:
44
branches:
55
- main
6+
- emscripten-ci2
67
pull_request:
78

89
concurrency:
@@ -402,3 +403,52 @@ jobs:
402403
shell: msys2 {0}
403404
run: |
404405
PATH="$PATH:/c/Users/runneradmin/.cargo/bin" nox -s test-mingw
406+
407+
test-emscripten:
408+
name: Test Emscripten
409+
runs-on: ubuntu-latest
410+
steps:
411+
- uses: actions/checkout@v3
412+
- uses: actions/setup-node@v3
413+
with:
414+
node-version: 18
415+
- run: |
416+
PYODIDE_VERSION=0.21.0-alpha.2
417+
418+
cd emscripten
419+
npm i [email protected] prettier
420+
cd node_modules/pyodide/
421+
node ../prettier/bin-prettier.js -w pyodide.asm.js
422+
EMSCRIPTEN_VERSION=$(node -p "require('./repodata.json').info.platform.split('_').slice(1).join('.')")
423+
PYTHON_VERSION=3.10.2
424+
425+
echo "PYODIDE_VERSION=$PYODIDE_VERSION" >> $GITHUB_ENV
426+
echo "EMSCRIPTEN_VERSION=$EMSCRIPTEN_VERSION" >> $GITHUB_ENV
427+
echo "PYTHON_VERSION=$PYTHON_VERSION" >> $GITHUB_ENV
428+
echo "ORIG_PATH=$PATH" >> $GITHUB_ENV
429+
- uses: actions-rs/toolchain@v1
430+
with:
431+
profile: minimal
432+
toolchain: nightly
433+
components: rust-src
434+
target: wasm32-unknown-emscripten
435+
override: true
436+
- uses: mymindstorm/setup-emsdk@v11
437+
with:
438+
version: ${{env.EMSCRIPTEN_VERSION}}
439+
actions-cache-folder: emsdk-cache
440+
- uses: actions/setup-python@v2
441+
id: setup-python
442+
with:
443+
python-version: ${{env.PYTHON_VERSION}}
444+
- run: pip install nox
445+
- uses: actions/cache@v3
446+
with:
447+
path: |
448+
tests/pyodide
449+
key: ${{ hashFiles('tests/*.js') }} - ${{ hashFiles('noxfile.py') }} - ${{ steps.setup-python.outputs.python-path }}
450+
- uses: Swatinem/rust-cache@v1
451+
- name: Test
452+
run: |
453+
export PATH=$ORIG_PATH:$PATH
454+
nox -s test-examples-emscripten

emscripten/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
builddir
2+
main.*
3+
!main.c
4+
pybuilddir.txt
5+
pyodide
6+
node_modules
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# system configuration generated and used by the sysconfig module
2+
build_time_vars = {
3+
"ABIFLAGS": "",
4+
"AR": "/src/emsdk/emsdk/upstream/emscripten/emar",
5+
"ARFLAGS": "rcs",
6+
"BLDSHARED": "emcc -sSIDE_MODULE=1 -L/src/emscripten/python-lib/",
7+
"CC": "emcc -I/src/emscripten/python-include/",
8+
"CCSHARED": "",
9+
"CFLAGS": "-Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g "
10+
"-fwrapv -O3 -Wall -O2 -g0 -fPIC",
11+
"EXT_SUFFIX": ".cpython-310-wasm32-emscripten.so",
12+
"HOST_GNU_TYPE": "wasm32-unknown-emscripten",
13+
"LDSHARED": "emcc -sSIDE_MODULE=1",
14+
"Py_DEBUG": "0",
15+
"py_version_nodot": "310",
16+
}

emscripten/emcc_wrapper.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env python3
2+
import subprocess
3+
import sys
4+
5+
6+
def update_args(args):
7+
# remove -lc. Not sure if it makes a difference but -lc doesn't belong here.
8+
# https://github.com/emscripten-core/emscripten/issues/17191
9+
for i in reversed(range(len(args))):
10+
if args[i] == "c" and args[i - 1] == "-l":
11+
del args[i - 1 : i + 1]
12+
13+
return args
14+
15+
16+
def main(args):
17+
args = update_args(args)
18+
return subprocess.call(["emcc"] + args)
19+
20+
21+
if __name__ == "__main__":
22+
args = sys.argv[1:]
23+
sys.exit(main(args))

emscripten/pyo3_config.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
implementation=CPython
2+
version=3.10
3+
shared=true
4+
abi3=false
5+
lib_name=python3.10
6+
pointer_width=32
7+
suppress_build_script_link_lines=false

emscripten/runner.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
const { opendir } = require("node:fs/promises");
2+
const { loadPyodide } = require("pyodide");
3+
4+
async function findWheel(distDir) {
5+
const dir = await opendir(distDir);
6+
for await (const dirent of dir) {
7+
if (dirent.name.endsWith("whl")) {
8+
return dirent.name;
9+
}
10+
}
11+
}
12+
13+
const pkgDir = process.argv[2];
14+
const distDir = pkgDir + "/dist";
15+
const testDir = pkgDir + "/tests";
16+
17+
async function main() {
18+
const wheelName = await findWheel(distDir);
19+
const wheelURL = `file:${distDir}/${wheelName}`;
20+
21+
try {
22+
pyodide = await loadPyodide();
23+
const FS = pyodide.FS;
24+
const NODEFS = FS.filesystems.NODEFS;
25+
FS.mkdir("/test_dir");
26+
FS.mount(NODEFS, { root: testDir }, "/test_dir");
27+
await pyodide.loadPackage(["micropip", "pytest", "tomli"]);
28+
const micropip = pyodide.pyimport("micropip");
29+
await micropip.install(wheelURL);
30+
const pytest = pyodide.pyimport("pytest");
31+
errcode = pytest.main(pyodide.toPy(["/test_dir", "-vv"]));
32+
} catch (e) {
33+
console.error(e);
34+
process.exit(1);
35+
}
36+
}
37+
38+
main();
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import sys
2+
import pytest
3+
4+
if sys.platform == "emscripten":
5+
6+
@pytest.fixture
7+
def benchmark():
8+
def result(func, *args, **kwargs):
9+
return func(*args, **kwargs)
10+
11+
return result

noxfile.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import sys
23
import tarfile
34
from glob import glob
45
from pathlib import Path
@@ -73,3 +74,51 @@ def chdir(path: Path):
7374
session.install("pytest", "cffi")
7475
session.install("--no-build-isolation", str(examples / "html-py-ever"))
7576
session.run("pytest", str(examples / "html-py-ever"))
77+
78+
79+
@nox.session(name="test-examples-emscripten")
80+
def test_examples_emscripten(session: nox.Session):
81+
session.install(".")
82+
emscripten_dir = Path("./emscripten").resolve()
83+
84+
session.run(
85+
"rustup",
86+
"component",
87+
"add",
88+
"rust-src",
89+
"--toolchain",
90+
"nightly",
91+
external=True,
92+
)
93+
examples_dir = Path("examples")
94+
test_crates = [
95+
examples_dir / "html-py-ever",
96+
examples_dir / "namespace_package",
97+
]
98+
for example in test_crates:
99+
env = os.environ.copy()
100+
env.update(
101+
RUSTUP_TOOLCHAIN="nightly",
102+
_SETUPTOOLSRUST_BUILD_STD="1",
103+
PYTHONPATH=str(emscripten_dir),
104+
_PYTHON_SYSCONFIGDATA_NAME="_sysconfigdata__emscripten_wasm32-emscripten",
105+
_PYTHON_HOST_PLATFORM="emscripten_3_1_14_wasm32",
106+
CARGO_BUILD_TARGET="wasm32-unknown-emscripten",
107+
CARGO_UNSTABLE_BUILD_STD="true",
108+
CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_LINKER=str(
109+
emscripten_dir / "emcc_wrapper.py"
110+
),
111+
PYO3_CONFIG_FILE=str(emscripten_dir / "pyo3_config.ini"),
112+
RUSTFLAGS=" ".join(
113+
[
114+
"-C relocation-model=pic",
115+
"-C link-arg=-sSIDE_MODULE=2",
116+
"-C link-arg=-sWASM_BIGINT",
117+
]
118+
),
119+
)
120+
with session.chdir(example):
121+
session.run("python", "setup.py", "bdist_wheel", env=env, external=True)
122+
123+
with session.chdir(emscripten_dir):
124+
session.run("node", "runner.js", str(example), external=True)

0 commit comments

Comments
 (0)