Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ extern "C" {
struct pyruntimestate;
struct _ceval_runtime_state;

/* WASI has limited call stack. wasmtime 0.36 can handle sufficient amount of
C stack frames for little more than 750 recursions. */
#ifndef Py_DEFAULT_RECURSION_LIMIT
# define Py_DEFAULT_RECURSION_LIMIT 1000
# ifdef __wasi__
# define Py_DEFAULT_RECURSION_LIMIT 750
# else
# define Py_DEFAULT_RECURSION_LIMIT 1000
# endif
#endif

#include "pycore_interp.h" // PyInterpreterState.eval_frame
Expand Down
4 changes: 4 additions & 0 deletions Lib/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ def libc_ver(executable=None, lib='', version='', chunksize=16384):

executable = sys.executable

if not executable:
# sys.executable is not set.
return lib, version
Comment thread
tiran marked this conversation as resolved.
Outdated

V = _comparable_version
# We use os.path.realpath()
# here to work around problems with Cygwin not being
Expand Down
10 changes: 8 additions & 2 deletions Lib/test/pythoninfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,14 @@ def format_attr(attr, value):
def collect_socket(info_add):
import socket

hostname = socket.gethostname()
info_add('socket.hostname', hostname)
try:
hostname = socket.gethostname()
except OSError:
# WASI SDK 15.0 does not have gethostname(2).
if sys.platform != "wasi":
raise
else:
info_add('socket.hostname', hostname)


def collect_sqlite(info_add):
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,11 @@ def get_original_stdout():
def _force_run(path, func, *args):
try:
return func(*args)
except FileNotFoundError as err:
# chmod() won't fix a missing file.
if verbose >= 2:
print('%s: %s' % (err.__class__.__name__, err))
raise
except OSError as err:
if verbose >= 2:
print('%s: %s' % (err.__class__.__name__, err))
Expand Down
4 changes: 3 additions & 1 deletion Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ def __getitem__(self, key):
self.assertEqual(d['z'], 12)

def test_extended_arg(self):
longexpr = 'x = x or ' + '-x' * 2500
# default: 1000 * 2.5 = 2500 repetitions
repeat = int(sys.getrecursionlimit() * 2.5)
longexpr = 'x = x or ' + '-x' * repeat
g = {}
code = '''
def f(x):
Expand Down
5 changes: 4 additions & 1 deletion Lib/test/test_fileio.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
from weakref import proxy
from functools import wraps

from test.support import cpython_only, swap_attr, gc_collect, is_emscripten
from test.support import (
cpython_only, swap_attr, gc_collect, is_emscripten, is_wasi
)
from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd)
from test.support.warnings_helper import check_warnings
from collections import UserList
Expand Down Expand Up @@ -65,6 +67,7 @@ def testAttributes(self):
self.assertRaises((AttributeError, TypeError),
setattr, f, attr, 'oops')

@unittest.skipIf(is_wasi, "WASI does not expose st_blksize.")
def testBlksize(self):
# test private _blksize attribute
blksize = io.DEFAULT_BUFFER_SIZE
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_largefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ def test_seekable(self):
def skip_no_disk_space(path, required):
def decorator(fun):
def wrapper(*args, **kwargs):
if not hasattr(shutil, "disk_usage"):
raise unittest.SkipTest("requires shutil.disk_usage")
if shutil.disk_usage(os.path.realpath(path)).free < required:
hsize = int(required / 1024 / 1024)
raise unittest.SkipTest(
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -5280,6 +5280,7 @@ def test_emit_after_closing_in_write_mode(self):
self.assertEqual(fp.read().strip(), '1')

class RotatingFileHandlerTest(BaseFileTest):
@unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.")
def test_should_not_rollover(self):
# If maxbytes is zero rollover never occurs
rh = logging.handlers.RotatingFileHandler(
Expand Down Expand Up @@ -5387,6 +5388,7 @@ def rotator(source, dest):
rh.close()

class TimedRotatingFileHandlerTest(BaseFileTest):
@unittest.skipIf(support.is_wasi, "WASI does not have /dev/null.")
def test_should_not_rollover(self):
# See bpo-45401. Should only ever rollover regular files
fh = logging.handlers.TimedRotatingFileHandler(
Expand Down
9 changes: 7 additions & 2 deletions Lib/test/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import fractions
import itertools
import locale
import mmap
import os
import pickle
import select
Expand Down Expand Up @@ -59,6 +58,10 @@
except ImportError:
INT_MAX = PY_SSIZE_T_MAX = sys.maxsize

try:
import mmap
except ImportError:
mmap = None

from test.support.script_helper import assert_python_ok
from test.support import unix_shell
Expand Down Expand Up @@ -2167,7 +2170,8 @@ def test_fchown(self):

@unittest.skipUnless(hasattr(os, 'fpathconf'), 'test needs os.fpathconf()')
@unittest.skipIf(
support.is_emscripten, "musl libc issue on Emscripten, bpo-46390"
support.is_emscripten or support.is_wasi,
"musl libc issue on Emscripten/WASI, bpo-46390"
)
def test_fpathconf(self):
self.check(os.pathconf, "PC_NAME_MAX")
Expand Down Expand Up @@ -2460,6 +2464,7 @@ def test_kill_int(self):
# os.kill on Windows can take an int which gets set as the exit code
self._kill(100)

@unittest.skipIf(mmap is None, "requires mmap")
def _kill_with_event(self, event, name):
tagname = "test_os_%s" % uuid.uuid1()
m = mmap.mmap(-1, 1, tagname)
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_signal.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ def test_interprocess_signal(self):
script = os.path.join(dirname, 'signalinterproctester.py')
assert_python_ok(script)

@unittest.skipUnless(
hasattr(signal, "valid_signals"),
"requires signal.valid_signals"
)
Comment thread
tiran marked this conversation as resolved.
Outdated
def test_valid_signals(self):
s = signal.valid_signals()
self.assertIsInstance(s, set)
Expand Down Expand Up @@ -212,6 +216,7 @@ def test_invalid_fd(self):
self.assertRaises((ValueError, OSError),
signal.set_wakeup_fd, fd)

@unittest.skipUnless(support.has_socket_support, "needs working sockets.")
def test_invalid_socket(self):
sock = socket.socket()
fd = sock.fileno()
Expand Down Expand Up @@ -241,6 +246,7 @@ def test_set_wakeup_fd_result(self):
self.assertEqual(signal.set_wakeup_fd(-1), -1)

@unittest.skipIf(support.is_emscripten, "Emscripten cannot fstat pipes.")
@unittest.skipUnless(support.has_socket_support, "needs working sockets.")
def test_set_wakeup_fd_socket_result(self):
sock1 = socket.socket()
self.addCleanup(sock1.close)
Expand Down
7 changes: 5 additions & 2 deletions Lib/test/test_tomllib/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import datetime
from decimal import Decimal as D
from pathlib import Path
import sys
import tempfile
import unittest

Expand Down Expand Up @@ -91,11 +92,13 @@ def test_deepcopy(self):
self.assertEqual(obj_copy, expected_obj)

def test_inline_array_recursion_limit(self):
nest_count = 470
# 470 with default recursion limit
nest_count = int(sys.getrecursionlimit() * 0.47)
recursive_array_toml = "arr = " + nest_count * "[" + nest_count * "]"
tomllib.loads(recursive_array_toml)

def test_inline_table_recursion_limit(self):
nest_count = 310
# 310 with default recursion limit
nest_count = int(sys.getrecursionlimit() * 0.31)
recursive_table_toml = nest_count * "key = {" + nest_count * "}"
tomllib.loads(recursive_table_toml)
1 change: 1 addition & 0 deletions Lib/test/test_zipimport.py
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ def testEmptyFile(self):
os_helper.create_empty_file(TESTMOD)
self.assertZipFailure(TESTMOD)

@unittest.skipIf(support.is_wasi, "mode 000 not supported.")
Comment thread
tiran marked this conversation as resolved.
Outdated
def testFileUnreadable(self):
os_helper.unlink(TESTMOD)
fd = os.open(TESTMOD, os.O_CREAT, 000)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Decrease default recursion limit on WASI to address limited call stack size.
2 changes: 1 addition & 1 deletion Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1481,7 +1481,7 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)

#elif defined(HAVE_CLOCK_GETTIME) && \
defined(CLOCK_PROCESS_CPUTIME_ID) && \
!defined(__EMSCRIPTEN__)
!defined(__EMSCRIPTEN__) && !defined(__wasi__)
#define HAVE_THREAD_TIME

#if defined(__APPLE__) && defined(__has_attribute) && __has_attribute(availability)
Expand Down
6 changes: 5 additions & 1 deletion Parser/parser.c

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Tools/peg_generator/pegen/c_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@
# define D(x)
#endif

# define MAXSTACK 6000
#ifdef __wasi__
# define MAXSTACK 4000
#else
# define MAXSTACK 6000
#endif

"""

Expand Down
21 changes: 19 additions & 2 deletions Tools/wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,27 @@ AddType application/wasm wasm

# WASI (wasm32-wasi)

WASI builds require [WASI SDK](https://github.com/WebAssembly/wasi-sdk) and
currently [wasix](https://github.com/singlestore-labs/wasix) for POSIX
WASI builds require [WASI SDK](https://github.com/WebAssembly/wasi-sdk) 15.0+
and currently [wasix](https://github.com/singlestore-labs/wasix) for POSIX
compatibility stubs.

## WASI limitations and issues (WASI SDK 15.0)

A lot of Emscripten limitations also apply to WASI. Noticable restrictions
are:

- Call stack size is limited. Default recursion limit and parser stack size
are smaller than in regular Python builds.
- ``socket(2)`` cannot create new socket file descriptors. WASI programs can
call read/write/accept on a file descriptor that is passed into the process.
- ``socket.gethostname()`` and host name resolution APIs like
``socket.gethostbyname()`` are not implemented and always fail.
- ``chmod(2)`` is not available. It's not possible to modify file permissions,
yet. A future version of WASI may provide a limited ``set_permissions`` API.
- File locking (``fcntl``) is not available.
- ``os.pipe()``, ``os.mkfifo()``, and ``os.mknod()`` are not supported.


# Detect WebAssembly builds

## Python code
Expand Down
21 changes: 21 additions & 0 deletions Tools/wasm/config.site-wasm32-wasi
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,24 @@ ac_cv_header_sys_resource_h=no

# undefined symbols / unsupported features
ac_cv_func_eventfd=no

# WASI SDK 15.0 has no pipe syscall.
ac_cv_func_pipe=no

# WASI SDK 15.0 cannot create fifos and special files.
ac_cv_func_mkfifo=no
ac_cv_func_mkfifoat=no
ac_cv_func_mknod=no
ac_cv_func_mknodat=no

# fdopendir() fails on SDK 15.0,
# OSError: [Errno 28] Invalid argument: '.'
ac_cv_func_fdopendir=no

# WASIX stubs we don't want to use.
ac_cv_func_kill=no

# WASI sockets are limited to operations on given socket fd and inet sockets.
# Disable AF_UNIX and AF_PACKET support, see socketmodule.h.
ac_cv_header_sys_un_h=no
ac_cv_header_netpacket_packet_h=no
1 change: 1 addition & 0 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -6690,8 +6690,10 @@ AS_CASE([$ac_sys_system],
],
[Emscripten/node*], [],
[WASI/*], [
dnl WASI SDK 15.0 does not support file locking.
PY_STDLIB_MOD_SET_NA(
[_ctypes_test],
[fcntl],
)
]
)
Expand Down