Skip to content

Commit 5d2d87c

Browse files
authored
Merge pull request RustPython#2442 from RustPython/wasm-wheels
Allow importing PyPI packages on wasm
2 parents 1453530 + 28a2697 commit 5d2d87c

28 files changed

+1086
-281
lines changed

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[flake8]
2+
# black's line length
3+
max-line-length = 88

.github/workflows/ci.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
name: CI
77

88
env:
9-
CARGO_ARGS: --features "ssl jit"
9+
CARGO_ARGS: --features ssl,jit
1010
NON_WASM_PACKAGES: >
1111
-p rustpython-bytecode
1212
-p rustpython-common

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ members = [
1515
]
1616

1717
[features]
18-
default = ["threading", "pylib"]
18+
default = ["threading", "pylib", "zlib"]
1919
flame-it = ["rustpython-vm/flame-it", "flame", "flamescope"]
2020
freeze-stdlib = ["rustpython-vm/freeze-stdlib"]
2121
jit = ["rustpython-vm/jit"]
2222
threading = ["rustpython-vm/threading"]
23+
zlib = ["rustpython-vm/zlib"]
2324

2425
ssl = ["rustpython-vm/ssl"]
2526

Lib/_dummy_os.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
"""
2+
A shim of the os module containing only simple path-related utilities
3+
"""
4+
5+
try:
6+
from os import *
7+
except ImportError:
8+
import abc
9+
10+
def __getattr__(name):
11+
raise OSError("no os specific module found")
12+
13+
def _shim():
14+
import _dummy_os, sys
15+
sys.modules['os'] = _dummy_os
16+
sys.modules['os.path'] = _dummy_os.path
17+
18+
import posixpath as path
19+
import sys
20+
sys.modules['os.path'] = path
21+
del sys
22+
23+
sep = path.sep
24+
25+
26+
def fspath(path):
27+
"""Return the path representation of a path-like object.
28+
29+
If str or bytes is passed in, it is returned unchanged. Otherwise the
30+
os.PathLike interface is used to get the path representation. If the
31+
path representation is not str or bytes, TypeError is raised. If the
32+
provided path is not str, bytes, or os.PathLike, TypeError is raised.
33+
"""
34+
if isinstance(path, (str, bytes)):
35+
return path
36+
37+
# Work from the object's type to match method resolution of other magic
38+
# methods.
39+
path_type = type(path)
40+
try:
41+
path_repr = path_type.__fspath__(path)
42+
except AttributeError:
43+
if hasattr(path_type, '__fspath__'):
44+
raise
45+
else:
46+
raise TypeError("expected str, bytes or os.PathLike object, "
47+
"not " + path_type.__name__)
48+
if isinstance(path_repr, (str, bytes)):
49+
return path_repr
50+
else:
51+
raise TypeError("expected {}.__fspath__() to return str or bytes, "
52+
"not {}".format(path_type.__name__,
53+
type(path_repr).__name__))
54+
55+
class PathLike(abc.ABC):
56+
57+
"""Abstract base class for implementing the file system path protocol."""
58+
59+
@abc.abstractmethod
60+
def __fspath__(self):
61+
"""Return the file system path representation of the object."""
62+
raise NotImplementedError
63+
64+
@classmethod
65+
def __subclasshook__(cls, subclass):
66+
return hasattr(subclass, '__fspath__')

Lib/fnmatch.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
The function translate(PATTERN) returns a regular expression
1010
corresponding to PATTERN. (It does not compile it.)
1111
"""
12-
import os
12+
try:
13+
import os
14+
except ImportError:
15+
import _dummy_os as os
1316
import posixpath
1417
import re
1518
import functools

Lib/genericpath.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
Do not use directly. The OS specific modules import the appropriate
44
functions from this module themselves.
55
"""
6-
import os
6+
try:
7+
import os
8+
except ImportError:
9+
import _dummy_os as os
710
import stat
811

