Coder Social home page Coder Social logo

sagemathinc / cowasm Goto Github PK

View Code? Open in Web Editor NEW
465.0 13.0 22.0 15.13 MB

CoWasm: Collaborative WebAssembly for Servers and Browsers. Built using Zig. Supports Python with extension modules, including numpy.

Home Page: https://cowasm.org

License: BSD 3-Clause "New" or "Revised" License

Dockerfile 0.05% Makefile 4.04% Python 21.30% JavaScript 3.28% TypeScript 14.75% C 39.95% Zig 5.25% Shell 0.41% Fortran 0.01% Roff 10.09% Yacc 0.71% CMake 0.01% Lua 0.01% Cython 0.14% CSS 0.01%
python wasm webassembly zig

cowasm's Introduction

CoWasm: Collaborative WebAssembly for Servers and Browsers

URL: https://github.com/sagemathinc/cowasm

DEMOS:

TEST STATUS:

  • make test CI

Or Type this if you have nodejs at least version 16 installed:

~$ npx python-wasm@latest
Python 3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3
5
>>> import numpy
>>> import sympy
...

NOTE: On Microsoft Windows you have to enter a few times, and there is an issue with terminal echo. We are working on this.

Packages

There are four subdirectories that each contain packages:

  • core - core functionality, including dynamic linking, a WASI implementation, openssl, and nontrivial posix extensions to node.js written in Zig. (This is analogous to emscripten.org.)
  • python - a WebAssembly build of Python, along with some nontrivial scientific libraries (This is analogous to pyodide.org.)
  • web - examples of how to use the other packages in web applications; this includes building https://cowasm.org.
  • desktop - a native Electron app that provides a sandboxed WebAssembly Python terminal running on your native filesystem.
  • sagemath - beginning of a port of https://sagemath.org to WebAssembly. Vasts amounts of work remain.

What is this?

CoWasm means "collaborative WebAssembly", and goes far beyond just Python. The collaboration aspects will be part of https://cocalc.com at some point in the future. CoWasm will support various technologies (such as libgit2 and realtime sync) that are important foundations for collaboration.

