Don't expose loadPyodide as global variable from ES6 module (#2249)

This commit is contained in:
Hood Chatham 2022-03-15 18:59:35 -07:00 committed by GitHub
parent 5bd042f6f7
commit 245e8e7a5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 39 additions and 30 deletions

View File

@ -55,6 +55,11 @@ substitutions:
way.
{pr}`2178`
- {{Enhancement}} When Pyodide is loaded as an ES6 module, no global
`loadPyodide` variable is created (instead, it should be accessed as an
attribute on the module).
{pr}`2249`
- {{Breaking}} Removed the `skip-host` key from the `meta.yaml` format. If
needed, install a host copy of the package with pip instead. {pr}`2256`

View File

@ -254,10 +254,6 @@ Module.handle_js_error = function (e: any) {
* easiest way is to only handle the exception in Python.
*/
export class PythonError extends Error {
/**
* The Python traceback.
*/
message: string;
/** The address of the error we are wrapping. We may later compare this
* against sys.last_value.
* WARNING: we don't own a reference to this pointer, dereferencing it

View File

@ -52,18 +52,23 @@ export function isPyProxy(jsobj: any): jsobj is PyProxy {
}
API.isPyProxy = isPyProxy;
declare var FinalizationRegistry: any;
declare var globalThis: any;
if (globalThis.FinalizationRegistry) {
Module.finalizationRegistry = new FinalizationRegistry(([ptr, cache]) => {
cache.leaked = true;
pyproxy_decref_cache(cache);
try {
Module._Py_DecRef(ptr);
} catch (e) {
// I'm not really sure what happens if an error occurs inside of a
// finalizer...
API.fatal_error(e);
Module.finalizationRegistry = new FinalizationRegistry(
([ptr, cache]: [ptr: number, cache: PyProxyCache]) => {
cache.leaked = true;
pyproxy_decref_cache(cache);
try {
Module._Py_DecRef(ptr);
} catch (e) {
// I'm not really sure what happens if an error occurs inside of a
// finalizer...
API.fatal_error(e);
}
}
});
);
// For some unclear reason this code screws up selenium FirefoxDriver. Works
// fine in chrome and when I test it in browser. It seems to be sensitive to
// changes that don't make a difference to the semantics.
@ -155,8 +160,8 @@ Module.pyproxy_new = function (ptrobj: number, cache?: PyProxyCache) {
};
function _getPtr(jsobj: any) {
let ptr = jsobj.$$.ptr;
if (ptr === null) {
let ptr: number = jsobj.$$.ptr;
if (ptr === 0) {
throw new Error(jsobj.$$.destroyed_msg);
}
return ptr;
@ -236,7 +241,7 @@ function pyproxy_decref_cache(cache: PyProxyCache) {
}
Module.pyproxy_destroy = function (proxy: PyProxy, destroyed_msg: string) {
if (proxy.$$.ptr === null) {
if (proxy.$$.ptr === 0) {
return;
}
let ptrobj = _getPtr(proxy);
@ -254,7 +259,7 @@ Module.pyproxy_destroy = function (proxy: PyProxy, destroyed_msg: string) {
// Maybe the destructor will call JavaScript code that will somehow try
// to use this proxy. Mark it deleted before decrementing reference count
// just in case!
proxy.$$.ptr = null;
proxy.$$.ptr = 0;
destroyed_msg += "\n" + `The object was of type "${proxy_type}" and `;
if (proxy_repr) {
destroyed_msg += `had repr "${proxy_repr}"`;
@ -941,7 +946,7 @@ let PyProxyHandlers = {
python_setattr(jsobj, jskey, jsval);
return true;
},
deleteProperty(jsobj: PyProxyClass, jskey: any) {
deleteProperty(jsobj: PyProxyClass, jskey: any): boolean {
let descr = Object.getOwnPropertyDescriptor(jsobj, jskey);
if (descr && !descr.writable) {
throw new TypeError(`Cannot delete read only field '${jskey}'`);
@ -955,7 +960,7 @@ let PyProxyHandlers = {
python_delattr(jsobj, jskey);
// Must return "false" if "jskey" is a nonconfigurable own property.
// Otherwise JavaScript will throw a TypeError.
return !descr || descr.configurable;
return !descr || !!descr.configurable;
},
ownKeys(jsobj: PyProxyClass) {
let ptrobj = _getPtr(jsobj);
@ -1484,6 +1489,7 @@ export class PyBuffer {
API.fatal_error(e);
}
this._released = true;
// @ts-ignore
this.data = null;
}
}

View File

@ -14,7 +14,7 @@ import {
PyProxyCallable,
PyBuffer,
TypedArray,
} from "../../build/pyodide";
} from "./pyodide";
async function main() {
let pyodide = await loadPyodide({ indexURL: "blah" });

View File

@ -46,7 +46,7 @@ const DEFAULT_CHANNEL = "default channel";
// Regexp for validating package name and URI
const package_uri_regexp = /^.*?([^\/]*)\.whl$/;
function _uri_to_package_name(package_uri: string): string {
function _uri_to_package_name(package_uri: string): string | undefined {
let match = package_uri_regexp.exec(package_uri);
if (match) {
let wheel_name = match[1].toLowerCase();
@ -202,6 +202,7 @@ function createLock() {
let releaseLock: () => void;
_lock = new Promise((resolve) => (releaseLock = resolve));
await old_lock;
// @ts-ignore
return releaseLock;
}
return acquireLock;

View File

@ -233,7 +233,7 @@ export async function loadPyodide(config: {
);
setStandardStreams(config.stdin, config.stdout, config.stderr);
setHomeDirectory(config.homedir);
setHomeDirectory(config.homedir!);
let moduleLoaded = new Promise((r) => (Module.postRun = r));
@ -270,4 +270,3 @@ export async function loadPyodide(config: {
pyodide.runPython("print('Python initialization complete')");
return pyodide;
}
(globalThis as any).loadPyodide = loadPyodide;

3
src/js/pyodide.umd.ts Normal file
View File

@ -0,0 +1,3 @@
import { loadPyodide } from "./pyodide";
export { loadPyodide };
(globalThis as any).loadPyodide = loadPyodide;

View File

@ -3,7 +3,7 @@ import { nodeResolve } from "@rollup/plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import ts from "rollup-plugin-ts";
function config({ input, format, minify, ext = "js" }) {
function config({ input, format, minify, ext }) {
const dir = `build/`;
// const minifierSuffix = minify ? ".min" : "";
const minifierSuffix = "";
@ -11,7 +11,7 @@ function config({ input, format, minify, ext = "js" }) {
input: `./src/js/${input}.ts`,
output: {
name: "loadPyodide",
file: `${dir}/${input}${minifierSuffix}.${ext}`,
file: `${dir}/pyodide${minifierSuffix}.${ext}`,
format,
sourcemap: true,
},
@ -39,5 +39,5 @@ export default [
// { input: "pyodide", format: "esm", minify: false, ext: "mjs" },
{ input: "pyodide", format: "esm", minify: true, ext: "mjs" },
// { input: "pyodide", format: "umd", minify: false },
{ input: "pyodide", format: "umd", minify: true },
{ input: "pyodide.umd", format: "umd", minify: true, ext: "js" },
].map(config);

View File

@ -4,7 +4,6 @@
"declaration": true,
"lib": ["ES2021", "DOM"],
"outDir": "../../build",
"rootDir": ".",
"esModuleInterop": true,
"target": "ES6",
"module": "ES2020",

View File

@ -19,7 +19,7 @@
</script>
<script type="module">
import { loadPyodide } from "./pyodide.mjs";
window.loadPyodide = loadPyodidea;
window.loadPyodide = loadPyodide;
</script>
</head>
<body></body>

View File

@ -322,7 +322,7 @@ def test_python2js_track_proxies(selenium):
function check(l){
for(let x of l){
if(pyodide.isPyProxy(x)){
assert(() => x.$$.ptr === null);
assert(() => x.$$.ptr === 0);
} else {
check(x);
}