@ai-ecoverse/wasix-python 3.14.2-15 → 3.14.2-18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@ CPython 3.14 for slicc WASIX (`commands` `python` / `python3`).
4
4
 
5
5
  ## Features
6
6
 
7
- - PIE dynamic-main (`dylink.0`) on wasix-sysroot 2025.9.30-18's `sysroot-ehpic` (legacy wasm EH), SOABI `cpython-314-wasm32-wasix`; native side modules (py-numpy, py-scipy, py-pandas, …) load by `dlopen`
7
+ - PIE dynamic-main (`dylink.0`) on wasix-sysroot 2025.9.30-27's `sysroot-ehpic` (legacy wasm EH), SOABI `cpython-314-wasm32-wasix`; native side modules (py-numpy, py-scipy, py-pandas, …) load by `dlopen`
8
8
  - **File modes** (3.14.2-12, on slicc-kernel ≥ 1.35.1; older kernels keep the no-op modes): `os.umask`, `open()`/`os.mkdir` create modes, `os.chmod`, `tempfile.mkstemp` 600 / `mkdtemp` 700, pip console scripts 755
9
9
  - Built in: `ssl`/`hashlib` (OpenSSL 3.5.9, `@ai-ecoverse/wasix-openssl`), `zlib` 1.3.1, `bz2`, `lzma` (xz 5.8.4), `sqlite3` (3.53.4; FTS5, JSON, math, R*Tree; no WAL, no extensions), `readline` 8.3 (ncurses 6.5 terminfo compiled in: xterm, screen, tmux, vt100, linux), `ctypes` / `_ctypes` (wasix-org/libffi; needs slicc-kernel#306 step 1 for `call_dynamic` + `closure_{allocate,free}`), `mmap`, `fcntl`, `termios`, `resource`, `pwd`, `grp`, `select`
10
10
  - No `fork`/`vfork`; `subprocess` via `os.posix_spawn` (`proc_spawn2`/`3`)
@@ -18,6 +18,58 @@ CPython 3.14 for slicc WASIX (`commands` `python` / `python3`).
18
18
 
19
19
  Since 3.14.2-12 the package is cross-built from source in CI (`build.sh`); see `THIRD-PARTY-NOTICES.md` for the statically linked libraries.
20
20
 
21
+ Since 3.14.2-18:
22
+ - `ctypes.CDLL(None)` has no `fork` (nor `_Fork`, `__wasi_proc_fork`, …):
23
+ python.wasm no longer exports them (homescoop#296). In 3.14.2-17 calling
24
+ `ctypes.CDLL(None).fork()` crashed the interpreter (a wasm trap): fork needs
25
+ Asyncify on every frame between it and `main`, and ctypes' frames have none.
26
+ `os.fork` stays absent; `subprocess`, `os.posix_spawn` and `os.system` work
27
+ as before.
28
+
29
+ Since 3.14.2-17 (wasix-sysroot -27):
30
+ - `os.utime(path)`, `pathlib.Path.touch()` and everything else that sets a
31
+ file's times to "now" set them to now; up to 3.14.2-16 they set them to
32
+ 0 (1970) (wasix-sysroot's broken `utimensat(NULL)`, homescoop#294).
33
+ - `os.times()`, `resource.getrusage(RUSAGE_SELF)` and `time.clock`-style
34
+ callers report the process CPU time slicc-kernel keeps; system and
35
+ children's times are 0. Up to -16 they held wall-clock values.
36
+ - An empty path is `FileNotFoundError` (`os.stat("")`, `open("")`), as on
37
+ Linux; files have owners on slicc-kernel ≥ 1.59.0 with users on
38
+ (`os.chown`, `os.stat().st_uid`), and `os.access` asks the kernel
39
+ (≥ 1.63.0).
40
+ - **A system site directory every user shares:**
41
+ `/usr/local/lib/python3.14/site-packages` is added (with `site.addsitedir`,
42
+ so its `.pth` files run) after python's own site-packages and the py-*
43
+ packages it finds, when it exists. An embedder can drop a `.pth` there once
44
+ for every user. A virtual environment sees it only with
45
+ `--system-site-packages`, as on Linux.
46
+ - The py-* discovery cache is per user:
47
+ `${XDG_CACHE_HOME:-~/.cache}/slicc-site/`, never in the package directory
48
+ (which other users cannot write); without a home or a writable cache
49
+ directory there is no cache.
50
+ - `pip` and `pip3` are commands (`python3 -m pip`); `pip install --user`
51
+ installs into the user's own site-packages.
52
+ - `python -m venv` takes about half as long: ensurepip runs the package's own
53
+ compiled pip instead of pip from the zipped wheel.
54
+
55
+ Since 3.14.2-16 (wasix-sysroot -22: the `slicc.libc` marker, no exported
56
+ itimer helper):
57
+ - ctypes calls variadic C functions (`printf`, `snprintf`, `sscanf`,
58
+ `open(path, flags, mode)`, `fcntl`, `ioctl`, …): our libffi passes the
59
+ variadic arguments the way the wasm32 C ABI does
60
+ (`patches/libffi-wasix-varargs.patch`). As on Apple arm64, set `argtypes` to
61
+ the **fixed** parameters (e.g. `[c_char_p]` for `printf`) and pass the rest
62
+ as typed ctypes values (`c_int`, `c_double`, …); without `argtypes` every
63
+ argument is taken as fixed, which is wrong for a variadic function on wasm32.
64
+ Pass `c_double` for `%f`: ctypes does not promote, and a variadic `c_float`
65
+ raises `RuntimeError: ffi_prep_cif_var failed` (libffi rejects it, as on
66
+ every platform).
67
+ 3.14.2-15 could not call them at all ("ffi_prep_cif_var failed").
68
+ - Signals during blocking calls follow PEP 475 on slicc-kernel ≥ 1.53.3, which
69
+ answers -22-marked programs with EINTR: a signal whose handler returns does
70
+ not shorten `time.sleep`/`select`/`poll`, and ^C raises `KeyboardInterrupt`
71
+ at once (`cert/signals.mjs`).
72
+
21
73
  Since 3.14.2-15:
22
74
  - `ctypes` / `_ctypes` (wasix-org/libffi) — needs slicc-kernel ≥ 1.51.0 (#306 /
23
75
  #316: `call_dynamic`, `closure_{allocate,prepare,free}`, POSIX `dlopen(NULL)` /
@@ -35,8 +87,8 @@ Since 3.14.2-15:
35
87
  and if the `wasix-python` it resolves to (Node's lookup from its real
36
88
  directory) is this python's exact version, so side modules never mix
37
89
  interpreter builds; the first package of a name wins. `python -v` reports
38
- what was skipped and why. The scan is cached in `.slicc-site-cache` in
39
- python's directory (keyed on the package directories and their
90
+ what was skipped and why. The scan is cached per user in
91
+ `${XDG_CACHE_HOME:-~/.cache}/slicc-site/` (since 3.14.2-17; keyed on the package directories and their
40
92
  `package.json` stamps; `-v` always rescans); with the cache, a start costs
41
93
  about 2 ms more than with discovery off, and less than the same directories
42
94
  on `PYTHONPATH`. As with `PYTHONPATH`, `.pth` files in those directories are
@@ -12,8 +12,8 @@ bin/python.wasm statically links:
12
12
  | SQLite | 3.53.4 | public domain | sqlite.org |
13
13
  | GNU Readline | 8.3 | GPL-3.0-or-later | gnu.org/software/readline |
14
14
  | ncurses (tinfo) | 6.5 | X11 | invisible-island.net/ncurses |
15
- | libffi | 3.5.1 | MIT | github.com/wasix-org/libffi |
16
- | wasix-libc | wasix-sysroot 2025.9.30-21 | Apache-2.0 WITH LLVM-exception, MIT | @ai-ecoverse/wasix-sysroot |
15
+ | libffi | 3.5.1 (wasix-org 09cbf7d + patches/libffi-wasix-varargs.patch) | MIT | github.com/wasix-org/libffi |
16
+ | wasix-libc | wasix-sysroot 2025.9.30-27 | Apache-2.0 WITH LLVM-exception, MIT | @ai-ecoverse/wasix-sysroot |
17
17
  | libc++, libc++abi, libunwind | wasix-libc v2026-07-03.1 sysroot-ehpic | Apache-2.0 WITH LLVM-exception | github.com/wasix-org/wasix-libc |
18
18
 
19
19
  lib/python3.14/site-packages/pip is pip (MIT), from CPython's ensurepip bundle.
package/bin/python.wasm CHANGED
Binary file
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/lib/libpython3.14.a
3
- size: 59362746 bytes
4
- sha256: b5320f13b4636974f7dcf92f662e9e9f488a051d092d7bff059ad787522bb0b1
3
+ size: 59362794 bytes
4
+ sha256: 778c4e87cac3d76368fc786d6112159cfd27802c16ad6870f2a3fa664fa3e5f9
@@ -24,9 +24,17 @@ resolves to (Node-style lookup from its real directory), if any, has the
24
24
  same exact version as this python: the same version is the same build, so
25
25
  native side modules never mix interpreter builds. The first package of a
26
26
  name wins; others are skipped (reported under -v).
27
- The result is cached in <python>/.slicc-site-cache, keyed on the package
28
- directories and their package.json stamps, plus the stamps of the
29
- wasix-python copies they resolved to; -v always rescans.
27
+ The result is cached per user in ${XDG_CACHE_HOME:-~/.cache}/slicc-site/
28
+ (3.14.2-17; before, <python>/.slicc-site-cache, which other users could not
29
+ write), keyed on the package directories and their package.json stamps, plus
30
+ the stamps of the wasix-python copies they resolved to; -v always rescans.
31
+ Without a home or a writable cache directory there is no cache.
32
+
33
+ system_site() (3.14.2-17): /usr/local/lib/python3.X/site-packages, when it
34
+ exists, goes on sys.path through site.addsitedir (so its .pth files run),
35
+ after python's own site-packages and the py-* directories: one place an
36
+ embedder can put a .pth for every user. Like discover(), it runs from the
37
+ base .pth only, so a venv sees it with --system-site-packages.
30
38
  """
31
39
  import os
32
40
  import sys
@@ -212,8 +220,8 @@ def discover():
212
220
  # slicc's OPFS; directory mtimes are not). A hit costs one stat per
213
221
  # package instead of realpath + read + parse + lookup.
214
222
  key = "\n".join(filter(None, [base, _stamp(real), *map(_stamp, found)]))
215
- cache = os.path.join(real, ".slicc-site-cache")
216
- if not sys.flags.verbose:
223
+ cache = _cache_path(real)
224
+ if cache and not sys.flags.verbose:
217
225
  try:
218
226
  with open(cache, encoding="utf-8") as f:
219
227
  head, _, rest = f.read().partition("\n\n")
@@ -231,15 +239,37 @@ def discover():
231
239
  for d in dirs:
232
240
  if d not in sys.path: # as PYTHONPATH would: .pth files there are not run
233
241
  sys.path.append(d)
242
+ if not cache:
243
+ return
234
244
  try:
245
+ os.makedirs(os.path.dirname(cache), exist_ok=True)
235
246
  tmp = f"{cache}.{os.getpid()}"
236
247
  with open(tmp, "w", encoding="utf-8") as f:
237
248
  f.write(key + "\n\n" + "\n".join(filter(None, map(_stamp, sorted(used)))) + "\n\n" + "\n".join(dirs))
238
249
  os.replace(tmp, cache)
239
- except OSError: # read-only install: no cache, scan every start
250
+ except OSError: # no writable cache directory: scan every start
240
251
  pass
241
252
 
242
253
 
254
+ def _cache_path(real):
255
+ base = os.environ.get("XDG_CACHE_HOME")
256
+ if not base:
257
+ home = os.environ.get("HOME")
258
+ if not home:
259
+ return None
260
+ base = os.path.join(home, ".cache")
261
+ return os.path.join(base, "slicc-site", real.strip("/").replace("/", "%") or "%")
262
+
263
+
264
+ def system_site():
265
+ d = f"/usr/local/lib/python{sys.version_info[0]}.{sys.version_info[1]}/site-packages"
266
+ if d in sys.path or not os.path.isdir(d):
267
+ return
268
+ import site
269
+
270
+ site.addsitedir(d)
271
+
272
+
243
273
  def _scan(real, found):
244
274
  me = _manifest(real)
245
275
  if not me or me.get("name") != _PY_PKG:
@@ -169,7 +169,13 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
169
169
  if verbosity:
170
170
  args += ["-" + "v" * verbosity]
171
171
 
172
- return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)])
172
+ pip_path = [os.fsdecode(tmp_wheel_path)]
173
+ installed = sysconfig.get_path("purelib", vars={"base": sys.base_prefix, "platbase": sys.base_prefix})
174
+ if (sys.platform == "wasi" and sys.prefix != sys.base_prefix and not root and not user
175
+ and os.path.isdir(os.path.join(installed, f"pip-{_PIP_VERSION}.dist-info"))):
176
+ pip_path = [installed]
177
+ args += ["--ignore-installed"]
178
+ return _run_pip([*args, "pip"], pip_path)
173
179
 
174
180
 
175
181
  def _uninstall_helper(*, verbosity=0):
@@ -1 +1 @@
1
- import _slicc_site; _slicc_site.fix(); _slicc_site.discover()
1
+ import _slicc_site; _slicc_site.fix(); _slicc_site.discover(); _slicc_site.system_site()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/wasix-python",
3
- "version": "3.14.2-15",
3
+ "version": "3.14.2-18",
4
4
  "description": "CPython 3.14 for slicc WASIX (commands python, python3; cross-built in CI on wasix-sysroot)",
5
5
  "license": "PSF-2.0 AND GPL-3.0-or-later",
6
6
  "engines": {
@@ -55,6 +55,32 @@
55
55
  "PYTHONHOME": "./",
56
56
  "PYTHONDONTWRITEBYTECODE": "1"
57
57
  }
58
+ },
59
+ "pip": {
60
+ "wasm": "bin/python.wasm",
61
+ "argv0Path": true,
62
+ "env": {
63
+ "PYTHONHOME": "./",
64
+ "PYTHONDONTWRITEBYTECODE": "1"
65
+ },
66
+ "argv0": "python3",
67
+ "args": [
68
+ "-m",
69
+ "pip"
70
+ ]
71
+ },
72
+ "pip3": {
73
+ "wasm": "bin/python.wasm",
74
+ "argv0Path": true,
75
+ "env": {
76
+ "PYTHONHOME": "./",
77
+ "PYTHONDONTWRITEBYTECODE": "1"
78
+ },
79
+ "argv0": "python3",
80
+ "args": [
81
+ "-m",
82
+ "pip"
83
+ ]
58
84
  }
59
85
  },
60
86
  "python": {