912
__all__ = ['commonprefix', 'exists', 'getatime', 'getctime', 'getmtime',

Lib/io.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,17 @@
5252
import abc
5353

5454
from _io import (DEFAULT_BUFFER_SIZE, BlockingIOError, UnsupportedOperation,
55-
open, open_code, FileIO, BytesIO, StringIO, BufferedReader,
55+
open, open_code, BytesIO, StringIO, BufferedReader,
5656
BufferedWriter, BufferedRWPair, BufferedRandom,
5757
# XXX RUSTPYTHON TODO: IncrementalNewlineDecoder
5858
# IncrementalNewlineDecoder, TextIOWrapper)
5959
TextIOWrapper)
6060

61+
try:
62+
from _io import FileIO
63+
except ImportError:
64+
pass
65+
6166
OpenWrapper = _io.open # for compatibility with _pyio
6267

6368
# Pretend this exception was created here.

Lib/linecache.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
import functools
99
import sys
10-
import os
10+
try:
11+
import os
12+
except ImportError:
13+
import _dummy_os as os
1114
import tokenize
1215

1316
__all__ = ["getline", "clearcache", "checkcache"]

Lib/posixpath.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
altsep = None
2323
devnull = '/dev/null'
2424

25-
import os
25+
try:
26+
import os
27+
except ImportError:
28+
import _dummy_os as os
2629
import sys
2730
import stat
2831
import genericpath

Lib/zipfile.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@
88
import importlib.util
99
import io
1010
import itertools
11-
import os
11+
try:
12+
import os
13+
except ImportError:
14+
import _dummy_os as os
1215
import posixpath
13-
import shutil
16+
try:
17+
import shutil
18+
except ImportError:
19+
pass
1420
import stat
1521
import struct
1622
import sys
17-
import threading
23+
try:
24+
import threading
25+
except ImportError:
26+
import _dummy_thread as threading
1827
import time
1928
import contextlib
2029
from collections import OrderedDict

common/src/lock/cell_lock.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ unsafe impl RawRwLock for RawCellRwLock {
121121

122122
unsafe impl RawRwLockDowngrade for RawCellRwLock {
123123
unsafe fn downgrade(&self) {
124-
// no-op -- we're always exclusively locked for this thread
124+
self.state.set(ONE_READER);
125125
}
126126
}
127127

@@ -170,7 +170,7 @@ unsafe impl RawRwLockUpgradeDowngrade for RawCellRwLock {
170170

171171
#[inline]
172172
unsafe fn downgrade_to_upgradable(&self) {
173-
// no-op -- we're always exclusively locked for this thread
173+
self.state.set(ONE_READER);
174174
}
175175
}
176176

vm/Cargo.toml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ include = ["src/**/*.rs", "Cargo.toml", "build.rs", "Lib/**/*.py"]
1010

1111
[features]
1212
default = ["compile-parse", "threading"]
13+
# TODO: use resolver = "2" instead of features
14+
zlib = ["libz-sys", "flate2/zlib"]
1315
vm-tracing-logging = []
1416
flame-it = ["flame", "flamer"]
1517
freeze-stdlib = ["rustpython-pylib"]
@@ -84,6 +86,10 @@ atty = "0.2"
8486
static_assertions = "1.1"
8587
half = "1.6"
8688
memchr = "2"
89+
crc32fast = "1.2.0"
90+
adler32 = "1.0.3"
91+
flate2 = "1.0.20"
92+
libz-sys = { version = "1.0", optional = true }
8793

8894
# RustPython crates implementing functionality based on CPython
8995
mt19937 = "2.0"
@@ -114,8 +120,6 @@ exitcode = "1.1.2"
114120
uname = "0.1.1"
115121

116122
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
117-
crc32fast = "1.2.0"
118-
adler32 = "1.0.3"
119123
gethostname = "0.2.0"
120124
socket2 = "0.3.19"
121125
rustyline = "6.0"
@@ -129,8 +133,6 @@ num_cpus = "1"
129133

130134
[target.'cfg(not(any(target_arch = "wasm32", target_os = "redox")))'.dependencies]
131135
dns-lookup = "1.0"
132-
flate2 = { version = "1.0.20", features = ["zlib"], default-features = false }
133-
libz-sys = "1.0"
134136

135137
[target.'cfg(windows)'.dependencies]
136138
winreg = "0.7"

vm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub mod frame;
5454
mod frozen;
5555
pub mod function;
5656
pub mod import;
57-
mod iterator;
57+
pub mod iterator;
5858
mod py_io;
5959
pub mod py_serde;
6060
pub mod pyobject;

vm/src/pyobjectrc.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ impl Drop for PyObjectRef {
307307
// CPython-compatible drop implementation
308308
let zelf = self.clone();
309309
if let Some(del_slot) = self.class().mro_find_map(|cls| cls.slots.del.load()) {
310-
crate::vm::thread::with_vm(&zelf, |vm| {
310+
let ret = crate::vm::thread::with_vm(&zelf, |vm| {
311311
if let Err(e) = del_slot(&zelf, vm) {
312312
// exception in del will be ignored but printed
313313
print!("Exception ignored in: ",);
@@ -327,6 +327,9 @@ impl Drop for PyObjectRef {
327327
}
328328
}
329329
});
330+
if ret.is_none() {
331+
warn!("couldn't run __del__ method for object")
332+
}
330333
}
331334

332335
// __del__ might have resurrected the object at this point, but that's fine,

vm/src/stdlib/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod tokenize;
4242
mod unicodedata;
4343
mod warnings;
4444
mod weakref;
45+
mod zlib;
4546

4647
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
4748
#[macro_use]
@@ -67,8 +68,6 @@ mod ssl;
6768
mod winapi;
6869
#[cfg(windows)]
6970
mod winreg;
70-
#[cfg(not(any(target_arch = "wasm32", target_os = "redox")))]
71-
mod zlib;
7271

7372
pub type StdlibInitFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine) -> PyObjectRef)>;
7473

@@ -103,6 +102,7 @@ pub fn get_module_inits() -> HashMap<String, StdlibInitFunc, ahash::RandomState>
103102
"_imp".to_owned() => Box::new(imp::make_module),
104103
"unicodedata".to_owned() => Box::new(unicodedata::make_module),
105104
"_warnings".to_owned() => Box::new(warnings::make_module),
105+
"zlib".to_owned() => Box::new(zlib::make_module),
106106
crate::sysmodule::sysconfigdata_name() => Box::new(sysconfigdata::make_module),
107107
};
108108

@@ -144,8 +144,6 @@ pub fn get_module_inits() -> HashMap<String, StdlibInitFunc, ahash::RandomState>
144144
modules.insert("_ssl".to_owned(), Box::new(ssl::make_module));
145145
#[cfg(feature = "threading")]
146146
modules.insert("_thread".to_owned(), Box::new(thread::make_module));
147-
#[cfg(not(target_os = "redox"))]
148-
modules.insert("zlib".to_owned(), Box::new(zlib::make_module));
149147
modules.insert(
150148
"faulthandler".to_owned(),
151149
Box::new(faulthandler::make_module),

0 commit comments

Comments
 (0)