mirror of https://github.com/pyodide/pyodide.git
MAINT Use prettier to format javascript (#1554)
Co-authored-by: Roman Yurchak <rth.yurchak@gmail.com>
This commit is contained in:
parent
7cf5bd5809
commit
ab1b6c8d24
|
@ -3,7 +3,7 @@ version: 2
|
|||
defaults: &defaults
|
||||
working_directory: ~/repo
|
||||
docker:
|
||||
- image: pyodide/pyodide-env:15
|
||||
- image: pyodide/pyodide-env:16
|
||||
environment:
|
||||
- EMSDK_NUM_CORES: 3
|
||||
EMCC_CORES: 3
|
||||
|
@ -21,12 +21,8 @@ jobs:
|
|||
command: make lint
|
||||
|
||||
test-docs:
|
||||
working_directory: ~/repo
|
||||
<<: *defaults
|
||||
resource_class: small
|
||||
|
||||
docker:
|
||||
- image: cimg/python:3.8.2-node
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
|
@ -34,8 +30,6 @@ jobs:
|
|||
name: Install prerequisites
|
||||
command: |
|
||||
pip install -r docs/requirements-doc.txt
|
||||
pip install pytest
|
||||
sudo npm install -g jsdoc
|
||||
|
||||
- run:
|
||||
name: Test docs
|
||||
|
@ -253,7 +247,7 @@ jobs:
|
|||
resource_class: small
|
||||
|
||||
docker:
|
||||
- image: cibuilds/github:0.13
|
||||
- image: cibuilds/github:0.13
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
|
31
Dockerfile
31
Dockerfile
|
@ -1,3 +1,4 @@
|
|||
FROM node:14.16.1-buster-slim AS node-image
|
||||
FROM python:3.8.2-slim-buster
|
||||
|
||||
RUN apt-get update \
|
||||
|
@ -6,7 +7,7 @@ RUN apt-get update \
|
|||
bzip2 ccache clang-format-6.0 cmake f2c g++ gfortran git make \
|
||||
patch pkg-config swig unzip wget xz-utils \
|
||||
# testing packages: libgconf-2-4 is necessary for running chromium
|
||||
libgconf-2-4 "chromium=89.*" \
|
||||
libgconf-2-4 "chromium=90.*" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip3 --no-cache-dir install \
|
||||
|
@ -23,7 +24,19 @@ RUN pip3 --no-cache-dir install \
|
|||
pytest-rerunfailures \
|
||||
pytest-xdist \
|
||||
pyyaml \
|
||||
"selenium==4.0.0.b3"
|
||||
"selenium==4.0.0.b3" \
|
||||
# Docs requirements
|
||||
sphinx \
|
||||
sphinx_book_theme \
|
||||
myst-parser==0.13.3 \
|
||||
sphinxcontrib-napoleon \
|
||||
packaging \
|
||||
sphinx-js==3.1 \
|
||||
autodocsumm \
|
||||
docutils==0.16 \
|
||||
sphinx-argparse-cli~=1.6.0 \
|
||||
sphinx-version-warning~=1.1.2 \
|
||||
sphinx-issues
|
||||
|
||||
# Get firefox 70.0.1 and geckodriver
|
||||
RUN wget -qO- https://ftp.mozilla.org/pub/firefox/releases/87.0/linux-x86_64/en-US/firefox-87.0.tar.bz2 | tar jx \
|
||||
|
@ -31,10 +44,22 @@ RUN wget -qO- https://ftp.mozilla.org/pub/firefox/releases/87.0/linux-x86_64/en-
|
|||
&& wget -qO- https://github.com/mozilla/geckodriver/releases/download/v0.29.1/geckodriver-v0.29.1-linux64.tar.gz | tar zxC /usr/local/bin/
|
||||
|
||||
# Get recent version of chromedriver
|
||||
RUN wget --quiet https://chromedriver.storage.googleapis.com/89.0.4389.23/chromedriver_linux64.zip \
|
||||
RUN wget --quiet https://chromedriver.storage.googleapis.com/90.0.4430.24/chromedriver_linux64.zip \
|
||||
&& unzip chromedriver_linux64.zip \
|
||||
&& mv $PWD/chromedriver /usr/local/bin \
|
||||
&& rm -f chromedriver_linux64.zip
|
||||
|
||||
COPY --from=node-image /usr/local/bin/node /usr/local/bin/
|
||||
COPY --from=node-image /usr/local/lib/node_modules /usr/local/lib/node_modules
|
||||
RUN ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
|
||||
&& ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx
|
||||
|
||||
RUN npm install -g \
|
||||
jsdoc \
|
||||
uglify-js \
|
||||
prettier \
|
||||
rollup \
|
||||
rollup-plugin-terser
|
||||
|
||||
CMD ["/bin/sh"]
|
||||
WORKDIR /src
|
||||
|
|
16
Makefile
16
Makefile
|
@ -5,7 +5,8 @@ include Makefile.envs
|
|||
.PHONY=check
|
||||
|
||||
FILEPACKAGER=$$EM_DIR/tools/file_packager.py
|
||||
UGLIFYJS=$(PYODIDE_ROOT)/node_modules/.bin/uglifyjs
|
||||
UGLIFYJS=npx uglifyjs
|
||||
PRETTIER=npx prettier
|
||||
|
||||
CPYTHONROOT=cpython
|
||||
CPYTHONLIB=$(CPYTHONROOT)/installs/python-$(PYVERSION)/lib/python$(PYMINOR)
|
||||
|
@ -116,15 +117,14 @@ update_base_url: \
|
|||
test: all
|
||||
pytest src emsdk/tests packages/*/test* pyodide_build -v
|
||||
|
||||
|
||||
lint:
|
||||
# check for unused imports, the rest is done by black
|
||||
flake8 --select=F401 src tools pyodide_build benchmark conftest.py docs
|
||||
clang-format-6.0 -output-replacements-xml `find src -type f -regex ".*\.\(c\|h\|js\)"` | (! grep '<replacement ')
|
||||
clang-format-6.0 -output-replacements-xml `find src -type f -regex ".*\.\(c\|h\\)"` | (! grep '<replacement ')
|
||||
$(PRETTIER) --check `find src -type f -name '*.js'`
|
||||
black --check .
|
||||
mypy --ignore-missing-imports pyodide_build/ src/ packages/micropip/micropip/ packages/*/test* conftest.py docs
|
||||
|
||||
|
||||
apply-lint:
|
||||
./tools/apply-lint.sh
|
||||
|
||||
|
@ -149,7 +149,7 @@ clean-all: clean
|
|||
$(CC) -o $@ -c $< $(MAIN_MODULE_CFLAGS) -Isrc/core/
|
||||
|
||||
|
||||
build/test.data: $(CPYTHONLIB) $(UGLIFYJS)
|
||||
build/test.data: $(CPYTHONLIB)
|
||||
( \
|
||||
cd $(CPYTHONLIB)/test; \
|
||||
find . -type d -name __pycache__ -prune -exec rm -rf {} \; \
|
||||
|
@ -160,12 +160,6 @@ build/test.data: $(CPYTHONLIB) $(UGLIFYJS)
|
|||
)
|
||||
$(UGLIFYJS) build/test.js -o build/test.js
|
||||
|
||||
|
||||
$(UGLIFYJS): emsdk/emsdk/.complete
|
||||
npm i --no-save uglify-js
|
||||
touch -h $(UGLIFYJS)
|
||||
|
||||
|
||||
$(CPYTHONLIB): emsdk/emsdk/.complete $(PYODIDE_EMCC) $(PYODIDE_CXX)
|
||||
date +"[%F %T] Building cpython..."
|
||||
make -C $(CPYTHONROOT)
|
||||
|
|
|
@ -8,7 +8,7 @@ import numpy as np
|
|||
|
||||
|
||||
def lstsqr(x, y):
|
||||
""" Computes the least-squares solution to a linear matrix equation. """
|
||||
"""Computes the least-squares solution to a linear matrix equation."""
|
||||
x_avg = np.average(x)
|
||||
y_avg = np.average(y)
|
||||
dx = x - x_avg
|
||||
|
|
|
@ -121,7 +121,7 @@ class PyodideAnalyzer:
|
|||
|
||||
|
||||
def get_jsdoc_content_directive(app):
|
||||
"""These directives need to close over app """
|
||||
"""These directives need to close over app"""
|
||||
|
||||
class JsDocContent(Directive):
|
||||
"""A directive that just dumps a summary table in place. There are no
|
||||
|
|
14
run_docker
14
run_docker
|
@ -1,5 +1,12 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
PYODIDE_IMAGE_REPO="pyodide"
|
||||
PYODIDE_IMAGE_TAG="16"
|
||||
PYODIDE_PREBUILT_IMAGE_TAG="0.17.0"
|
||||
DEFAULT_PYODIDE_DOCKER_IMAGE="${PYODIDE_IMAGE_REPO}/pyodide-env:${PYODIDE_IMAGE_TAG}"
|
||||
DEFAULT_PYODIDE_SYSTEM_PORT="8000"
|
||||
DOCKER_COMMAND="/bin/bash"
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
|
||||
|
@ -28,13 +35,6 @@ function error() {
|
|||
exit 255
|
||||
}
|
||||
|
||||
|
||||
PYODIDE_IMAGE_TAG="15"
|
||||
PYODIDE_PREBUILT_IMAGE_TAG="0.17.0"
|
||||
DEFAULT_PYODIDE_DOCKER_IMAGE="pyodide/pyodide-env:${PYODIDE_IMAGE_TAG}"
|
||||
DEFAULT_PYODIDE_SYSTEM_PORT="8000"
|
||||
DOCKER_COMMAND="/bin/bash"
|
||||
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
|
|
|
@ -13,10 +13,9 @@
|
|||
* This file to be included from pyproxy.c This uses the JS_FILE macro defined
|
||||
* in include_js_file.h
|
||||
*/
|
||||
// clang-format off
|
||||
JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
||||
JS_FILE(pyproxy_init_js, () => {
|
||||
0, 0; /* Magic, see include_js_file.h */
|
||||
Module.PyProxies = {};
|
||||
// clang-format on
|
||||
|
||||
if (globalThis.FinalizationRegistry) {
|
||||
Module.finalizationRegistry = new FinalizationRegistry((ptr) => {
|
||||
|
@ -41,7 +40,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// }
|
||||
// });
|
||||
} else {
|
||||
Module.finalizationRegistry = {register() {}, unregister() {}};
|
||||
Module.finalizationRegistry = { register() {}, unregister() {} };
|
||||
// Module.bufferFinalizationRegistry = finalizationRegistry;
|
||||
}
|
||||
|
||||
|
@ -65,7 +64,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* still make "prototype in proxy" be true though.
|
||||
* @private
|
||||
*/
|
||||
Module.pyproxy_new = function(ptrobj) {
|
||||
Module.pyproxy_new = function (ptrobj) {
|
||||
let flags = _pyproxy_getflags(ptrobj);
|
||||
let cls = Module.getPyProxyClass(flags);
|
||||
// Reflect.construct calls the constructor of Module.PyProxyClass but sets
|
||||
|
@ -87,8 +86,9 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
} else {
|
||||
target = Object.create(cls.prototype);
|
||||
}
|
||||
Object.defineProperty(target, "$$",
|
||||
{value : {ptr : ptrobj, type : 'PyProxy'}});
|
||||
Object.defineProperty(target, "$$", {
|
||||
value: { ptr: ptrobj, type: "PyProxy" },
|
||||
});
|
||||
_Py_IncRef(ptrobj);
|
||||
let proxy = new Proxy(target, Module.PyProxyHandlers);
|
||||
Module.finalizationRegistry.register(proxy, ptrobj, proxy);
|
||||
|
@ -112,14 +112,13 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* PyProxy is minimal.
|
||||
* @private
|
||||
*/
|
||||
Module.getPyProxyClass = function(flags) {
|
||||
Module.getPyProxyClass = function (flags) {
|
||||
let result = _pyproxyClassMap.get(flags);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
let descriptors = {};
|
||||
// clang-format off
|
||||
for(let [feature_flag, methods] of [
|
||||
for (let [feature_flag, methods] of [
|
||||
[HAS_LENGTH, Module.PyProxyLengthMethods],
|
||||
[HAS_GET, Module.PyProxyGetItemMethods],
|
||||
[HAS_SET, Module.PyProxySetItemMethods],
|
||||
|
@ -129,14 +128,13 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
[IS_AWAITABLE, Module.PyProxyAwaitableMethods],
|
||||
[IS_BUFFER, Module.PyProxyBufferMethods],
|
||||
[IS_CALLABLE, Module.PyProxyCallableMethods],
|
||||
]){
|
||||
// clang-format on
|
||||
]) {
|
||||
if (flags & feature_flag) {
|
||||
Object.assign(descriptors, Object.getOwnPropertyDescriptors(methods));
|
||||
}
|
||||
}
|
||||
let new_proto = Object.create(Module.PyProxyClass.prototype, descriptors);
|
||||
function PyProxy() {};
|
||||
function PyProxy() {}
|
||||
PyProxy.prototype = new_proto;
|
||||
_pyproxyClassMap.set(flags, PyProxy);
|
||||
return PyProxy;
|
||||
|
@ -148,7 +146,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// Now a lot of boilerplate to wrap the abstract Object protocol wrappers
|
||||
// defined in pyproxy.c in Javascript functions.
|
||||
|
||||
Module.callPyObjectKwargs = function(ptrobj, ...jsargs) {
|
||||
Module.callPyObjectKwargs = function (ptrobj, ...jsargs) {
|
||||
// We don't do any checking for kwargs, checks are in PyProxy.callKwargs
|
||||
// which only is used when the keyword arguments come from the user.
|
||||
let kwargs = jsargs.pop();
|
||||
|
@ -162,8 +160,13 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
let idkwnames = Module.hiwire.new_value(kwargs_names);
|
||||
let idresult;
|
||||
try {
|
||||
idresult =
|
||||
__pyproxy_apply(ptrobj, idargs, num_pos_args, idkwnames, num_kwargs);
|
||||
idresult = __pyproxy_apply(
|
||||
ptrobj,
|
||||
idargs,
|
||||
num_pos_args,
|
||||
idkwnames,
|
||||
num_kwargs
|
||||
);
|
||||
} catch (e) {
|
||||
Module.fatal_error(e);
|
||||
} finally {
|
||||
|
@ -176,16 +179,18 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
return Module.hiwire.pop_value(idresult);
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
Module.callPyObject = function(ptrobj, ...jsargs) {
|
||||
Module.callPyObject = function (ptrobj, ...jsargs) {
|
||||
return Module.callPyObjectKwargs(ptrobj, ...jsargs, {});
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
Module.PyProxyClass = class {
|
||||
constructor() { throw new TypeError('PyProxy is not a constructor'); }
|
||||
constructor() {
|
||||
throw new TypeError("PyProxy is not a constructor");
|
||||
}
|
||||
|
||||
get[Symbol.toStringTag]() { return "PyProxy"; }
|
||||
get [Symbol.toStringTag]() {
|
||||
return "PyProxy";
|
||||
}
|
||||
/**
|
||||
* The name of the type of the object.
|
||||
*
|
||||
|
@ -278,11 +283,14 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
callKwargs(...jsargs) {
|
||||
if (jsargs.length === 0) {
|
||||
throw new TypeError(
|
||||
"callKwargs requires at least one argument (the key word argument object)");
|
||||
"callKwargs requires at least one argument (the key word argument object)"
|
||||
);
|
||||
}
|
||||
let kwargs = jsargs[jsargs.length - 1];
|
||||
if (kwargs.constructor !== undefined &&
|
||||
kwargs.constructor.name !== "Object") {
|
||||
if (
|
||||
kwargs.constructor !== undefined &&
|
||||
kwargs.constructor.name !== "Object"
|
||||
) {
|
||||
throw new TypeError("kwargs argument is not an object");
|
||||
}
|
||||
return Module.callPyObjectKwargs(_getPtr(this), ...jsargs);
|
||||
|
@ -309,7 +317,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
_pythonexc2js();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Controlled by HAS_GET, appears for any class with __getitem__,
|
||||
|
@ -323,7 +331,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* @param {any} key The key to look up.
|
||||
* @returns The corresponding value.
|
||||
*/
|
||||
get : function(key) {
|
||||
get: function (key) {
|
||||
let ptrobj = _getPtr(this);
|
||||
let idkey = Module.hiwire.new_value(key);
|
||||
let idresult;
|
||||
|
@ -356,7 +364,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* @param {any} key The key to set.
|
||||
* @param {any} value The value to set it to.
|
||||
*/
|
||||
set : function(key, value) {
|
||||
set: function (key, value) {
|
||||
let ptrobj = _getPtr(this);
|
||||
let idkey = Module.hiwire.new_value(key);
|
||||
let idval = Module.hiwire.new_value(value);
|
||||
|
@ -380,7 +388,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
*
|
||||
* @param {any} key The key to delete.
|
||||
*/
|
||||
delete : function(key) {
|
||||
delete: function (key) {
|
||||
let ptrobj = _getPtr(this);
|
||||
let idkey = Module.hiwire.new_value(key);
|
||||
let errcode;
|
||||
|
@ -394,7 +402,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
if (errcode === -1) {
|
||||
_pythonexc2js();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// Controlled by HAS_CONTAINS flag, appears for any class with __contains__ or
|
||||
|
@ -408,7 +416,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* @param {*} key The key to check for.
|
||||
* @returns {bool} Is ``key`` present?
|
||||
*/
|
||||
has : function(key) {
|
||||
has: function (key) {
|
||||
let ptrobj = _getPtr(this);
|
||||
let idkey = Module.hiwire.new_value(key);
|
||||
let result;
|
||||
|
@ -426,7 +434,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
},
|
||||
};
|
||||
|
||||
class TempError extends Error {};
|
||||
class TempError extends Error {}
|
||||
|
||||
/**
|
||||
* A helper for [Symbol.iterator].
|
||||
|
@ -485,7 +493,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
*
|
||||
* @returns {Iterator} An iterator for the proxied Python object.
|
||||
*/
|
||||
[Symbol.iterator] : function() {
|
||||
[Symbol.iterator]: function () {
|
||||
let ptrobj = _getPtr(this);
|
||||
let token = {};
|
||||
let iterptr;
|
||||
|
@ -504,7 +512,9 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// Controlled by IS_ITERATOR, appears for any object with a __next__ or
|
||||
// tp_iternext method.
|
||||
Module.PyProxyIteratorMethods = {
|
||||
[Symbol.iterator] : function() { return this; },
|
||||
[Symbol.iterator]: function () {
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* This translates to the Python code ``next(obj)``. Returns the next value
|
||||
* of the generator. See the documentation for `Generator.prototype.next
|
||||
|
@ -524,7 +534,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* ``StopIteration(result_value)`` exception, ``next`` returns ``{done :
|
||||
* true, value : result_value}``.
|
||||
*/
|
||||
next : function(arg) {
|
||||
next: function (arg) {
|
||||
let idresult;
|
||||
// Note: arg is optional, if arg is not supplied, it will be undefined
|
||||
// which gets converted to "Py_None". This is as intended.
|
||||
|
@ -545,7 +555,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
_pythonexc2js();
|
||||
}
|
||||
let value = Module.hiwire.pop_value(idresult);
|
||||
return {done, value};
|
||||
return { done, value };
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -630,8 +640,10 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// here:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
|
||||
Module.PyProxyHandlers = {
|
||||
isExtensible : function() { return true },
|
||||
has : function(jsobj, jskey) {
|
||||
isExtensible: function () {
|
||||
return true;
|
||||
},
|
||||
has: function (jsobj, jskey) {
|
||||
// Note: must report "prototype" in proxy when we are callable.
|
||||
// (We can return the wrong value from "get" handler though.)
|
||||
let objHasKey = Reflect.has(jsobj, jskey);
|
||||
|
@ -639,12 +651,12 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
return true;
|
||||
}
|
||||
// python_hasattr will crash when given a Symbol.
|
||||
if (typeof (jskey) === "symbol") {
|
||||
if (typeof jskey === "symbol") {
|
||||
return false;
|
||||
}
|
||||
return python_hasattr(jsobj, jskey);
|
||||
},
|
||||
get : function(jsobj, jskey) {
|
||||
get: function (jsobj, jskey) {
|
||||
// Preference order:
|
||||
// 1. things we have to return to avoid making Javascript angry
|
||||
// 2. the result of Python getattr
|
||||
|
@ -653,11 +665,11 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// 1. things we have to return to avoid making Javascript angry
|
||||
// This conditional looks funky but it's the only thing I found that
|
||||
// worked right in all cases.
|
||||
if ((jskey in jsobj) && !(jskey in Object.getPrototypeOf(jsobj))) {
|
||||
if (jskey in jsobj && !(jskey in Object.getPrototypeOf(jsobj))) {
|
||||
return Reflect.get(jsobj, jskey);
|
||||
}
|
||||
// python_getattr will crash when given a Symbol
|
||||
if (typeof (jskey) === "symbol") {
|
||||
if (typeof jskey === "symbol") {
|
||||
return Reflect.get(jsobj, jskey);
|
||||
}
|
||||
// 2. The result of getattr
|
||||
|
@ -668,13 +680,14 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// 3. stuff from the prototype chain.
|
||||
return Reflect.get(jsobj, jskey);
|
||||
},
|
||||
set : function(jsobj, jskey, jsval) {
|
||||
set: function (jsobj, jskey, jsval) {
|
||||
// We're only willing to set properties on the python object, throw an
|
||||
// error if user tries to write over any key of type 1. things we have to
|
||||
// return to avoid making Javascript angry
|
||||
if (typeof (jskey) === "symbol") {
|
||||
if (typeof jskey === "symbol") {
|
||||
throw new TypeError(
|
||||
`Cannot set read only field '${jskey.description}'`);
|
||||
`Cannot set read only field '${jskey.description}'`
|
||||
);
|
||||
}
|
||||
// Again this is a funny looking conditional, I found it as the result of
|
||||
// a lengthy search for something that worked right.
|
||||
|
@ -685,13 +698,14 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
python_setattr(jsobj, jskey, jsval);
|
||||
return true;
|
||||
},
|
||||
deleteProperty : function(jsobj, jskey) {
|
||||
deleteProperty: function (jsobj, jskey) {
|
||||
// We're only willing to delete properties on the python object, throw an
|
||||
// error if user tries to write over any key of type 1. things we have to
|
||||
// return to avoid making Javascript angry
|
||||
if (typeof (jskey) === "symbol") {
|
||||
if (typeof jskey === "symbol") {
|
||||
throw new TypeError(
|
||||
`Cannot delete read only field '${jskey.description}'`);
|
||||
`Cannot delete read only field '${jskey.description}'`
|
||||
);
|
||||
}
|
||||
let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
|
||||
if (descr && !descr.writable) {
|
||||
|
@ -702,7 +716,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// Otherwise Javascript will throw a TypeError.
|
||||
return !descr || descr.configurable;
|
||||
},
|
||||
ownKeys : function(jsobj) {
|
||||
ownKeys: function (jsobj) {
|
||||
let ptrobj = _getPtr(jsobj);
|
||||
let idresult;
|
||||
try {
|
||||
|
@ -717,11 +731,9 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
result.push(...Reflect.ownKeys(jsobj));
|
||||
return result;
|
||||
},
|
||||
// clang-format off
|
||||
apply : function(jsobj, jsthis, jsargs) {
|
||||
apply: function (jsobj, jsthis, jsargs) {
|
||||
return jsobj.apply(jsthis, jsargs);
|
||||
},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -735,7 +747,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* event loop if necessary.
|
||||
* @private
|
||||
*/
|
||||
_ensure_future : function() {
|
||||
_ensure_future: function () {
|
||||
let ptrobj = _getPtr(this);
|
||||
let resolveHandle;
|
||||
let rejectHandle;
|
||||
|
@ -747,8 +759,11 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
let reject_handle_id = Module.hiwire.new_value(rejectHandle);
|
||||
let errcode;
|
||||
try {
|
||||
errcode = __pyproxy_ensure_future(ptrobj, resolve_handle_id,
|
||||
reject_handle_id);
|
||||
errcode = __pyproxy_ensure_future(
|
||||
ptrobj,
|
||||
resolve_handle_id,
|
||||
reject_handle_id
|
||||
);
|
||||
} catch (e) {
|
||||
Module.fatal_error(e);
|
||||
} finally {
|
||||
|
@ -779,7 +794,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* argument if the awaitable fails.
|
||||
* @returns {Promise} The resulting Promise.
|
||||
*/
|
||||
then : function(onFulfilled, onRejected) {
|
||||
then: function (onFulfilled, onRejected) {
|
||||
let promise = this._ensure_future();
|
||||
return promise.then(onFulfilled, onRejected);
|
||||
},
|
||||
|
@ -798,7 +813,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* argument if the awaitable fails.
|
||||
* @returns {Promise} The resulting Promise.
|
||||
*/
|
||||
catch : function(onRejected) {
|
||||
catch: function (onRejected) {
|
||||
let promise = this._ensure_future();
|
||||
return promise.catch(onRejected);
|
||||
},
|
||||
|
@ -820,34 +835,32 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* result as the original Promise, but only after executing the
|
||||
* ``onFinally`` handler.
|
||||
*/
|
||||
finally : function(onFinally) {
|
||||
finally: function (onFinally) {
|
||||
let promise = this._ensure_future();
|
||||
return promise.finally(onFinally);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
Module.PyProxyCallableMethods = {prototype : Function.prototype};
|
||||
Module.PyProxyCallableMethods = { prototype: Function.prototype };
|
||||
|
||||
// clang-format off
|
||||
let type_to_array_map = new Map([
|
||||
[ "i8", Int8Array ],
|
||||
[ "u8", Uint8Array ],
|
||||
[ "u8clamped", Uint8ClampedArray ],
|
||||
[ "i16", Int16Array ],
|
||||
[ "u16", Uint16Array ],
|
||||
[ "i32", Int32Array ],
|
||||
[ "u32", Uint32Array ],
|
||||
[ "i32", Int32Array ],
|
||||
[ "u32", Uint32Array ],
|
||||
["i8", Int8Array],
|
||||
["u8", Uint8Array],
|
||||
["u8clamped", Uint8ClampedArray],
|
||||
["i16", Int16Array],
|
||||
["u16", Uint16Array],
|
||||
["i32", Int32Array],
|
||||
["u32", Uint32Array],
|
||||
["i32", Int32Array],
|
||||
["u32", Uint32Array],
|
||||
// if these aren't available, will be globalThis.BigInt64Array will be
|
||||
// undefined rather than raising a ReferenceError.
|
||||
[ "i64", globalThis.BigInt64Array],
|
||||
[ "u64", globalThis.BigUint64Array],
|
||||
[ "f32", Float32Array ],
|
||||
[ "f64", Float64Array ],
|
||||
[ "dataview", DataView ],
|
||||
["i64", globalThis.BigInt64Array],
|
||||
["u64", globalThis.BigUint64Array],
|
||||
["f32", Float32Array],
|
||||
["f64", Float64Array],
|
||||
["dataview", DataView],
|
||||
]);
|
||||
// clang-format on
|
||||
|
||||
Module.PyProxyBufferMethods = {
|
||||
/**
|
||||
|
@ -880,7 +893,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* <https://docs.python.org/3/library/struct.html#format-strings>`_.
|
||||
* @returns :any:`PyBuffer`
|
||||
*/
|
||||
getBuffer : function(type) {
|
||||
getBuffer: function (type) {
|
||||
let ArrayType = undefined;
|
||||
if (type) {
|
||||
ArrayType = type_to_array_map.get(type);
|
||||
|
@ -928,25 +941,32 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
let bigEndian = false;
|
||||
if (ArrayType === undefined) {
|
||||
[ArrayType, bigEndian] = Module.processBufferFormatString(
|
||||
format, " In this case, you can pass an explicit type argument.");
|
||||
format,
|
||||
" In this case, you can pass an explicit type argument."
|
||||
);
|
||||
}
|
||||
let alignment =
|
||||
parseInt(ArrayType.name.replace(/[^0-9]/g, "")) / 8 || 1;
|
||||
parseInt(ArrayType.name.replace(/[^0-9]/g, "")) / 8 || 1;
|
||||
if (bigEndian && alignment > 1) {
|
||||
throw new Error(
|
||||
"Javascript has no native support for big endian buffers. " +
|
||||
"Javascript has no native support for big endian buffers. " +
|
||||
"In this case, you can pass an explicit type argument. " +
|
||||
"For instance, `getBuffer('dataview')` will return a `DataView`" +
|
||||
"which has native support for reading big endian data." +
|
||||
"Alternatively, toJs will automatically convert the buffer " +
|
||||
"to little endian.");
|
||||
"to little endian."
|
||||
);
|
||||
}
|
||||
let numBytes = maxByteOffset - minByteOffset;
|
||||
if (numBytes !== 0 && (startByteOffset % alignment !== 0 ||
|
||||
minByteOffset % alignment !== 0 ||
|
||||
maxByteOffset % alignment !== 0)) {
|
||||
if (
|
||||
numBytes !== 0 &&
|
||||
(startByteOffset % alignment !== 0 ||
|
||||
minByteOffset % alignment !== 0 ||
|
||||
maxByteOffset % alignment !== 0)
|
||||
) {
|
||||
throw new Error(
|
||||
`Buffer does not have valid alignment for a ${ArrayType.name}`);
|
||||
`Buffer does not have valid alignment for a ${ArrayType.name}`
|
||||
);
|
||||
}
|
||||
let numEntries = numBytes / alignment;
|
||||
let offset = (startByteOffset - minByteOffset) / alignment;
|
||||
|
@ -961,27 +981,26 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
}
|
||||
|
||||
success = true;
|
||||
// clang-format off
|
||||
let result = Object.create(Module.PyBuffer.prototype,
|
||||
let result = Object.create(
|
||||
Module.PyBuffer.prototype,
|
||||
Object.getOwnPropertyDescriptors({
|
||||
offset,
|
||||
readonly,
|
||||
format,
|
||||
itemsize,
|
||||
ndim : shape.length,
|
||||
nbytes : numBytes,
|
||||
ndim: shape.length,
|
||||
nbytes: numBytes,
|
||||
shape,
|
||||
strides,
|
||||
data,
|
||||
c_contiguous,
|
||||
f_contiguous,
|
||||
_view_ptr : view_ptr,
|
||||
_released : false
|
||||
_view_ptr: view_ptr,
|
||||
_released: false,
|
||||
})
|
||||
);
|
||||
// Module.bufferFinalizationRegistry.register(result, view_ptr, result);
|
||||
return result;
|
||||
// clang-format on
|
||||
} finally {
|
||||
if (!success) {
|
||||
try {
|
||||
|
@ -992,10 +1011,9 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* A class to allow access to a Python data buffers from Javascript. These are
|
||||
* produced by :any:`PyProxy.getBuffer` and cannot be constructed directly.
|
||||
|
@ -1062,7 +1080,6 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
* buffer.data.byteLength
|
||||
* );
|
||||
*/
|
||||
// clang-format on
|
||||
Module.PyBuffer = class PyBuffer {
|
||||
constructor() {
|
||||
// FOR_JSDOC_ONLY is a macro that deletes its argument.
|
||||
|
@ -1151,7 +1168,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
*/
|
||||
this.f_contiguous;
|
||||
});
|
||||
throw new TypeError('PyBuffer is not a constructor');
|
||||
throw new TypeError("PyBuffer is not a constructor");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1177,16 +1194,14 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
// access like `pyodide.globals.x`.
|
||||
let globalsPropertyAccessWarned = false;
|
||||
let globalsPropertyAccessWarningMsg =
|
||||
"Access to pyodide.globals via pyodide.globals.key is deprecated and " +
|
||||
"will be removed in version 0.18.0. Use pyodide.globals.get('key'), " +
|
||||
"pyodide.globals.set('key', value), pyodide.globals.delete('key') instead.";
|
||||
"Access to pyodide.globals via pyodide.globals.key is deprecated and " +
|
||||
"will be removed in version 0.18.0. Use pyodide.globals.get('key'), " +
|
||||
"pyodide.globals.set('key', value), pyodide.globals.delete('key') instead.";
|
||||
let NamespaceProxyHandlers = {
|
||||
// clang-format off
|
||||
has : function(obj, key) {
|
||||
has: function (obj, key) {
|
||||
return Reflect.has(obj, key) || obj.has(key);
|
||||
},
|
||||
// clang-format on
|
||||
get : function(obj, key) {
|
||||
get: function (obj, key) {
|
||||
if (Reflect.has(obj, key)) {
|
||||
return Reflect.get(obj, key);
|
||||
}
|
||||
|
@ -1197,7 +1212,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
}
|
||||
return result;
|
||||
},
|
||||
set : function(obj, key, value) {
|
||||
set: function (obj, key, value) {
|
||||
if (Reflect.has(obj, key)) {
|
||||
throw new Error(`Cannot set read only field ${key}`);
|
||||
}
|
||||
|
@ -1207,7 +1222,7 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
}
|
||||
obj.set(key, value);
|
||||
},
|
||||
ownKeys : function(obj) {
|
||||
ownKeys: function (obj) {
|
||||
let result = new Set(Reflect.ownKeys(obj));
|
||||
let iter = obj.keys();
|
||||
for (let key of iter) {
|
||||
|
@ -1215,13 +1230,11 @@ JS_FILE(pyproxy_init_js, () => {0,0; /* Magic, see include_js_file.h */
|
|||
}
|
||||
iter.destroy();
|
||||
return Array.from(result);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
Module.wrapNamespace = function wrapNamespace(ns) {
|
||||
return new Proxy(ns, NamespaceProxyHandlers);
|
||||
};
|
||||
// clang-format on
|
||||
return 0;
|
||||
});
|
||||
|
|
|
@ -17,89 +17,92 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
* is true if the format suggests a big endian array.
|
||||
* @private
|
||||
*/
|
||||
Module.processBufferFormatString = function(formatStr, errorMessage = "") {
|
||||
Module.processBufferFormatString = function (formatStr, errorMessage = "") {
|
||||
if (formatStr.length > 2) {
|
||||
throw new Error("Expected format string to have length <= 2, " +
|
||||
`got '${formatStr}'.` + errorMessage);
|
||||
throw new Error(
|
||||
"Expected format string to have length <= 2, " +
|
||||
`got '${formatStr}'.` +
|
||||
errorMessage
|
||||
);
|
||||
}
|
||||
let formatChar = formatStr.slice(-1);
|
||||
let alignChar = formatStr.slice(0, -1);
|
||||
let bigEndian;
|
||||
switch (alignChar) {
|
||||
case "!":
|
||||
case ">":
|
||||
bigEndian = true;
|
||||
break;
|
||||
case "<":
|
||||
case "@":
|
||||
case "=":
|
||||
case "":
|
||||
bigEndian = false;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unrecognized alignment character ${alignChar}.` +
|
||||
errorMessage);
|
||||
case "!":
|
||||
case ">":
|
||||
bigEndian = true;
|
||||
break;
|
||||
case "<":
|
||||
case "@":
|
||||
case "=":
|
||||
case "":
|
||||
bigEndian = false;
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unrecognized alignment character ${alignChar}.` + errorMessage
|
||||
);
|
||||
}
|
||||
let arrayType;
|
||||
switch (formatChar) {
|
||||
case 'b':
|
||||
arrayType = Int8Array;
|
||||
break;
|
||||
case 's':
|
||||
case 'p':
|
||||
case 'c':
|
||||
case 'B':
|
||||
case '?':
|
||||
arrayType = Uint8Array;
|
||||
break;
|
||||
case 'h':
|
||||
arrayType = Int16Array;
|
||||
break;
|
||||
case 'H':
|
||||
arrayType = Uint16Array;
|
||||
break;
|
||||
case 'i':
|
||||
case 'l':
|
||||
case 'n':
|
||||
arrayType = Int32Array;
|
||||
break;
|
||||
case 'I':
|
||||
case 'L':
|
||||
case 'N':
|
||||
case 'P':
|
||||
arrayType = Uint32Array;
|
||||
break;
|
||||
case 'q':
|
||||
// clang-format off
|
||||
if (globalThis.BigInt64Array === undefined) {
|
||||
// clang-format on
|
||||
throw new Error("BigInt64Array is not supported on this browser." +
|
||||
errorMessage);
|
||||
}
|
||||
arrayType = BigInt64Array;
|
||||
break;
|
||||
case 'Q':
|
||||
// clang-format off
|
||||
if (globalThis.BigUint64Array === undefined) {
|
||||
// clang-format on
|
||||
throw new Error("BigUint64Array is not supported on this browser." +
|
||||
errorMessage);
|
||||
}
|
||||
arrayType = BigUint64Array;
|
||||
break;
|
||||
case 'f':
|
||||
arrayType = Float32Array;
|
||||
break;
|
||||
case 'd':
|
||||
arrayType = Float64Array;
|
||||
break;
|
||||
case "e":
|
||||
throw new Error("Javascript has no Float16 support.");
|
||||
default:
|
||||
throw new Error(`Unrecognized format character '${formatChar}'.` +
|
||||
errorMessage);
|
||||
case "b":
|
||||
arrayType = Int8Array;
|
||||
break;
|
||||
case "s":
|
||||
case "p":
|
||||
case "c":
|
||||
case "B":
|
||||
case "?":
|
||||
arrayType = Uint8Array;
|
||||
break;
|
||||
case "h":
|
||||
arrayType = Int16Array;
|
||||
break;
|
||||
case "H":
|
||||
arrayType = Uint16Array;
|
||||
break;
|
||||
case "i":
|
||||
case "l":
|
||||
case "n":
|
||||
arrayType = Int32Array;
|
||||
break;
|
||||
case "I":
|
||||
case "L":
|
||||
case "N":
|
||||
case "P":
|
||||
arrayType = Uint32Array;
|
||||
break;
|
||||
case "q":
|
||||
if (globalThis.BigInt64Array === undefined) {
|
||||
throw new Error(
|
||||
"BigInt64Array is not supported on this browser." + errorMessage
|
||||
);
|
||||
}
|
||||
arrayType = BigInt64Array;
|
||||
break;
|
||||
case "Q":
|
||||
if (globalThis.BigUint64Array === undefined) {
|
||||
throw new Error(
|
||||
"BigUint64Array is not supported on this browser." + errorMessage
|
||||
);
|
||||
}
|
||||
arrayType = BigUint64Array;
|
||||
break;
|
||||
case "f":
|
||||
arrayType = Float32Array;
|
||||
break;
|
||||
case "d":
|
||||
arrayType = Float64Array;
|
||||
break;
|
||||
case "e":
|
||||
throw new Error("Javascript has no Float16 support.");
|
||||
default:
|
||||
throw new Error(
|
||||
`Unrecognized format character '${formatChar}'.` + errorMessage
|
||||
);
|
||||
}
|
||||
return [ arrayType, bigEndian ];
|
||||
return [arrayType, bigEndian];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -113,7 +116,7 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
* the WASM heap)
|
||||
* @private
|
||||
*/
|
||||
Module.python2js_buffer_1d_contiguous = function(ptr, stride, n) {
|
||||
Module.python2js_buffer_1d_contiguous = function (ptr, stride, n) {
|
||||
"use strict";
|
||||
let byteLength = stride * n;
|
||||
// Note: slice here is a copy (as opposed to subarray which is not)
|
||||
|
@ -135,8 +138,13 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
* the WASM heap)
|
||||
* @private
|
||||
*/
|
||||
Module.python2js_buffer_1d_noncontiguous = function(ptr, stride, suboffset, n,
|
||||
itemsize) {
|
||||
Module.python2js_buffer_1d_noncontiguous = function (
|
||||
ptr,
|
||||
stride,
|
||||
suboffset,
|
||||
n,
|
||||
itemsize
|
||||
) {
|
||||
"use strict";
|
||||
let byteLength = itemsize * n;
|
||||
// Make new memory of the appropriate size
|
||||
|
@ -171,13 +179,12 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
* @returns A nested Javascript array, the result of the conversion.
|
||||
* @private
|
||||
*/
|
||||
Module._python2js_buffer_recursive = function(ptr, curdim, bufferData) {
|
||||
Module._python2js_buffer_recursive = function (ptr, curdim, bufferData) {
|
||||
"use strict";
|
||||
// When indexing HEAP32 we need to divide the pointer by 4
|
||||
let n = HEAP32[bufferData.shape / 4 + curdim];
|
||||
let stride = HEAP32[bufferData.strides / 4 + curdim];
|
||||
let suboffset = -1;
|
||||
// clang-format off
|
||||
if (bufferData.suboffsets !== 0) {
|
||||
suboffset = HEAP32[bufferData.suboffsets / 4 + curdim];
|
||||
}
|
||||
|
@ -188,11 +195,15 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
arraybuffer = Module.python2js_buffer_1d_contiguous(ptr, stride, n);
|
||||
} else {
|
||||
arraybuffer = Module.python2js_buffer_1d_noncontiguous(
|
||||
ptr, stride, suboffset, n, bufferData.itemsize);
|
||||
ptr,
|
||||
stride,
|
||||
suboffset,
|
||||
n,
|
||||
bufferData.itemsize
|
||||
);
|
||||
}
|
||||
return bufferData.converter(arraybuffer);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
let result = [];
|
||||
for (let i = 0; i < n; ++i) {
|
||||
|
@ -203,7 +214,8 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
curptr = HEAP32[curptr / 4] + suboffset;
|
||||
}
|
||||
result.push(
|
||||
Module._python2js_buffer_recursive(curPtr, curdim + 1, bufferData));
|
||||
Module._python2js_buffer_recursive(curPtr, curdim + 1, bufferData)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
@ -224,45 +236,39 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
* conversion.
|
||||
* @returns A converter function ArrayBuffer => TypedArray
|
||||
*/
|
||||
Module.get_converter = function(format, itemsize) {
|
||||
Module.get_converter = function (format, itemsize) {
|
||||
"use strict";
|
||||
let formatStr = UTF8ToString(format);
|
||||
let [ArrayType, bigEndian] = Module.processBufferFormatString(formatStr);
|
||||
let formatChar = formatStr.slice(-1);
|
||||
// clang-format off
|
||||
switch (formatChar) {
|
||||
case "s":
|
||||
let decoder = new TextDecoder("utf8");
|
||||
return (buff) => decoder.decode(buff);
|
||||
case "?":
|
||||
return (buff) => Array.from(new Uint8Array(buff), x => !!x);
|
||||
return (buff) => Array.from(new Uint8Array(buff), (x) => !!x);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
if (!bigEndian) {
|
||||
// clang-format off
|
||||
return buff => new ArrayType(buff);
|
||||
// clang-format on
|
||||
return (buff) => new ArrayType(buff);
|
||||
}
|
||||
let getFuncName;
|
||||
let setFuncName;
|
||||
switch (itemsize) {
|
||||
case 2:
|
||||
getFuncName = "getUint16";
|
||||
setFuncName = "setUint16";
|
||||
break;
|
||||
case 4:
|
||||
getFuncName = "getUint32";
|
||||
setFuncName = "setUint32";
|
||||
break;
|
||||
case 8:
|
||||
getFuncName = "getFloat64";
|
||||
setFuncName = "setFloat64";
|
||||
break;
|
||||
default:
|
||||
// clang-format off
|
||||
throw new Error(`Unexpected size ${ itemsize }`);
|
||||
// clang-format on
|
||||
case 2:
|
||||
getFuncName = "getUint16";
|
||||
setFuncName = "setUint16";
|
||||
break;
|
||||
case 4:
|
||||
getFuncName = "getUint32";
|
||||
setFuncName = "setUint32";
|
||||
break;
|
||||
case 8:
|
||||
getFuncName = "getFloat64";
|
||||
setFuncName = "setFloat64";
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unexpected size ${itemsize}`);
|
||||
}
|
||||
function swapFunc(buff) {
|
||||
let dataview = new DataView(buff);
|
||||
|
@ -274,8 +280,6 @@ JS_FILE(python2js_buffer_init, () => {
|
|||
}
|
||||
return buff;
|
||||
}
|
||||
// clang-format off
|
||||
return buff => new ArrayType(swapFunc(buff));
|
||||
// clang-format on
|
||||
return (buff) => new ArrayType(swapFunc(buff));
|
||||
};
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ try:
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
""""""
|
||||
""" """
|
||||
|
||||
def object_entries(self) -> "JsProxy":
|
||||
"The Javascript API ``Object.entries(object)``"
|
||||
|
|
|
@ -136,7 +136,7 @@ class _InteractiveConsole(code.InteractiveConsole):
|
|||
self.compile.compiler.flags |= ast.PyCF_ALLOW_TOP_LEVEL_AWAIT # type: ignore
|
||||
|
||||
def redirect_stdstreams(self):
|
||||
""" Toggle stdout/stderr redirections. """
|
||||
"""Toggle stdout/stderr redirections."""
|
||||
# already redirected?
|
||||
if self._streams_redirected:
|
||||
return
|
||||
|
@ -193,7 +193,7 @@ class _InteractiveConsole(code.InteractiveConsole):
|
|||
self.restore_stdstreams()
|
||||
|
||||
def flush_all(self):
|
||||
""" Force stdout/stderr flush. """
|
||||
"""Force stdout/stderr flush."""
|
||||
with self.stdstreams_redirections():
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
@ -264,7 +264,7 @@ class _InteractiveConsole(code.InteractiveConsole):
|
|||
self.restore_stdstreams()
|
||||
|
||||
def banner(self):
|
||||
""" A banner similar to the one printed by the real Python interpreter. """
|
||||
"""A banner similar to the one printed by the real Python interpreter."""
|
||||
# copyied from https://github.com/python/cpython/blob/799f8489d418b7f9207d333eac38214931bd7dcc/Lib/code.py#L214
|
||||
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
|
||||
version = platform.python_version()
|
||||
|
|
259
src/pyodide.js
259
src/pyodide.js
|
@ -20,11 +20,12 @@ globalThis.pyodide = {};
|
|||
* @returns The Pyodide module.
|
||||
* @async
|
||||
*/
|
||||
globalThis.loadPyodide = async function(config = {}) {
|
||||
globalThis.loadPyodide = async function (config = {}) {
|
||||
if (globalThis.__pyodideLoading) {
|
||||
if (globalThis.languagePluginURL) {
|
||||
throw new Error(
|
||||
"Pyodide is already loading because languagePluginURL is defined.");
|
||||
"Pyodide is already loading because languagePluginURL is defined."
|
||||
);
|
||||
} else {
|
||||
throw new Error("Pyodide is already loading.");
|
||||
}
|
||||
|
@ -36,10 +37,10 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
// indexURL in any case.
|
||||
let baseURL = config.indexURL || "{{ PYODIDE_BASE_URL }}";
|
||||
if (baseURL.endsWith(".js")) {
|
||||
baseURL = baseURL.substr(0, baseURL.lastIndexOf('/'));
|
||||
baseURL = baseURL.substr(0, baseURL.lastIndexOf("/"));
|
||||
}
|
||||
if (!baseURL.endsWith("/")) {
|
||||
baseURL += '/';
|
||||
baseURL += "/";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -54,21 +55,28 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let loadScript;
|
||||
if (self.document) { // browser
|
||||
if (self.document) {
|
||||
// browser
|
||||
loadScript = (url) => import(url);
|
||||
} else if (self.importScripts) { // webworker
|
||||
loadScript = async (url) => { // This is async only for consistency
|
||||
} else if (self.importScripts) {
|
||||
// webworker
|
||||
loadScript = async (url) => {
|
||||
// This is async only for consistency
|
||||
self.importScripts(url);
|
||||
};
|
||||
} else {
|
||||
throw new Error("Cannot determine runtime environment");
|
||||
}
|
||||
|
||||
function recursiveDependencies(names, _messageCallback, errorCallback,
|
||||
sharedLibsOnly) {
|
||||
function recursiveDependencies(
|
||||
names,
|
||||
_messageCallback,
|
||||
errorCallback,
|
||||
sharedLibsOnly
|
||||
) {
|
||||
const packages = Module.packages.dependencies;
|
||||
const loadedPackages = Module.loadedPackages;
|
||||
const sharedLibraries = Module.packages.shared_library;
|
||||
|
@ -93,8 +101,11 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
const pkgname = _uri_to_package_name(name);
|
||||
if (pkgname !== undefined) {
|
||||
if (toLoad.has(pkgname) && toLoad.get(pkgname) !== name) {
|
||||
errorCallback(`Loading same package ${pkgname} from ${name} and ${
|
||||
toLoad.get(pkgname)}`);
|
||||
errorCallback(
|
||||
`Loading same package ${pkgname} from ${name} and ${toLoad.get(
|
||||
pkgname
|
||||
)}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
toLoad.set(pkgname, name);
|
||||
|
@ -129,15 +140,15 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
let package_uri = toLoad.get(pkg);
|
||||
if (package_uri != DEFAULT_CHANNEL) {
|
||||
return package_uri.replace(/\.js$/, ".data");
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
return baseURL + path;
|
||||
};
|
||||
|
||||
if (toLoad.size === 0) {
|
||||
return Promise.resolve('No new packages to load');
|
||||
return Promise.resolve("No new packages to load");
|
||||
} else {
|
||||
let packageNames = Array.from(toLoad.keys()).join(', ');
|
||||
let packageNames = Array.from(toLoad.keys()).join(", ");
|
||||
messageCallback(`Loading ${packageNames}`);
|
||||
}
|
||||
|
||||
|
@ -155,19 +166,21 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
continue;
|
||||
} else {
|
||||
errorCallback(
|
||||
`URI mismatch, attempting to load package ${pkg} from ${uri} ` +
|
||||
`while it is already loaded from ${
|
||||
loaded}. To override a dependency, ` +
|
||||
`load the custom package first.`);
|
||||
`URI mismatch, attempting to load package ${pkg} from ${uri} ` +
|
||||
`while it is already loaded from ${loaded}. To override a dependency, ` +
|
||||
`load the custom package first.`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let scriptSrc = uri === DEFAULT_CHANNEL ? `${baseURL}${pkg}.js` : uri;
|
||||
messageCallback(`Loading ${pkg} from ${scriptSrc}`);
|
||||
scriptPromises.push(loadScript(scriptSrc).catch(() => {
|
||||
errorCallback(`Couldn't load package from URL ${scriptSrc}`);
|
||||
toLoad.delete(pkg);
|
||||
}));
|
||||
scriptPromises.push(
|
||||
loadScript(scriptSrc).catch(() => {
|
||||
errorCallback(`Couldn't load package from URL ${scriptSrc}`);
|
||||
toLoad.delete(pkg);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// When the JS loads, it synchronously adds a runDependency to emscripten.
|
||||
|
@ -175,7 +188,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
// emscripten. This function returns a promise that resolves when there are
|
||||
// no pending runDependencies.
|
||||
function waitRunDependency() {
|
||||
const promise = new Promise(r => {
|
||||
const promise = new Promise((r) => {
|
||||
Module.monitorRunDependencies = (n) => {
|
||||
if (n === 0) {
|
||||
r();
|
||||
|
@ -207,10 +220,10 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
|
||||
let resolveMsg;
|
||||
if (packageList.length > 0) {
|
||||
let packageNames = packageList.join(', ');
|
||||
let packageNames = packageList.join(", ");
|
||||
resolveMsg = `Loaded ${packageNames}`;
|
||||
} else {
|
||||
resolveMsg = 'No packages loaded';
|
||||
resolveMsg = "No packages loaded";
|
||||
}
|
||||
|
||||
Module.reportUndefinedSymbols();
|
||||
|
@ -219,9 +232,10 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
|
||||
// We have to invalidate Python's import caches, or it won't
|
||||
// see the new files.
|
||||
Module.runPythonSimple('import importlib\n' +
|
||||
'importlib.invalidate_caches()\n');
|
||||
};
|
||||
Module.runPythonSimple(
|
||||
"import importlib\n" + "importlib.invalidate_caches()\n"
|
||||
);
|
||||
}
|
||||
|
||||
// This is a promise that is resolved iff there are no pending package loads.
|
||||
// It never fails.
|
||||
|
@ -235,7 +249,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
async function acquirePackageLock() {
|
||||
let old_lock = _package_lock;
|
||||
let releaseLock;
|
||||
_package_lock = new Promise(resolve => releaseLock = resolve);
|
||||
_package_lock = new Promise((resolve) => (releaseLock = resolve));
|
||||
await old_lock;
|
||||
return releaseLock;
|
||||
}
|
||||
|
@ -268,7 +282,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* messages (optional)
|
||||
* @async
|
||||
*/
|
||||
Module.loadPackage = async function(names, messageCallback, errorCallback) {
|
||||
Module.loadPackage = async function (names, messageCallback, errorCallback) {
|
||||
if (Module.isPyProxy(names)) {
|
||||
let temp;
|
||||
try {
|
||||
|
@ -280,14 +294,18 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
}
|
||||
|
||||
if (!Array.isArray(names)) {
|
||||
names = [ names ];
|
||||
names = [names];
|
||||
}
|
||||
// get shared library packages and load those first
|
||||
// otherwise bad things happen with linking them in firefox.
|
||||
let sharedLibraryNames = [];
|
||||
try {
|
||||
let sharedLibraryPackagesToLoad =
|
||||
recursiveDependencies(names, messageCallback, errorCallback, true);
|
||||
let sharedLibraryPackagesToLoad = recursiveDependencies(
|
||||
names,
|
||||
messageCallback,
|
||||
errorCallback,
|
||||
true
|
||||
);
|
||||
for (let pkg of sharedLibraryPackagesToLoad) {
|
||||
sharedLibraryNames.push(pkg[0]);
|
||||
}
|
||||
|
@ -310,20 +328,23 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
}
|
||||
}
|
||||
let dynamicLoadHandler = {
|
||||
get : function(obj, prop) {
|
||||
if (prop === 'handle') {
|
||||
return function(bytes, name) {
|
||||
get: function (obj, prop) {
|
||||
if (prop === "handle") {
|
||||
return function (bytes, name) {
|
||||
obj[prop].apply(obj, arguments);
|
||||
this["asyncWasmLoadPromise"] =
|
||||
this["asyncWasmLoadPromise"].then(function() {
|
||||
Module.loadDynamicLibrary(name,
|
||||
{global : true, nodelete : true})
|
||||
this["asyncWasmLoadPromise"] = this["asyncWasmLoadPromise"].then(
|
||||
function () {
|
||||
Module.loadDynamicLibrary(name, {
|
||||
global: true,
|
||||
nodelete: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
} else {
|
||||
return obj[prop];
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
var loadPluginOverride = new Proxy(oldPlugin, dynamicLoadHandler);
|
||||
// restore the preload plugin
|
||||
|
@ -331,11 +352,17 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
|
||||
let releaseLock = await acquirePackageLock();
|
||||
try {
|
||||
await _loadPackage(sharedLibraryNames, messageCallback || console.log,
|
||||
errorCallback || console.error);
|
||||
await _loadPackage(
|
||||
sharedLibraryNames,
|
||||
messageCallback || console.log,
|
||||
errorCallback || console.error
|
||||
);
|
||||
Module.preloadPlugins.shift(loadPluginOverride);
|
||||
await _loadPackage(names, messageCallback || console.log,
|
||||
errorCallback || console.error);
|
||||
await _loadPackage(
|
||||
names,
|
||||
messageCallback || console.log,
|
||||
errorCallback || console.error
|
||||
);
|
||||
} finally {
|
||||
releaseLock();
|
||||
}
|
||||
|
@ -357,42 +384,39 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
}
|
||||
try {
|
||||
recurse();
|
||||
} catch (err) {
|
||||
;
|
||||
}
|
||||
} catch (err) {}
|
||||
|
||||
let recursionLimit = depth / 50;
|
||||
if (recursionLimit > 1000) {
|
||||
recursionLimit = 1000;
|
||||
}
|
||||
pyodide.runPythonSimple(
|
||||
`import sys; sys.setrecursionlimit(int(${recursionLimit}))`);
|
||||
};
|
||||
`import sys; sys.setrecursionlimit(int(${recursionLimit}))`
|
||||
);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Rearrange namespace for public API
|
||||
// clang-format off
|
||||
let PUBLIC_API = [
|
||||
'globals',
|
||||
'pyodide_py',
|
||||
'version',
|
||||
'loadPackage',
|
||||
'loadPackagesFromImports',
|
||||
'loadedPackages',
|
||||
'isPyProxy',
|
||||
'pyimport',
|
||||
'runPython',
|
||||
'runPythonAsync',
|
||||
'registerJsModule',
|
||||
'unregisterJsModule',
|
||||
'setInterruptBuffer',
|
||||
'toPy',
|
||||
'PythonError',
|
||||
"globals",
|
||||
"pyodide_py",
|
||||
"version",
|
||||
"loadPackage",
|
||||
"loadPackagesFromImports",
|
||||
"loadedPackages",
|
||||
"isPyProxy",
|
||||
"pyimport",
|
||||
"runPython",
|
||||
"runPythonAsync",
|
||||
"registerJsModule",
|
||||
"unregisterJsModule",
|
||||
"setInterruptBuffer",
|
||||
"toPy",
|
||||
"PythonError",
|
||||
];
|
||||
// clang-format on
|
||||
|
||||
function makePublicAPI(module, public_api) {
|
||||
let namespace = {_module : module};
|
||||
let namespace = { _module: module };
|
||||
module.public_api = namespace;
|
||||
for (let name of public_api) {
|
||||
namespace[name] = module[name];
|
||||
|
@ -405,37 +429,41 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
|
||||
Module.noImageDecoding = true;
|
||||
Module.noAudioDecoding = true;
|
||||
Module.noWasmDecoding =
|
||||
false; // we preload wasm using the built in plugin now
|
||||
Module.noWasmDecoding = false; // we preload wasm using the built in plugin now
|
||||
Module.preloadedWasm = {};
|
||||
|
||||
let fatal_error_occurred = false;
|
||||
Module.fatal_error = function(e) {
|
||||
Module.fatal_error = function (e) {
|
||||
if (fatal_error_occurred) {
|
||||
console.error("Recursive call to fatal_error. Inner error was:");
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
fatal_error_occurred = true;
|
||||
console.error("Pyodide has suffered a fatal error. " +
|
||||
"Please report this to the Pyodide maintainers.");
|
||||
console.error("The cause of the fatal error was:")
|
||||
console.error(
|
||||
"Pyodide has suffered a fatal error. " +
|
||||
"Please report this to the Pyodide maintainers."
|
||||
);
|
||||
console.error("The cause of the fatal error was:");
|
||||
console.error(e);
|
||||
try {
|
||||
let fd_stdout = 1;
|
||||
Module.__Py_DumpTraceback(fd_stdout,
|
||||
Module._PyGILState_GetThisThreadState());
|
||||
Module.__Py_DumpTraceback(
|
||||
fd_stdout,
|
||||
Module._PyGILState_GetThisThreadState()
|
||||
);
|
||||
for (let key of PUBLIC_API) {
|
||||
if (key === "version") {
|
||||
continue;
|
||||
}
|
||||
Object.defineProperty(Module.public_api, key, {
|
||||
enumerable : true,
|
||||
configurable : true,
|
||||
get : () => {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: () => {
|
||||
throw new Error(
|
||||
"Pyodide already fatally failed and can no longer be used.");
|
||||
}
|
||||
"Pyodide already fatally failed and can no longer be used."
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (Module.on_fatal) {
|
||||
|
@ -469,7 +497,6 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
*/
|
||||
Module.globals = {}; // actually defined in runPythonSimple below
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* A Javascript error caused by a Python exception.
|
||||
*
|
||||
|
@ -494,7 +521,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
Module.PythonError = class PythonError {
|
||||
// actually defined in error_handling.c. TODO: would be good to move this
|
||||
// documentation and the definition of PythonError to error_handling.js
|
||||
constructor(){
|
||||
constructor() {
|
||||
/**
|
||||
* The Python traceback.
|
||||
* @type {string}
|
||||
|
@ -502,7 +529,6 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
this.message;
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -539,7 +565,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
Module.runPythonSimple = function(code) {
|
||||
Module.runPythonSimple = function (code) {
|
||||
let code_c_string = Module.stringToNewUTF8(code);
|
||||
let errcode;
|
||||
try {
|
||||
|
@ -567,11 +593,10 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* @returns The result of the Python code translated to Javascript. See the
|
||||
* documentation for :any:`pyodide.eval_code` for more info.
|
||||
*/
|
||||
Module.runPython = function(code, globals = Module.globals) {
|
||||
Module.runPython = function (code, globals = Module.globals) {
|
||||
return Module.pyodide_py.eval_code(code, globals);
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* Inspect a Python code chunk and use :js:func:`pyodide.loadPackage` to
|
||||
* install any known packages that the code chunk imports. Uses the Python API
|
||||
|
@ -593,7 +618,11 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* :any:`pyodide.loadPackage` (optional).
|
||||
* @async
|
||||
*/
|
||||
Module.loadPackagesFromImports = async function(code, messageCallback, errorCallback) {
|
||||
Module.loadPackagesFromImports = async function (
|
||||
code,
|
||||
messageCallback,
|
||||
errorCallback
|
||||
) {
|
||||
let imports = Module.pyodide_py.find_imports(code).toJs();
|
||||
if (imports.length === 0) {
|
||||
return;
|
||||
|
@ -607,11 +636,12 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
}
|
||||
if (packages.size) {
|
||||
await Module.loadPackage(
|
||||
Array.from(packages.keys()), messageCallback, errorCallback
|
||||
Array.from(packages.keys()),
|
||||
messageCallback,
|
||||
errorCallback
|
||||
);
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Access a Python object in the global namespace from Javascript.
|
||||
|
@ -622,10 +652,11 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* @param {string} name Python variable name
|
||||
* @returns The Python object translated to Javascript.
|
||||
*/
|
||||
Module.pyimport = name => {
|
||||
Module.pyimport = (name) => {
|
||||
console.warn(
|
||||
"Access to the Python global namespace via pyodide.pyimport is deprecated and " +
|
||||
"will be removed in version 0.18.0. Use pyodide.globals.get('key') instead.");
|
||||
"Access to the Python global namespace via pyodide.pyimport is deprecated and " +
|
||||
"will be removed in version 0.18.0. Use pyodide.globals.get('key') instead."
|
||||
);
|
||||
return Module.globals.get(name);
|
||||
};
|
||||
/**
|
||||
|
@ -649,7 +680,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* @returns The result of the Python code translated to Javascript.
|
||||
* @async
|
||||
*/
|
||||
Module.runPythonAsync = async function(code) {
|
||||
Module.runPythonAsync = async function (code) {
|
||||
let coroutine = Module.pyodide_py.eval_code_async(code, Module.globals);
|
||||
try {
|
||||
let result = await coroutine;
|
||||
|
@ -659,7 +690,6 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* Registers the Javascript object ``module`` as a Javascript module named
|
||||
* ``name``. This module can then be imported from Python using the standard
|
||||
|
@ -671,7 +701,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* @param {string} name Name of the Javascript module to add
|
||||
* @param {object} module Javascript object backing the module
|
||||
*/
|
||||
Module.registerJsModule = function(name, module) {
|
||||
Module.registerJsModule = function (name, module) {
|
||||
Module.pyodide_py.register_js_module(name, module);
|
||||
};
|
||||
|
||||
|
@ -686,10 +716,9 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
*
|
||||
* @param {string} name Name of the Javascript module to remove
|
||||
*/
|
||||
Module.unregisterJsModule = function(name) {
|
||||
Module.unregisterJsModule = function (name) {
|
||||
Module.pyodide_py.unregister_js_module(name);
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Convert the Javascript object to a Python object as best as possible.
|
||||
|
@ -705,10 +734,9 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* conversion.
|
||||
* @returns {PyProxy} The object converted to Python.
|
||||
*/
|
||||
Module.toPy = function(obj, depth = -1) {
|
||||
Module.toPy = function (obj, depth = -1) {
|
||||
// No point in converting these, it'd be dumb to proxy them so they'd just
|
||||
// get converted back by `js2python` at the end
|
||||
// clang-format off
|
||||
switch (typeof obj) {
|
||||
case "string":
|
||||
case "number":
|
||||
|
@ -717,7 +745,6 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
case "undefined":
|
||||
return obj;
|
||||
}
|
||||
// clang-format on
|
||||
if (!obj || Module.isPyProxy(obj)) {
|
||||
return obj;
|
||||
}
|
||||
|
@ -727,9 +754,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
try {
|
||||
obj_id = Module.hiwire.new_value(obj);
|
||||
py_result = Module.__js2python_convert(obj_id, new Map(), depth);
|
||||
// clang-format off
|
||||
if(py_result === 0){
|
||||
// clang-format on
|
||||
if (py_result === 0) {
|
||||
Module._pythonexc2js();
|
||||
}
|
||||
if (Module._JsProxy_Check(py_result)) {
|
||||
|
@ -738,9 +763,7 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
// return Module.pyproxy_new(py_result);
|
||||
}
|
||||
result = Module._python2js(py_result);
|
||||
// clang-format off
|
||||
if (result === 0) {
|
||||
// clang-format on
|
||||
Module._pythonexc2js();
|
||||
}
|
||||
} finally {
|
||||
|
@ -754,13 +777,13 @@ globalThis.loadPyodide = async function(config = {}) {
|
|||
* @param jsobj {any} Object to test.
|
||||
* @returns {bool} Is ``jsobj`` a :any:`PyProxy`?
|
||||
*/
|
||||
Module.isPyProxy = function(jsobj) {
|
||||
return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === 'PyProxy';
|
||||
Module.isPyProxy = function (jsobj) {
|
||||
return !!jsobj && jsobj.$$ !== undefined && jsobj.$$.type === "PyProxy";
|
||||
};
|
||||
|
||||
Module.locateFile = (path) => baseURL + path;
|
||||
|
||||
let moduleLoaded = new Promise(r => Module.postRun = r);
|
||||
let moduleLoaded = new Promise((r) => (Module.postRun = r));
|
||||
|
||||
const scriptSrc = `${baseURL}pyodide.asm.js`;
|
||||
|
||||
|
@ -794,7 +817,7 @@ def temp(Module):
|
|||
|
||||
Module.saveState = () => Module.pyodide_py._state.save_state();
|
||||
Module.restoreState = (state) =>
|
||||
Module.pyodide_py._state.restore_state(state);
|
||||
Module.pyodide_py._state.restore_state(state);
|
||||
|
||||
Module.init_dict.get("temp")(Module);
|
||||
// Module.runPython works starting from here!
|
||||
|
@ -816,8 +839,9 @@ def temp(Module):
|
|||
|
||||
if (globalThis.languagePluginUrl) {
|
||||
console.warn(
|
||||
"languagePluginUrl is deprecated and will be removed in version 0.18.0, " +
|
||||
"instead use loadPyodide({ indexURL : <some_url>})");
|
||||
"languagePluginUrl is deprecated and will be removed in version 0.18.0, " +
|
||||
"instead use loadPyodide({ indexURL : <some_url>})"
|
||||
);
|
||||
|
||||
/**
|
||||
* A deprecated parameter that specifies the Pyodide ``indexURL``. If present,
|
||||
|
@ -840,6 +864,7 @@ if (globalThis.languagePluginUrl) {
|
|||
* @type Promise
|
||||
* @deprecated Will be removed in version 0.18.0
|
||||
*/
|
||||
globalThis.languagePluginLoader =
|
||||
loadPyodide({indexURL : globalThis.languagePluginUrl});
|
||||
globalThis.languagePluginLoader = loadPyodide({
|
||||
indexURL: globalThis.languagePluginUrl,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
importScripts('./pyodide.js')
|
||||
importScripts("./pyodide.js");
|
||||
|
||||
onmessage = async function(e) {
|
||||
onmessage = async function (e) {
|
||||
try {
|
||||
const data = e.data;
|
||||
for (let key of Object.keys(data)) {
|
||||
if (key !== 'python') {
|
||||
if (key !== "python") {
|
||||
// Keys other than python must be arguments for the python script.
|
||||
// Set them on self, so that `from js import key` works.
|
||||
self[key] = data[key];
|
||||
|
@ -12,15 +12,15 @@ onmessage = async function(e) {
|
|||
}
|
||||
|
||||
if (typeof self.__pyodideLoading === "undefined") {
|
||||
await loadPyodide({indexURL : '{{ PYODIDE_BASE_URL }}'});
|
||||
await loadPyodide({ indexURL: "{{ PYODIDE_BASE_URL }}" });
|
||||
}
|
||||
await self.pyodide.loadPackagesFromImports(data.python);
|
||||
let results = await self.pyodide.runPythonAsync(data.python);
|
||||
self.postMessage({results});
|
||||
self.postMessage({ results });
|
||||
} catch (e) {
|
||||
// if you prefer messages with the error
|
||||
self.postMessage({error : e.message + '\n' + e.stack});
|
||||
self.postMessage({ error: e.message + "\n" + e.stack });
|
||||
// if you prefer onerror events
|
||||
// setTimeout(() => { throw err; });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
FILES="$(git ls-files --others --exclude-standard '*.c' '*.h' '*.js')"
|
||||
FILES+=" $(git diff HEAD --name-only '*.c' '*.h' '*.js')"
|
||||
FILES="$(git ls-files --others --exclude-standard '*.js')"
|
||||
FILES+=" $(git diff HEAD --name-only '*.js')"
|
||||
if [[ $FILES != " " ]]; then
|
||||
prettier --write ${FILES}
|
||||
fi
|
||||
|
||||
FILES="$(git ls-files --others --exclude-standard '*.c' '*.h')"
|
||||
FILES+=" $(git diff HEAD --name-only '*.c' '*.h')"
|
||||
if [[ $FILES != " " ]]; then
|
||||
clang-format-6.0 -i -verbose ${FILES}
|
||||
fi
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
#!/bin/bash
|
||||
FILES=$(git diff --cached --name-only *.c *.h *.js)
|
||||
if [ -z "$FILES" ]; then
|
||||
exit 0
|
||||
FILES=$(git diff --cached --name-only *.c *.h)
|
||||
if [ -n "$FILES" ]; then
|
||||
echo hi
|
||||
# Change files, stage changes
|
||||
clang-format-6.0 -verbose -i $FILES
|
||||
git add $FILES
|
||||
fi
|
||||
|
||||
# Change files, stage changes
|
||||
clang-format-6.0 -verbose -i $FILES
|
||||
git add $FILES
|
||||
FILES=$(git diff --cached --name-only *.js)
|
||||
if [ -n "$FILES" ]; then
|
||||
# Change files, stage changes
|
||||
./node_modules/.bin/prettier --write $FILES
|
||||
git add $FILES
|
||||
fi
|
||||
|
|
Loading…
Reference in New Issue