MAINT Use prettier to format javascript (#1554)

Co-authored-by: Roman Yurchak <rth.yurchak@gmail.com>
This commit is contained in:
Hood Chatham 2021-05-01 13:17:32 -04:00 committed by GitHub
parent 7cf5bd5809
commit ab1b6c8d24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 449 additions and 382 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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;
});

View File

@ -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));
};
});

View File

@ -30,7 +30,7 @@ try:
"""
def __init__(self):
""""""
""" """
def object_entries(self) -> "JsProxy":
"The Javascript API ``Object.entries(object)``"

View File

@ -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()

View File

@ -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,
});
}

View File

@ -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; });
}
}
};

View File

@ -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

View File

@ -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