The underlying software components that CoWasm is built on (i.e., that we didn't write) are mostly extremely stable and mature. Zig is less stable, but we mostly use Zig for its amazing cross compilation support and packaging of clang/llvm and musl-libc, which are themselves both very mature. Many other components, such as Python, Dash, Numpy, etc., are ridiculously mature multidecade old projects. Moreover, other components of CoWasm such as memfs are libraries with 10M+ downloads per week that are heavily used in production.

The goal of CoWasm is overall somewhat similar to all of emscripten, WebAssembly.sh, wapm.io, and Pyodide combined, in various ways.

  • Unlike WebAssembly.sh and wapm.io (but similar to Pyodide), we make VERY heavy use of shared dynamic libraries (e.g., -fPIC code), which is only possible because of a plugin contributed from emscripten to LLVM. The "Co" in CoWasm suggestion "collaboration" or "sharing", which also reflects how the binaries in this project are structured.
  • We use actual editline (similar to readline) instead of a Javascript terminal. Moreover, unlike other webassembly shells, we just use a real command line shell (dash = Debian Almquist Shell). We also have a userspace including ports of many coreutils, e.g., ls, head, tail, etc.
  • Unlike emscripten, we use modern Typescript, our code is more modular, and we make use of existing components when possible (e.g., the nodejs memfs project), instead of using our own.
  • A core design constraint is to efficiently run on a wide range of platforms, not mainly in the browser like emscripten, and not mainly on servers like wasmer. CoWasm should run on servers, desktops (e.g., as an electron app), an iPad/iOS app, and in web browsers.
  • There is no business unfriendly GPL code in CoWasm. CoWasm itself is extremely liberally licensed and business friendly. The license of all new code and most components is 3-clause BSD. CoWasm will serve as a foundation for other projects with more restrictive licenses:
    • CoCalc will build on top of CoWasm to provide a graphical interface and realtime collaboration, and that will be a commercial product.
    • Products like GP/PARI SageMath will build on CoWasm to provide GPL-licensed mathematics software.

Python

An exciting package in CoWasm is python-wasm, which is a build of Python for WebAssembly, which supports both servers and browsers. It also supports extension modules such as numpy. See python/README.md for more details.

Try python-wasm

Try the python-wasm REPL under node.js (version at least 16):

~$ npx python-wasm@latest
Python 3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 (git@github.com:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3
5
>>> import sys; sys.version
'3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 (git@github.com:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571'
>>> sys.platform
'wasi'

Install python-wasm

Install python-wasm into your project, and try it via the library interface and the node.js terminal.

npm install python-wasm

Then from the nodejs REPL:

~/cowasm/core/python-wasm$ node
Welcome to Node.js v19.0.0.
Type ".help" for more information.
> {syncPython, asyncPython} = require('.')
{
  syncPython: [AsyncFunction: syncPython],
  asyncPython: [AsyncFunction: asyncPython],
  default: [AsyncFunction: asyncPython]
}
> python = await syncPython(); 0;
0
> python.exec('import sys')
undefined
> python.repr('sys.version')
"'3.11.0b3 (main, Jul 14 2022, 22:22:40) [Clang 13.0.1 ([email protected]:ziglang/zig-bootstrap.git 623481199fe17f4311cbdbbf'"
> python.exec('import numpy')
undefined
> python.repr('numpy.linspace(0, 10, num=5)')
'array([ 0. ,  2.5,  5. ,  7.5, 10. ])'

There is also a Python REPL that is part of python-wasm:

> python.terminal()
Python 3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 (git@github.com:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3   # you can edit using readline
5
>>> input('name? ')*3
name? william  <-- I just typed "william"
'williamwilliamwilliam'
>>> import time; time.sleep(3)  # sleep works
>>> while True: pass   # ctrl+c works, but exits this terminal
> # back in node.

You can also use python-wasm in your own web applications via webpack. In the browser, this transparently uses SharedArrayBuffers if available, and falls back to ServiceWorkers.

Build from Source

We support and regularly test building CoWasm from source on the following platforms:

  • x86 macOS and aarch64 macOS (Apple Silicon M1)
  • x86 and aarch64 Linux

Prerequisites

You need Node.js version at least 16.x, pnpm and several standard dev tools listed below. The dependency you need for every possible package are as follows:

sudo apt-get install git make cmake curl dpkg-dev m4 yasm texinfo python-is-python3 libtool tcl zip libncurses-dev

If you also want to install node v18 and pnpm on Ubuntu, you could do:

     sudo curl -sL https://deb.nodesource.com/setup_18.x | bash - \
  && sudo apt-get install -y nodejs \
  && sudo npm install -g npm pnpm
  • On Linux RPM based system, e.g., Fedora 37:
dnf install git make cmake curl dpkg-dev m4 yasm texinfo libtool tcl zip ncurses-devel perl
  • On ArchLinux:
pacman -Sy binutils git nodejs npm cmake curl m4 yasm texinfo python libtool tcl zip unzip patch binutils diffutils

NOTE: pnpm is not in the Arch Linux official package sets. You may want to install it from Arch User Repository (AUR) AUR (en) - pnpm.

  • Currently, the only way to build CoWasm from source on MS Windows is to use a Docker container running Linux. Using WSL2 (maybe) works but is too slow.

In addition you need to install Node.js version at least 16.x and install the pnpm package manager.

Notes about Zig

You do NOT need to install Zig, and it doesn't matter if you have a random version of Zig on your system already. A zig binary is download automatically. We use zig (instead of any system-wide clang, etc. compilers) for building all compiled code and write some code in the zig language. Since zig is fairly unstable it is critical to use the exact version that we provide.

Build

To build any package in the src/packages directory, cd into that directory, then:

make

That's it, usually. You do not have to run build at the top level and you can start with building any specific package -- it will automatically cause any required dependencies to get installed or built.

You can also force building of every single package and running its test suite if you want:

~/cowasm$ make test
...
##########################################################
#                                                        #
#   CONGRATULATIONS -- FULL COWASM TEST SUITE PASSED!    #
#
#   Fri Oct 28 12:32:19 AM UTC 2022
#   Linux aarch64
#   Git Branch: main
#                                                        #
##########################################################

Depending on your computer, the build should take less than 30 minutes, and about 6GB's of disk space.

This installs a specific tested version of Zig and Nodejs, then builds native and WebAssembly versions of CPython and many dependencies, and also builds all the Typescript code. It also builds many other interesting programs with ports to WebAssembly, though many are not completely finished (e.g., there is the dash shell and ports of tar and BSD coreutils). As mentioned, building from source is regularly tested on Linux and MacOS with both x86_64 and ARM (M1) processors:

  • Linux: tested on both x86_64 and aarch64 Ubuntu
  • MacOS: tested on both x86_64 and M1 mac with standard XCode command live dev tools installed.

CoWasm does not use the compilers on the system, and instead uses clang/llvm as shipped with Zig. If you're using Windows, you'll have to use Linux via a virtual machine or Docker.

Pull latest code, build and test

At the top level run ./bin/rebuild-all :

~/cowasm$ ./bin/rebuild-all

This does make clean, pulls the latest code, then runs the full build and test suite. Fortunately, zig caches a lot of build artifacts, so subsequent builds are faster.

NOTE/WARNING: Zig's cache is in ~/.cache/zig and it can get HUGE. As far as I can tell, I think it just grows and grows without bound (it's not an LRU cache), and I think there are no tools to "manage" it besides just rm -rf it periodically.

What is tested?

Note that running make test at the top level does NOT run the full test suite of every package, since it takes quite a while and there are still some failing tests, since CoWasm doesn't support enough of what Python expects. It does run a large supported subset of the cpython test suite (it's the part that I got to pass so far, which is over 80%). As an example, the sympy test suite is massive, takes a very long time to run, and doesn't even work for me natively; instead, we just run a handful of small tests to ensure sympy is working at all. Similarly, for Cython, we run all their demos, but not the full test suite. A longer term goal of CoWasm is to support a second more thorough testing regime that runs the full test suite of each package. There will likely always be issues due to WASM not being a multiuser POSIX system, but it's good to know what those issues are!

You can also use the WebAssembly Python REPL directly on the command line.

~/cowasm$ ./bin/python-wasm 
Python 3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3
5
>>> import sys
>>> sys.platform
'wasi'
>>> sys.executable
'/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/cowasm/core/cpython/bin/python-wasm'
>>> ^D
~/cowasm$

The above directly runs the `python.wasm` executable produced by building cPython. You can instead run an enhanced version (e.g., with signal support) with more options in the python-wasm package:

~/cowasm$ . bin/env.sh 
~/cowasm$ cd core/python-wasm/
~/cowasm/core/python-wasm$ ./bin/python-wasm 
Python 3.11.0 (main, Oct 27 2022, 10:03:11) [Clang 15.0.3 (git@github.com:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> import time; t=time.time(); print(sum(range(10**7)), time.time()-t)
49999995000000 0.8989999294281006
>>> ^D
~/cowasm/core/python-wasm$

As mentioned above, you can use python-wasm as a library in node.js. There is a synchronous api that runs in the same thread as the import, and an asynchronous api that runs in a worker thread.

~/cowasm$ . bin/env.sh 
~/cowasm$ cd core/python-wasm/
~/cowasm/core/python-wasm$ node
Welcome to Node.js v19.0.0.
Type ".help" for more information.
> python = require('.')
{
  syncPython: [AsyncFunction: syncPython],
  asyncPython: [AsyncFunction: asyncPython],
  default: [AsyncFunction: asyncPython]
}
> const { exec, repr} = await python.asyncPython();
undefined
> await repr('31**37')
'15148954872646847105498509334067131813327318808179940511'
> await exec('import time; t=time.time(); print(sum(range(10**7)), time.time()-t)')
49999995000000 0.8880000114440918

And yes you can run many async Python's in parallel in the same node.js process, with each running in its own thread:

~/cowasm/core/python-wasm$ nodeWelcome to Node.js v19.0.0.
Type ".help" for more information.
> python = require('.')
{
  syncPython: [AsyncFunction: syncPython],
  asyncPython: [AsyncFunction: asyncPython],
  default: [AsyncFunction: asyncPython]
}
> const { exec, repr} = await python.asyncPython();
undefined
> await exec('import time; t=time.time(); print(sum(range(10**7)), time.time()-t)')
49999995000000 0.8880000114440918
undefined
>
> const v = [await python.asyncPython(), await python.asyncPython(), await python.asyncPython()]; 0;
0
> s = 'import time; t=time.time(); print(sum(range(10**7)), time.time()-t)'
'import time; t=time.time(); print(sum(range(10**7)), time.time()-t)'
> d = new Date(); console.log(await Promise.all([v[0].exec(s), v[1].exec(s), v[2].exec(s)]), new Date() - d)
49999995000000 0.8919999599456787
49999995000000 0.8959999084472656
49999995000000 0.8929998874664307
[ undefined, undefined, undefined ] 905
undefined

What's the goal?

Our initial goal is to create a WebAssembly build of the core Python and dependent packages, which runs both on the command line with Node.js and in the major web browsers (via npm modules that you can include via webpack). This is done. It should also be relatively easy to build from source on both Linux and MacOS (x86_64 and aarch64) and to easily run the cpython test suite,_ with a clearly defined supported list of passing tests. The compilation system is based on Zig, which provides excellent caching and cross compilation, and each package is built using make.

How does CoWasm compare to Emscripten and Pyodide?

Pyodide currently provides far more packages. However, there is no reason that CoWasm couldn't eventually support as much or more than Pyodide.

Our main longterm application is to make CoCalc available on a much wider range of computers. As such, we are building a foundation here on which to support a substantial part of the scientific Python ecosystem and the SageMath packages (a pure math analogue of the scientific Python stack). I'm the founder of SageMath, hence this motivation (some relevant work has been done here).

Some of our code will be written in the Zig language. However, we are mostly targeting just the parts that are used for Python, which is a small subset of the general problem. Our software license -- BSD 3-clause -- is compatible with their's and we hope to at least learn from their solutions to problems.

More about how Pyodide and python-wasm differ...

More about building from source

How to build

Just type make. (Do NOT type make -j8; it probably won't work.)

...$ make

This runs a single top level Makefile that builds all the packages. The build process for each individual package is also accomplished using a Makefile with two includes that impose some structure. We don't use shell scripts or Python code to orchestrate building anything, since make is much cleaner and easier to read, maintain and debug... and of course make contains shell scripts in it. (History lesson: homebrew is a lot more successful than Macports.)

What happens

In most subdirectories foo/ of core, this makefile creates some subdirectories:

  • core/foo/dist/[native|wasm] -- a native or WebAssembly build of the package; this has binaries, headers, and libs. These get used by other packages. We rarely build the native version.
  • core/build/[native|wasm] - build artifacts for the native or WebAssembly build; can be safely deleted

No common prefix directory

Unlike some systems, where everything is built and installed into a single prefix directory, here we build everything in its own self-contained package dist directory. When a package like cpython depends on another package like lzma , our Makefile for cpython explicitly references packages/lzma/dist. This makes it easier to uninstall packages, update them, etc., without having to track what files are in any package, whereas using a common directory for everything can be a mess with possibly conflicting versions of files, and makes versioning and dependencies very explicit. Of course, it makes the environment variables and build commands potentially much longer. In some cases, we gather together files from these dist directories in distributions, e.g., see make bin-wasm.

Native and Wasm

The build typically create directories dist/nativeand dist/wasm. The dist/native artifacts are only of value on the computer where you ran the build, since they are architecture dependent and can easily depend on libraries on your system. In contrast, the dist/wasm artifacts are platform independent. They can be used nearly everywhere: on servers via WASM, on ARM computers (e.g., aarch64 linux, Apple Silicon, etc.), and in modern web browsers.

Standalone WASM executables

The bin directory has scripts zcc and z++ that are C and C++ compiler wrappers around Zig + Node. They create binaries that you can run on the command line as normal. Under the hood there's a wrapper script that calls node.js and the wasi runtime.

$ . bin/env.sh
$ echo 'int main() { printf("hello from Web Assembly: %d\n", 2+2); }' > a.c
$ zcc a.c
$ ls -l
a.c  a.out  a.out.wasm  ...
$ ./a.out   # this actually runs nodejs + python-wasm
hello from Web Assembly: 4

This isn't currently used here for building python-wasm, but it's an extremely powerful tool. (For example, I used it with JSage to cross compile the NTL library to Web Assembly...)

Run a script from the terminal:

~/cowasm$ echo "import sys; print(f'hi from {sys.platform}')" > a.py
~/cowasm$ bin/python-wasm a.py
hi from wasi

The python-wasm package has a bin/python-wasm script that can run Python programs that including interactive blocking input:

~/cowasm/core/python-wasm$ echo "name = input('name? '); print(name*3)" > a.py
~/cowasm/core/python-wasm$ ./bin/python-wasm a.py
name? william
williamwilliamwilliam

Contact

Email [email protected] or @wstein389 if find this interesting and want to help out.

CoWasm is an open source 3-clause BSD licensed project. It includes components and dependencies that may be licensed in other ways, but nothing is GPL licensed, except some code in the sagemath subdirectory (which nothing else depends on).

cowasm's People

Contributors

bobuk avatar oroppas avatar rgl avatar williamstein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cowasm's Issues

Does cowasm support threads?

Hi, thanks for this wonderful effort.

I was wondering if I can use multithreaded WASI wasm module compiled from Rust. Would it be possible? If not, is that kind of PR acceptable?

support time.sleep properly

In Pyodide doing import time; time.sleep(10) just silently does nothing right now. See pyodide/pyodide#2354 for their discussion.

I've seen some other python wasm shell somewhere online that just spun the cpu 100% for approx 10 seconds.

On python-wasm here it gives an oserror.

The solution for python-wasm is just to properly implement whatever select system call is required, which should be completely straightforward given our model.

strange issue with a static variable

In packages/cpython/build/wasm/Python/ceval.c there is a function

int
_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
{
    assert(is_tstate_valid(tstate));
    /* The caller must hold the GIL */
    assert(PyGILState_Check());

    static int reentrant = 0;
    if (reentrant) {
        _PyErr_SetString(tstate, PyExc_RuntimeError, "Cannot install a profile function "
                         "while another profile function is being installed");
        reentrant = 0;
        return -1;
    }
    reentrant = 1;
...

It's called the first time when you do this:

~/python-wasm/packages/cpython$ pw-d
Welcome to Node.js v18.9.0.
Type ".help" for more information.
> Python 3.11.0rc1 (main, Sep 14 2022, 08:57:39) [Clang 14.0.6 (git@github.com:ziglang/zig-bootstrap.git 9dd8ca3a7f80f1677f1ad4d5 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> import cProfile; pr = cProfile.Profile()
>>> pr.enable()
_PyEval_SetProfile being called and reentrant = 19  // requires editing "ceval.c" to see this
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: Cannot install a profile function while another profile function is being installed

For some reason the value of reentrant is initially 19, which can't happen.... unless there is some sort of memory corruption somewhere nearby. So this indicates some sort of subtle bug.

create new directory of packages that depend on core and python

Right now some core/ packages depend on python/ for good reason, e.g., dash-wasm, since we want to include python-wasm in the dash-wasm environment. Actually that might be the only one. This makes it so building just core involves building a lot of python stuff, e.g., numpy.

Fix this. The question is where should dash-wasm go? I don't know yet.

windows is not support?

Hi, I tried, it seems could not run on windows.

C:\Users\Liu.D.H>npx python-wasm
Need to install the following packages:
  python-wasm
Ok to proceed? (y)
/bin/bash: C:\Users\Liu.D.H\AppData\Local\npm-cache\_npx\3e7b7466c13fbc48\node_modules\.bin\..\python-wasm\bin\zython: No such file or directory

C:\Users\Liu.D.H>where npx
C:\Program Files\nodejs\npx
C:\Program Files\nodejs\npx.cmd
C:\Users\Liu.D.H\AppData\Roaming\npm\npx
C:\Users\Liu.D.H\AppData\Roaming\npm\npx.cmd

C:\Users\Liu.D.H>
C:\Users\Liu.D.H>npm i -g python-wasm

added 27 packages, and audited 28 packages in 1s

5 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

C:\Users\Liu.D.H>python-wasm
/bin/bash: C:\Users\Liu.D.H\AppData\Roaming\npm\node_modules\python-wasm\bin\zython: No such file or directory

C:\Users\Liu.D.H>
C:\Users\Liu.D.H>node -v
v18.4.0

C:\Users\Liu.D.H>npm -v
8.5.1

C:\Users\Liu.D.H>

Compatibility with Emscriptenforge, Pyodide, Pyscript?

  • Does cowasm intend to invent a new WASM packaging format?
  • Will it be possible to use pyodide packages with cowasm?
  • Will it be possible to use cowasm packages with pyodide (pyscript,)?
  • Cocalc is composed of conda packages (from conda-forge?) now
  • Conda-forge noarch packages can be installed with emscriptenforge without modification
  • Emscriptenforge WASM packages are built with empack, hosted on Quetz, and installed with picomamba
  • Will cowasm be able to use emscriptenforge packages?

.

Reusable interpreters by save/restore state

As background, I have a long tutorial about test-first development for browser-Python with Vitest. It has a section on speeding up test runs to use one interpreter instance for all tests.

I'm interested in writing a variation of that tutorial, using cowasm. Does it have a story for resetting an interpreter to a known, saved state in NodeJS?

As an aside, can you have multiple interpreters, in Node and/or browser?

start sagemath port

This will be something to do once (or if) numpy builds and works using zig. I say "or if", since it's not guaranteed this will ever happen, e.g., my current status is llvm segfaulting.

In any case, "start the sagemath port" is really something that would happen in a new repo, and is about building important dependencies of sage, e.g., like I started in https://github.com/sagemathinc/jsage (pari, gmp, etc.). The architecture will be:

  1. python-wasm -- this repo -- really just a way to build CPython+dylink support for WASM in the browser and node using zig+node.js. This is just the small core which is why this has a very boring name. It's just yet another build of cpython and a tiny bit more.
  2. unknown name, maybe scientific-python-wasm -- will be a new repo with non-core scientific packages (cython, sympy, numpy, etc.), and a similar scope to pyodide. This will depend on 1.
  3. unknown name, maybe sage-python-wasm -- we be yet another repo dedicated to building packages for wasm that are needed for sagemath. A relevant trac ticket is here: https://trac.sagemath.org/ticket/34539

support bun as an alternative to nodejs for the server runtime environment

Currently we use node.js for tooling and running python-wasm on the command line.

However, there is a new project https://bun.sh/ that is similar to Node.js, but written using Zig instead of C/C++. Since (1) we're also using Zig and typescript extensively for python-wasm, and (2) bun is very fast and modern with native typescript support, it would be natural to use bun for python-wasm, at least optionally. It might me faster startup times, faster execution, etc., and also easier to read code if we want to dive into the runtime itself. A blocker prerequisite for this is WebWorker support, which bun.sh does NOT have. It's on the roadmap here:

oven-sh/bun#159

native Microsoft Windows command line python-wasm terminal

Right now with a native windows terminal and node.js 16 official binaries, you can install python-wasm:

npm install python-wasm

and start the CLI and use it as follows:

node> require('python-wasm').terminal()
...
> Python ...
>>> import math
>>> math.[tab] works

Amazingly, readline (hence tab completion, line editing, etc.,) actually fully works. However, it's tedious to have to type node, then require, etc., to start things. The point of this issue is just to provide a script like bin/python-wasm that directly starts the cli. I'm not sure how important this is...

Build fails on Arch Linux

Hi,

I haven't been able to figure out why the build fails on my side. In the log:

LOG from webpack.FileSystemInfo
<w> Managed item /home/ryutas/packages/cowasm/cowasm/packages/browser/node_modules/python-wasm isn't a directory or doesn't contain a package.json (see snapshot.managedPaths option)
+ 12 hidden lines

and

ryutas@archlinux ~/packages/cowasm/cowasm
ls -l packages/browser/node_modules/python-wasm
lrwxrwxrwx 1 ryutas ryutas 17 Jan 20 07:16 packages/browser/node_modules/python-wasm -> ../../python-wasm

but I don't see any pytnon-wasm in packages directory. Am I missing something?
Any advice will be greatly appreciated. Thank you!

Here is the full log:

ryutas@archlinux ~/packages/cowasm/cowasm
make
./bin/make-all all packages/browser/ packages/build/ packages/bzip2/ packages/coreutils/ packages/cowasm.org/ packages/cowasm.sh/ packages/dash/ packages/dash-wasm/ packages/dylink/ packages/f2c/ packages/kernel/ packages/less/ packages/libedit/ packages/libffi/ packages/libgit2/ packages/libpng/ packages/lua/ packages/luatex/ packages/lzma/ packages/man/ packages/ncurses/ packages/openssl/ packages/posix-browser/ packages/posix-node/ packages/posix-wasm/ packages/rogue/ packages/sqlite/ packages/tar/ packages/termcap/ packages/terminal/ packages/viz/ packages/wasi-js/ packages/wasm-opt/ packages/zlib/

TARGET=$1
shift
ROOTDIR=`pwd`

for PACKAGE in $*
do
    cd "$ROOTDIR/$PACKAGE"
    echo $PACKAGE
    if [ $TARGET = "all" ]; then
        make
    else
        make $TARGET
    fi
done
packages/browser/
make[1]: Entering directory '/home/ryutas/packages/cowasm/cowasm/packages/browser'
npm ci

added 471 packages, and audited 1886 packages in 12s

102 packages are looking for funding
  run `npm fund` for details

1 high severity vulnerability

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
npm run build

> @cowasm/[email protected] build
> webpack

asset main.bundle.js 461 KiB [compared for emit] (name: main)
asset index.html 246 bytes [compared for emit]
runtime modules 1.13 KiB 5 modules
modules by path ./node_modules/ 156 KiB
  modules by path ./node_modules/assert/build/ 67.8 KiB 4 modules
  modules by path ./node_modules/object-is/*.js 1.14 KiB 4 modules
  modules by path ./node_modules/is-nan/*.js 1.2 KiB 4 modules
  modules by path ./node_modules/util/ 27.9 KiB 3 modules
  modules by path ./node_modules/object-keys/*.js 4.36 KiB 3 modules
  modules by path ./node_modules/debug/src/*.js 12 KiB 2 modules
  modules by path ./node_modules/call-bind/*.js 1.68 KiB 2 modules
  modules by path ./node_modules/function-bind/*.js 1.55 KiB 2 modules
  modules by path ./node_modules/has-symbols/*.js 2.13 KiB 2 modules
  + 18 modules
modules by path ./src/*.ts 9.31 KiB
  ./src/index.ts 2.94 KiB [built] [code generated]
  ./src/python.ts 6.37 KiB [built] [code generated] [1 error]

LOG from webpack.FileSystemInfo
<w> Managed item /home/ryutas/packages/cowasm/cowasm/packages/browser/node_modules/python-wasm isn't a directory or doesn't contain a package.json (see snapshot.managedPaths option)
+ 12 hidden lines

ERROR in ./src/python.ts 38:0-37
Module not found: Error: Can't resolve 'python-wasm' in '/home/ryutas/packages/cowasm/cowasm/packages/browser/src'
 @ ./src/index.ts 39:0-30 46:37-43

ERROR in /home/ryutas/packages/cowasm/cowasm/packages/browser/src/kernel.ts
3:28-44
[tsl] ERROR in /home/ryutas/packages/cowasm/cowasm/packages/browser/src/kernel.ts(3,29)
      TS2306: File '/home/ryutas/packages/cowasm/cowasm/packages/kernel/index.d.ts' is not a module.

ERROR in /home/ryutas/packages/cowasm/cowasm/packages/browser/src/python.ts
./src/python.ts 3:23-36
[tsl] ERROR in /home/ryutas/packages/cowasm/cowasm/packages/browser/src/python.ts(3,24)
      TS2307: Cannot find module 'python-wasm' or its corresponding type declarations.
 @ ./src/index.ts 39:0-30 46:37-43

3 errors have detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.

webpack 5.73.0 compiled with 3 errors in 1720 ms
make[1]: *** [Makefile:9: /home/ryutas/packages/cowasm/cowasm/packages/browser/dist/.built] Error 1
make[1]: Leaving directory '/home/ryutas/packages/cowasm/cowasm/packages/browser'
make: *** [Makefile:10: all] Error 2

AttributeError: module 'os' has no attribute 'waitstatus_to_exitcode'

Figure out why this happens. This gets hit very easily, e.g., in the terminal:

>>> import math; help(math)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<frozen _sitebuiltins>", line 103, in __call__
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 2005, in __call__
    # special case these keywords since they are objects too
^^^^^^^^^^^^^^^^^^
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 2064, in help
    ''')
         
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 1788, in doc
    'global': ('global', 'nonlocal NAMESPACES'),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 1560, in pager
    # We've hereby abandoned whatever text hasn't been written,
^^^
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 1585, in <lambda>
    
     
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/pydoc.py", line 1604, in pipepager
    try:
    ^^^^^
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/subprocess.py", line 736, in <module>
    if not _can_fork_exec:
^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/subprocess.py", line 1893, in Popen
    delay = 0.0005 # 500 us -> initial delay of 1 ms
                                          ^^^^^^^^^^^
AttributeError: module 'os' has no attribute 'waitstatus_to_exitcode'

Obviously creating a subprocess like this isn't the optimal way to do paging in python-wasm; maybe there is an option or flag to python that changes the behavior?

Optimize wasm files with wasm-opt

I noticed that the wasm files on the website are not optimized with wasm-opt. E.g. running wasm-opt -O on b5423d0ccb3dd1ef21ca.wasm leads to a 5% code size reduction. (There might also be a speed benefit, as e.g. it ends up removing around 10% of total functions - unless those were entirely unused before, they'd be inlined now.)

Not a big deal of course, just wanted to mention this as a possible improvement. Also it might be nice to port wasm-opt itself with CoWasm, and then optimize the website with those.

Really cool project btw!

wasi-js getImportObject

Hi! Thanks for this. I'm looking at the wasi-js example, and wondering where can get the value of wasmOpts here?

import { WASI } from "wasi-js";
import fs from "fs";
import nodeBindings from "wasi-js/dist/bindings/node";

const wasi = new WASI({
  args: [],
  env: {},
  bindings: {...nodeBindings, fs},
});

const source = await readFile(pathToWasm);
const typedArray = new Uint8Array(source);
const result = await WebAssembly.instantiate(typedArray, wasmOpts); // where can we wasmOpts
wasi.start(result.instance);

I tried looking at the WASI implementation of node 20 and tried to do it as well - but it is undefined:

const result = await WebAssembly.instantiate(typedArray, wasi.getImportObject()); // getImportObject is undefined

Any tips? Thank you!

idea to make initial loading in a webpage much faster (mainly for repl).

Here's what is actually accessed on init:

~/python-wasm/packages/python-wasm$ npx jest dist/wasm/posix/stdlib.test.js
  console.log
    mapFlags openSync / 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /pybuilddir.txt 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11/encodings/__init__.pyc 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11/encodings 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11/encodings/aliases.pyc 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11/encodings/utf_8.pyc 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log
    mapFlags openSync /usr/lib/python3.11/lib-dynload 0 undefined

      at Object.openSync (../wasi/src/fs.ts:156:13)

  console.log

Maybe we can make a python-init.zip that is TINY and includes only those files. The main python.zip is only extracted and mounted slightly later after python has started...

wasix: a relevant project

There is something called WASIX that is "an effort to port legacy POSIX APIs (including many with questionable design such as fork()) to WASM." This is a relevant issue in the Zig repo -- ziglang/zig#17115

CoWasm itself is also an effort written in zig to port legacy POSIX APIs (including many with questionable design such as fork()) to WASM. So discussions about WASIX are relevant to this project.

The functionality WASIX claims to have in their blog post https://wasmer.io/posts/announcing-wasix seems in some cases to be significantly more than Cowasm, e.g., actual pthreads support (?).

support signals... at least SIGINT so you can use control+c to interrupt a running computation

One example where work is needed is

this.stdinBuffer = this.waitForStdin();

in wasi.ts. The above will wait forever for stdin, but should only wait the specified amount
of time. For Python in python-wasm/packages/cpython/build/wasm/Modules/readline.c it looks like the amount of time is 0.1 seconds... and after that time, there is an explicit call to check for signals. That said, maybe we'll just end the waitForStdin when there is a signal.

cowasm.sh: sometimes running python more than once leads to "Fatal Python error: init_sys_streams: can't initialize sys standard streams"

This is presumably just some state involving /sys/stdout, /sys/stdin, etc. with our "run a subprocess" functionality.

It happened in this session using https://cowasm.sh

Type 'ls /usr/bin' for a list of commands, including python (with numpy), lua, sqlite3, date, and du.
This is new and *many* things are not implemented.  Output redirection and capture is not implemented.
Visit https://github.com/sagemathinc/cowasm and contribute.

sh$ hanoi
sh$ viz
Name collision 'xterm-new' between
        xf|xterm-new|modern xterm:,
and     xf|xterm-new|modern xterm:,
...now  modern xterm:,
Cannot remove alias 'modern xterm:,'
Name collision 'xterm-basic' between
        xb|xterm-basic|modern xterm common:,
and     xb|xterm-basic|modern xterm common:,
...now  modern xterm common:,
Cannot remove alias 'modern xterm common:,'
Name collision 'xterm-vt220' between
        vt|xterm-vt220|xterm emulating vt220:,
and     vt|xterm-vt220|xterm emulating vt220:,
...now  xterm emulating vt220:,
Cannot remove alias 'xterm emulating vt220:,'
Name collision 'xterm-24' between
        v1|xterm-24|xterms|vs100|24x80 xterm:,
and     v1|xterm-24|xterms|vs100|24x80 xterm:,
...now  xterms|vs100|24x80 xterm:,
...now  vs100|24x80 xterm:,
...now  24x80 xterm:,
Cannot remove alias '24x80 xterm:,'
Name collision 'xterm-65' between
        v2|xterm-65|65x80 xterm:,
and     v2|xterm-65|65x80 xterm:,
...now  65x80 xterm:,
Cannot remove alias '65x80 xterm:,'
Name collision 'xterm-bold' between
        vb|xterm-bold|xterm with bold for underline:,
and     vb|xterm-bold|xterm with bold for underline:,
...now  xterm with bold for underline:,
Cannot remove alias 'xterm with bold for underline:,'
Name collision 'xterm-boldso' between
        vB|xterm-boldso|xterm with bold for standout:,
and     vB|xterm-boldso|xterm with bold for standout:,
...now  xterm with bold for standout:,
Cannot remove alias 'xterm with bold for standout:,'
Name collision 'xterm-mono' between
        vm|xterm-mono|monochrome xterm:,
and     vm|xterm-mono|monochrome xterm:,
...now  monochrome xterm:,
Cannot remove alias 'monochrome xterm:,'
Name collision 'xterm-noapp' between
        xn|xterm-noapp|xterm with cursor keys in normal mode:,
and     xn|xterm-noapp|xterm with cursor keys in normal mode:,
...now  xterm with cursor keys in normal mode:,
Cannot remove alias 'xterm with cursor keys in normal mode:,'
Name collision 'xterm-color' between
        vc|xterm-color|generic "ANSI" color xterm:,
and     vc|xterm-color|generic "ANSI" color xterm:,
...now  generic "ANSI" color xterm:,
Cannot remove alias 'generic "ANSI" color xterm:,'
Name collision 'xterm-16color' between
        x1|xterm-16color|xterm alias:,
and     x1|xterm-16color|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-88color' between
        x2|xterm-88color|xterm alias:,
and     x2|xterm-88color|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-direct' between
        x4|xterm-direct|xterm alias:,
and     x4|xterm-direct|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-nrc' between
        xi|xterm-nrc|xterm alias:,
and     xi|xterm-nrc|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-rep' between
        xr|xterm-rep|xterm alias:,
and     xr|xterm-rep|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-xmc' between
        xx|xterm-xmc|xterm alias:,
and     xx|xterm-xmc|xterm alias:,
...now  xterm alias:,
Cannot remove alias 'xterm alias:,'
Name collision 'xterm-8bit' between
        x8|xterm-8bit|xterm terminal emulator 8-bit controls (X Window System):,
and     x8|xterm-8bit|xterm terminal emulator 8-bit controls (X Window System):,
...now  xterm terminal emulator 8-bit controls (X Window System):,
Cannot remove alias 'xterm terminal emulator 8-bit controls (X Window System):,'
Name collision 'xterm-hp' between
        hp|xterm-hp|xterm with hpterm function keys:,
and     hp|xterm-hp|xterm with hpterm function keys:,
...now  xterm with hpterm function keys:,
Cannot remove alias 'xterm with hpterm function keys:,'
Name collision 'xterm-sco' between
        xS|xterm-sco|xterm with SCO function keys:,
and     xS|xterm-sco|xterm with SCO function keys:,
...now  xterm with SCO function keys:,
Cannot remove alias 'xterm with SCO function keys:,'
Name collision 'xterm-vt52' between
        v5|xterm-vt52|xterm emulating vt52:,
and     v5|xterm-vt52|xterm emulating vt52:,
...now  xterm emulating vt52:,
Cannot remove alias 'xterm emulating vt52:,'
Name collision 'xterm-sun' between
        xs|xterm-sun|xterm with Sun functionkeys:,
sh$ python
Python 3.11.0 (main, Nov  3 2022, 20:56:18) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
sh$ python
Python 3.11.0 (main, Nov  3 2022, 20:56:18) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> ^D
sh$ python
Python 3.11.0 (main, Nov  3 2022, 20:56:18) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> import json
>>> json.dumps(range(100))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/cowasm/packages/cpython/build/wasm/Lib/json/__init__.py", line 231, in dumps
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/cowasm/packages/cpython/build/wasm/Lib/json/encoder.py", line 200, in encode
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/cowasm/packages/cpython/build/wasm/Lib/json/encoder.py", line 258, in iterencode
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/cowasm/packages/cpython/build/wasm/Lib/json/encoder.py", line 180, in default
TypeError: Object of type range is not JSON serializable
>>> json.dumps(list(range(100)))
'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]'
>>> json.dumps(list(range(1000)))
'[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999]'
>>> 
>>> 
>>> 
>>> open('a.json').write(json.dumps(list(range(1000))))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 44] No such file or directory: 'a.json'
>>> open('/tmp/a.json').write(json.dumps(list(range(1000))))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 44] No such file or directory: '/tmp/a.json'
>>> open('a.json','w').write(json.dumps(list(range(1000)))) 
4890
>>> ^D
sh$ ls
a.json dev    usr
sh$ ls -l
total 9
----------  1 0  0  4890 Nov  4 04:20 a.json
d---------  1 0  0     0 Nov  4 04:14 dev
d---------  1 0  0     0 Nov  4 04:14 usr
sh$ cat a.json
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999]sh$ 
sh$ 
sh$ 
sh$ 
sh$ 
sh$ python3
sh: 18: python3: not found
sh$ python 
Fatal Python error: init_sys_streams: can't initialize sys standard streams
Python runtime state: core initialized
OSError: [Errno 8] Bad file descriptor

Current thread 0x00131d10 (most recent call first):
  <no Python frame>
sh$ 

switch to pnpm

This is #50

The main significant remaining issues is that we need to automate building the dependencies, since
sibling packages are now installed directly, rather than from npm. This happens automatically and
is awesome! It does mean some additional work. Maybe a script that just automates building deps,
as determined by parsing what is installed.

Also, we'll need to update the docs, and make sure pnpm is installed. We might instead use pnpm env to
have pnpm install node instead. Hmmm...

This problem of building the deps in a workspace also comes up in CoCalc and isn't totally solved there either.
For that it's maybe a lot harder due to circular deps? In any case, I wonder if there is a common solution.

improve os.popen stub

Right now attempts to use os.popen crash the entire python process:

~/python-wasm/packages/cpython$ ../../bin/python-wasm 
Welcome to Node.js v16.13.0.
Type ".help" for more information.
> iPython 3.11.0b3 (main, Jul 23 2022, 06:21:39) [Clang 13.0.1 (git@github.com:ziglang/zig-bootstrap.git 623481199fe17f4311cbdbbf on wasi
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.popen('ls')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<frozen os>", line 986, in popen
  File "/Users/wstein/build/cocalc/src/data/projects/2c9318d1-4f8b-4910-8da7-68a965514c95/python-wasm/packages/cpython/build/wasm/Lib/subprocess.py", line 805, in __init__
OSError: [Errno 58] wasi does not support processes.
>>> 
~/python-wasm/packages/cpython$ 

It would be better if instead you see an error but the whole process doesn't exit. This must be possible, and might just involve improving whatever stub is being called.

The above error message comes from:

lib/python3.11/subprocess.py:                errno.ENOTSUP, f"{sys.platform} does not support processes."

sqlite doesn't work when using the filesystem

Currently the sqlite in cowasm works fine when used in memory. However, if you instead try to use it with the filesystem, there are problems.

I noticed that this post about yet another python.wasm build says they have a modified sqlite they build. Maybe it has a solution to my problem?

wasi-js: warnings are printed to stdout

Hello,

I just switched from wasmer to wasi-js in the WasiCaml project (https://github.com/remixlabs/wasicaml). There are a lot of scripts running WASI-fied wasm code, and some of them also write to stdout. I found in the stdout of one script the string

cpu waiting for stdin: please define a way to sleep!

which causes the further build to fail. Obviously, this warning is from wasi-js and printed with console.log which goes to stdout. For scripting, this is very unfortunate - whereas messages in stderr are typically no problem. Can you switch to console.warn or console.error instead?

Btw, thanks for picking the code up and maintaining it.

make service worker use its own python-wasm scope so it doesn't conflict with other service workers

We finally have service workers working, e.g., at https://python-wasm.org. However, they just use the / scope. This would presumably conflict with embedding python-wasm into sites that have their own service worker at that scope, e.g., https://cocalc.com has a service worker at /.

That said, it's not clear to me that python-wasm is ever going to be embedded not as an iframe in other web applications, and if it is embedded as an iframe, I think the scope issue goes away. Anyway, recording this here for future thought.

Support importing host functions

Hello... EXCELLENT project you've got here. I'm the founder of Suborbital, and we're currently investigating different ways to support Python in our E2 Core project and our SE2 platform. This project seems like it would be a very good method.

In order to use this, I'd love to know if it's currently possible to import functions from the Wasm host? We use Wasmtime, and have a set of host functions that we make available to the runtime (such as making HTTP requests, etc), and in other languages like Rust, you can import these host-provided functions to call them. (example from our SDK)

If this is possible, I'd love to learn how, and we'd love to build a prototype of Python support using zython.

If it's not possible, we'd love to contribute to the project and help out any way we can (code, testing, sponsorship, anything!)

Please let me know :)

make the web terminal demo a bit nicer

  • ability to select theme and font size (persist in localStorage)
  • dynamically resize to browser dimensions
  • make the header, etc., links cleaner
  • add a favicon (maybe python's since this is literally unpatched cpython running)

upgrade to mpmath 1.3

After many years, mpmath is now at version 1.3! (Instead of 1.0.)

It would be nice to upgrade cowasm to use it. Installing it is fine, but the test suite now uses pytest, so actually running the test suite is the blocker now for this issue.

dash: pipes are not working - RuntimeError: unreachable

this will crash the shell at https://cowasm.sh/

seq 1 10 | head -n 1

js console

658.bundle.js:2 /usr/bin/sh RuntimeError: unreachable
    at growjobtab (wasm://wasm/00521052)
    at makejob (wasm://wasm/00521052)
    at evalpipe (wasm://wasm/00521052)
    at evaltree (wasm://wasm/00521052)
    at cmdloop (wasm://wasm/00521052)
    at main (wasm://wasm/00521052)
    at e.default.run (658.bundle.js:2:52854)
    at Object.cowasm_vforkexec (658.bundle.js:2:4329)
    at n.<computed> (658.bundle.js:2:6410)
    at /aa318ea0a6040fd50963.wasm

in npx dash-wasm: after the cat command, subsequent commands have problems with stdout

(a probably related issue: #42 )

// error when I used dash-wasm that was installed by npm

cd ~/10-cowasm/node_modules/dash-wasm

npx dash-wasm -x

(cowasm)$ cat wrongname1
+ cat wrongname1
cat: wrongname1: No such file or directory

(cowasm)$ cat wrongname1
+ cat wrongname1
cat: wrongname1: No such file or directory
cat: stdout: Bad file descriptor


(cowasm)$ cat /cowasm/usr/share/termcap
+ cat /cowasm/usr/share/termcap
cat: stdout: Bad file descriptor


(cowasm)$ echo abc
+ echo abc
sh: 4: echo: echo: I/O error


(cowasm)$ python
+ python
Python 3.11.0 (main, Nov 29 2022, 20:26:05) [Clang 15.0.3 ([email protected]:ziglang/zig-bootstrap.git 0ce789d0f7a4d89fdc4d9571 on wasi
Type "help", "copyright", "credits" or "license" for more information.

# i cannot see what i am typing
# 78*89
# aaaaaaaaa
# quit()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 8] Bad file descriptor

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'aaaaaaaaa' is not defined

Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
OSError: [Errno 8] Bad file descriptor


(cowasm)$

(in browser, commands work correctly)

(but with 1 extra error message)

EDIT I have cut this chapter into a comment

(in a built dash, and using only the cat from the tar package, no errors)

EDIT I have cut this chapter into a comment

LATER: bin/cat from fs.zip ... errors even when I bypassed dash-wasm ... when I ran it from npx kernel dash

in a comment

LATER: the built ./cat from the tar package ... works ok even when I ran it from npx dash-wasm

in a comment

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.