Revert "Upgrade Pyodide to version 0.28.3"

This reverts commit 73471b397f.
This commit is contained in:
Feodor Fitsner 2025-09-26 11:22:32 -07:00
parent 73471b397f
commit 7be5c21e14
14 changed files with 68 additions and 400 deletions

View File

@ -1,8 +1,5 @@
// Generated by dts-bundle-generator v8.1.2
/**
* @docgroup pyodide.ffi
*/
export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
interface PyProxy {
[x: string]: any;
@ -40,7 +37,7 @@ declare class PyProxy {
get type(): string;
/**
* Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to
* :js:func:`~exports.loadPyodide` in which case it will return `repr(o)`)
* :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`)
*/
toString(): string;
/**
@ -74,7 +71,7 @@ declare class PyProxy {
* @param options
* @return The JavaScript object resulting from the conversion.
*/
toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, eager_converter, }?: {
toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, }?: {
/** How many layers deep to perform the conversion. Defaults to infinite */
depth?: number;
/**
@ -109,15 +106,6 @@ declare class PyProxy {
* documentation of :meth:`~pyodide.ffi.to_js`.
*/
default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any;
/**
* Optional callback to convert objects which gets called after ``str``,
* ``int``, ``float``, ``bool``, ``None``, and ``JsProxy`` are converted but
* *before* any default conversions are applied to standard data structures.
*
* Its arguments are the same as `dict_converter`.
* See the documentation of :meth:`~pyodide.ffi.to_js`.
*/
eager_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any;
}): any;
}
/**

View File

@ -1,6 +1,6 @@
{
"name": "pyodide",
"version": "0.28.3",
"version": "0.27.5",
"description": "The Pyodide JavaScript package",
"keywords": [
"python",
@ -14,10 +14,9 @@
"bugs": {
"url": "https://github.com/pyodide/pyodide/issues"
},
"license": "MPL-2.0",
"license": "Apache-2.0",
"devDependencies": {
"@types/assert": "^1.5.6",
"@types/emscripten": "^1.40.1",
"@types/expect": "^24.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^20.8.4",
@ -26,7 +25,7 @@
"chai-as-promised": "^7.1.1",
"cross-env": "^7.0.3",
"dts-bundle-generator": "^8.1.1",
"esbuild": "^0.25.0",
"esbuild": "^0.17.12",
"express": "^4.17.3",
"mocha": "^9.0.2",
"npm-run-all": "^4.1.5",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,14 @@
// Generated by dts-bundle-generator v8.1.2
/**
*
* The Pyodide version.
*
* The version here is a Python version, following :pep:`440`. This is different
* from the version in ``package.json`` which follows the node package manager
* version convention.
*/
export declare const version: string;
interface CanvasInterface {
setCanvas2D(canvas: HTMLCanvasElement): void;
getCanvas2D(): HTMLCanvasElement | undefined;
@ -26,9 +35,6 @@ declare function setStderr(options?: {
write?: (buffer: Uint8Array) => number;
isatty?: boolean;
}): void;
/**
* @docgroup pyodide.ffi
*/
/** @deprecated Use `import type { TypedArray } from "pyodide/ffi"` instead */
export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
type FSNode = {
@ -38,9 +44,7 @@ type FSNode = {
mode: number;
};
type FSStream = {
tty?: {
ops: object;
};
tty?: boolean;
seekable?: boolean;
stream_ops: FSStreamOps;
node: FSNode;
@ -53,107 +57,45 @@ type FSStreamOpsGen<T> = {
read: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number;
write: (a: T, b: Uint8Array, offset: number, length: number, pos: number) => number;
};
/** @deprecated Use `import type { PyodideFSType } from "pyodide/ffi"` instead */
interface PyodideFSType {
interface FSType {
unlink: (path: string) => void;
mkdirTree: (path: string, mode?: number) => void;
chdir: (path: string) => void;
symlink: (target: string, src: string) => FSNode;
createDevice: ((parent: string, name: string, input?: (() => number | null) | null, output?: ((code: number) => void) | null) => FSNode) & {
major: number;
};
closeStream: (fd: number) => void;
open: (path: string, flags: string | number, mode?: number) => FSStream;
makedev: (major: number, minor: number) => number;
mkdev: (path: string, dev: number) => FSNode;
filesystems: any;
stat: (path: string, dontFollow?: boolean) => any;
readdir: (path: string) => string[];
isDir: (mode: number) => boolean;
isMountpoint: (mode: FSNode) => boolean;
lookupPath: (path: string, options?: {
follow_mount?: boolean;
}) => {
node: FSNode;
};
open: (path: string, flags: string | number, mode?: number) => FSStream;
filesystems: any;
isMountpoint: (node: FSNode) => boolean;
closeStream: (fd: number) => void;
registerDevice<T>(dev: number, ops: FSStreamOpsGen<T>): void;
isFile: (mode: number) => boolean;
writeFile: (path: string, contents: any, o?: {
canOwn?: boolean;
}) => void;
}
type FSType = Omit<typeof FS, "lookupPath"> & PyodideFSType;
/**
* The lockfile platform info. The ``abi_version`` field is used to check if the
* lockfile is compatible with the interpreter. The remaining fields are
* informational.
*/
interface LockfileInfo {
/**
* Machine architecture. At present, only can be wasm32. Pyodide has no wasm64
* build.
*/
arch: "wasm32";
/**
* The ABI version is structured as ``yyyy_patch``. For the lockfile to be
* compatible with the current interpreter this field must match exactly with
* the ABI version of the interpreter.
*/
abi_version: string;
/**
* The Emscripten versions for instance, `emscripten_4_0_9`. Different
* Emscripten versions have different ABIs so if this changes ``abi_version``
* must also change.
*/
platform: string;
/**
* The Pyodide version the lockfile was made with. Informational only, has no
* compatibility implications. May be removed in the future.
*/
version: string;
/**
* The Python version this lock file was made with. If the minor version
* changes (e.g, 3.12 to 3.13) this changes the ABI and the ``abi_version``
* must change too. Patch versions do not imply a change to the
* ``abi_version``.
*/
python: string;
}
/**
* A package entry in the lock file.
*/
interface LockfilePackage {
/**
* The unnormalized name of the package.
*/
name: string;
version: string;
/**
* The file name or url of the package wheel. If it's relative, it will be
* resolved with respect to ``packageBaseUrl``. If there is no
* ``packageBaseUrl``, attempting to install a package with a relative
* ``file_name`` will fail.
*/
file_name: string;
package_type: PackageType;
/**
* The installation directory. Will be ``site`` except for certain system
* dynamic libraries that need to go on the global LD_LIBRARY_PATH.
*/
install_dir: "site" | "dynlib";
/**
* Integrity. Must be present unless ``checkIntegrity: false`` is passed to
* ``loadPyodide``.
*/
sha256: string;
/**
* The set of imports provided by this package as best we can tell. Used by
* :js:func:`pyodide.loadPackagesFromImports` to work out what packages to
* install.
*/
imports: string[];
/**
* The set of dependencies of this package.
*/
depends: string[];
}
/**
* The type of a package lockfile.
*/
interface Lockfile {
info: LockfileInfo;
packages: Record<string, LockfilePackage>;
chmod: (path: string, mode: number) => void;
utime: (path: string, atime: number, mtime: number) => void;
rmdir: (path: string) => void;
mount: (type: any, opts: any, mountpoint: string) => any;
write: (stream: FSStream, buffer: any, offset: number, length: number, position?: number) => number;
close: (stream: FSStream) => void;
ErrnoError: {
new (errno: number): Error;
};
registerDevice<T>(dev: number, ops: FSStreamOpsGen<T>): void;
syncfs(dir: boolean, oncomplete: (val: void) => void): void;
findObject(a: string, dontResolveLastLink?: boolean): any;
readFile(a: string): Uint8Array;
}
type PackageType = "package" | "cpython_module" | "shared_library" | "static_library";
interface PackageData {
@ -197,7 +139,7 @@ declare class PyProxy {
get type(): string;
/**
* Returns `str(o)` (unless `pyproxyToStringRepr: true` was passed to
* :js:func:`~exports.loadPyodide` in which case it will return `repr(o)`)
* :js:func:`~globalThis.loadPyodide` in which case it will return `repr(o)`)
*/
toString(): string;
/**
@ -231,7 +173,7 @@ declare class PyProxy {
* @param options
* @return The JavaScript object resulting from the conversion.
*/
toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, eager_converter, }?: {
toJs({ depth, pyproxies, create_pyproxies, dict_converter, default_converter, }?: {
/** How many layers deep to perform the conversion. Defaults to infinite */
depth?: number;
/**
@ -266,15 +208,6 @@ declare class PyProxy {
* documentation of :meth:`~pyodide.ffi.to_js`.
*/
default_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any;
/**
* Optional callback to convert objects which gets called after ``str``,
* ``int``, ``float``, ``bool``, ``None``, and ``JsProxy`` are converted but
* *before* any default conversions are applied to standard data structures.
*
* Its arguments are the same as `dict_converter`.
* See the documentation of :meth:`~pyodide.ffi.to_js`.
*/
eager_converter?: (obj: PyProxy, convert: (obj: PyProxy) => any, cacheConversion: (obj: PyProxy, result: any) => void) => any;
}): any;
}
declare class PyProxyWithLength extends PyProxy {
@ -1132,7 +1065,7 @@ declare class PythonError extends Error {
type NativeFS = {
syncfs: () => Promise<void>;
};
declare class PyodideAPI_ {
declare class PyodideAPI {
/** @hidden */
static version: string;
/** @hidden */
@ -1140,7 +1073,7 @@ declare class PyodideAPI_ {
messageCallback?: (message: string) => void;
errorCallback?: (message: string) => void;
checkIntegrity?: boolean;
}) => Promise<PackageData[]>;
}) => Promise<Array<PackageData>>;
/** @hidden */
static loadedPackages: LoadedPackages;
/** @hidden */
@ -1510,38 +1443,16 @@ declare class PyodideAPI_ {
*/
static setDebug(debug: boolean): boolean;
/**
* @private
*
* @param param0
* @returns
*/
static makeMemorySnapshot({ serializer, }?: {
serializer?: (obj: any) => any;
}): Uint8Array;
/**
* Returns the pyodide lockfile used to load the current Pyodide instance.
* The format of the lockfile is defined in the `pyodide/pyodide-lock
* <https://github.com/pyodide/pyodide-lock>`_ repository.
*/
static get lockfile(): Lockfile;
/**
* Returns the URL or path with respect to which relative paths in the lock
* file are resolved, or undefined.
*/
static get lockfileBaseUrl(): string | undefined;
}
/**
* The return type of :js:func:`~exports.loadPyodide`. See
* :ref:`the pyodide api docs <js-api-pyodide>` for more information.
* @hidetype
* @docgroup exports
*/
export type PyodideAPI = typeof PyodideAPI_;
/**
* The Pyodide version.
*
* The version here is a Python version, following :pep:`440`. This is different
* from the version in ``package.json`` which follows the node package manager
* version convention.
*/
export declare const version: string;
/** @hidden */
export type PyodideInterface = typeof PyodideAPI;
/**
* See documentation for loadPyodide.
* @hidden
@ -1549,7 +1460,7 @@ export declare const version: string;
type ConfigType = {
indexURL: string;
packageCacheDir: string;
lockFileContents: Lockfile | string | Promise<Lockfile | string>;
lockFileURL: string;
fullStdLib?: boolean;
stdLibURL?: string;
stdin?: () => string;
@ -1569,8 +1480,6 @@ type ConfigType = {
enableRunUntilComplete: boolean;
checkAPIVersion: boolean;
BUILD_ID: string;
packageBaseUrl?: string;
cdnUrl: string;
};
/**
* Load the main Pyodide wasm module and initialize it.
@ -1611,26 +1520,6 @@ export declare function loadPyodide(options?: {
* Default: ```${indexURL}/pyodide-lock.json```
*/
lockFileURL?: string;
/**
* The contents of a lockfile. If a string, it should be valid json and
* ``JSON.parse()`` should return a ``Lockfile`` instance. See
* :js:interface:`~pyodide.Lockfile` for the schema.
*/
lockFileContents?: Lockfile | string | Promise<Lockfile | string>;
/**
* The base url relative to which a relative value of
* :js:attr:`~pyodide.LockfilePackage.file_name` is interpreted. If
* ``lockfileContents`` is provided, then ``lockFileContents`` must be
* provided explicitly in order to install packages with relative paths.
*
* Otherwise, the default is calculated as follows:
*
* 1. If `lockFileURL` contains a ``/``, the default is everything before the last
* ``/`` in ``lockFileURL``.
* 2. If in the browser, the default is ``location.toString()``.
* 3. Otherwise, the default is `'.'`.
*/
packageBaseUrl?: string;
/**
* Load the full Python standard library. Setting this to false excludes
* unvendored modules from the standard library.
@ -1707,13 +1596,12 @@ export declare function loadPyodide(options?: {
packages?: string[];
/**
* Opt into the old behavior where :js:func:`PyProxy.toString() <pyodide.ffi.PyProxy.toString>`
* calls :py:func:`repr` and not :py:class:`str() <str>`. Deprecated.
* calls :py:func:`repr` and not :py:class:`str() <str>`.
* @deprecated
*/
pyproxyToStringRepr?: boolean;
/**
* Make loop.run_until_complete() function correctly using stack switching.
* Default: ``true``.
* Make loop.run_until_complete() function correctly using stack switching
*/
enableRunUntilComplete?: boolean;
/**
@ -1730,23 +1618,13 @@ export declare function loadPyodide(options?: {
fsInit?: (FS: FSType, info: {
sitePackages: string;
}) => Promise<void>;
/**
* Opt into the old behavior where JavaScript `null` is converted to `None`
* instead of `jsnull`. Deprecated.
* @deprecated
*/
convertNullToNone?: boolean;
/** @ignore */
_makeSnapshot?: boolean;
/** @ignore */
_loadSnapshot?: Uint8Array | ArrayBuffer | PromiseLike<Uint8Array | ArrayBuffer>;
/** @ignore */
_snapshotDeserializer?: (obj: any) => any;
}): Promise<PyodideAPI>;
export type {
PyodideAPI as PyodideInterface,
};
}): Promise<PyodideInterface>;
export type {};
export type {Lockfile, LockfileInfo, LockfilePackage, PackageData};
export type {PackageData};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -e
if [[ $1 == "-m" ]] && [[ $2 == "pip" ]]; then
# redirect python -m pip to execute in host environment
shift 2
which $(dirname $0)/pip > /dev/null || { \
>&2 echo "Cannot find pyodide pip. Make a pyodide venv first?" && exit 1; \
}
exec $(dirname $0)/pip $@
fi
which node > /dev/null || { \
>&2 echo "No node executable found on the path" && exit 1; \
}
ARGS=$(node -e "$(cat <<"EOF"
const major_version = Number(process.version.split(".")[0].slice(1));
if(major_version < 18) {
console.error("Need node version >= 18. Got node version", process.version);
process.exit(1);
}
if (major_version >= 20) {
process.stdout.write("--experimental-wasm-stack-switching");
}
EOF
)")
# Macs come with FreeBSD coreutils which doesn't have the -s option
# so feature detect and work around it.
if which grealpath > /dev/null; then
# It has brew installed gnu core utils, use that
REALPATH="grealpath -s"
elif which realpath > /dev/null && realpath --version > /dev/null 2> /dev/null && realpath --version | grep GNU > /dev/null; then
# realpath points to GNU realpath so use it.
REALPATH="realpath -s"
else
# Shim for macs without GNU coreutils
abs_path () {
echo "$(cd "$(dirname "$1")" || exit; pwd)/$(basename "$1")"
}
REALPATH=abs_path
fi
RESOLVED_DIR=$(dirname $(realpath "$0"))
# Compute our own path, not following symlinks and pass it in so that
# node_entry.mjs can set sys.executable correctly.
# Intentionally allow word splitting on $NODEFLAGS.
exec node $NODEFLAGS $ARGS $RESOLVED_DIR/python_cli_entry.mjs --this-program="$($REALPATH "$0")" "$@"

View File

@ -1,147 +0,0 @@
import { loadPyodide } from "./pyodide.mjs";
import { readdirSync } from "fs";
/**
* Determine which native top level directories to mount into the Emscripten
* file system.
*
* This is a bit brittle, if the machine has a top level directory with certain
* names it is possible this could break. The most surprising one here is tmp, I
* am not sure why but if we link tmp then the process silently fails.
*/
function dirsToMount() {
return readdirSync("/")
.filter((dir) => !["dev", "lib", "proc"].includes(dir))
.map((dir) => "/" + dir);
}
const thisProgramFlag = "--this-program=";
const thisProgramIndex = process.argv.findIndex((x) =>
x.startsWith(thisProgramFlag),
);
const args = process.argv.slice(thisProgramIndex + 1);
const _sysExecutable = process.argv[thisProgramIndex].slice(
thisProgramFlag.length,
);
function fsInit(FS) {
const mounts = dirsToMount();
for (const mount of mounts) {
FS.mkdirTree(mount);
FS.mount(FS.filesystems.NODEFS, { root: mount }, mount);
}
}
async function main() {
let py;
try {
py = await loadPyodide({
args,
_sysExecutable,
env: Object.assign(
{
PYTHONINSPECT: "",
},
process.env,
{ HOME: process.cwd() },
),
fullStdLib: false,
fsInit,
});
} catch (e) {
if (e.constructor.name !== "ExitStatus") {
throw e;
}
// If the user passed `--help`, `--version`, or a set of command line
// arguments that is invalid in some way, we will exit here.
process.exit(e.status);
}
py.setStdout();
py.setStderr();
let sideGlobals = py.runPython("{}");
function handleExit(code) {
if (code === undefined) {
code = 0;
}
if (py._module._Py_FinalizeEx() < 0) {
code = 120;
}
// It's important to call `process.exit` immediately after
// `_Py_FinalizeEx` because otherwise any asynchronous tasks still
// scheduled will segfault.
process.exit(code);
}
sideGlobals.set("handleExit", handleExit);
py.runPython(
`
from pyodide._package_loader import SITE_PACKAGES, should_load_dynlib
from pyodide.ffi import to_js
import re
dynlibs_to_load = to_js([
str(path) for path in SITE_PACKAGES.glob("**/*.so*")
if should_load_dynlib(path)
])
`,
{ globals: sideGlobals },
);
const dynlibs = sideGlobals.get("dynlibs_to_load");
for (const dynlib of dynlibs) {
try {
await py._module.API.loadDynlib(dynlib);
} catch (e) {
console.error("Failed to load lib ", dynlib);
console.error(e);
}
}
py.runPython(
`
import asyncio
# Keep the event loop alive until all tasks are finished, or SystemExit or
# KeyboardInterupt is raised.
loop = asyncio.get_event_loop()
# Make sure we don't run _no_in_progress_handler before we finish _run_main.
loop._in_progress += 1
loop._no_in_progress_handler = handleExit
loop._system_exit_handler = handleExit
loop._keyboard_interrupt_handler = lambda: handleExit(130)
# Make shutil.get_terminal_size tell the terminal size accurately.
import shutil
from js.process import stdout
import os
def get_terminal_size(fallback=(80, 24)):
columns = getattr(stdout, "columns", None)
rows = getattr(stdout, "rows", None)
if columns is None:
columns = fallback[0]
if rows is None:
rows = fallback[1]
return os.terminal_size((columns, rows))
shutil.get_terminal_size = get_terminal_size
`,
{ globals: sideGlobals },
);
let errcode;
try {
if (py._module.jspiSupported) {
errcode = await py._module.promisingRunMain();
} else {
errcode = py._module._run_main();
}
} catch (e) {
if (e.constructor.name === "ExitStatus") {
process.exit(e.status);
}
py._api.fatal_error(e);
}
if (errcode) {
process.exit(errcode);
}
py.runPython("loop._decrement_in_progress()", { globals: sideGlobals });
}
main().catch((e) => {
console.error(e);
process.exit(1);
});

View File

@ -1,4 +1,4 @@
const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.28.3/full/pyodide.js";
const defaultPyodideUrl = "https://cdn.jsdelivr.net/pyodide/v0.27.7/full/pyodide.js";
let _apps = {};
let _documentUrl = document.URL;