This adds the altair packages and closes#4579. I wasn't sure what tests would be appropriate, it seems like some package like mpl, pandas, etc tests very specific things whereas others such as shapely, bokeh, statsmodels, etc keep it more minimal. I started minimal for now but happy to add more if there are issues.
Consider the code:
```js
pyodide.runPython(`
def a():
raise Exception("hi")
def b():
return 7;
`);
const a = pyodide.globals.get("a");
const b = pyodide.globals.get("b");
const p = a.callSyncifying();
assert(b() === 7);
await p;
```
This used to misbehave because because a()'s error status got stolen by b().
This happened because the promising function is a separate task from the js code
in callPyObjectSuspending, so the sequence of events goes:
- enter main task,
- enter callPyObjectSuspending(a)
- enter promisingApply(a)
- sets error flag and returns NULL
- queue continue callPyObjectSuspending(a) in event loop
now looks like [main task, continue callPyObjectSuspending(a)]
- enter b()
- enter Python
- returns 7 with error state still set
- rejects with "SystemError: <function b at 0x1140f20> returned a result with an exception set"
- queue continue main() in event loop
- continue callPyObjectSuspending(a)
- pythonexc2js called attempting to read error flag set by promisingApply(a), fails with
PythonError: TypeError: Pyodide internal error: no exception type or value
The solution: at the end of `_pyproxy_apply_promising` we move the error
flag into errStatus argument. In callPyObjectSuspending when we're ready we
move the error back from the errorStatus variable into the error flag before
calling `pythonexc2js()`
The only behavior change here should be that we are setting `sys.last_exc`
(added in Python3.12). Since we haven't released with Python 3.12 yet, this
doesn't need a changelog.
Python 3.12 added a bunch of modern APIs that handle a single exception object
rather than the (type, val, tb) triples. They also repaired various quirks of
the old error handling APIs. They are much easier to work with. Also, now that
we have `capture_stderr` and `restore_stderr` we can use `PyErr_Print()` to
format the traceback. This allows us to cut out a fair amount of code in
error_handling.c.
This now uses `sys.excepthook` to format exceptions. We set `sys.excepthook` to
`traceback.print_exception` because the default excepthook does not respect the
linecache which we use to implement `pyodide.runPython("...", {file:
"some_file.py"});`
The Sage library uses IPython.lib.pretty
Patches for making at least import IPython work
on Pyodide have been upstreamed in 8.22
The other added packages are dependencies of IPython.
Most of these cases it would have thrown an error all along and this just adds a clearer error message. The only case where this adds a new error is if the directory is nonempty but is not a file system root. But in that case, it's unexpected that it overwrites the original directory contents. The documentation says:
> If it does exist, it must be empty.
So people might reasonably expect us to throw an error in that case rather than silently overwriting.
When bumping the protobuf package, it turned out that it wasn't trivial.
I therefore decided to split adding the tests and bumping the version in two PR's. That
way these tests could be merged first, and act as a nice regression test.
This should make debugging these failures way easier.
Example output:
```
leaked proxies:
tuple (1, 2) Traceback at creation:
at trace_pyproxy_alloc (/home/rchatham/Documents/programming/pyodide/dist/pyodide.asm.js:3640:23)
...
```
This updates `pystate.c` to save and restore the current event loop task. This allows us to stack switch out of one async task and then block for the completion of another async task.
We also add `callPyObjectMaybeSuspending` which uses `promisingApply` if stack switching is available and otherwise makes a normal call. We add a private keyword argument `_may_syncify` to `create_once_callable` and have the event loop use this so async tasks can stack switch. We also make the promise handles use `callPyObjectMaybeSuspending` so that `promise.then`, `promise.finally_`, etc can use stack switching.
xfail sisl and bokeh tests on firefox since they time out.
make a separate test that loads sisl and does nothing else to separate the loading time from the testing time.