diff --git a/.circleci/config.yml b/.circleci/config.yml index 3df8dd0af..67cfe19c3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -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 diff --git a/Dockerfile b/Dockerfile index cb6e19c07..bf64934b7 100644 --- a/Dockerfile +++ b/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 diff --git a/Makefile b/Makefile index aecfe3fd6..8b3570cd5 100644 --- a/Makefile +++ b/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 ' {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 */ * `_. * @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; }); diff --git a/src/core/python2js_buffer.js b/src/core/python2js_buffer.js index 38d1ae541..9e4c1869e 100644 --- a/src/core/python2js_buffer.js +++ b/src/core/python2js_buffer.js @@ -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)); }; }); diff --git a/src/pyodide-py/_pyodide/_core.py b/src/pyodide-py/_pyodide/_core.py index f32f38d47..6f8a67650 100644 --- a/src/pyodide-py/_pyodide/_core.py +++ b/src/pyodide-py/_pyodide/_core.py @@ -30,7 +30,7 @@ try: """ def __init__(self): - """""" + """ """ def object_entries(self) -> "JsProxy": "The Javascript API ``Object.entries(object)``" diff --git a/src/pyodide-py/pyodide/console.py b/src/pyodide-py/pyodide/console.py index cf3ccefbe..5fbd2407c 100644 --- a/src/pyodide-py/pyodide/console.py +++ b/src/pyodide-py/pyodide/console.py @@ -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() diff --git a/src/pyodide.js b/src/pyodide.js index a7b071eb9..88fe1c3c6 100644 --- a/src/pyodide.js +++ b/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 : })"); + "languagePluginUrl is deprecated and will be removed in version 0.18.0, " + + "instead use loadPyodide({ indexURL : })" + ); /** * 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, + }); } diff --git a/src/webworker.js b/src/webworker.js index 212b68ebe..0a8d6e3af 100644 --- a/src/webworker.js +++ b/src/webworker.js @@ -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; }); } -} +}; diff --git a/tools/apply-lint.sh b/tools/apply-lint.sh index 51b4b7daf..595b9cc71 100755 --- a/tools/apply-lint.sh +++ b/tools/apply-lint.sh @@ -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 diff --git a/tools/clang-format-precommit.sh b/tools/clang-format-precommit.sh index 2caf01576..d40745c90 100755 --- a/tools/clang-format-precommit.sh +++ b/tools/clang-format-precommit.sh @@ -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